Add switchdev_port_bridge_getlink_deferred() which does a deferred object dump operation, this is required for e.g: DSA switches which typically have sleeping I/O operations which is incompatible with being in atomic context obviously.
Signed-off-by: Florian Fainelli <f.faine...@gmail.com> --- include/net/switchdev.h | 3 ++ net/switchdev/switchdev.c | 79 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/include/net/switchdev.h b/include/net/switchdev.h index eba80c4fc56f..087761b0df49 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -189,6 +189,9 @@ int call_switchdev_notifiers(unsigned long val, struct net_device *dev, int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, u32 filter_mask, int nlflags); +int switchdev_port_bridge_getlink_deferred(struct sk_buff *skb, u32 pid, + u32 seq, struct net_device *dev, + u32 filter_mask, int nlflags); int switchdev_port_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags); int switchdev_port_bridge_dellink(struct net_device *dev, diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 4fa9972d72d2..ab614a9dd872 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -776,12 +776,14 @@ static int switchdev_port_vlan_dump_cb(struct switchdev_obj *obj) return err; } -static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, - u32 filter_mask) +static int __switchdev_port_vlan_fill(struct sk_buff *skb, + struct net_device *dev, + u32 filter_mask, u32 obj_flags) { struct switchdev_vlan_dump dump = { .vlan.obj.orig_dev = dev, .vlan.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, + .vlan.obj.flags = obj_flags, .skb = skb, .filter_mask = filter_mask, }; @@ -802,17 +804,27 @@ static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, return err == -EOPNOTSUPP ? 0 : err; } -/** - * switchdev_port_bridge_getlink - Get bridge port attributes - * - * @dev: port device - * - * Called for SELF on rtnl_bridge_getlink to get bridge port - * attributes. - */ -int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, - struct net_device *dev, u32 filter_mask, - int nlflags) +static int switchdev_port_vlan_fill_deferred(struct sk_buff *skb, + struct net_device *dev, + u32 filter_mask) +{ + return __switchdev_port_vlan_fill(skb, dev, filter_mask, + SWITCHDEV_F_DEFER); +} + +static int switchdev_port_vlan_fill(struct sk_buff *skb, + struct net_device *dev, + u32 filter_mask) +{ + return __switchdev_port_vlan_fill(skb, dev, filter_mask, 0); +} + +static int __switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, + u32 seq, struct net_device *dev, + u32 filter_mask, int nlflags, + int (*fill_cb)(struct sk_buff *skb, + struct net_device *d, + u32 filter_mask)) { struct switchdev_attr attr = { .orig_dev = dev, @@ -829,12 +841,49 @@ int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, if (err && err != -EOPNOTSUPP) return err; - return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, + return ndo_dflt_bridge_getlink(skb, pid, seq, d, mode, attr.u.brport_flags, mask, nlflags, - filter_mask, switchdev_port_vlan_fill); + filter_mask, fill_cb); +} + +/** + * switchdev_port_bridge_getlink - Get bridge port attributes + * + * @dev: port device + * + * Called for SELF on rtnl_bridge_getlink to get bridge port + * attributes. + */ +int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, + struct net_device *dev, u32 filter_mask, + int nlflags) +{ + return __switchdev_port_bridge_getlink(skb, pid, seq, dev, filter_mask, + nlflags, + switchdev_port_vlan_fill); } EXPORT_SYMBOL_GPL(switchdev_port_bridge_getlink); +/** + * switchdev_port_bridge_getlink_deferred - Get bridge port attributes + * (deferred variant) + * + * @dev: port device + * + * Called for SELF on rtnl_bridge_getlink to get bridge port + * attributes. + */ +int switchdev_port_bridge_getlink_deferred(struct sk_buff *skb, u32 pid, + u32 seq, struct net_device *dev, + u32 filter_mask, + int nlflags) +{ + return __switchdev_port_bridge_getlink(skb, pid, seq, dev, filter_mask, + nlflags, + switchdev_port_vlan_fill_deferred); +} +EXPORT_SYMBOL_GPL(switchdev_port_bridge_getlink_deferred); + static int switchdev_port_br_setflag(struct net_device *dev, struct nlattr *nlattr, unsigned long brport_flag) -- 2.9.3