| From fc9e50f5a5a4e1fa9ba2756f745a13e693cf6a06 Mon Sep 17 00:00:00 2001 |
| From: Tom Herbert <tom@herbertland.com> |
| Date: Tue, 15 Dec 2015 15:41:37 -0800 |
| Subject: netlink: add a start callback for starting a netlink dump |
| |
| From: Tom Herbert <tom@herbertland.com> |
| |
| commit fc9e50f5a5a4e1fa9ba2756f745a13e693cf6a06 upstream. |
| |
| The start callback allows the caller to set up a context for the |
| dump callbacks. Presumably, the context can then be destroyed in |
| the done callback. |
| |
| Signed-off-by: Tom Herbert <tom@herbertland.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Cc: Guenter Roeck <linux@roeck-us.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| include/linux/netlink.h | 2 ++ |
| include/net/genetlink.h | 2 ++ |
| net/netlink/af_netlink.c | 4 ++++ |
| net/netlink/genetlink.c | 16 ++++++++++++++++ |
| 4 files changed, 24 insertions(+) |
| |
| --- a/include/linux/netlink.h |
| +++ b/include/linux/netlink.h |
| @@ -131,6 +131,7 @@ netlink_skb_clone(struct sk_buff *skb, g |
| struct netlink_callback { |
| struct sk_buff *skb; |
| const struct nlmsghdr *nlh; |
| + int (*start)(struct netlink_callback *); |
| int (*dump)(struct sk_buff * skb, |
| struct netlink_callback *cb); |
| int (*done)(struct netlink_callback *cb); |
| @@ -153,6 +154,7 @@ struct nlmsghdr * |
| __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags); |
| |
| struct netlink_dump_control { |
| + int (*start)(struct netlink_callback *); |
| int (*dump)(struct sk_buff *skb, struct netlink_callback *); |
| int (*done)(struct netlink_callback *); |
| void *data; |
| --- a/include/net/genetlink.h |
| +++ b/include/net/genetlink.h |
| @@ -114,6 +114,7 @@ static inline void genl_info_net_set(str |
| * @flags: flags |
| * @policy: attribute validation policy |
| * @doit: standard command callback |
| + * @start: start callback for dumps |
| * @dumpit: callback for dumpers |
| * @done: completion callback for dumps |
| * @ops_list: operations list |
| @@ -122,6 +123,7 @@ struct genl_ops { |
| const struct nla_policy *policy; |
| int (*doit)(struct sk_buff *skb, |
| struct genl_info *info); |
| + int (*start)(struct netlink_callback *cb); |
| int (*dumpit)(struct sk_buff *skb, |
| struct netlink_callback *cb); |
| int (*done)(struct netlink_callback *cb); |
| --- a/net/netlink/af_netlink.c |
| +++ b/net/netlink/af_netlink.c |
| @@ -2203,6 +2203,7 @@ int __netlink_dump_start(struct sock *ss |
| |
| cb = &nlk->cb; |
| memset(cb, 0, sizeof(*cb)); |
| + cb->start = control->start; |
| cb->dump = control->dump; |
| cb->done = control->done; |
| cb->nlh = nlh; |
| @@ -2216,6 +2217,9 @@ int __netlink_dump_start(struct sock *ss |
| |
| mutex_unlock(nlk->cb_mutex); |
| |
| + if (cb->start) |
| + cb->start(cb); |
| + |
| ret = netlink_dump(sk); |
| sock_put(sk); |
| |
| --- a/net/netlink/genetlink.c |
| +++ b/net/netlink/genetlink.c |
| @@ -513,6 +513,20 @@ void *genlmsg_put(struct sk_buff *skb, u |
| } |
| EXPORT_SYMBOL(genlmsg_put); |
| |
| +static int genl_lock_start(struct netlink_callback *cb) |
| +{ |
| + /* our ops are always const - netlink API doesn't propagate that */ |
| + const struct genl_ops *ops = cb->data; |
| + int rc = 0; |
| + |
| + if (ops->start) { |
| + genl_lock(); |
| + rc = ops->start(cb); |
| + genl_unlock(); |
| + } |
| + return rc; |
| +} |
| + |
| static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb) |
| { |
| /* our ops are always const - netlink API doesn't propagate that */ |
| @@ -577,6 +591,7 @@ static int genl_family_rcv_msg(struct ge |
| .module = family->module, |
| /* we have const, but the netlink API doesn't */ |
| .data = (void *)ops, |
| + .start = genl_lock_start, |
| .dump = genl_lock_dumpit, |
| .done = genl_lock_done, |
| }; |
| @@ -588,6 +603,7 @@ static int genl_family_rcv_msg(struct ge |
| } else { |
| struct netlink_dump_control c = { |
| .module = family->module, |
| + .start = ops->start, |
| .dump = ops->dumpit, |
| .done = ops->done, |
| }; |