diff options
author | JP Abgrall <jpa@google.com> | 2011-08-18 15:05:47 -0700 |
---|---|---|
committer | JP Abgrall <jpa@google.com> | 2011-08-19 19:03:17 -0700 |
commit | 97aca38ddd3421bb7f13bf1c41566b23429906ae (patch) | |
tree | 77a93128fe308de57d9f4a05526e4214e5c31b1b /net/netfilter | |
parent | efcf89c8eb62b7c0c5976cb94f892c891afea199 (diff) | |
download | kernel_samsung_espresso10-97aca38ddd3421bb7f13bf1c41566b23429906ae.zip kernel_samsung_espresso10-97aca38ddd3421bb7f13bf1c41566b23429906ae.tar.gz kernel_samsung_espresso10-97aca38ddd3421bb7f13bf1c41566b23429906ae.tar.bz2 |
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/netfilter')
-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 b9dcfde..968693c 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 */ |