@@ -693,6 +693,8 @@ struct proto {
int (*backlog_rcv) (struct sock *sk,
struct sk_buff *skb);
+ void (*free_socket)(struct sock *sk);
+
/* Keeping track of sk's, looking them up, and port selection methods. */
void (*hash)(struct sock *sk);
void (*unhash)(struct sock *sk);
@@ -1027,18 +1027,20 @@ out_free:
static void sk_prot_free(struct proto *prot, struct sock *sk)
{
- struct kmem_cache *slab;
- struct module *owner;
+ security_sk_free(sk);
+ if (prot->free_socket)
+ prot->free_socket(sk);
+ else {
+ struct kmem_cache *slab;
- owner = prot->owner;
- slab = prot->slab;
+ slab = prot->slab;
- security_sk_free(sk);
- if (slab != NULL)
- kmem_cache_free(slab, sk);
- else
- kfree(sk);
- module_put(owner);
+ if (slab != NULL)
+ kmem_cache_free(slab, sk);
+ else
+ kfree(sk);
+ module_put(prot->owner);
+ }
}
/**
@@ -81,6 +81,7 @@ struct netlink_sock {
struct mutex cb_def_mutex;
void (*netlink_rcv)(struct sk_buff *skb);
struct module *module;
+ struct rcu_head rcu;
};
struct listeners_rcu_head {
@@ -394,10 +395,22 @@ static void netlink_remove(struct sock *sk)
netlink_table_ungrab();
}
+static void rcu_free_socket(struct rcu_head *rcu)
+{
+ kfree(container_of(rcu, struct netlink_sock, rcu));
+ module_put(THIS_MODULE);
+}
+
+static void free_socket(struct sock *sk)
+{
+ call_rcu(&nlk_sk(sk)->rcu, rcu_free_socket);
+}
+
static struct proto netlink_proto = {
.name = "NETLINK",
.owner = THIS_MODULE,
.obj_size = sizeof(struct netlink_sock),
+ .free_socket = free_socket,
};
static int __netlink_create(struct net *net, struct socket *sock,