mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
genl: Fix genl dumpit() locking.
In case of genl-family with parallel ops off, dumpif() callback
is expected to run under genl_lock, But commit def3117493
(genl: Allow concurrent genl callbacks.) changed this behaviour
where only first dumpit() op was called under genl-lock.
For subsequent dump, only nlk->cb_lock was taken.
Following patch fixes it by defining locked dumpit() and done()
callback which takes care of genl-locking.
CC: Jesse Gross <jesse@nicira.com>
CC: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a3097bda78
commit
9b96309c5b
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user