From 097e66c578459f79e3a2128c54e9df5194e1419a Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 19 Nov 2007 22:29:30 -0800 Subject: [NET]: Make AF_UNIX per network namespace safe [v2] Because of the global nature of garbage collection, and because of the cost of per namespace hash tables unix_socket_table has been kept global. With a filter added on lookups so we don't see sockets from the wrong namespace. Currently I don't fold the namesapce into the hash so multiple namespaces using the same socket name will be guaranteed a hash collision. Changes from v1: - fixed unix_seq_open Signed-off-by: Denis V. Lunev Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- net/unix/af_unix.c | 118 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 92 insertions(+), 26 deletions(-) (limited to 'net/unix/af_unix.c') diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 060bba4567d..ecad42b72ad 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -270,7 +270,8 @@ static inline void unix_insert_socket(struct hlist_head *list, struct sock *sk) spin_unlock(&unix_table_lock); } -static struct sock *__unix_find_socket_byname(struct sockaddr_un *sunname, +static struct sock *__unix_find_socket_byname(struct net *net, + struct sockaddr_un *sunname, int len, int type, unsigned hash) { struct sock *s; @@ -279,6 +280,9 @@ static struct sock *__unix_find_socket_byname(struct sockaddr_un *sunname, sk_for_each(s, node, &unix_socket_table[hash ^ type]) { struct unix_sock *u = unix_sk(s); + if (s->sk_net != net) + continue; + if (u->addr->len == len && !memcmp(u->addr->name, sunname, len)) goto found; @@ -288,21 +292,22 @@ found: return s; } -static inline struct sock *unix_find_socket_byname(struct sockaddr_un *sunname, +static inline struct sock *unix_find_socket_byname(struct net *net, + struct sockaddr_un *sunname, int len, int type, unsigned hash) { struct sock *s; spin_lock(&unix_table_lock); - s = __unix_find_socket_byname(sunname, len, type, hash); + s = __unix_find_socket_byname(net, sunname, len, type, hash); if (s) sock_hold(s); spin_unlock(&unix_table_lock); return s; } -static struct sock *unix_find_socket_byinode(struct inode *i) +static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i) { struct sock *s; struct hlist_node *node; @@ -312,6 +317,9 @@ static struct sock *unix_find_socket_byinode(struct inode *i) &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { struct dentry *dentry = unix_sk(s)->dentry; + if (s->sk_net != net) + continue; + if(dentry && dentry->d_inode == i) { sock_hold(s); @@ -631,9 +639,6 @@ out: static int unix_create(struct net *net, struct socket *sock, int protocol) { - if (net != &init_net) - return -EAFNOSUPPORT; - if (protocol && protocol != PF_UNIX) return -EPROTONOSUPPORT; @@ -677,6 +682,7 @@ static int unix_release(struct socket *sock) static int unix_autobind(struct socket *sock) { struct sock *sk = sock->sk; + struct net *net = sk->sk_net; struct unix_sock *u = unix_sk(sk); static u32 ordernum = 1; struct unix_address * addr; @@ -703,7 +709,7 @@ retry: spin_lock(&unix_table_lock); ordernum = (ordernum+1)&0xFFFFF; - if (__unix_find_socket_byname(addr->name, addr->len, sock->type, + if (__unix_find_socket_byname(net, addr->name, addr->len, sock->type, addr->hash)) { spin_unlock(&unix_table_lock); /* Sanity yield. It is unusual case, but yet... */ @@ -723,7 +729,8 @@ out: mutex_unlock(&u->readlock); return err; } -static struct sock *unix_find_other(struct sockaddr_un *sunname, int len, +static struct sock *unix_find_other(struct net *net, + struct sockaddr_un *sunname, int len, int type, unsigned hash, int *error) { struct sock *u; @@ -741,7 +748,7 @@ static struct sock *unix_find_other(struct sockaddr_un *sunname, int len, err = -ECONNREFUSED; if (!S_ISSOCK(nd.dentry->d_inode->i_mode)) goto put_fail; - u=unix_find_socket_byinode(nd.dentry->d_inode); + u=unix_find_socket_byinode(net, nd.dentry->d_inode); if (!u) goto put_fail; @@ -757,7 +764,7 @@ static struct sock *unix_find_other(struct sockaddr_un *sunname, int len, } } else { err = -ECONNREFUSED; - u=unix_find_socket_byname(sunname, len, type, hash); + u=unix_find_socket_byname(net, sunname, len, type, hash); if (u) { struct dentry *dentry; dentry = unix_sk(u)->dentry; @@ -779,6 +786,7 @@ fail: static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sock *sk = sock->sk; + struct net *net = sk->sk_net; struct unix_sock *u = unix_sk(sk); struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; struct dentry * dentry = NULL; @@ -853,7 +861,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (!sunaddr->sun_path[0]) { err = -EADDRINUSE; - if (__unix_find_socket_byname(sunaddr, addr_len, + if (__unix_find_socket_byname(net, sunaddr, addr_len, sk->sk_type, hash)) { unix_release_addr(addr); goto out_unlock; @@ -919,6 +927,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { struct sock *sk = sock->sk; + struct net *net = sk->sk_net; struct sockaddr_un *sunaddr=(struct sockaddr_un*)addr; struct sock *other; unsigned hash; @@ -935,7 +944,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, goto out; restart: - other=unix_find_other(sunaddr, alen, sock->type, hash, &err); + other=unix_find_other(net, sunaddr, alen, sock->type, hash, &err); if (!other) goto out; @@ -1015,6 +1024,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, { struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; struct sock *sk = sock->sk; + struct net *net = sk->sk_net; struct unix_sock *u = unix_sk(sk), *newu, *otheru; struct sock *newsk = NULL; struct sock *other = NULL; @@ -1054,7 +1064,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, restart: /* Find listening sock. */ - other = unix_find_other(sunaddr, addr_len, sk->sk_type, hash, &err); + other = unix_find_other(net, sunaddr, addr_len, sk->sk_type, hash, &err); if (!other) goto out; @@ -1330,6 +1340,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, { struct sock_iocb *siocb = kiocb_to_siocb(kiocb); struct sock *sk = sock->sk; + struct net *net = sk->sk_net; struct unix_sock *u = unix_sk(sk); struct sockaddr_un *sunaddr=msg->msg_name; struct sock *other = NULL; @@ -1393,7 +1404,7 @@ restart: if (sunaddr == NULL) goto out_free; - other = unix_find_other(sunaddr, namelen, sk->sk_type, + other = unix_find_other(net, sunaddr, namelen, sk->sk_type, hash, &err); if (other==NULL) goto out_free; @@ -2006,12 +2017,18 @@ static unsigned int unix_poll(struct file * file, struct socket *sock, poll_tabl #ifdef CONFIG_PROC_FS -static struct sock *unix_seq_idx(int *iter, loff_t pos) +struct unix_iter_state { + struct net *net; + int i; +}; +static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos) { loff_t off = 0; struct sock *s; - for (s = first_unix_socket(iter); s; s = next_unix_socket(iter, s)) { + for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) { + if (s->sk_net != iter->net) + continue; if (off == pos) return s; ++off; @@ -2022,17 +2039,24 @@ static struct sock *unix_seq_idx(int *iter, loff_t pos) static void *unix_seq_start(struct seq_file *seq, loff_t *pos) { + struct unix_iter_state *iter = seq->private; spin_lock(&unix_table_lock); - return *pos ? unix_seq_idx(seq->private, *pos - 1) : ((void *) 1); + return *pos ? unix_seq_idx(iter, *pos - 1) : ((void *) 1); } static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) { + struct unix_iter_state *iter = seq->private; + struct sock *sk = v; ++*pos; if (v == (void *)1) - return first_unix_socket(seq->private); - return next_unix_socket(seq->private, v); + sk = first_unix_socket(&iter->i); + else + sk = next_unix_socket(&iter->i, sk); + while (sk && (sk->sk_net != iter->net)) + sk = next_unix_socket(&iter->i, sk); + return sk; } static void unix_seq_stop(struct seq_file *seq, void *v) @@ -2094,7 +2118,27 @@ static const struct seq_operations unix_seq_ops = { static int unix_seq_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &unix_seq_ops, sizeof(int)); + struct unix_iter_state *it; + + it = __seq_open_private(file, &unix_seq_ops, + sizeof(struct unix_iter_state)); + if (it == NULL) + return -ENOMEM; + + it->net = get_proc_net(inode); + if (it->net == NULL) { + seq_release_private(inode, file); + return -ENXIO; + } + return 0; +} + +static int unix_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct unix_iter_state *iter = seq->private; + put_net(iter->net); + return seq_release_private(inode, file); } static const struct file_operations unix_seq_fops = { @@ -2102,7 +2146,7 @@ static const struct file_operations unix_seq_fops = { .open = unix_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = unix_seq_release, }; #endif @@ -2113,6 +2157,30 @@ static struct net_proto_family unix_family_ops = { .owner = THIS_MODULE, }; + +static int unix_net_init(struct net *net) +{ + int error = -ENOMEM; + +#ifdef CONFIG_PROC_FS + if (!proc_net_fops_create(net, "unix", 0, &unix_seq_fops)) + goto out; +#endif + error = 0; +out: + return 0; +} + +static void unix_net_exit(struct net *net) +{ + proc_net_remove(net, "unix"); +} + +static struct pernet_operations unix_net_ops = { + .init = unix_net_init, + .exit = unix_net_exit, +}; + static int __init af_unix_init(void) { int rc = -1; @@ -2128,9 +2196,7 @@ static int __init af_unix_init(void) } sock_register(&unix_family_ops); -#ifdef CONFIG_PROC_FS - proc_net_fops_create(&init_net, "unix", 0, &unix_seq_fops); -#endif + register_pernet_subsys(&unix_net_ops); unix_sysctl_register(); out: return rc; @@ -2140,8 +2206,8 @@ static void __exit af_unix_exit(void) { sock_unregister(PF_UNIX); unix_sysctl_unregister(); - proc_net_remove(&init_net, "unix"); proto_unregister(&unix_proto); + unregister_pernet_subsys(&unix_net_ops); } module_init(af_unix_init); -- cgit v1.2.3-70-g09d2 From e372c41401993b45c721c4d92730e7e0a79f7c1b Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 19 Nov 2007 22:31:54 -0800 Subject: [NET]: Consolidate net namespace related proc files creation. Signed-off-by: Denis V. Lunev Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- fs/proc/proc_net.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/seq_file.h | 13 +++++++++++++ net/core/dev.c | 28 +++++----------------------- net/core/dev_mcast.c | 26 ++++---------------------- net/netlink/af_netlink.c | 33 +++++++-------------------------- net/packet/af_packet.c | 26 ++++---------------------- net/unix/af_unix.c | 31 ++++++------------------------- net/wireless/wext.c | 24 +++--------------------- 8 files changed, 80 insertions(+), 139 deletions(-) (limited to 'net/unix/af_unix.c') diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 0afe21ee060..cfc4f6c072f 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -22,10 +22,48 @@ #include #include #include +#include #include "internal.h" +int seq_open_net(struct inode *ino, struct file *f, + const struct seq_operations *ops, int size) +{ + struct net *net; + struct seq_net_private *p; + + BUG_ON(size < sizeof(*p)); + + net = get_proc_net(ino); + if (net == NULL) + return -ENXIO; + + p = __seq_open_private(f, ops, size); + if (p == NULL) { + put_net(net); + return -ENOMEM; + } + p->net = net; + return 0; +} +EXPORT_SYMBOL_GPL(seq_open_net); + +int seq_release_net(struct inode *ino, struct file *f) +{ + struct seq_file *seq; + struct seq_net_private *p; + + seq = f->private_data; + p = seq->private; + + put_net(p->net); + seq_release_private(ino, f); + return 0; +} +EXPORT_SYMBOL_GPL(seq_release_net); + + struct proc_dir_entry *proc_net_fops_create(struct net *net, const char *name, mode_t mode, const struct file_operations *fops) { diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index ebbc02b325f..648dfeb444d 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -63,5 +63,18 @@ extern struct list_head *seq_list_start_head(struct list_head *head, extern struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos); +struct net; +struct seq_net_private { + struct net *net; +}; + +int seq_open_net(struct inode *, struct file *, + const struct seq_operations *, int); +int seq_release_net(struct inode *, struct file *); +static inline struct net *seq_file_net(struct seq_file *seq) +{ + return ((struct seq_net_private *)seq->private)->net; +} + #endif #endif diff --git a/net/core/dev.c b/net/core/dev.c index 0879f52115e..d0e23d8310f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2364,7 +2364,7 @@ static int dev_ifconf(struct net *net, char __user *arg) */ void *dev_seq_start(struct seq_file *seq, loff_t *pos) { - struct net *net = seq->private; + struct net *net = seq_file_net(seq); loff_t off; struct net_device *dev; @@ -2382,7 +2382,7 @@ void *dev_seq_start(struct seq_file *seq, loff_t *pos) void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct net *net = seq->private; + struct net *net = seq_file_net(seq); ++*pos; return v == SEQ_START_TOKEN ? first_net_device(net) : next_net_device((struct net_device *)v); @@ -2481,26 +2481,8 @@ static const struct seq_operations dev_seq_ops = { static int dev_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int res; - res = seq_open(file, &dev_seq_ops); - if (!res) { - seq = file->private_data; - seq->private = get_proc_net(inode); - if (!seq->private) { - seq_release(inode, file); - res = -ENXIO; - } - } - return res; -} - -static int dev_seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct net *net = seq->private; - put_net(net); - return seq_release(inode, file); + return seq_open_net(inode, file, &dev_seq_ops, + sizeof(struct seq_net_private)); } static const struct file_operations dev_seq_fops = { @@ -2508,7 +2490,7 @@ static const struct file_operations dev_seq_fops = { .open = dev_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = dev_seq_release, + .release = seq_release_net, }; static const struct seq_operations softnet_seq_ops = { diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 69fff16ece1..63f0b33d7ce 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -187,7 +187,7 @@ EXPORT_SYMBOL(dev_mc_unsync); #ifdef CONFIG_PROC_FS static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos) { - struct net *net = seq->private; + struct net *net = seq_file_net(seq); struct net_device *dev; loff_t off = 0; @@ -241,26 +241,8 @@ static const struct seq_operations dev_mc_seq_ops = { static int dev_mc_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int res; - res = seq_open(file, &dev_mc_seq_ops); - if (!res) { - seq = file->private_data; - seq->private = get_proc_net(inode); - if (!seq->private) { - seq_release(inode, file); - res = -ENXIO; - } - } - return res; -} - -static int dev_mc_seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct net *net = seq->private; - put_net(net); - return seq_release(inode, file); + return seq_open_net(inode, file, &dev_mc_seq_ops, + sizeof(struct seq_net_private)); } static const struct file_operations dev_mc_seq_fops = { @@ -268,7 +250,7 @@ static const struct file_operations dev_mc_seq_fops = { .open = dev_mc_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = dev_mc_seq_release, + .release = seq_release_net, }; #endif diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index de3988ba1f4..1518244ffad 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1681,7 +1681,7 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid, #ifdef CONFIG_PROC_FS struct nl_seq_iter { - struct net *net; + struct seq_net_private p; int link; int hash_idx; }; @@ -1699,7 +1699,7 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) for (j = 0; j <= hash->mask; j++) { sk_for_each(s, node, &hash->table[j]) { - if (iter->net != s->sk_net) + if (iter->p.net != s->sk_net) continue; if (off == pos) { iter->link = i; @@ -1734,7 +1734,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) s = v; do { s = sk_next(s); - } while (s && (iter->net != s->sk_net)); + } while (s && (iter->p.net != s->sk_net)); if (s) return s; @@ -1746,7 +1746,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) for (; j <= hash->mask; j++) { s = sk_head(&hash->table[j]); - while (s && (iter->net != s->sk_net)) + while (s && (iter->p.net != s->sk_net)) s = sk_next(s); if (s) { iter->link = i; @@ -1802,27 +1802,8 @@ static const struct seq_operations netlink_seq_ops = { static int netlink_seq_open(struct inode *inode, struct file *file) { - struct nl_seq_iter *iter; - - iter = __seq_open_private(file, &netlink_seq_ops, sizeof(*iter)); - if (!iter) - return -ENOMEM; - - iter->net = get_proc_net(inode); - if (!iter->net) { - seq_release_private(inode, file); - return -ENXIO; - } - - return 0; -} - -static int netlink_seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct nl_seq_iter *iter = seq->private; - put_net(iter->net); - return seq_release_private(inode, file); + return seq_open_net(inode, file, &netlink_seq_ops, + sizeof(struct nl_seq_iter)); } static const struct file_operations netlink_seq_fops = { @@ -1830,7 +1811,7 @@ static const struct file_operations netlink_seq_fops = { .open = netlink_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = netlink_seq_release, + .release = seq_release_net, }; #endif diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 45e3cbcb276..ace29f1c4c5 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1871,7 +1871,7 @@ static inline struct sock *packet_seq_idx(struct net *net, loff_t off) static void *packet_seq_start(struct seq_file *seq, loff_t *pos) { - struct net *net = seq->private; + struct net *net = seq_file_net(seq); read_lock(&net->packet_sklist_lock); return *pos ? packet_seq_idx(net, *pos - 1) : SEQ_START_TOKEN; } @@ -1924,26 +1924,8 @@ static const struct seq_operations packet_seq_ops = { static int packet_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int res; - res = seq_open(file, &packet_seq_ops); - if (!res) { - seq = file->private_data; - seq->private = get_proc_net(inode); - if (!seq->private) { - seq_release(inode, file); - res = -ENXIO; - } - } - return res; -} - -static int packet_seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq= file->private_data; - struct net *net = seq->private; - put_net(net); - return seq_release(inode, file); + return seq_open_net(inode, file, &packet_seq_ops, + sizeof(struct seq_net_private)); } static const struct file_operations packet_seq_fops = { @@ -1951,7 +1933,7 @@ static const struct file_operations packet_seq_fops = { .open = packet_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = packet_seq_release, + .release = seq_release_net, }; #endif diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index ecad42b72ad..eacddb21a9b 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2018,7 +2018,7 @@ static unsigned int unix_poll(struct file * file, struct socket *sock, poll_tabl #ifdef CONFIG_PROC_FS struct unix_iter_state { - struct net *net; + struct seq_net_private p; int i; }; static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos) @@ -2027,7 +2027,7 @@ static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos) struct sock *s; for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) { - if (s->sk_net != iter->net) + if (s->sk_net != iter->p.net) continue; if (off == pos) return s; @@ -2054,7 +2054,7 @@ static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) sk = first_unix_socket(&iter->i); else sk = next_unix_socket(&iter->i, sk); - while (sk && (sk->sk_net != iter->net)) + while (sk && (sk->sk_net != iter->p.net)) sk = next_unix_socket(&iter->i, sk); return sk; } @@ -2118,27 +2118,8 @@ static const struct seq_operations unix_seq_ops = { static int unix_seq_open(struct inode *inode, struct file *file) { - struct unix_iter_state *it; - - it = __seq_open_private(file, &unix_seq_ops, - sizeof(struct unix_iter_state)); - if (it == NULL) - return -ENOMEM; - - it->net = get_proc_net(inode); - if (it->net == NULL) { - seq_release_private(inode, file); - return -ENXIO; - } - return 0; -} - -static int unix_seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct unix_iter_state *iter = seq->private; - put_net(iter->net); - return seq_release_private(inode, file); + return seq_open_net(inode, file, &unix_seq_ops, + sizeof(struct unix_iter_state)); } static const struct file_operations unix_seq_fops = { @@ -2146,7 +2127,7 @@ static const struct file_operations unix_seq_fops = { .open = unix_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = unix_seq_release, + .release = seq_release_net, }; #endif diff --git a/net/wireless/wext.c b/net/wireless/wext.c index db03ed5ce05..1e4cf615f87 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -673,26 +673,8 @@ static const struct seq_operations wireless_seq_ops = { static int wireless_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int res; - res = seq_open(file, &wireless_seq_ops); - if (!res) { - seq = file->private_data; - seq->private = get_proc_net(inode); - if (!seq->private) { - seq_release(inode, file); - res = -ENXIO; - } - } - return res; -} - -static int wireless_seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct net *net = seq->private; - put_net(net); - return seq_release(inode, file); + return seq_open_net(inode, file, &wireless_seq_ops, + sizeof(struct seq_net_private)); } static const struct file_operations wireless_seq_fops = { @@ -700,7 +682,7 @@ static const struct file_operations wireless_seq_fops = { .open = wireless_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = wireless_seq_release, + .release = seq_release_net, }; int wext_proc_init(struct net *net) -- cgit v1.2.3-70-g09d2 From a53eb3feb2718bf906e81be89fae823b9b6157b6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 23 Nov 2007 20:30:01 +0800 Subject: [UNIX] Move the unix sock iterators in to proper place The first_unix_socket() and next_unix_sockets() are now used in proc file and in forall_unix_socets macro only. The forall_unix_sockets is not used in this file at all so remove it. After this move the helpers to where they really belong, i.e. closer to proc code under the #ifdef CONFIG_PROC_FS option. Signed-off-by: Pavel Emelyanov Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/unix/af_unix.c | 49 +++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 26 deletions(-) (limited to 'net/unix/af_unix.c') diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index eacddb21a9b..0f1ecbf86d0 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -127,32 +127,6 @@ static atomic_t unix_nr_socks = ATOMIC_INIT(0); #define UNIX_ABSTRACT(sk) (unix_sk(sk)->addr->hash != UNIX_HASH_SIZE) -static struct sock *first_unix_socket(int *i) -{ - for (*i = 0; *i <= UNIX_HASH_SIZE; (*i)++) { - if (!hlist_empty(&unix_socket_table[*i])) - return __sk_head(&unix_socket_table[*i]); - } - return NULL; -} - -static struct sock *next_unix_socket(int *i, struct sock *s) -{ - struct sock *next = sk_next(s); - /* More in this chain? */ - if (next) - return next; - /* Look for next non-empty chain. */ - for ((*i)++; *i <= UNIX_HASH_SIZE; (*i)++) { - if (!hlist_empty(&unix_socket_table[*i])) - return __sk_head(&unix_socket_table[*i]); - } - return NULL; -} - -#define forall_unix_sockets(i, s) \ - for (s = first_unix_socket(&(i)); s; s = next_unix_socket(&(i),(s))) - #ifdef CONFIG_SECURITY_NETWORK static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) { @@ -2017,6 +1991,29 @@ static unsigned int unix_poll(struct file * file, struct socket *sock, poll_tabl #ifdef CONFIG_PROC_FS +static struct sock *first_unix_socket(int *i) +{ + for (*i = 0; *i <= UNIX_HASH_SIZE; (*i)++) { + if (!hlist_empty(&unix_socket_table[*i])) + return __sk_head(&unix_socket_table[*i]); + } + return NULL; +} + +static struct sock *next_unix_socket(int *i, struct sock *s) +{ + struct sock *next = sk_next(s); + /* More in this chain? */ + if (next) + return next; + /* Look for next non-empty chain. */ + for ((*i)++; *i <= UNIX_HASH_SIZE; (*i)++) { + if (!hlist_empty(&unix_socket_table[*i])) + return __sk_head(&unix_socket_table[*i]); + } + return NULL; +} + struct unix_iter_state { struct seq_net_private p; int i; -- cgit v1.2.3-70-g09d2 From 8d8ad9d7c4bfe79bc91b7fc419ecfb9dcdfe6a51 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 26 Nov 2007 20:10:50 +0800 Subject: [NET]: Name magic constants in sock_wake_async() The sock_wake_async() performs a bit different actions depending on "how" argument. Unfortunately this argument ony has numerical magic values. I propose to give names to their constants to help people reading this function callers understand what's going on without looking into this function all the time. I suppose this is 2.6.25 material, but if it's not (or the naming seems poor/bad/awful), I can rework it against the current net-2.6 tree. Signed-off-by: Pavel Emelyanov Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/net.h | 7 +++++++ net/atm/common.c | 2 +- net/core/sock.c | 8 ++++---- net/core/stream.c | 2 +- net/dccp/input.c | 8 ++++---- net/dccp/output.c | 2 +- net/ipv4/tcp_input.c | 12 ++++++------ net/rxrpc/af_rxrpc.c | 2 +- net/sctp/socket.c | 3 ++- net/socket.c | 9 ++++----- net/unix/af_unix.c | 8 ++++---- 11 files changed, 35 insertions(+), 28 deletions(-) (limited to 'net/unix/af_unix.c') diff --git a/include/linux/net.h b/include/linux/net.h index 0235d917d5c..f95f12c5840 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -186,6 +186,13 @@ struct net_proto_family { struct iovec; struct kvec; +enum { + SOCK_WAKE_IO, + SOCK_WAKE_WAITD, + SOCK_WAKE_SPACE, + SOCK_WAKE_URG, +}; + extern int sock_wake_async(struct socket *sk, int how, int band); extern int sock_register(const struct net_proto_family *fam); extern void sock_unregister(int family); diff --git a/net/atm/common.c b/net/atm/common.c index eba09a04f6b..c865517ba44 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -113,7 +113,7 @@ static void vcc_write_space(struct sock *sk) if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible(sk->sk_sleep); - sk_wake_async(sk, 2, POLL_OUT); + sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); } read_unlock(&sk->sk_callback_lock); diff --git a/net/core/sock.c b/net/core/sock.c index eac7aa0721d..118214047ed 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1498,7 +1498,7 @@ static void sock_def_error_report(struct sock *sk) read_lock(&sk->sk_callback_lock); if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible(sk->sk_sleep); - sk_wake_async(sk,0,POLL_ERR); + sk_wake_async(sk, SOCK_WAKE_IO, POLL_ERR); read_unlock(&sk->sk_callback_lock); } @@ -1507,7 +1507,7 @@ static void sock_def_readable(struct sock *sk, int len) read_lock(&sk->sk_callback_lock); if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible(sk->sk_sleep); - sk_wake_async(sk,1,POLL_IN); + sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); read_unlock(&sk->sk_callback_lock); } @@ -1524,7 +1524,7 @@ static void sock_def_write_space(struct sock *sk) /* Should agree with poll, otherwise some programs break */ if (sock_writeable(sk)) - sk_wake_async(sk, 2, POLL_OUT); + sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); } read_unlock(&sk->sk_callback_lock); @@ -1539,7 +1539,7 @@ void sk_send_sigurg(struct sock *sk) { if (sk->sk_socket && sk->sk_socket->file) if (send_sigurg(&sk->sk_socket->file->f_owner)) - sk_wake_async(sk, 3, POLL_PRI); + sk_wake_async(sk, SOCK_WAKE_URG, POLL_PRI); } void sk_reset_timer(struct sock *sk, struct timer_list* timer, diff --git a/net/core/stream.c b/net/core/stream.c index b2fb846f42a..5586879bb9b 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -35,7 +35,7 @@ void sk_stream_write_space(struct sock *sk) if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible(sk->sk_sleep); if (sock->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) - sock_wake_async(sock, 2, POLL_OUT); + sock_wake_async(sock, SOCK_WAKE_SPACE, POLL_OUT); } } diff --git a/net/dccp/input.c b/net/dccp/input.c index df0fb2c149a..ef299fbd7c2 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -37,7 +37,7 @@ static void dccp_rcv_close(struct sock *sk, struct sk_buff *skb) dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED); dccp_fin(sk, skb); dccp_set_state(sk, DCCP_CLOSED); - sk_wake_async(sk, 1, POLL_HUP); + sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_HUP); } static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb) @@ -90,7 +90,7 @@ static void dccp_rcv_reset(struct sock *sk, struct sk_buff *skb) dccp_fin(sk, skb); if (err && !sock_flag(sk, SOCK_DEAD)) - sk_wake_async(sk, 0, POLL_ERR); + sk_wake_async(sk, SOCK_WAKE_IO, POLL_ERR); dccp_time_wait(sk, DCCP_TIME_WAIT, 0); } @@ -416,7 +416,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, if (!sock_flag(sk, SOCK_DEAD)) { sk->sk_state_change(sk); - sk_wake_async(sk, 0, POLL_OUT); + sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT); } if (sk->sk_write_pending || icsk->icsk_ack.pingpong || @@ -624,7 +624,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, switch (old_state) { case DCCP_PARTOPEN: sk->sk_state_change(sk); - sk_wake_async(sk, 0, POLL_OUT); + sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT); break; } } else if (unlikely(dh->dccph_type == DCCP_PKT_SYNC)) { diff --git a/net/dccp/output.c b/net/dccp/output.c index f49544618f2..33ce737ef3a 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -170,7 +170,7 @@ void dccp_write_space(struct sock *sk) wake_up_interruptible(sk->sk_sleep); /* Should agree with poll, otherwise some programs break */ if (sock_writeable(sk)) - sk_wake_async(sk, 2, POLL_OUT); + sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); read_unlock(&sk->sk_callback_lock); } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 79996b16b94..97ea3eda206 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3595,9 +3595,9 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) /* Do not send POLL_HUP for half duplex close. */ if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE) - sk_wake_async(sk, 1, POLL_HUP); + sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_HUP); else - sk_wake_async(sk, 1, POLL_IN); + sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); } } @@ -4956,7 +4956,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, if (!sock_flag(sk, SOCK_DEAD)) { sk->sk_state_change(sk); - sk_wake_async(sk, 0, POLL_OUT); + sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT); } if (sk->sk_write_pending || @@ -5186,9 +5186,9 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, * are not waked up, because sk->sk_sleep == * NULL and sk->sk_socket == NULL. */ - if (sk->sk_socket) { - sk_wake_async(sk,0,POLL_OUT); - } + if (sk->sk_socket) + sk_wake_async(sk, + SOCK_WAKE_IO, POLL_OUT); tp->snd_una = TCP_SKB_CB(skb)->ack_seq; tp->snd_wnd = ntohs(th->window) << diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index d6389450c4b..5e82f1c0afb 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -65,7 +65,7 @@ static void rxrpc_write_space(struct sock *sk) if (rxrpc_writable(sk)) { if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible(sk->sk_sleep); - sk_wake_async(sk, 2, POLL_OUT); + sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); } read_unlock(&sk->sk_callback_lock); } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index ea9649ca0b2..dc2f9221f09 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6008,7 +6008,8 @@ static void __sctp_write_space(struct sctp_association *asoc) */ if (sock->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) - sock_wake_async(sock, 2, POLL_OUT); + sock_wake_async(sock, + SOCK_WAKE_SPACE, POLL_OUT); } } } diff --git a/net/socket.c b/net/socket.c index aeeab388cc3..9ebca5c695d 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1070,20 +1070,19 @@ int sock_wake_async(struct socket *sock, int how, int band) if (!sock || !sock->fasync_list) return -1; switch (how) { - case 1: - + case SOCK_WAKE_WAITD: if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) break; goto call_kill; - case 2: + case SOCK_WAKE_SPACE: if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags)) break; /* fall through */ - case 0: + case SOCK_WAKE_IO: call_kill: __kill_fasync(sock->fasync_list, SIGIO, band); break; - case 3: + case SOCK_WAKE_URG: __kill_fasync(sock->fasync_list, SIGURG, band); } return 0; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 0f1ecbf86d0..393197afb19 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -317,7 +317,7 @@ static void unix_write_space(struct sock *sk) if (unix_writable(sk)) { if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible_sync(sk->sk_sleep); - sk_wake_async(sk, 2, POLL_OUT); + sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); } read_unlock(&sk->sk_callback_lock); } @@ -403,7 +403,7 @@ static int unix_release_sock (struct sock *sk, int embrion) unix_state_unlock(skpair); skpair->sk_state_change(skpair); read_lock(&skpair->sk_callback_lock); - sk_wake_async(skpair,1,POLL_HUP); + sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP); read_unlock(&skpair->sk_callback_lock); } sock_put(skpair); /* It may now die */ @@ -1900,9 +1900,9 @@ static int unix_shutdown(struct socket *sock, int mode) other->sk_state_change(other); read_lock(&other->sk_callback_lock); if (peer_mode == SHUTDOWN_MASK) - sk_wake_async(other,1,POLL_HUP); + sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP); else if (peer_mode & RCV_SHUTDOWN) - sk_wake_async(other,1,POLL_IN); + sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN); read_unlock(&other->sk_callback_lock); } if (other) -- cgit v1.2.3-70-g09d2 From 97577e38284f48ca773392e2d401af2f6c95dc08 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 1 Dec 2007 23:40:40 +1100 Subject: [UNIX]: Extend unix_sysctl_(un)register prototypes Add the struct net * argument to both of them to use in the future. Also make the register one return an error code. It is useless right now, but will make the future patches much simpler. Signed-off-by: Pavel Emelyanov Acked-by: Eric W. Biederman Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/af_unix.h | 8 ++++---- net/unix/af_unix.c | 4 ++-- net/unix/sysctl_net_unix.c | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'net/unix/af_unix.c') diff --git a/include/net/af_unix.h b/include/net/af_unix.h index a1c805d7f48..e0fba269d09 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -60,11 +60,11 @@ struct unix_sock { #ifdef CONFIG_SYSCTL extern int sysctl_unix_max_dgram_qlen; -extern void unix_sysctl_register(void); -extern void unix_sysctl_unregister(void); +extern int unix_sysctl_register(struct net *net); +extern void unix_sysctl_unregister(struct net *net); #else -static inline void unix_sysctl_register(void) {} -static inline void unix_sysctl_unregister(void) {} +static inline int unix_sysctl_register(struct net *net) { return 0; } +static inline void unix_sysctl_unregister(struct net *net) {} #endif #endif #endif diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 393197afb19..a0aa6d3c2c0 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2175,7 +2175,7 @@ static int __init af_unix_init(void) sock_register(&unix_family_ops); register_pernet_subsys(&unix_net_ops); - unix_sysctl_register(); + unix_sysctl_register(&init_net); out: return rc; } @@ -2183,7 +2183,7 @@ out: static void __exit af_unix_exit(void) { sock_unregister(PF_UNIX); - unix_sysctl_unregister(); + unix_sysctl_unregister(&init_net); proto_unregister(&unix_proto); unregister_pernet_subsys(&unix_net_ops); } diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c index eb0bd57ebad..b2e0407e1b7 100644 --- a/net/unix/sysctl_net_unix.c +++ b/net/unix/sysctl_net_unix.c @@ -48,12 +48,13 @@ static ctl_table unix_root_table[] = { static struct ctl_table_header * unix_sysctl_header; -void unix_sysctl_register(void) +int unix_sysctl_register(struct net *net) { unix_sysctl_header = register_sysctl_table(unix_root_table); + return unix_sysctl_header == NULL ? -ENOMEM : 0; } -void unix_sysctl_unregister(void) +void unix_sysctl_unregister(struct net *net) { unregister_sysctl_table(unix_sysctl_header); } -- cgit v1.2.3-70-g09d2 From d392e49756a99ba51577d265d6db83e3f01c6ac8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 1 Dec 2007 23:44:15 +1100 Subject: [UNIX]: Move the sysctl_unix_max_dgram_qlen This will make all the sub-namespaces always use the default value (10) and leave the tuning via sysctl to the init namespace only. Per-namespace tuning is coming. Signed-off-by: Pavel Emelyanov Acked-by: Eric W. Biederman Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/net_namespace.h | 3 +++ net/unix/af_unix.c | 6 +++--- net/unix/sysctl_net_unix.c | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'net/unix/af_unix.c') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 235214c4c23..b0cf07519b8 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -38,6 +38,9 @@ struct net { /* List of all packet sockets. */ rwlock_t packet_sklist_lock; struct hlist_head packet_sklist; + + /* unix sockets */ + int sysctl_unix_max_dgram_qlen; }; #ifdef CONFIG_NET diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index a0aa6d3c2c0..73620d61762 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -117,8 +117,6 @@ #include #include -int sysctl_unix_max_dgram_qlen __read_mostly = 10; - static struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1]; static DEFINE_SPINLOCK(unix_table_lock); static atomic_t unix_nr_socks = ATOMIC_INIT(0); @@ -594,7 +592,7 @@ static struct sock * unix_create1(struct net *net, struct socket *sock) &af_unix_sk_receive_queue_lock_key); sk->sk_write_space = unix_write_space; - sk->sk_max_ack_backlog = sysctl_unix_max_dgram_qlen; + sk->sk_max_ack_backlog = net->sysctl_unix_max_dgram_qlen; sk->sk_destruct = unix_sock_destructor; u = unix_sk(sk); u->dentry = NULL; @@ -2140,6 +2138,8 @@ static int unix_net_init(struct net *net) { int error = -ENOMEM; + net->sysctl_unix_max_dgram_qlen = 10; + #ifdef CONFIG_PROC_FS if (!proc_net_fops_create(net, "unix", 0, &unix_seq_fops)) goto out; diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c index b2e0407e1b7..c46cec04d23 100644 --- a/net/unix/sysctl_net_unix.c +++ b/net/unix/sysctl_net_unix.c @@ -18,7 +18,7 @@ static ctl_table unix_table[] = { { .ctl_name = NET_UNIX_MAX_DGRAM_QLEN, .procname = "max_dgram_qlen", - .data = &sysctl_unix_max_dgram_qlen, + .data = &init_net.sysctl_unix_max_dgram_qlen, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec -- cgit v1.2.3-70-g09d2 From 1597fbc0faf88c42edb3fe42e92e53b83c3f120e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 1 Dec 2007 23:51:01 +1100 Subject: [UNIX]: Make the unix sysctl tables per-namespace This is the core. * add the ctl_table_header on the struct net; * make the unix_sysctl_register and _unregister clone the table; * moves calls to them into per-net init and exit callbacks; * move the .data pointer in the proper place. Signed-off-by: Pavel Emelyanov Acked-by: Eric W. Biederman Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/net_namespace.h | 3 +++ net/unix/af_unix.c | 9 ++++++--- net/unix/sysctl_net_unix.c | 27 ++++++++++++++++++++++----- 3 files changed, 31 insertions(+), 8 deletions(-) (limited to 'net/unix/af_unix.c') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index b0cf07519b8..f97b2a4469a 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -11,6 +11,8 @@ struct proc_dir_entry; struct net_device; struct sock; +struct ctl_table_header; + struct net { atomic_t count; /* To decided when the network * namespace should be freed. @@ -41,6 +43,7 @@ struct net { /* unix sockets */ int sysctl_unix_max_dgram_qlen; + struct ctl_table_header *unix_ctl; }; #ifdef CONFIG_NET diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 73620d61762..b8a2189fb5c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2139,10 +2139,14 @@ static int unix_net_init(struct net *net) int error = -ENOMEM; net->sysctl_unix_max_dgram_qlen = 10; + if (unix_sysctl_register(net)) + goto out; #ifdef CONFIG_PROC_FS - if (!proc_net_fops_create(net, "unix", 0, &unix_seq_fops)) + if (!proc_net_fops_create(net, "unix", 0, &unix_seq_fops)) { + unix_sysctl_unregister(net); goto out; + } #endif error = 0; out: @@ -2151,6 +2155,7 @@ out: static void unix_net_exit(struct net *net) { + unix_sysctl_unregister(net); proc_net_remove(net, "unix"); } @@ -2175,7 +2180,6 @@ static int __init af_unix_init(void) sock_register(&unix_family_ops); register_pernet_subsys(&unix_net_ops); - unix_sysctl_register(&init_net); out: return rc; } @@ -2183,7 +2187,6 @@ out: static void __exit af_unix_exit(void) { sock_unregister(PF_UNIX); - unix_sysctl_unregister(&init_net); proto_unregister(&unix_proto); unregister_pernet_subsys(&unix_net_ops); } diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c index 43dd356730f..553ef6a487d 100644 --- a/net/unix/sysctl_net_unix.c +++ b/net/unix/sysctl_net_unix.c @@ -32,16 +32,33 @@ static struct ctl_path unix_path[] = { { }, }; -static struct ctl_table_header * unix_sysctl_header; - int unix_sysctl_register(struct net *net) { - unix_sysctl_header = register_sysctl_paths(unix_path, unix_table); - return unix_sysctl_header == NULL ? -ENOMEM : 0; + struct ctl_table *table; + + table = kmemdup(unix_table, sizeof(unix_table), GFP_KERNEL); + if (table == NULL) + goto err_alloc; + + table[0].data = &net->sysctl_unix_max_dgram_qlen; + net->unix_ctl = register_net_sysctl_table(net, unix_path, table); + if (net->unix_ctl == NULL) + goto err_reg; + + return 0; + +err_reg: + kfree(table); +err_alloc: + return -ENOMEM; } void unix_sysctl_unregister(struct net *net) { - unregister_sysctl_table(unix_sysctl_header); + struct ctl_table *table; + + table = net->unix_ctl->ctl_table_arg; + unregister_sysctl_table(net->unix_ctl); + kfree(table); } -- cgit v1.2.3-70-g09d2 From a0a53c8ba95451feef6c1975016f0a1eb3044ad4 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 11 Dec 2007 04:19:17 -0800 Subject: [NETNS]: struct net content re-work (v3) Recently David Miller and Herbert Xu pointed out that struct net becomes overbloated and un-maintainable. There are two solutions: - provide a pointer to a network subsystem definition from struct net. This costs an additional dereferrence - place sub-system definition into the structure itself. This will speedup run-time access at the cost of recompilation time The second approach looks better for us. Other sub-systems will follow. Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/net_namespace.h | 6 +++--- include/net/netns/unix.h | 13 +++++++++++++ net/unix/af_unix.c | 4 ++-- net/unix/sysctl_net_unix.c | 12 ++++++------ 4 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 include/net/netns/unix.h (limited to 'net/unix/af_unix.c') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index b62e31fca47..d943fd4eaba 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -8,6 +8,8 @@ #include #include +#include + struct proc_dir_entry; struct net_device; struct sock; @@ -45,9 +47,7 @@ struct net { rwlock_t packet_sklist_lock; struct hlist_head packet_sklist; - /* unix sockets */ - int sysctl_unix_max_dgram_qlen; - struct ctl_table_header *unix_ctl; + struct netns_unix unx; }; #ifdef CONFIG_NET diff --git a/include/net/netns/unix.h b/include/net/netns/unix.h new file mode 100644 index 00000000000..284649d4dfb --- /dev/null +++ b/include/net/netns/unix.h @@ -0,0 +1,13 @@ +/* + * Unix network namespace + */ +#ifndef __NETNS_UNIX_H__ +#define __NETNS_UNIX_H__ + +struct ctl_table_header; +struct netns_unix { + int sysctl_max_dgram_qlen; + struct ctl_table_header *ctl; +}; + +#endif /* __NETNS_UNIX_H__ */ diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index b8a2189fb5c..63a9239571a 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -592,7 +592,7 @@ static struct sock * unix_create1(struct net *net, struct socket *sock) &af_unix_sk_receive_queue_lock_key); sk->sk_write_space = unix_write_space; - sk->sk_max_ack_backlog = net->sysctl_unix_max_dgram_qlen; + sk->sk_max_ack_backlog = net->unx.sysctl_max_dgram_qlen; sk->sk_destruct = unix_sock_destructor; u = unix_sk(sk); u->dentry = NULL; @@ -2138,7 +2138,7 @@ static int unix_net_init(struct net *net) { int error = -ENOMEM; - net->sysctl_unix_max_dgram_qlen = 10; + net->unx.sysctl_max_dgram_qlen = 10; if (unix_sysctl_register(net)) goto out; diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c index 553ef6a487d..77513d7e35f 100644 --- a/net/unix/sysctl_net_unix.c +++ b/net/unix/sysctl_net_unix.c @@ -18,7 +18,7 @@ static ctl_table unix_table[] = { { .ctl_name = NET_UNIX_MAX_DGRAM_QLEN, .procname = "max_dgram_qlen", - .data = &init_net.sysctl_unix_max_dgram_qlen, + .data = &init_net.unx.sysctl_max_dgram_qlen, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -40,9 +40,9 @@ int unix_sysctl_register(struct net *net) if (table == NULL) goto err_alloc; - table[0].data = &net->sysctl_unix_max_dgram_qlen; - net->unix_ctl = register_net_sysctl_table(net, unix_path, table); - if (net->unix_ctl == NULL) + table[0].data = &net->unx.sysctl_max_dgram_qlen; + net->unx.ctl = register_net_sysctl_table(net, unix_path, table); + if (net->unx.ctl == NULL) goto err_reg; return 0; @@ -57,8 +57,8 @@ void unix_sysctl_unregister(struct net *net) { struct ctl_table *table; - table = net->unix_ctl->ctl_table_arg; - unregister_sysctl_table(net->unix_ctl); + table = net->unx.ctl->ctl_table_arg; + unregister_sysctl_table(net->unx.ctl); kfree(table); } -- cgit v1.2.3-70-g09d2 From 9a429c4983deae020f1e757ecc8f547b6d4e2f2b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 1 Jan 2008 21:58:02 -0800 Subject: [NET]: Add some acquires/releases sparse annotations. Add __acquires() and __releases() annotations to suppress some sparse warnings. example of warnings : net/ipv4/udp.c:1555:14: warning: context imbalance in 'udp_seq_start' - wrong count at exit net/ipv4/udp.c:1571:13: warning: context imbalance in 'udp_seq_stop' - unexpected unlock Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 2 ++ net/core/dev_mcast.c | 2 ++ net/core/gen_stats.c | 1 + net/core/neighbour.c | 2 ++ net/core/sock.c | 2 ++ net/ipv4/fib_hash.c | 2 ++ net/ipv4/inet_hashtables.c | 1 + net/ipv4/udp.c | 2 ++ net/ipv6/anycast.c | 2 ++ net/ipv6/ip6_flowlabel.c | 2 ++ net/ipv6/mcast.c | 4 ++++ net/netlink/af_netlink.c | 4 ++++ net/sched/sch_generic.c | 4 ++++ net/sunrpc/cache.c | 2 ++ net/unix/af_unix.c | 2 ++ net/xfrm/xfrm_state.c | 2 ++ 16 files changed, 36 insertions(+) (limited to 'net/unix/af_unix.c') diff --git a/net/core/dev.c b/net/core/dev.c index 7153e94f50a..eee77424309 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2368,6 +2368,7 @@ static int dev_ifconf(struct net *net, char __user *arg) * in detail. */ void *dev_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(dev_base_lock) { struct net *net = seq_file_net(seq); loff_t off; @@ -2394,6 +2395,7 @@ void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) } void dev_seq_stop(struct seq_file *seq, void *v) + __releases(dev_base_lock) { read_unlock(&dev_base_lock); } diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 63f0b33d7ce..cadbfbf7e7f 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -186,6 +186,7 @@ EXPORT_SYMBOL(dev_mc_unsync); #ifdef CONFIG_PROC_FS static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(dev_base_lock) { struct net *net = seq_file_net(seq); struct net_device *dev; @@ -206,6 +207,7 @@ static void *dev_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void dev_mc_seq_stop(struct seq_file *seq, void *v) + __releases(dev_base_lock) { read_unlock(&dev_base_lock); } diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c index bcc25591d8a..8073561f7c6 100644 --- a/net/core/gen_stats.c +++ b/net/core/gen_stats.c @@ -55,6 +55,7 @@ rtattr_failure: int gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type, int xstats_type, spinlock_t *lock, struct gnet_dump *d) + __acquires(lock) { memset(d, 0, sizeof(*d)); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index bd899d55773..802493327a8 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2313,6 +2313,7 @@ static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos) } void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags) + __acquires(tbl->lock) { struct neigh_seq_state *state = seq->private; loff_t pos_minus_one; @@ -2356,6 +2357,7 @@ out: EXPORT_SYMBOL(neigh_seq_next); void neigh_seq_stop(struct seq_file *seq, void *v) + __releases(tbl->lock) { struct neigh_seq_state *state = seq->private; struct neigh_table *tbl = state->tbl; diff --git a/net/core/sock.c b/net/core/sock.c index 3804e7df626..3d7757ee2fc 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2025,6 +2025,7 @@ EXPORT_SYMBOL(proto_unregister); #ifdef CONFIG_PROC_FS static void *proto_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(proto_list_lock) { read_lock(&proto_list_lock); return seq_list_start_head(&proto_list, *pos); @@ -2036,6 +2037,7 @@ static void *proto_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void proto_seq_stop(struct seq_file *seq, void *v) + __releases(proto_list_lock) { read_unlock(&proto_list_lock); } diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 9d540415847..ee1ffdb3044 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -936,6 +936,7 @@ static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos) } static void *fib_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(fib_hash_lock) { void *v = NULL; @@ -952,6 +953,7 @@ static void *fib_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void fib_seq_stop(struct seq_file *seq, void *v) + __releases(fib_hash_lock) { read_unlock(&fib_hash_lock); } diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 2e5814a8436..88a059e04e3 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -96,6 +96,7 @@ EXPORT_SYMBOL(inet_put_port); * exclusive lock release). It should be ifdefed really. */ void inet_listen_wlock(struct inet_hashinfo *hashinfo) + __acquires(hashinfo->lhash_lock) { write_lock(&hashinfo->lhash_lock); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 35328436075..02fcccd0486 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1550,6 +1550,7 @@ static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos) } static void *udp_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(udp_hash_lock) { read_lock(&udp_hash_lock); return *pos ? udp_get_idx(seq, *pos-1) : (void *)1; @@ -1569,6 +1570,7 @@ static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void udp_seq_stop(struct seq_file *seq, void *v) + __releases(udp_hash_lock) { read_unlock(&udp_hash_lock); } diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index f915c4df982..5c4190060e7 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -504,6 +504,7 @@ static struct ifacaddr6 *ac6_get_idx(struct seq_file *seq, loff_t pos) } static void *ac6_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(dev_base_lock) { read_lock(&dev_base_lock); return ac6_get_idx(seq, *pos); @@ -518,6 +519,7 @@ static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void ac6_seq_stop(struct seq_file *seq, void *v) + __releases(dev_base_lock) { struct ac6_iter_state *state = ac6_seq_private(seq); if (likely(state->idev != NULL)) { diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index d0babea8981..2b7d9ee9883 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -629,6 +629,7 @@ static struct ip6_flowlabel *ip6fl_get_idx(struct seq_file *seq, loff_t pos) } static void *ip6fl_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(ip6_fl_lock) { read_lock_bh(&ip6_fl_lock); return *pos ? ip6fl_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; @@ -647,6 +648,7 @@ static void *ip6fl_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void ip6fl_seq_stop(struct seq_file *seq, void *v) + __releases(ip6_fl_lock) { read_unlock_bh(&ip6_fl_lock); } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 82b12940c2a..ab228d1ea11 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2373,6 +2373,7 @@ static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos) } static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(dev_base_lock) { read_lock(&dev_base_lock); return igmp6_mc_get_idx(seq, *pos); @@ -2387,6 +2388,7 @@ static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void igmp6_mc_seq_stop(struct seq_file *seq, void *v) + __releases(dev_base_lock) { struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); if (likely(state->idev != NULL)) { @@ -2516,6 +2518,7 @@ static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos) } static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(dev_base_lock) { read_lock(&dev_base_lock); return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; @@ -2533,6 +2536,7 @@ static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) + __releases(dev_base_lock) { struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); if (likely(state->im != NULL)) { diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index dbd7cad1c9a..be07f1b45ee 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -171,6 +171,7 @@ static void netlink_sock_destruct(struct sock *sk) */ static void netlink_table_grab(void) + __acquires(nl_table_lock) { write_lock_irq(&nl_table_lock); @@ -193,6 +194,7 @@ static void netlink_table_grab(void) } static inline void netlink_table_ungrab(void) + __releases(nl_table_lock) { write_unlock_irq(&nl_table_lock); wake_up(&nl_table_wait); @@ -1728,6 +1730,7 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) } static void *netlink_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(nl_table_lock) { read_lock(&nl_table_lock); return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : SEQ_START_TOKEN; @@ -1776,6 +1779,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void netlink_seq_stop(struct seq_file *seq, void *v) + __releases(nl_table_lock) { read_unlock(&nl_table_lock); } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 9be2f152455..ea5a05b172c 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -40,12 +40,16 @@ */ void qdisc_lock_tree(struct net_device *dev) + __acquires(dev->queue_lock) + __acquires(dev->ingress_lock) { spin_lock_bh(&dev->queue_lock); spin_lock(&dev->ingress_lock); } void qdisc_unlock_tree(struct net_device *dev) + __releases(dev->ingress_lock) + __releases(dev->queue_lock) { spin_unlock(&dev->ingress_lock); spin_unlock_bh(&dev->queue_lock); diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 8e05557414c..73f053d0cc7 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1127,6 +1127,7 @@ struct handle { }; static void *c_start(struct seq_file *m, loff_t *pos) + __acquires(cd->hash_lock) { loff_t n = *pos; unsigned hash, entry; @@ -1183,6 +1184,7 @@ static void *c_next(struct seq_file *m, void *p, loff_t *pos) } static void c_stop(struct seq_file *m, void *p) + __releases(cd->hash_lock) { struct cache_detail *cd = ((struct handle*)m->private)->cd; read_unlock(&cd->hash_lock); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 63a9239571a..eea75888805 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2033,6 +2033,7 @@ static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos) static void *unix_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(unix_table_lock) { struct unix_iter_state *iter = seq->private; spin_lock(&unix_table_lock); @@ -2055,6 +2056,7 @@ static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void unix_seq_stop(struct seq_file *seq, void *v) + __releases(unix_table_lock) { spin_unlock(&unix_table_lock); } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 6bf876c866d..65f5ea4ae4c 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -211,6 +211,7 @@ static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family) } static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo) + __releases(xfrm_state_afinfo_lock) { write_unlock_bh(&xfrm_state_afinfo_lock); } @@ -1909,6 +1910,7 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) } static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) + __releases(xfrm_state_afinfo_lock) { read_unlock(&xfrm_state_afinfo_lock); } -- cgit v1.2.3-70-g09d2