Re: [PATCH 3/3] afs: Implement namespacing

From: Christoph Hellwig
Date: Tue May 15 2018 - 13:38:53 EST


So the real question here is why afs needs a write callback as the first
user of /proc/net ever in a day and time were we've deprecated adding
new proc files. This is a discussion that should be had with linux-fsdevel
and netdev in Cc.

On Tue, May 01, 2018 at 12:20:39AM +0100, David Howells wrote:
> Implement namespacing within AFS, but don't yet let mounts occur outside
> the init namespace. An additional patch will be required propagate the
> network namespace across automounts.
>
> Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
> ---
>
> fs/afs/cell.c | 4
> fs/afs/cmservice.c | 2
> fs/afs/internal.h | 43 +++--
> fs/afs/main.c | 33 +++-
> fs/afs/netdevices.c | 6 -
> fs/afs/proc.c | 414 +++++++++++++--------------------------------------
> fs/afs/rxrpc.c | 2
> fs/afs/super.c | 20 +-
> 8 files changed, 176 insertions(+), 348 deletions(-)
>
> diff --git a/fs/afs/cell.c b/fs/afs/cell.c
> index fdf4c36cff79..a98a8a3d5544 100644
> --- a/fs/afs/cell.c
> +++ b/fs/afs/cell.c
> @@ -528,7 +528,7 @@ static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
> NULL, 0,
> cell, 0, true);
> #endif
> - ret = afs_proc_cell_setup(net, cell);
> + ret = afs_proc_cell_setup(cell);
> if (ret < 0)
> return ret;
> spin_lock(&net->proc_cells_lock);
> @@ -544,7 +544,7 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)
> {
> _enter("%s", cell->name);
>
> - afs_proc_cell_remove(net, cell);
> + afs_proc_cell_remove(cell);
>
> spin_lock(&net->proc_cells_lock);
> list_del_init(&cell->proc_link);
> diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
> index 357de908df3a..4c89b1f4c02b 100644
> --- a/fs/afs/cmservice.c
> +++ b/fs/afs/cmservice.c
> @@ -550,7 +550,7 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
> nifs = 0;
> ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL);
> if (ifs) {
> - nifs = afs_get_ipv4_interfaces(ifs, 32, false);
> + nifs = afs_get_ipv4_interfaces(call->net, ifs, 32, false);
> if (nifs < 0) {
> kfree(ifs);
> ifs = NULL;
> diff --git a/fs/afs/internal.h b/fs/afs/internal.h
> index f8086ec95e24..58f4de6390d0 100644
> --- a/fs/afs/internal.h
> +++ b/fs/afs/internal.h
> @@ -22,6 +22,8 @@
> #include <linux/backing-dev.h>
> #include <linux/uuid.h>
> #include <net/net_namespace.h>
> +#include <net/netns/generic.h>
> +#include <net/sock.h>
> #include <net/af_rxrpc.h>
>
> #include "afs.h"
> @@ -40,7 +42,8 @@ struct afs_mount_params {
> afs_voltype_t type; /* type of volume requested */
> int volnamesz; /* size of volume name */
> const char *volname; /* name of volume to mount */
> - struct afs_net *net; /* Network namespace in effect */
> + struct net *net_ns; /* Network namespace in effect */
> + struct afs_net *net; /* the AFS net namespace stuff */
> struct afs_cell *cell; /* cell in which to find volume */
> struct afs_volume *volume; /* volume record */
> struct key *key; /* key to use for secure mounting */
> @@ -189,7 +192,7 @@ struct afs_read {
> * - there's one superblock per volume
> */
> struct afs_super_info {
> - struct afs_net *net; /* Network namespace */
> + struct net *net_ns; /* Network namespace */
> struct afs_cell *cell; /* The cell in which the volume resides */
> struct afs_volume *volume; /* volume record */
> bool dyn_root; /* True if dynamic root */
> @@ -210,7 +213,6 @@ struct afs_sysnames {
> char *subs[AFS_NR_SYSNAME];
> refcount_t usage;
> unsigned short nr;
> - short error;
> char blank[1];
> };
>
> @@ -218,6 +220,7 @@ struct afs_sysnames {
> * AFS network namespace record.
> */
> struct afs_net {
> + struct net *net; /* Backpointer to the owning net namespace */
> struct afs_uuid uuid;
> bool live; /* F if this namespace is being removed */
>
> @@ -280,7 +283,6 @@ struct afs_net {
> };
>
> extern const char afs_init_sysname[];
> -extern struct afs_net __afs_net;// Dummy AFS network namespace; TODO: replace with real netns
>
> enum afs_cell_state {
> AFS_CELL_UNSET,
> @@ -787,34 +789,36 @@ extern int afs_drop_inode(struct inode *);
> * main.c
> */
> extern struct workqueue_struct *afs_wq;
> +extern int afs_net_id;
>
> -static inline struct afs_net *afs_d2net(struct dentry *dentry)
> +static inline struct afs_net *afs_net(struct net *net)
> {
> - return &__afs_net;
> + return net_generic(net, afs_net_id);
> }
>
> -static inline struct afs_net *afs_i2net(struct inode *inode)
> +static inline struct afs_net *afs_sb2net(struct super_block *sb)
> {
> - return &__afs_net;
> + return afs_net(AFS_FS_S(sb)->net_ns);
> }
>
> -static inline struct afs_net *afs_v2net(struct afs_vnode *vnode)
> +static inline struct afs_net *afs_d2net(struct dentry *dentry)
> {
> - return &__afs_net;
> + return afs_sb2net(dentry->d_sb);
> }
>
> -static inline struct afs_net *afs_sock2net(struct sock *sk)
> +static inline struct afs_net *afs_i2net(struct inode *inode)
> {
> - return &__afs_net;
> + return afs_sb2net(inode->i_sb);
> }
>
> -static inline struct afs_net *afs_get_net(struct afs_net *net)
> +static inline struct afs_net *afs_v2net(struct afs_vnode *vnode)
> {
> - return net;
> + return afs_i2net(&vnode->vfs_inode);
> }
>
> -static inline void afs_put_net(struct afs_net *net)
> +static inline struct afs_net *afs_sock2net(struct sock *sk)
> {
> + return net_generic(sock_net(sk), afs_net_id);
> }
>
> static inline void __afs_stat(atomic_t *s)
> @@ -842,15 +846,16 @@ extern void afs_mntpt_kill_timer(void);
> /*
> * netdevices.c
> */
> -extern int afs_get_ipv4_interfaces(struct afs_interface *, size_t, bool);
> +extern int afs_get_ipv4_interfaces(struct afs_net *, struct afs_interface *,
> + size_t, bool);
>
> /*
> * proc.c
> */
> extern int __net_init afs_proc_init(struct afs_net *);
> extern void __net_exit afs_proc_cleanup(struct afs_net *);
> -extern int afs_proc_cell_setup(struct afs_net *, struct afs_cell *);
> -extern void afs_proc_cell_remove(struct afs_net *, struct afs_cell *);
> +extern int afs_proc_cell_setup(struct afs_cell *);
> +extern void afs_proc_cell_remove(struct afs_cell *);
> extern void afs_put_sysnames(struct afs_sysnames *);
>
> /*
> @@ -983,7 +988,7 @@ extern bool afs_annotate_server_list(struct afs_server_list *, struct afs_server
> * super.c
> */
> extern int __init afs_fs_init(void);
> -extern void __exit afs_fs_exit(void);
> +extern void afs_fs_exit(void);
>
> /*
> * vlclient.c
> diff --git a/fs/afs/main.c b/fs/afs/main.c
> index d7560168b3bf..7d2c1354e2ca 100644
> --- a/fs/afs/main.c
> +++ b/fs/afs/main.c
> @@ -15,6 +15,7 @@
> #include <linux/completion.h>
> #include <linux/sched.h>
> #include <linux/random.h>
> +#include <linux/proc_fs.h>
> #define CREATE_TRACE_POINTS
> #include "internal.h"
>
> @@ -32,7 +33,7 @@ module_param(rootcell, charp, 0);
> MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
>
> struct workqueue_struct *afs_wq;
> -struct afs_net __afs_net;
> +static struct proc_dir_entry *afs_proc_symlink;
>
> #if defined(CONFIG_ALPHA)
> const char afs_init_sysname[] = "alpha_linux26";
> @@ -67,11 +68,13 @@ const char afs_init_sysname[] = "unknown_linux26";
> /*
> * Initialise an AFS network namespace record.
> */
> -static int __net_init afs_net_init(struct afs_net *net)
> +static int __net_init afs_net_init(struct net *net_ns)
> {
> struct afs_sysnames *sysnames;
> + struct afs_net *net = afs_net(net_ns);
> int ret;
>
> + net->net = net_ns;
> net->live = true;
> generate_random_uuid((unsigned char *)&net->uuid);
>
> @@ -142,8 +145,10 @@ static int __net_init afs_net_init(struct afs_net *net)
> /*
> * Clean up and destroy an AFS network namespace record.
> */
> -static void __net_exit afs_net_exit(struct afs_net *net)
> +static void __net_exit afs_net_exit(struct net *net_ns)
> {
> + struct afs_net *net = afs_net(net_ns);
> +
> net->live = false;
> afs_cell_purge(net);
> afs_purge_servers(net);
> @@ -152,6 +157,13 @@ static void __net_exit afs_net_exit(struct afs_net *net)
> afs_put_sysnames(net->sysnames);
> }
>
> +static struct pernet_operations afs_net_ops = {
> + .init = afs_net_init,
> + .exit = afs_net_exit,
> + .id = &afs_net_id,
> + .size = sizeof(struct afs_net),
> +};
> +
> /*
> * initialise the AFS client FS module
> */
> @@ -178,7 +190,7 @@ static int __init afs_init(void)
> goto error_cache;
> #endif
>
> - ret = afs_net_init(&__afs_net);
> + ret = register_pernet_subsys(&afs_net_ops);
> if (ret < 0)
> goto error_net;
>
> @@ -187,10 +199,18 @@ static int __init afs_init(void)
> if (ret < 0)
> goto error_fs;
>
> + afs_proc_symlink = proc_symlink("fs/afs", NULL, "../self/net/afs");
> + if (IS_ERR(afs_proc_symlink)) {
> + ret = PTR_ERR(afs_proc_symlink);
> + goto error_proc;
> + }
> +
> return ret;
>
> +error_proc:
> + afs_fs_exit();
> error_fs:
> - afs_net_exit(&__afs_net);
> + unregister_pernet_subsys(&afs_net_ops);
> error_net:
> #ifdef CONFIG_AFS_FSCACHE
> fscache_unregister_netfs(&afs_cache_netfs);
> @@ -219,8 +239,9 @@ static void __exit afs_exit(void)
> {
> printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n");
>
> + proc_remove(afs_proc_symlink);
> afs_fs_exit();
> - afs_net_exit(&__afs_net);
> + unregister_pernet_subsys(&afs_net_ops);
> #ifdef CONFIG_AFS_FSCACHE
> fscache_unregister_netfs(&afs_cache_netfs);
> #endif
> diff --git a/fs/afs/netdevices.c b/fs/afs/netdevices.c
> index 50bd5bb1c4fb..2a009d1939d7 100644
> --- a/fs/afs/netdevices.c
> +++ b/fs/afs/netdevices.c
> @@ -17,8 +17,8 @@
> * - maxbufs must be at least 1
> * - returns the number of interface records in the buffer
> */
> -int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
> - bool wantloopback)
> +int afs_get_ipv4_interfaces(struct afs_net *net, struct afs_interface *bufs,
> + size_t maxbufs, bool wantloopback)
> {
> struct net_device *dev;
> struct in_device *idev;
> @@ -27,7 +27,7 @@ int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
> ASSERT(maxbufs > 0);
>
> rtnl_lock();
> - for_each_netdev(&init_net, dev) {
> + for_each_netdev(net->net, dev) {
> if (dev->type == ARPHRD_LOOPBACK && !wantloopback)
> continue;
> idev = __in_dev_get_rtnl(dev);
> diff --git a/fs/afs/proc.c b/fs/afs/proc.c
> index 363383e9961f..9f748687d2c2 100644
> --- a/fs/afs/proc.c
> +++ b/fs/afs/proc.c
> @@ -17,14 +17,14 @@
> #include <linux/uaccess.h>
> #include "internal.h"
>
> -static inline struct afs_net *afs_proc2net(struct file *f)
> +static inline struct afs_net *afs_seq2net(struct seq_file *m)
> {
> - return &__afs_net;
> + return afs_net(seq_file_net(m));
> }
>
> -static inline struct afs_net *afs_seq2net(struct seq_file *m)
> +static inline struct afs_net *afs_seq2net_single(struct seq_file *m)
> {
> - return &__afs_net; // TODO: use seq_file_net(m)
> + return afs_net(seq_file_single_net(m));
> }
>
> /*
> @@ -75,28 +75,20 @@ static const struct seq_operations afs_proc_cells_ops = {
> * handle writes to /proc/fs/afs/cells
> * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
> */
> -static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
> - size_t size, loff_t *_pos)
> +static int afs_proc_cells_write(struct file *file, char *buf, size_t size)
> {
> - struct afs_net *net = afs_proc2net(file);
> - char *kbuf, *name, *args;
> + struct seq_file *m = file->private_data;
> + struct afs_net *net = afs_seq2net(m);
> + char *name, *args;
> int ret;
>
> - /* start by dragging the command into memory */
> - if (size <= 1 || size >= PAGE_SIZE)
> - return -EINVAL;
> -
> - kbuf = memdup_user_nul(buf, size);
> - if (IS_ERR(kbuf))
> - return PTR_ERR(kbuf);
> -
> /* trim to first NL */
> - name = memchr(kbuf, '\n', size);
> + name = memchr(buf, '\n', size);
> if (name)
> *name = 0;
>
> /* split into command, name and argslist */
> - name = strchr(kbuf, ' ');
> + name = strchr(buf, ' ');
> if (!name)
> goto inval;
> do {
> @@ -115,9 +107,9 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
> goto inval;
>
> /* determine command to perform */
> - _debug("cmd=%s name=%s args=%s", kbuf, name, args);
> + _debug("cmd=%s name=%s args=%s", buf, name, args);
>
> - if (strcmp(kbuf, "add") == 0) {
> + if (strcmp(buf, "add") == 0) {
> struct afs_cell *cell;
>
> cell = afs_lookup_cell(net, name, strlen(name), args, true);
> @@ -133,10 +125,9 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
> goto inval;
> }
>
> - ret = size;
> + ret = 0;
>
> done:
> - kfree(kbuf);
> _leave(" = %d", ret);
> return ret;
>
> @@ -146,68 +137,23 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
> goto done;
> }
>
> -static int afs_proc_cells_open(struct inode *inode, struct file *file)
> -{
> - struct seq_file *m;
> - int ret;
> -
> - ret = seq_open(file, &afs_proc_cells_ops);
> - if (ret < 0)
> - return ret;
> -
> - m = file->private_data;
> - m->private = PDE_DATA(inode);
> - return 0;
> -}
> -
> -static const struct file_operations afs_proc_cells_fops = {
> - .open = afs_proc_cells_open,
> - .read = seq_read,
> - .write = afs_proc_cells_write,
> - .llseek = seq_lseek,
> - .release = seq_release,
> -};
> -
> /*
> - * Read the name of the current workstation cell.
> + * Display the name of the current workstation cell.
> */
> -static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
> - size_t size, loff_t *_pos)
> +static int afs_proc_rootcell_show(struct seq_file *m, void *v)
> {
> struct afs_cell *cell;
> - struct afs_net *net = afs_proc2net(file);
> - unsigned int seq = 0;
> - char name[AFS_MAXCELLNAME + 1];
> - int len;
> -
> - if (*_pos > 0)
> - return 0;
> - if (!net->ws_cell)
> - return 0;
> -
> - rcu_read_lock();
> - do {
> - read_seqbegin_or_lock(&net->cells_lock, &seq);
> - len = 0;
> - cell = rcu_dereference_raw(net->ws_cell);
> - if (cell) {
> - len = cell->name_len;
> - memcpy(name, cell->name, len);
> - }
> - } while (need_seqretry(&net->cells_lock, seq));
> - done_seqretry(&net->cells_lock, seq);
> - rcu_read_unlock();
> -
> - if (!len)
> - return 0;
> -
> - name[len++] = '\n';
> - if (len > size)
> - len = size;
> - if (copy_to_user(buf, name, len) != 0)
> - return -EFAULT;
> - *_pos = 1;
> - return len;
> + struct afs_net *net;
> +
> + net = afs_seq2net_single(m);
> + if (net->ws_cell) {
> + rcu_read_lock();
> + cell = rcu_dereference(net->ws_cell);
> + if (cell)
> + seq_printf(m, "%s\n", cell->name);
> + rcu_read_unlock();
> + }
> + return 0;
> }
>
> /*
> @@ -216,52 +162,34 @@ static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
> *
> * echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell
> */
> -static ssize_t afs_proc_rootcell_write(struct file *file,
> - const char __user *buf,
> - size_t size, loff_t *_pos)
> +static int afs_proc_rootcell_write(struct file *file, char *buf, size_t size)
> {
> - struct afs_net *net = afs_proc2net(file);
> - char *kbuf, *s;
> + struct seq_file *m = file->private_data;
> + struct afs_net *net = afs_seq2net_single(m);
> + char *s;
> int ret;
>
> - /* start by dragging the command into memory */
> - if (size <= 1 || size >= PAGE_SIZE)
> - return -EINVAL;
> -
> - kbuf = memdup_user_nul(buf, size);
> - if (IS_ERR(kbuf))
> - return PTR_ERR(kbuf);
> -
> ret = -EINVAL;
> - if (kbuf[0] == '.')
> + if (buf[0] == '.')
> goto out;
> - if (memchr(kbuf, '/', size))
> + if (memchr(buf, '/', size))
> goto out;
>
> /* trim to first NL */
> - s = memchr(kbuf, '\n', size);
> + s = memchr(buf, '\n', size);
> if (s)
> *s = 0;
>
> /* determine command to perform */
> - _debug("rootcell=%s", kbuf);
> + _debug("rootcell=%s", buf);
>
> - ret = afs_cell_init(net, kbuf);
> - if (ret >= 0)
> - ret = size; /* consume everything, always */
> + ret = afs_cell_init(net, buf);
>
> out:
> - kfree(kbuf);
> _leave(" = %d", ret);
> return ret;
> }
>
> -static const struct file_operations afs_proc_rootcell_fops = {
> - .read = afs_proc_rootcell_read,
> - .write = afs_proc_rootcell_write,
> - .llseek = no_llseek,
> -};
> -
> static const char afs_vol_types[3][3] = {
> [AFSVL_RWVOL] = "RW",
> [AFSVL_ROVOL] = "RO",
> @@ -273,8 +201,8 @@ static const char afs_vol_types[3][3] = {
> */
> static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
> {
> - struct afs_cell *cell = m->private;
> struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
> + struct afs_cell *cell = PDE_DATA(file_inode(m->file));
>
> /* Display header on line 1 */
> if (v == &cell->proc_volumes) {
> @@ -292,24 +220,24 @@ static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
> static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
> __acquires(cell->proc_lock)
> {
> - struct afs_cell *cell = m->private;
> + struct afs_cell *cell = PDE_DATA(file_inode(m->file));
>
> read_lock(&cell->proc_lock);
> return seq_list_start_head(&cell->proc_volumes, *_pos);
> }
>
> -static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
> +static void *afs_proc_cell_volumes_next(struct seq_file *m, void *v,
> loff_t *_pos)
> {
> - struct afs_cell *cell = p->private;
> + struct afs_cell *cell = PDE_DATA(file_inode(m->file));
>
> return seq_list_next(v, &cell->proc_volumes, _pos);
> }
>
> -static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
> +static void afs_proc_cell_volumes_stop(struct seq_file *m, void *v)
> __releases(cell->proc_lock)
> {
> - struct afs_cell *cell = p->private;
> + struct afs_cell *cell = PDE_DATA(file_inode(m->file));
>
> read_unlock(&cell->proc_lock);
> }
> @@ -321,33 +249,6 @@ static const struct seq_operations afs_proc_cell_volumes_ops = {
> .show = afs_proc_cell_volumes_show,
> };
>
> -static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)
> -{
> - struct afs_cell *cell;
> - struct seq_file *m;
> - int ret;
> -
> - cell = PDE_DATA(inode);
> - if (!cell)
> - return -ENOENT;
> -
> - ret = seq_open(file, &afs_proc_cell_volumes_ops);
> - if (ret < 0)
> - return ret;
> -
> - m = file->private_data;
> - m->private = cell;
> -
> - return 0;
> -}
> -
> -static const struct file_operations afs_proc_cell_volumes_fops = {
> - .open = afs_proc_cell_volumes_open,
> - .read = seq_read,
> - .llseek = seq_lseek,
> - .release = seq_release,
> -};
> -
> /*
> * Display the list of Volume Location servers we're using for a cell.
> */
> @@ -370,7 +271,7 @@ static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
> __acquires(rcu)
> {
> struct afs_addr_list *alist;
> - struct afs_cell *cell = m->private;
> + struct afs_cell *cell = PDE_DATA(file_inode(m->file));
> loff_t pos = *_pos;
>
> rcu_read_lock();
> @@ -388,11 +289,11 @@ static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
> return alist->addrs + pos;
> }
>
> -static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
> +static void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v,
> loff_t *_pos)
> {
> struct afs_addr_list *alist;
> - struct afs_cell *cell = p->private;
> + struct afs_cell *cell = PDE_DATA(file_inode(m->file));
> loff_t pos;
>
> alist = rcu_dereference(cell->vl_addrs);
> @@ -405,7 +306,7 @@ static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
> return alist->addrs + pos;
> }
>
> -static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
> +static void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v)
> __releases(rcu)
> {
> rcu_read_unlock();
> @@ -418,33 +319,6 @@ static const struct seq_operations afs_proc_cell_vlservers_ops = {
> .show = afs_proc_cell_vlservers_show,
> };
>
> -static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)
> -{
> - struct afs_cell *cell;
> - struct seq_file *m;
> - int ret;
> -
> - cell = PDE_DATA(inode);
> - if (!cell)
> - return -ENOENT;
> -
> - ret = seq_open(file, &afs_proc_cell_vlservers_ops);
> - if (ret<0)
> - return ret;
> -
> - m = file->private_data;
> - m->private = cell;
> -
> - return 0;
> -}
> -
> -static const struct file_operations afs_proc_cell_vlservers_fops = {
> - .open = afs_proc_cell_vlservers_open,
> - .read = seq_read,
> - .llseek = seq_lseek,
> - .release = seq_release,
> -};
> -
> /*
> * Display the list of fileservers we're using within a namespace.
> */
> @@ -479,7 +353,7 @@ static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
> return seq_hlist_next_rcu(v, &afs_seq2net(m)->fs_proc, _pos);
> }
>
> -static void afs_proc_servers_stop(struct seq_file *p, void *v)
> +static void afs_proc_servers_stop(struct seq_file *m, void *v)
> __releases(rcu)
> {
> rcu_read_unlock();
> @@ -492,18 +366,6 @@ static const struct seq_operations afs_proc_servers_ops = {
> .show = afs_proc_servers_show,
> };
>
> -static int afs_proc_servers_open(struct inode *inode, struct file *file)
> -{
> - return seq_open(file, &afs_proc_servers_ops);
> -}
> -
> -static const struct file_operations afs_proc_servers_fops = {
> - .open = afs_proc_servers_open,
> - .read = seq_read,
> - .llseek = seq_lseek,
> - .release = seq_release,
> -};
> -
> /*
> * Display the list of strings that may be substituted for the @sys pathname
> * macro.
> @@ -523,10 +385,11 @@ static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
> __acquires(&net->sysnames_lock)
> {
> struct afs_net *net = afs_seq2net(m);
> - struct afs_sysnames *names = net->sysnames;
> + struct afs_sysnames *names;
>
> read_lock(&net->sysnames_lock);
>
> + names = net->sysnames;
> if (*pos >= names->nr)
> return NULL;
> return (void *)(unsigned long)(*pos + 1);
> @@ -561,35 +424,21 @@ static const struct seq_operations afs_proc_sysname_ops = {
> /*
> * Allow the @sys substitution to be configured.
> */
> -static ssize_t afs_proc_sysname_write(struct file *file,
> - const char __user *buf,
> - size_t size, loff_t *_pos)
> +static int afs_proc_sysname_write(struct file *file, char *buf, size_t size)
> {
> - struct afs_sysnames *sysnames;
> + struct afs_sysnames *sysnames, *kill;
> struct seq_file *m = file->private_data;
> - char *kbuf = NULL, *s, *p, *sub;
> + struct afs_net *net = afs_seq2net(m);
> + char *s, *p, *sub;
> int ret, len;
>
> - sysnames = m->private;
> + sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
> if (!sysnames)
> - return -EINVAL;
> - if (sysnames->error)
> - return sysnames->error;
> -
> - if (size >= PAGE_SIZE - 1) {
> - sysnames->error = -EINVAL;
> - return -EINVAL;
> - }
> - if (size == 0)
> - return 0;
> -
> - kbuf = memdup_user_nul(buf, size);
> - if (IS_ERR(kbuf))
> - return PTR_ERR(kbuf);
> -
> - inode_lock(file_inode(file));
> + return -ENOMEM;
> + refcount_set(&sysnames->usage, 1);
> + kill = sysnames;
>
> - p = kbuf;
> + p = buf;
> while ((s = strsep(&p, " \t\n"))) {
> len = strlen(s);
> if (len == 0)
> @@ -630,16 +479,23 @@ static ssize_t afs_proc_sysname_write(struct file *file,
> sysnames->nr++;
> }
>
> - ret = size; /* consume everything, always */
> + if (sysnames->nr == 0) {
> + sysnames->subs[0] = sysnames->blank;
> + sysnames->nr++;
> + }
> +
> + write_lock(&net->sysnames_lock);
> + kill = net->sysnames;
> + net->sysnames = sysnames;
> + write_unlock(&net->sysnames_lock);
> + ret = 0;
> out:
> - inode_unlock(file_inode(file));
> - kfree(kbuf);
> + afs_put_sysnames(kill);
> return ret;
>
> invalid:
> ret = -EINVAL;
> error:
> - sysnames->error = ret;
> goto out;
> }
>
> @@ -655,75 +511,12 @@ void afs_put_sysnames(struct afs_sysnames *sysnames)
> }
> }
>
> -static int afs_proc_sysname_release(struct inode *inode, struct file *file)
> -{
> - struct afs_sysnames *sysnames, *kill = NULL;
> - struct seq_file *m = file->private_data;
> - struct afs_net *net = afs_seq2net(m);
> -
> - sysnames = m->private;
> - if (sysnames) {
> - if (!sysnames->error) {
> - kill = sysnames;
> - if (sysnames->nr == 0) {
> - sysnames->subs[0] = sysnames->blank;
> - sysnames->nr++;
> - }
> - write_lock(&net->sysnames_lock);
> - kill = net->sysnames;
> - net->sysnames = sysnames;
> - write_unlock(&net->sysnames_lock);
> - }
> - afs_put_sysnames(kill);
> - }
> -
> - return seq_release(inode, file);
> -}
> -
> -/*
> - * Handle opening of /proc/fs/afs/sysname. If it is opened for writing, we
> - * assume the caller wants to change the substitution list and we allocate a
> - * buffer to hold the list.
> - */
> -static int afs_proc_sysname_open(struct inode *inode, struct file *file)
> -{
> - struct afs_sysnames *sysnames;
> - struct seq_file *m;
> - int ret;
> -
> - ret = seq_open(file, &afs_proc_sysname_ops);
> - if (ret < 0)
> - return ret;
> -
> - if (file->f_mode & FMODE_WRITE) {
> - sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
> - if (!sysnames) {
> - seq_release(inode, file);
> - return -ENOMEM;
> - }
> -
> - refcount_set(&sysnames->usage, 1);
> - m = file->private_data;
> - m->private = sysnames;
> - }
> -
> - return 0;
> -}
> -
> -static const struct file_operations afs_proc_sysname_fops = {
> - .open = afs_proc_sysname_open,
> - .read = seq_read,
> - .llseek = seq_lseek,
> - .release = afs_proc_sysname_release,
> - .write = afs_proc_sysname_write,
> -};
> -
> /*
> * Display general per-net namespace statistics.
> */
> static int afs_proc_stats_show(struct seq_file *m, void *v)
> {
> - struct afs_net *net = afs_seq2net(m);
> + struct afs_net *net = afs_seq2net_single(m);
>
> seq_puts(m, "kAFS statistics\n");
>
> @@ -749,38 +542,28 @@ static int afs_proc_stats_show(struct seq_file *m, void *v)
> return 0;
> }
>
> -/*
> - * Open "/proc/fs/afs/stats" to allow reading of the stat counters.
> - */
> -static int afs_proc_stats_open(struct inode *inode, struct file *file)
> -{
> - return single_open(file, afs_proc_stats_show, NULL);
> -}
> -
> -static const struct file_operations afs_proc_stats_fops = {
> - .open = afs_proc_stats_open,
> - .read = seq_read,
> - .llseek = seq_lseek,
> - .release = single_release,
> -};
> -
> /*
> * initialise /proc/fs/afs/<cell>/
> */
> -int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
> +int afs_proc_cell_setup(struct afs_cell *cell)
> {
> struct proc_dir_entry *dir;
> + struct afs_net *net = cell->net;
>
> _enter("%p{%s},%p", cell, cell->name, net->proc_afs);
>
> - dir = proc_mkdir(cell->name, net->proc_afs);
> + dir = proc_net_mkdir(net->net, cell->name, net->proc_afs);
> if (!dir)
> goto error_dir;
>
> - if (!proc_create_data("vlservers", 0, dir,
> - &afs_proc_cell_vlservers_fops, cell) ||
> - !proc_create_data("volumes", 0, dir,
> - &afs_proc_cell_volumes_fops, cell))
> + if (!proc_create_net_data("vlservers", 0444, dir,
> + &afs_proc_cell_vlservers_ops,
> + sizeof(struct seq_net_private),
> + cell) ||
> + !proc_create_net_data("volumes", 0444, dir,
> + &afs_proc_cell_volumes_ops,
> + sizeof(struct seq_net_private),
> + cell))
> goto error_tree;
>
> _leave(" = 0");
> @@ -796,12 +579,12 @@ int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
> /*
> * remove /proc/fs/afs/<cell>/
> */
> -void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
> +void afs_proc_cell_remove(struct afs_cell *cell)
> {
> - _enter("");
> + struct afs_net *net = cell->net;
>
> + _enter("");
> remove_proc_subtree(cell->name, net->proc_afs);
> -
> _leave("");
> }
>
> @@ -810,24 +593,39 @@ void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
> */
> int afs_proc_init(struct afs_net *net)
> {
> + struct proc_dir_entry *p;
> +
> _enter("");
>
> - net->proc_afs = proc_mkdir("fs/afs", NULL);
> - if (!net->proc_afs)
> + p = proc_net_mkdir(net->net, "afs", net->net->proc_net);
> + if (!p)
> goto error_dir;
>
> - if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) ||
> - !proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops) ||
> - !proc_create("servers", 0644, net->proc_afs, &afs_proc_servers_fops) ||
> - !proc_create("stats", 0644, net->proc_afs, &afs_proc_stats_fops) ||
> - !proc_create("sysname", 0644, net->proc_afs, &afs_proc_sysname_fops))
> + if (!proc_create_net_data_write("cells", 0644, p,
> + &afs_proc_cells_ops,
> + afs_proc_cells_write,
> + sizeof(struct seq_net_private),
> + NULL) ||
> + !proc_create_net_single_write("rootcell", 0644, p,
> + afs_proc_rootcell_show,
> + afs_proc_rootcell_write,
> + NULL) ||
> + !proc_create_net("servers", 0444, p, &afs_proc_servers_ops,
> + sizeof(struct seq_net_private)) ||
> + !proc_create_net_single("stats", 0444, p, afs_proc_stats_show, NULL) ||
> + !proc_create_net_data_write("sysname", 0644, p,
> + &afs_proc_sysname_ops,
> + afs_proc_sysname_write,
> + sizeof(struct seq_net_private),
> + NULL))
> goto error_tree;
>
> + net->proc_afs = p;
> _leave(" = 0");
> return 0;
>
> error_tree:
> - proc_remove(net->proc_afs);
> + proc_remove(p);
> error_dir:
> _leave(" = -ENOMEM");
> return -ENOMEM;
> diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
> index 5c6263972ec9..e58fa0e15798 100644
> --- a/fs/afs/rxrpc.c
> +++ b/fs/afs/rxrpc.c
> @@ -45,7 +45,7 @@ int afs_open_socket(struct afs_net *net)
>
> _enter("");
>
> - ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket);
> + ret = sock_create_kern(net->net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket);
> if (ret < 0)
> goto error_1;
>
> diff --git a/fs/afs/super.c b/fs/afs/super.c
> index 65081ec3c36e..593820372848 100644
> --- a/fs/afs/super.c
> +++ b/fs/afs/super.c
> @@ -48,6 +48,8 @@ struct file_system_type afs_fs_type = {
> };
> MODULE_ALIAS_FS("afs");
>
> +int afs_net_id;
> +
> static const struct super_operations afs_super_ops = {
> .statfs = afs_statfs,
> .alloc_inode = afs_alloc_inode,
> @@ -117,7 +119,7 @@ int __init afs_fs_init(void)
> /*
> * clean up the filesystem
> */
> -void __exit afs_fs_exit(void)
> +void afs_fs_exit(void)
> {
> _enter("");
>
> @@ -351,7 +353,7 @@ static int afs_test_super(struct super_block *sb, void *data)
> struct afs_super_info *as1 = data;
> struct afs_super_info *as = AFS_FS_S(sb);
>
> - return (as->net == as1->net &&
> + return (as->net_ns == as1->net_ns &&
> as->volume &&
> as->volume->vid == as1->volume->vid);
> }
> @@ -437,7 +439,7 @@ static struct afs_super_info *afs_alloc_sbi(struct afs_mount_params *params)
>
> as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
> if (as) {
> - as->net = afs_get_net(params->net);
> + as->net_ns = get_net(params->net_ns);
> if (params->dyn_root)
> as->dyn_root = true;
> else
> @@ -450,8 +452,8 @@ static void afs_destroy_sbi(struct afs_super_info *as)
> {
> if (as) {
> afs_put_volume(as->cell, as->volume);
> - afs_put_cell(as->net, as->cell);
> - afs_put_net(as->net);
> + afs_put_cell(afs_net(as->net_ns), as->cell);
> + put_net(as->net_ns);
> kfree(as);
> }
> }
> @@ -472,12 +474,13 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
> _enter(",,%s,%p", dev_name, options);
>
> memset(&params, 0, sizeof(params));
> - params.net = &__afs_net;
>
> ret = -EINVAL;
> if (current->nsproxy->net_ns != &init_net)
> goto error;
> -
> + params.net_ns = current->nsproxy->net_ns;
> + params.net = afs_net(params.net_ns);
> +
> /* parse the options and device name */
> if (options) {
> ret = afs_parse_options(&params, options, &dev_name);
> @@ -571,7 +574,8 @@ static void afs_kill_super(struct super_block *sb)
> * deactivating the superblock.
> */
> if (as->volume)
> - afs_clear_callback_interests(as->net, as->volume->servers);
> + afs_clear_callback_interests(afs_net(as->net_ns),
> + as->volume->servers);
> kill_anon_super(sb);
> if (as->volume)
> afs_deactivate_volume(as->volume);
---end quoted text---