|
@@ -544,6 +544,30 @@ void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
|
|
|
}
|
|
|
EXPORT_SYMBOL(genlmsg_put);
|
|
|
|
|
|
+static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
+{
|
|
|
+ struct genl_ops *ops = cb->data;
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ genl_lock();
|
|
|
+ rc = ops->dumpit(skb, cb);
|
|
|
+ genl_unlock();
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static int genl_lock_done(struct netlink_callback *cb)
|
|
|
+{
|
|
|
+ struct genl_ops *ops = cb->data;
|
|
|
+ int rc = 0;
|
|
|
+
|
|
|
+ if (ops->done) {
|
|
|
+ genl_lock();
|
|
|
+ rc = ops->done(cb);
|
|
|
+ genl_unlock();
|
|
|
+ }
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
static int genl_family_rcv_msg(struct genl_family *family,
|
|
|
struct sk_buff *skb,
|
|
|
struct nlmsghdr *nlh)
|
|
@@ -572,15 +596,32 @@ static int genl_family_rcv_msg(struct genl_family *family,
|
|
|
return -EPERM;
|
|
|
|
|
|
if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
|
|
|
- struct netlink_dump_control c = {
|
|
|
- .dump = ops->dumpit,
|
|
|
- .done = ops->done,
|
|
|
- };
|
|
|
+ int rc;
|
|
|
|
|
|
if (ops->dumpit == NULL)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- return netlink_dump_start(net->genl_sock, skb, nlh, &c);
|
|
|
+ if (!family->parallel_ops) {
|
|
|
+ struct netlink_dump_control c = {
|
|
|
+ .data = ops,
|
|
|
+ .dump = genl_lock_dumpit,
|
|
|
+ .done = genl_lock_done,
|
|
|
+ };
|
|
|
+
|
|
|
+ genl_unlock();
|
|
|
+ rc = netlink_dump_start(net->genl_sock, skb, nlh, &c);
|
|
|
+ genl_lock();
|
|
|
+
|
|
|
+ } else {
|
|
|
+ struct netlink_dump_control c = {
|
|
|
+ .dump = ops->dumpit,
|
|
|
+ .done = ops->done,
|
|
|
+ };
|
|
|
+
|
|
|
+ rc = netlink_dump_start(net->genl_sock, skb, nlh, &c);
|
|
|
+ }
|
|
|
+
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
if (ops->doit == NULL)
|