Subject: [PATCH] nethost: Cleanup the refcounting.... From: Eric W. Biederman Date: 1137670506 -0700 - Split the reference count into to counts. One that tracks when we should free a nethost and another that tracks if nethost is still in use. - Normalize the names of the nethost functions. This also made it easy to detect the places where we were peforming refcounts. - Only count processes and sockets as entities towards keeping a nethost alive. Count everything else as meerly users that should go away when the nethost destroctor event is called. The big benefit of this is it allows the possibility of catching bugs in object lifetimes. --- include/linux/nethost.h | 29 +++++++++++++++-------------- include/net/inet_timewait_sock.h | 2 +- kernel/exit.c | 2 +- kernel/fork.c | 4 ++-- net/core/host.c | 14 +++++++------- net/core/sock.c | 7 +++---- net/ipv4/af_inet.c | 1 - net/ipv4/inet_timewait_sock.c | 2 +- net/ipv4/inetpeer.c | 6 +++--- net/key/af_key.c | 2 +- net/xfrm/xfrm_policy.c | 4 ++-- net/xfrm/xfrm_state.c | 4 ++-- 12 files changed, 38 insertions(+), 39 deletions(-) eb4ec79f93f1747d7eb7616bfaa5e62abf3ba6ab diff --git a/include/linux/nethost.h b/include/linux/nethost.h index b0e7d75..650a972 100644 --- a/include/linux/nethost.h +++ b/include/linux/nethost.h @@ -26,12 +26,12 @@ struct nethost { }; -static inline void hold_host(struct nethost *host) +static inline void nethost_hold(struct nethost *host) { atomic_inc(&host->use_count); } -static inline void release_host(struct nethost *host) +static inline void nethost_release(struct nethost *host) { atomic_dec(&host->use_count); } @@ -49,17 +49,17 @@ extern int loopback_setup(struct net_dev #ifdef CONFIG_NET -extern void __put_host(struct nethost *host); -extern int __copy_host(int flags, struct task_struct *p); +extern void __nethost_put(struct nethost *host); +extern int __copy_nethost(int flags, struct task_struct *p); extern int nethost_init(void); #else /* ! CONFIG_NET */ -static inline void __put_host(struct nethost *host) +static inline void __nethost_put(struct nethost *host) { kfree(host); } -static inline void __copy_host(int flags, struct task_struct *p) +static inline void __copy_nethost(int flags, struct task_struct *p) { struct nethost *host; host = kmalloc(sizeof(*host), GFP_KERNEL); @@ -78,33 +78,34 @@ static inline void __copy_host(int flags #endif /* CONFIG_NET */ -static inline void get_host(struct nethost *host) +static inline struct nethost *nethost_get(struct nethost *host) { atomic_inc(&host->count); + return host; } -static inline void put_host(struct nethost *host) +static inline void nethost_put(struct nethost *host) { if (atomic_dec_and_test(&host->count)) - __put_host(host); + __nethost_put(host); } -static inline int copy_host(int flags, struct task_struct *p) +static inline int copy_nethost(int flags, struct task_struct *p) { int ret = 0; if (likely(!(flags & CLONE_NHOST))) { - get_host(p->host); + nethost_get(p->host); } else { - ret = __copy_host(flags, p); + ret = __copy_nethost(flags, p); } return ret; } -static inline void exit_host(struct task_struct *tsk) +static inline void exit_nethost(struct task_struct *tsk) { struct nethost *host = tsk->host; tsk->host = NULL; - put_host(host); + nethost_put(host); } #endif /* _LINUX_NETHOST_H */ diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 4d44721..bf22a60 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -199,7 +199,7 @@ static inline void inet_twsk_put(struct printk(KERN_DEBUG "%s timewait_sock %p released\n", tw->tw_prot->name, tw); #endif - put_host(tw->tw_host); + nethost_release(tw->tw_host); kmem_cache_free(tw->tw_prot->twsk_slab, tw); } } diff --git a/kernel/exit.c b/kernel/exit.c index f130e9b..216cb2b 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -885,7 +885,7 @@ fastcall NORET_TYPE void do_exit(long co exit_thread(); cpuset_exit(tsk); exit_keys(tsk); - exit_host(tsk); + exit_nethost(tsk); if (group_dead && tsk->signal->leader) disassociate_ctty(1); diff --git a/kernel/fork.c b/kernel/fork.c index 8883c56..b77cd8f 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1007,7 +1007,7 @@ static task_t *copy_process(unsigned lon if ((retval = audit_alloc(p))) goto bad_fork_cleanup_security; /* copy all the process information */ - if ((retval = copy_host(clone_flags, p))) + if ((retval = copy_nethost(clone_flags, p))) goto bad_fork_cleanup_audit; if ((retval = copy_sysvipc(clone_flags, p))) goto bad_fork_cleanup_host; @@ -1208,7 +1208,7 @@ bad_fork_cleanup_semundo: bad_fork_cleanup_sysvipc: exit_sysvipc(p); bad_fork_cleanup_host: - exit_host(p); + exit_nethost(p); bad_fork_cleanup_audit: audit_free(p); bad_fork_cleanup_security: diff --git a/net/core/host.c b/net/core/host.c index d69b72c..a3bacef 100644 --- a/net/core/host.c +++ b/net/core/host.c @@ -20,7 +20,7 @@ extern void netdev_sysfs_fini(struct net */ static struct notifier_block *nethost_chain; -static void nethost_fini(struct nethost *host) +static void nethost_destroy(struct nethost *host) { unsigned long rebroadcast_time, warning_time; @@ -42,7 +42,7 @@ static void nethost_fini(struct nethost } msleep(250); if (time_after(jiffies, warning_time + 10 * HZ)) { - printk(KERN_EMERG "nethost_fini: " + printk(KERN_EMERG "nethost_destroy: " "waiting for nethost to become free. Usage " "count = %d\n", atomic_read(&host->use_count)); @@ -52,7 +52,7 @@ static void nethost_fini(struct nethost } -static void do_put_host(void *arg) +static void nethost_cleanup(void *arg) { struct nethost *host = arg; struct net_device *lo, *dev; @@ -97,7 +97,7 @@ static void do_put_host(void *arg) rtnl_unlock(); /* Cleanup any remaning protocol state */ - nethost_fini(host); + nethost_destroy(host); /* Now free the sysfs class */ netdev_sysfs_fini(host); @@ -106,10 +106,10 @@ static void do_put_host(void *arg) kfree(host); } -void __put_host(struct nethost *host) +void __nethost_put(struct nethost *host) { /* Cleanup the host structure in process context */ - INIT_WORK(&host->work, do_put_host, host); + INIT_WORK(&host->work, nethost_cleanup, host); schedule_work(&host->work); } @@ -147,7 +147,7 @@ out_undo: } -int __copy_host(int flags, struct task_struct *p) +int __copy_nethost(int flags, struct task_struct *p) { struct nethost *host; int err; diff --git a/net/core/sock.c b/net/core/sock.c index 9fe5e4f..f4855f9 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -660,8 +660,7 @@ struct sock *sk_alloc(int family, gfp_t */ sk->sk_prot = sk->sk_prot_creator = prot; sock_lock_init(sk); - sk->sk_host = current->host; - get_host(sk->sk_host); + sk->sk_host = nethost_get(current->host); } if (security_sk_alloc(sk, family, priority)) @@ -701,7 +700,7 @@ void sk_free(struct sock *sk) __FUNCTION__, atomic_read(&sk->sk_omem_alloc)); if (sk->sk_host) - put_host(sk->sk_host); + nethost_put(sk->sk_host); security_sk_free(sk); if (sk->sk_prot_creator->slab != NULL) kmem_cache_free(sk->sk_prot_creator->slab, sk); @@ -778,7 +777,7 @@ struct sock *sk_clone(const struct sock if (newsk->sk_prot->sockets_allocated) atomic_inc(newsk->sk_prot->sockets_allocated); - get_host(newsk->sk_host); + nethost_get(newsk->sk_host); } out: return newsk; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4f4d04f..8ce385e 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -398,7 +398,6 @@ lookup_protocol: if (sk->sk_prot->init) { err = sk->sk_prot->init(sk); if (err) { - put_host(sk->sk_host); sk_common_release(sk); } } diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 4343e52..e6e0451 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -110,7 +110,7 @@ struct inet_timewait_sock *inet_twsk_all tw->tw_ipv6only = 0; tw->tw_prot = sk->sk_prot_creator; tw->tw_host = sk->sk_host; - get_host(tw->tw_host); + nethost_hold(tw->tw_host); atomic_set(&tw->tw_refcnt, 1); inet_twsk_dead_node_init(tw); } diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 4b37af2..b936cbb 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -333,7 +333,7 @@ static void unlink_from_pool(struct inet write_unlock_bh(&peer_pool_lock); if (do_free) { - put_host(p->host); + nethost_release(p->host); kmem_cache_free(peer_cachep, p); } else @@ -414,7 +414,7 @@ struct inet_peer *inet_getpeer(struct ne n->ip_id_count = secure_ip_id(daddr); n->tcp_ts_stamp = 0; n->host = host; - get_host(n->host); + nethost_hold(n->host); write_lock_bh(&peer_pool_lock); /* Check if an entry has suddenly appeared. */ @@ -441,7 +441,7 @@ out_free: /* Remove the entry from unused list if it was there. */ unlink_from_unused(p); /* Drop references to the network host */ - put_host(n->host); + nethost_release(n->host); /* Free preallocated the preallocated node. */ kmem_cache_free(peer_cachep, n); return p; diff --git a/net/key/af_key.c b/net/key/af_key.c index dee3c8b..9ce671e 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -970,7 +970,7 @@ static struct xfrm_state * pfkey_msg2xfr if (x == NULL) return ERR_PTR(-ENOBUFS); - get_host(host); + nethost_hold(host); x->host = host; x->id.proto = proto; x->id.spi = sa->sadb_sa_spi; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index a1b4938..c854426 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -242,7 +242,7 @@ struct xfrm_policy *xfrm_policy_alloc(st policy->timer.data = (unsigned long)policy; policy->timer.function = xfrm_policy_timer; policy->host = host; - get_host(policy->host); + nethost_hold(policy->host); } return policy; } @@ -261,7 +261,7 @@ void __xfrm_policy_destroy(struct xfrm_p if (del_timer(&policy->timer)) BUG(); - put_host(policy->host); + nethost_release(policy->host); kfree(policy); } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index a170716..50a810c 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -228,7 +228,7 @@ static int __xfrm_state_delete(struct xf list_del(&x->byspi); atomic_dec(&x->refcnt); } - put_host(x->host); + nethost_release(x->host); x->host = NULL; spin_unlock(&xfrm_state_lock); if (del_timer(&x->timer)) @@ -383,7 +383,7 @@ xfrm_state_find(xfrm_address_t *daddr, x /* Initialize temporary selector matching only * to current session. */ x->host = fl->host; - get_host(x->host); + nethost_hold(x->host); xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); if (km_query(x, tmpl, pol) == 0) { -- 1.0.GIT