afs: Implement network namespacing
authorDavid Howells <dhowells@redhat.com>
Fri, 18 May 2018 10:46:15 +0000 (11:46 +0100)
committerDavid Howells <dhowells@redhat.com>
Wed, 23 May 2018 11:01:15 +0000 (12:01 +0100)
Implement network 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@redhat.com>
fs/afs/cell.c
fs/afs/cmservice.c
fs/afs/internal.h
fs/afs/main.c
fs/afs/netdevices.c
fs/afs/proc.c
fs/afs/rxrpc.c
fs/afs/super.c

index 80fd127239ce5e232c7eb923ebd625d436efa0a1..bb92b54d2a4a74dbdb3bd0ecba60b51daf637b95 100644 (file)
@@ -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);
index 357de908df3ab258c6b0d2d3fbf8cdf94e7b1575..4c89b1f4c02bdce95464382fda35c0ab546bacea 100644 (file)
@@ -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;
index 5d922ad148a8c1d17279270a7684a0625447a95d..e6cef5702ae202154fdab97ddaab288773167dc8 100644 (file)
@@ -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
index d7560168b3bf7fa8887fa77cd7bd982e06af49f0..7d2c1354e2ca5e2b1d3e4c53016a22696c63dbe8 100644 (file)
@@ -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 @@ error_sysnames:
 /*
  * 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
index 50bd5bb1c4fb1b4b91c25980f5f1452509c540e6..2a009d1939d7ffbd4047818b9f0bf0da3ffabc85 100644 (file)
@@ -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);
index 362f281b1b165f8aae845684bf754c4f8fb86e46..3512b9b66cafe22e584b160da0fd58f0729fd486 100644 (file)
 #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,59 +137,23 @@ inval:
        goto done;
 }
 
-static int afs_proc_cells_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &afs_proc_cells_ops);
-}
-
-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 (!rcu_access_pointer(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 (rcu_access_pointer(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;
 }
 
 /*
@@ -207,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",
@@ -289,18 +226,18 @@ static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
        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 = PDE_DATA(file_inode(p->file));
+       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 = PDE_DATA(file_inode(p->file));
+       struct afs_cell *cell = PDE_DATA(file_inode(m->file));
 
        read_unlock(&cell->proc_lock);
 }
@@ -352,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 = PDE_DATA(file_inode(p->file));
+       struct afs_cell *cell = PDE_DATA(file_inode(m->file));
        loff_t pos;
 
        alist = rcu_dereference(cell->vl_addrs);
@@ -369,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();
@@ -382,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.
  */
@@ -443,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();
@@ -456,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.
@@ -487,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);
@@ -525,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;
+               return -ENOMEM;
+       refcount_set(&sysnames->usage, 1);
+       kill = sysnames;
 
-       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));
-
-       p = kbuf;
+       p = buf;
        while ((s = strsep(&p, " \t\n"))) {
                len = strlen(s);
                if (len == 0)
@@ -594,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;
 }
 
@@ -619,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");
 
@@ -716,21 +545,25 @@ static int afs_proc_stats_show(struct seq_file *m, void *v)
 /*
  * 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_seq_data("vlservers", 0, dir,
-                                 &afs_proc_cell_vlservers_ops, cell))
-               goto error_tree;
-       if (!proc_create_seq_data("volumes", 0, dir,
-                                 &afs_proc_cell_volumes_ops, 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");
@@ -746,12 +579,12 @@ error_dir:
 /*
  * 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("");
 }
 
@@ -760,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_seq("servers", 0644, net->proc_afs, &afs_proc_servers_ops) ||
-           !proc_create_single("stats", 0644, net->proc_afs, afs_proc_stats_show) ||
-           !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;
index 5c6263972ec9a5651a28fd7ea7c80398e737a090..e58fa0e15798bc3b25191f50df88341d7bb6a8ee 100644 (file)
@@ -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;
 
index 65081ec3c36e572c5822d756b86abb52ed757f90..59382037284810e856d724cd38a2062d768b7bbc 100644 (file)
@@ -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);