diff options
author | JP Abgrall <jpa@google.com> | 2011-08-18 15:05:47 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:39:01 -0800 |
commit | 75b42c5c126340d437ac23bb21d69c176563d68e (patch) | |
tree | 846dfb982cf39342407159faa1160fb92a3fa55e /net | |
parent | df760f56dfdb8ece4d43f79afa3f6d4d32a1baa9 (diff) |
netfilter: xt_qtaguid: Fix sockfd_put() call within spinlock
sockfd_put() risks sleeping.
So when doing a delete ctrl command, defer the sockfd_put() and
kfree() to outside of the spinlock.
Change-Id: I5f8ab51d05888d885b2fbb035f61efa5b7abb88a
Signed-off-by: JP Abgrall <jpa@google.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/xt_qtaguid.c | 24 |
1 files changed, 17 insertions, 7 deletions
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index b9dcfde99762..968693cb1bc0 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -1325,6 +1325,7 @@ static int ctrl_cmd_delete(const char *input) struct iface_stat *iface_entry; struct rb_node *node; struct sock_tag *st_entry; + struct rb_root st_to_free_tree = RB_ROOT; struct tag_stat *ts_entry; struct tag_counter_set *tcs_entry; @@ -1362,18 +1363,27 @@ static int ctrl_cmd_delete(const char *input) continue; if (!acct_tag || st_entry->tag == tag) { - CT_DEBUG("qtaguid: ctrl_delete(): " - "erase st: sk=%p tag=0x%llx (uid=%u)\n", - st_entry->sk, - st_entry->tag, - entry_uid); rb_erase(&st_entry->sock_node, &sock_tag_tree); - sockfd_put(st_entry->socket); - kfree(st_entry); + /* Can't sockfd_put() within spinlock, do it later. */ + sock_tag_tree_insert(st_entry, &st_to_free_tree); } } spin_unlock_bh(&sock_tag_list_lock); + node = rb_first(&st_to_free_tree); + while (node) { + st_entry = rb_entry(node, struct sock_tag, sock_node); + node = rb_next(node); + CT_DEBUG("qtaguid: ctrl_delete(): " + "erase st: sk=%p tag=0x%llx (uid=%u)\n", + st_entry->sk, + st_entry->tag, + entry_uid); + rb_erase(&st_entry->sock_node, &st_to_free_tree); + sockfd_put(st_entry->socket); + kfree(st_entry); + } + tag = combine_atag_with_uid(acct_tag, uid); /* Delete tag counter-sets */ |