summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJP Abgrall <jpa@google.com>2011-08-18 15:05:47 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:39:01 -0800
commit75b42c5c126340d437ac23bb21d69c176563d68e (patch)
tree846dfb982cf39342407159faa1160fb92a3fa55e /net
parentdf760f56dfdb8ece4d43f79afa3f6d4d32a1baa9 (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.c24
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 */