All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] afs: Network-namespacing
@ 2018-05-23 12:16 David Howells
  2018-05-23 12:16 ` [PATCH 1/8] afs: Move /proc management functions to the end of the file David Howells
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: David Howells @ 2018-05-23 12:16 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, linux-kernel


Hi Al,

Can you pull these patches on top of Christoph's procfs changes?  The patches
do:

 (*) Rearrange fs/afs/proc.c to get rid of the forward declarations and
     simplify the commenting.

 (*) Supply functions that allow writable net proc files to be created
     (this could be extended to provide writing on non-net proc files).

 (*) Implement network namespacing in AFS and simplify the proc usage,
     using the new convenience functions provided.

I've included another couple of small patches also:

 (*) afs_net::ws_cell should be annotated and accessed for RCU.  This patch
     would conflict with the other patches if separate.

 (*) Fix a sparse warning where sparse can't manage to follow the locking
     in a function.

Note that these patches don't quite complete network namespacing; the last
bit requires the mount API patches to allow propagation of the network
namespace across automounts.

The patches are tagged here:

	git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git
	afs-namespace-20180523

The patches can be found here also:

	http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=afs-namespace

David
---
David Howells (8):
      afs: Move /proc management functions to the end of the file
      afs: Rearrange fs/afs/proc.c by moving fops and open functions down
      afs: Rearrange fs/afs/proc.c to move the show routines up
      afs: Rearrange fs/afs/proc.c to remove remaining predeclarations.
      proc: Add a way to make network proc files writable
      afs: Fix a Sparse warning in xdr_decode_AFSFetchStatus()
      afs: Mark afs_net::ws_cell as __rcu and set using rcu functions
      afs: Implement network namespacing


 fs/afs/cell.c           |   12 -
 fs/afs/cmservice.c      |    2 
 fs/afs/fsclient.c       |   97 +++---
 fs/afs/internal.h       |   45 +--
 fs/afs/main.c           |   33 ++
 fs/afs/netdevices.c     |    6 
 fs/afs/proc.c           |  787 +++++++++++++++++------------------------------
 fs/afs/rxrpc.c          |    2 
 fs/afs/super.c          |   20 +
 fs/proc/generic.c       |   24 +
 fs/proc/internal.h      |    2 
 fs/proc/proc_net.c      |   92 +++++
 include/linux/proc_fs.h |   12 +
 13 files changed, 552 insertions(+), 582 deletions(-)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/8] afs: Move /proc management functions to the end of the file
  2018-05-23 12:16 [PATCH 0/8] afs: Network-namespacing David Howells
@ 2018-05-23 12:16 ` David Howells
  2018-05-23 12:16 ` [PATCH 2/8] afs: Rearrange fs/afs/proc.c by moving fops and open functions down David Howells
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2018-05-23 12:16 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, linux-kernel

In fs/afs/proc.c, move functions that create and remove /proc files to the
end of the source file as a first stage in getting rid of all the forward
declarations.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/proc.c |  160 ++++++++++++++++++++++++++++-----------------------------
 1 file changed, 79 insertions(+), 81 deletions(-)

diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 3aad32762989..4bb612b04f3c 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -127,45 +127,6 @@ static const struct file_operations afs_proc_sysname_fops = {
 	.write		= afs_proc_sysname_write,
 };
 
-static int afs_proc_stats_show(struct seq_file *m, void *v);
-
-/*
- * initialise the /proc/fs/afs/ directory
- */
-int afs_proc_init(struct afs_net *net)
-{
-	_enter("");
-
-	net->proc_afs = proc_mkdir("fs/afs", NULL);
-	if (!net->proc_afs)
-		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))
-		goto error_tree;
-
-	_leave(" = 0");
-	return 0;
-
-error_tree:
-	proc_remove(net->proc_afs);
-error_dir:
-	_leave(" = -ENOMEM");
-	return -ENOMEM;
-}
-
-/*
- * clean up the /proc/fs/afs/ directory
- */
-void afs_proc_cleanup(struct afs_net *net)
-{
-	proc_remove(net->proc_afs);
-	net->proc_afs = NULL;
-}
-
 /*
  * open "/proc/fs/afs/cells" which provides a summary of extant cells
  */
@@ -383,48 +344,6 @@ static ssize_t afs_proc_rootcell_write(struct file *file,
 	return ret;
 }
 
-/*
- * initialise /proc/fs/afs/<cell>/
- */
-int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
-{
-	struct proc_dir_entry *dir;
-
-	_enter("%p{%s},%p", cell, cell->name, net->proc_afs);
-
-	dir = proc_mkdir(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))
-		goto error_tree;
-
-	_leave(" = 0");
-	return 0;
-
-error_tree:
-	remove_proc_subtree(cell->name, net->proc_afs);
-error_dir:
-	_leave(" = -ENOMEM");
-	return -ENOMEM;
-}
-
-/*
- * remove /proc/fs/afs/<cell>/
- */
-void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
-{
-	_enter("");
-
-	remove_proc_subtree(cell->name, net->proc_afs);
-
-	_leave("");
-}
-
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
@@ -842,3 +761,82 @@ static int afs_proc_stats_show(struct seq_file *m, void *v)
 		   atomic_long_read(&net->n_store_bytes));
 	return 0;
 }
+
+/*
+ * initialise /proc/fs/afs/<cell>/
+ */
+int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
+{
+	struct proc_dir_entry *dir;
+
+	_enter("%p{%s},%p", cell, cell->name, net->proc_afs);
+
+	dir = proc_mkdir(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))
+		goto error_tree;
+
+	_leave(" = 0");
+	return 0;
+
+error_tree:
+	remove_proc_subtree(cell->name, net->proc_afs);
+error_dir:
+	_leave(" = -ENOMEM");
+	return -ENOMEM;
+}
+
+/*
+ * remove /proc/fs/afs/<cell>/
+ */
+void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
+{
+	_enter("");
+
+	remove_proc_subtree(cell->name, net->proc_afs);
+
+	_leave("");
+}
+
+/*
+ * initialise the /proc/fs/afs/ directory
+ */
+int afs_proc_init(struct afs_net *net)
+{
+	_enter("");
+
+	net->proc_afs = proc_mkdir("fs/afs", NULL);
+	if (!net->proc_afs)
+		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))
+		goto error_tree;
+
+	_leave(" = 0");
+	return 0;
+
+error_tree:
+	proc_remove(net->proc_afs);
+error_dir:
+	_leave(" = -ENOMEM");
+	return -ENOMEM;
+}
+
+/*
+ * clean up the /proc/fs/afs/ directory
+ */
+void afs_proc_cleanup(struct afs_net *net)
+{
+	proc_remove(net->proc_afs);
+	net->proc_afs = NULL;
+}

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/8] afs: Rearrange fs/afs/proc.c by moving fops and open functions down
  2018-05-23 12:16 [PATCH 0/8] afs: Network-namespacing David Howells
  2018-05-23 12:16 ` [PATCH 1/8] afs: Move /proc management functions to the end of the file David Howells
@ 2018-05-23 12:16 ` David Howells
  2018-05-23 12:17 ` [PATCH 3/8] afs: Rearrange fs/afs/proc.c to move the show routines up David Howells
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2018-05-23 12:16 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, linux-kernel

Rearrange fs/afs/proc.c by moving fops and open functions down so as to
remove predeclarations.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/proc.c |   71 ++++++++++++++++++++++-----------------------------------
 1 file changed, 27 insertions(+), 44 deletions(-)

diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 4bb612b04f3c..22ce99df3208 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -27,13 +27,10 @@ static inline struct afs_net *afs_seq2net(struct seq_file *m)
 	return &__afs_net; // TODO: use seq_file_net(m)
 }
 
-static int afs_proc_cells_open(struct inode *inode, struct file *file);
 static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
 static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
 static void afs_proc_cells_stop(struct seq_file *p, void *v);
 static int afs_proc_cells_show(struct seq_file *m, void *v);
-static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
-				    size_t size, loff_t *_pos);
 
 static const struct seq_operations afs_proc_cells_ops = {
 	.start	= afs_proc_cells_start,
@@ -42,26 +39,6 @@ static const struct seq_operations afs_proc_cells_ops = {
 	.show	= afs_proc_cells_show,
 };
 
-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,
-};
-
-static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
-				      size_t size, loff_t *_pos);
-static ssize_t afs_proc_rootcell_write(struct file *file,
-				       const char __user *buf,
-				       size_t size, loff_t *_pos);
-
-static const struct file_operations afs_proc_rootcell_fops = {
-	.read		= afs_proc_rootcell_read,
-	.write		= afs_proc_rootcell_write,
-	.llseek		= no_llseek,
-};
-
 static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
 					loff_t *pos);
@@ -101,16 +78,11 @@ static const struct seq_operations afs_proc_servers_ops = {
 	.show	= afs_proc_servers_show,
 };
 
-static int afs_proc_sysname_open(struct inode *inode, struct file *file);
-static int afs_proc_sysname_release(struct inode *inode, struct file *file);
 static void *afs_proc_sysname_start(struct seq_file *p, loff_t *pos);
 static void *afs_proc_sysname_next(struct seq_file *p, void *v,
 					loff_t *pos);
 static void afs_proc_sysname_stop(struct seq_file *p, void *v);
 static int afs_proc_sysname_show(struct seq_file *m, void *v);
-static ssize_t afs_proc_sysname_write(struct file *file,
-				      const char __user *buf,
-				      size_t size, loff_t *_pos);
 
 static const struct seq_operations afs_proc_sysname_ops = {
 	.start	= afs_proc_sysname_start,
@@ -119,22 +91,6 @@ static const struct seq_operations afs_proc_sysname_ops = {
 	.show	= afs_proc_sysname_show,
 };
 
-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,
-};
-
-/*
- * open "/proc/fs/afs/cells" which provides a summary of extant cells
- */
-static int afs_proc_cells_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &afs_proc_cells_ops);
-}
-
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
@@ -261,6 +217,19 @@ 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)
+{
+	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,
+};
+
 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
 				      size_t size, loff_t *_pos)
 {
@@ -344,6 +313,12 @@ static ssize_t afs_proc_rootcell_write(struct file *file,
 	return ret;
 }
 
+static const struct file_operations afs_proc_rootcell_fops = {
+	.read		= afs_proc_rootcell_read,
+	.write		= afs_proc_rootcell_write,
+	.llseek		= no_llseek,
+};
+
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
@@ -731,6 +706,14 @@ static int afs_proc_sysname_show(struct seq_file *m, void *v)
 	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
  */

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/8] afs: Rearrange fs/afs/proc.c to move the show routines up
  2018-05-23 12:16 [PATCH 0/8] afs: Network-namespacing David Howells
  2018-05-23 12:16 ` [PATCH 1/8] afs: Move /proc management functions to the end of the file David Howells
  2018-05-23 12:16 ` [PATCH 2/8] afs: Rearrange fs/afs/proc.c by moving fops and open functions down David Howells
@ 2018-05-23 12:17 ` David Howells
  2018-05-23 12:17 ` [PATCH 4/8] afs: Rearrange fs/afs/proc.c to remove remaining predeclarations David Howells
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2018-05-23 12:17 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, linux-kernel

Rearrange fs/afs/proc.c to move the show routines up to the top of each
block so the order is show, iteration, ops, file ops, fops.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/proc.c |  150 +++++++++++++++++++++++++++++----------------------------
 1 file changed, 75 insertions(+), 75 deletions(-)

diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 22ce99df3208..b20098b7b7ee 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -91,6 +91,25 @@ static const struct seq_operations afs_proc_sysname_ops = {
 	.show	= afs_proc_sysname_show,
 };
 
+/*
+ * display a header line followed by a load of cell lines
+ */
+static int afs_proc_cells_show(struct seq_file *m, void *v)
+{
+	struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
+	struct afs_net *net = afs_seq2net(m);
+
+	if (v == &net->proc_cells) {
+		/* display header on line 1 */
+		seq_puts(m, "USE NAME\n");
+		return 0;
+	}
+
+	/* display one cell per line on subsequent lines */
+	seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name);
+	return 0;
+}
+
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
@@ -123,25 +142,6 @@ static void afs_proc_cells_stop(struct seq_file *m, void *v)
 	rcu_read_unlock();
 }
 
-/*
- * display a header line followed by a load of cell lines
- */
-static int afs_proc_cells_show(struct seq_file *m, void *v)
-{
-	struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
-	struct afs_net *net = afs_seq2net(m);
-
-	if (v == &net->proc_cells) {
-		/* display header on line 1 */
-		seq_puts(m, "USE NAME\n");
-		return 0;
-	}
-
-	/* display one cell per line on subsequent lines */
-	seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name);
-	return 0;
-}
-
 /*
  * handle writes to /proc/fs/afs/cells
  * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
@@ -319,6 +319,33 @@ static const struct file_operations afs_proc_rootcell_fops = {
 	.llseek		= no_llseek,
 };
 
+static const char afs_vol_types[3][3] = {
+	[AFSVL_RWVOL]	= "RW",
+	[AFSVL_ROVOL]	= "RO",
+	[AFSVL_BACKVOL]	= "BK",
+};
+
+/*
+ * display a header line followed by a load of volume lines
+ */
+static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
+{
+	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
+	struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
+
+	/* Display header on line 1 */
+	if (v == &cell->proc_volumes) {
+		seq_puts(m, "USE VID      TY\n");
+		return 0;
+	}
+
+	seq_printf(m, "%3d %08x %s\n",
+		   atomic_read(&vol->usage), vol->vid,
+		   afs_vol_types[vol->type]);
+
+	return 0;
+}
+
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
@@ -357,30 +384,21 @@ static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
 	read_unlock(&cell->proc_lock);
 }
 
-static const char afs_vol_types[3][3] = {
-	[AFSVL_RWVOL]	= "RW",
-	[AFSVL_ROVOL]	= "RO",
-	[AFSVL_BACKVOL]	= "BK",
-};
-
 /*
  * display a header line followed by a load of volume lines
  */
-static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
+static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
 {
-	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
-	struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
+	struct sockaddr_rxrpc *addr = v;
 
-	/* Display header on line 1 */
-	if (v == &cell->proc_volumes) {
-		seq_puts(m, "USE VID      TY\n");
+	/* display header on line 1 */
+	if (v == (void *)1) {
+		seq_puts(m, "ADDRESS\n");
 		return 0;
 	}
 
-	seq_printf(m, "%3d %08x %s\n",
-		   atomic_read(&vol->usage), vol->vid,
-		   afs_vol_types[vol->type]);
-
+	/* display one cell per line on subsequent lines */
+	seq_printf(m, "%pISp\n", &addr->transport);
 	return 0;
 }
 
@@ -442,18 +460,22 @@ static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
 /*
  * display a header line followed by a load of volume lines
  */
-static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
+static int afs_proc_servers_show(struct seq_file *m, void *v)
 {
-	struct sockaddr_rxrpc *addr = v;
+	struct afs_server *server;
+	struct afs_addr_list *alist;
 
-	/* display header on line 1 */
-	if (v == (void *)1) {
-		seq_puts(m, "ADDRESS\n");
+	if (v == SEQ_START_TOKEN) {
+		seq_puts(m, "UUID                                 USE ADDR\n");
 		return 0;
 	}
 
-	/* display one cell per line on subsequent lines */
-	seq_printf(m, "%pISp\n", &addr->transport);
+	server = list_entry(v, struct afs_server, proc_link);
+	alist = rcu_dereference(server->addresses);
+	seq_printf(m, "%pU %3d %pISp\n",
+		   &server->uuid,
+		   atomic_read(&server->usage),
+		   &alist->addrs[alist->index].transport);
 	return 0;
 }
 
@@ -489,28 +511,6 @@ static void afs_proc_servers_stop(struct seq_file *p, void *v)
 	rcu_read_unlock();
 }
 
-/*
- * display a header line followed by a load of volume lines
- */
-static int afs_proc_servers_show(struct seq_file *m, void *v)
-{
-	struct afs_server *server;
-	struct afs_addr_list *alist;
-
-	if (v == SEQ_START_TOKEN) {
-		seq_puts(m, "UUID                                 USE ADDR\n");
-		return 0;
-	}
-
-	server = list_entry(v, struct afs_server, proc_link);
-	alist = rcu_dereference(server->addresses);
-	seq_printf(m, "%pU %3d %pISp\n",
-		   &server->uuid,
-		   atomic_read(&server->usage),
-		   &alist->addrs[alist->index].transport);
-	return 0;
-}
-
 void afs_put_sysnames(struct afs_sysnames *sysnames)
 {
 	int i;
@@ -663,6 +663,17 @@ static int afs_proc_sysname_release(struct inode *inode, struct file *file)
 	return seq_release(inode, file);
 }
 
+static int afs_proc_sysname_show(struct seq_file *m, void *v)
+{
+	struct afs_net *net = afs_seq2net(m);
+	struct afs_sysnames *sysnames = net->sysnames;
+	unsigned int i = (unsigned long)v - 1;
+
+	if (i < sysnames->nr)
+		seq_printf(m, "%s\n", sysnames->subs[i]);
+	return 0;
+}
+
 static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
 	__acquires(&net->sysnames_lock)
 {
@@ -695,17 +706,6 @@ static void afs_proc_sysname_stop(struct seq_file *m, void *v)
 	read_unlock(&net->sysnames_lock);
 }
 
-static int afs_proc_sysname_show(struct seq_file *m, void *v)
-{
-	struct afs_net *net = afs_seq2net(m);
-	struct afs_sysnames *sysnames = net->sysnames;
-	unsigned int i = (unsigned long)v - 1;
-
-	if (i < sysnames->nr)
-		seq_printf(m, "%s\n", sysnames->subs[i]);
-	return 0;
-}
-
 static const struct file_operations afs_proc_sysname_fops = {
 	.open		= afs_proc_sysname_open,
 	.read		= seq_read,

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/8] afs: Rearrange fs/afs/proc.c to remove remaining predeclarations.
  2018-05-23 12:16 [PATCH 0/8] afs: Network-namespacing David Howells
                   ` (2 preceding siblings ...)
  2018-05-23 12:17 ` [PATCH 3/8] afs: Rearrange fs/afs/proc.c to move the show routines up David Howells
@ 2018-05-23 12:17 ` David Howells
  2018-05-23 12:17 ` [PATCH 5/8] proc: Add a way to make network proc files writable David Howells
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2018-05-23 12:17 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, linux-kernel

Rearrange fs/afs/proc.c to get rid of all the remaining predeclarations.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/proc.c |  352 ++++++++++++++++++++++++++-------------------------------
 1 file changed, 160 insertions(+), 192 deletions(-)

diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index b20098b7b7ee..b45ee7576aa8 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -27,72 +27,8 @@ static inline struct afs_net *afs_seq2net(struct seq_file *m)
 	return &__afs_net; // TODO: use seq_file_net(m)
 }
 
-static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
-static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
-static void afs_proc_cells_stop(struct seq_file *p, void *v);
-static int afs_proc_cells_show(struct seq_file *m, void *v);
-
-static const struct seq_operations afs_proc_cells_ops = {
-	.start	= afs_proc_cells_start,
-	.next	= afs_proc_cells_next,
-	.stop	= afs_proc_cells_stop,
-	.show	= afs_proc_cells_show,
-};
-
-static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
-static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
-					loff_t *pos);
-static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
-static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
-
-static const struct seq_operations afs_proc_cell_volumes_ops = {
-	.start	= afs_proc_cell_volumes_start,
-	.next	= afs_proc_cell_volumes_next,
-	.stop	= afs_proc_cell_volumes_stop,
-	.show	= afs_proc_cell_volumes_show,
-};
-
-static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
-static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
-					  loff_t *pos);
-static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
-static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
-
-static const struct seq_operations afs_proc_cell_vlservers_ops = {
-	.start	= afs_proc_cell_vlservers_start,
-	.next	= afs_proc_cell_vlservers_next,
-	.stop	= afs_proc_cell_vlservers_stop,
-	.show	= afs_proc_cell_vlservers_show,
-};
-
-static void *afs_proc_servers_start(struct seq_file *p, loff_t *pos);
-static void *afs_proc_servers_next(struct seq_file *p, void *v,
-					loff_t *pos);
-static void afs_proc_servers_stop(struct seq_file *p, void *v);
-static int afs_proc_servers_show(struct seq_file *m, void *v);
-
-static const struct seq_operations afs_proc_servers_ops = {
-	.start	= afs_proc_servers_start,
-	.next	= afs_proc_servers_next,
-	.stop	= afs_proc_servers_stop,
-	.show	= afs_proc_servers_show,
-};
-
-static void *afs_proc_sysname_start(struct seq_file *p, loff_t *pos);
-static void *afs_proc_sysname_next(struct seq_file *p, void *v,
-					loff_t *pos);
-static void afs_proc_sysname_stop(struct seq_file *p, void *v);
-static int afs_proc_sysname_show(struct seq_file *m, void *v);
-
-static const struct seq_operations afs_proc_sysname_ops = {
-	.start	= afs_proc_sysname_start,
-	.next	= afs_proc_sysname_next,
-	.stop	= afs_proc_sysname_stop,
-	.show	= afs_proc_sysname_show,
-};
-
 /*
- * display a header line followed by a load of cell lines
+ * Display the list of cells known to the namespace.
  */
 static int afs_proc_cells_show(struct seq_file *m, void *v)
 {
@@ -110,38 +46,31 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)
 	return 0;
 }
 
-/*
- * set up the iterator to start reading from the cells list and return the
- * first item
- */
 static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
 	__acquires(rcu)
 {
-	struct afs_net *net = afs_seq2net(m);
-
 	rcu_read_lock();
-	return seq_list_start_head(&net->proc_cells, *_pos);
+	return seq_list_start_head(&afs_seq2net(m)->proc_cells, *_pos);
 }
 
-/*
- * move to next cell in cells list
- */
 static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
 {
-	struct afs_net *net = afs_seq2net(m);
-
-	return seq_list_next(v, &net->proc_cells, pos);
+	return seq_list_next(v, &afs_seq2net(m)->proc_cells, pos);
 }
 
-/*
- * clean up after reading from the cells list
- */
 static void afs_proc_cells_stop(struct seq_file *m, void *v)
 	__releases(rcu)
 {
 	rcu_read_unlock();
 }
 
+static const struct seq_operations afs_proc_cells_ops = {
+	.start	= afs_proc_cells_start,
+	.next	= afs_proc_cells_next,
+	.stop	= afs_proc_cells_stop,
+	.show	= afs_proc_cells_show,
+};
+
 /*
  * handle writes to /proc/fs/afs/cells
  * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
@@ -230,6 +159,9 @@ static const struct file_operations afs_proc_cells_fops = {
 	.release	= seq_release,
 };
 
+/*
+ * Read 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)
 {
@@ -270,8 +202,10 @@ static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
 }
 
 /*
- * handle writes to /proc/fs/afs/rootcell
- * - to initialize rootcell: echo "cell.name:192.168.231.14"
+ * Set the current workstation cell and optionally supply its list of volume
+ * location servers.
+ *
+ *	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,
@@ -326,7 +260,7 @@ static const char afs_vol_types[3][3] = {
 };
 
 /*
- * display a header line followed by a load of volume lines
+ * Display the list of volumes known to a cell.
  */
 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
 {
@@ -346,36 +280,23 @@ static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
 	return 0;
 }
 
-/*
- * set up the iterator to start reading from the cells list and return the
- * first item
- */
 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
 	__acquires(cell->proc_lock)
 {
 	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
 
-	_enter("cell=%p pos=%Ld", cell, *_pos);
-
 	read_lock(&cell->proc_lock);
 	return seq_list_start_head(&cell->proc_volumes, *_pos);
 }
 
-/*
- * move to next cell in cells list
- */
 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
 					loff_t *_pos)
 {
 	struct afs_cell *cell = PDE_DATA(file_inode(p->file));
 
-	_enter("cell=%p pos=%Ld", cell, *_pos);
 	return seq_list_next(v, &cell->proc_volumes, _pos);
 }
 
-/*
- * clean up after reading from the cells list
- */
 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
 	__releases(cell->proc_lock)
 {
@@ -384,8 +305,15 @@ static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
 	read_unlock(&cell->proc_lock);
 }
 
+static const struct seq_operations afs_proc_cell_volumes_ops = {
+	.start	= afs_proc_cell_volumes_start,
+	.next	= afs_proc_cell_volumes_next,
+	.stop	= afs_proc_cell_volumes_stop,
+	.show	= afs_proc_cell_volumes_show,
+};
+
 /*
- * display a header line followed by a load of volume lines
+ * Display the list of Volume Location servers we're using for a cell.
  */
 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
 {
@@ -402,10 +330,6 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
 	return 0;
 }
 
-/*
- * set up the iterator to start reading from the cells list and return the
- * first item
- */
 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
 	__acquires(rcu)
 {
@@ -428,9 +352,6 @@ static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
 	return alist->addrs + pos;
 }
 
-/*
- * move to next cell in cells list
- */
 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
 					  loff_t *_pos)
 {
@@ -448,17 +369,48 @@ static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
 	return alist->addrs + pos;
 }
 
-/*
- * clean up after reading from the cells list
- */
 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
 	__releases(rcu)
 {
 	rcu_read_unlock();
 }
 
+static const struct seq_operations afs_proc_cell_vlservers_ops = {
+	.start	= afs_proc_cell_vlservers_start,
+	.next	= afs_proc_cell_vlservers_next,
+	.stop	= afs_proc_cell_vlservers_stop,
+	.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 a header line followed by a load of volume lines
+ * Display the list of fileservers we're using within a namespace.
  */
 static int afs_proc_servers_show(struct seq_file *m, void *v)
 {
@@ -479,82 +431,99 @@ static int afs_proc_servers_show(struct seq_file *m, void *v)
 	return 0;
 }
 
-/*
- * Set up the iterator to start reading from the server list and return the
- * first item.
- */
 static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos)
 	__acquires(rcu)
 {
-	struct afs_net *net = afs_seq2net(m);
-
 	rcu_read_lock();
-	return seq_hlist_start_head_rcu(&net->fs_proc, *_pos);
+	return seq_hlist_start_head_rcu(&afs_seq2net(m)->fs_proc, *_pos);
 }
 
-/*
- * move to next cell in cells list
- */
 static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
 {
-	struct afs_net *net = afs_seq2net(m);
-
-	return seq_hlist_next_rcu(v, &net->fs_proc, _pos);
+	return seq_hlist_next_rcu(v, &afs_seq2net(m)->fs_proc, _pos);
 }
 
-/*
- * clean up after reading from the cells list
- */
 static void afs_proc_servers_stop(struct seq_file *p, void *v)
 	__releases(rcu)
 {
 	rcu_read_unlock();
 }
 
-void afs_put_sysnames(struct afs_sysnames *sysnames)
-{
-	int i;
+static const struct seq_operations afs_proc_servers_ops = {
+	.start	= afs_proc_servers_start,
+	.next	= afs_proc_servers_next,
+	.stop	= afs_proc_servers_stop,
+	.show	= afs_proc_servers_show,
+};
 
-	if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
-		for (i = 0; i < sysnames->nr; i++)
-			if (sysnames->subs[i] != afs_init_sysname &&
-			    sysnames->subs[i] != sysnames->blank)
-				kfree(sysnames->subs[i]);
-	}
+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,
+};
+
 /*
- * 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.
+ * Display the list of strings that may be substituted for the @sys pathname
+ * macro.
  */
-static int afs_proc_sysname_open(struct inode *inode, struct file *file)
+static int afs_proc_sysname_show(struct seq_file *m, void *v)
 {
-	struct afs_sysnames *sysnames;
-	struct seq_file *m;
-	int ret;
+	struct afs_net *net = afs_seq2net(m);
+	struct afs_sysnames *sysnames = net->sysnames;
+	unsigned int i = (unsigned long)v - 1;
 
-	ret = seq_open(file, &afs_proc_sysname_ops);
-	if (ret < 0)
-		return ret;
+	if (i < sysnames->nr)
+		seq_printf(m, "%s\n", sysnames->subs[i]);
+	return 0;
+}
 
-	if (file->f_mode & FMODE_WRITE) {
-		sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
-		if (!sysnames) {
-			seq_release(inode, file);
-			return -ENOMEM;
-		}
+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;
 
-		refcount_set(&sysnames->usage, 1);
-		m = file->private_data;
-		m->private = sysnames;
-	}
+	read_lock(&net->sysnames_lock);
 
-	return 0;
+	if (*pos >= names->nr)
+		return NULL;
+	return (void *)(unsigned long)(*pos + 1);
+}
+
+static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct afs_net *net = afs_seq2net(m);
+	struct afs_sysnames *names = net->sysnames;
+
+	*pos += 1;
+	if (*pos >= names->nr)
+		return NULL;
+	return (void *)(unsigned long)(*pos + 1);
+}
+
+static void afs_proc_sysname_stop(struct seq_file *m, void *v)
+	__releases(&net->sysnames_lock)
+{
+	struct afs_net *net = afs_seq2net(m);
+
+	read_unlock(&net->sysnames_lock);
 }
 
+static const struct seq_operations afs_proc_sysname_ops = {
+	.start	= afs_proc_sysname_start,
+	.next	= afs_proc_sysname_next,
+	.stop	= afs_proc_sysname_stop,
+	.show	= afs_proc_sysname_show,
+};
+
 /*
- * Handle writes to /proc/fs/afs/sysname to set the @sys substitution.
+ * Allow the @sys substitution to be configured.
  */
 static ssize_t afs_proc_sysname_write(struct file *file,
 				      const char __user *buf,
@@ -638,6 +607,18 @@ static ssize_t afs_proc_sysname_write(struct file *file,
 	goto out;
 }
 
+void afs_put_sysnames(struct afs_sysnames *sysnames)
+{
+	int i;
+
+	if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
+		for (i = 0; i < sysnames->nr; i++)
+			if (sysnames->subs[i] != afs_init_sysname &&
+			    sysnames->subs[i] != sysnames->blank)
+				kfree(sysnames->subs[i]);
+	}
+}
+
 static int afs_proc_sysname_release(struct inode *inode, struct file *file)
 {
 	struct afs_sysnames *sysnames, *kill = NULL;
@@ -663,47 +644,34 @@ static int afs_proc_sysname_release(struct inode *inode, struct file *file)
 	return seq_release(inode, file);
 }
 
-static int afs_proc_sysname_show(struct seq_file *m, void *v)
-{
-	struct afs_net *net = afs_seq2net(m);
-	struct afs_sysnames *sysnames = net->sysnames;
-	unsigned int i = (unsigned long)v - 1;
-
-	if (i < sysnames->nr)
-		seq_printf(m, "%s\n", sysnames->subs[i]);
-	return 0;
-}
-
-static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
-	__acquires(&net->sysnames_lock)
+/*
+ * 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_net *net = afs_seq2net(m);
-	struct afs_sysnames *names = net->sysnames;
-
-	read_lock(&net->sysnames_lock);
-
-	if (*pos >= names->nr)
-		return NULL;
-	return (void *)(unsigned long)(*pos + 1);
-}
+	struct afs_sysnames *sysnames;
+	struct seq_file *m;
+	int ret;
 
-static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
-{
-	struct afs_net *net = afs_seq2net(m);
-	struct afs_sysnames *names = net->sysnames;
+	ret = seq_open(file, &afs_proc_sysname_ops);
+	if (ret < 0)
+		return ret;
 
-	*pos += 1;
-	if (*pos >= names->nr)
-		return NULL;
-	return (void *)(unsigned long)(*pos + 1);
-}
+	if (file->f_mode & FMODE_WRITE) {
+		sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
+		if (!sysnames) {
+			seq_release(inode, file);
+			return -ENOMEM;
+		}
 
-static void afs_proc_sysname_stop(struct seq_file *m, void *v)
-	__releases(&net->sysnames_lock)
-{
-	struct afs_net *net = afs_seq2net(m);
+		refcount_set(&sysnames->usage, 1);
+		m = file->private_data;
+		m->private = sysnames;
+	}
 
-	read_unlock(&net->sysnames_lock);
+	return 0;
 }
 
 static const struct file_operations afs_proc_sysname_fops = {

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/8] proc: Add a way to make network proc files writable
  2018-05-23 12:16 [PATCH 0/8] afs: Network-namespacing David Howells
                   ` (3 preceding siblings ...)
  2018-05-23 12:17 ` [PATCH 4/8] afs: Rearrange fs/afs/proc.c to remove remaining predeclarations David Howells
@ 2018-05-23 12:17 ` David Howells
  2018-05-23 12:17 ` [PATCH 6/8] afs: Fix a Sparse warning in xdr_decode_AFSFetchStatus() David Howells
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2018-05-23 12:17 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, linux-kernel

Provide two extra functions, proc_create_net_data_write() and
proc_create_net_single_write() that act like their non-write versions but
also set a write method in the proc_dir_entry struct.

An internal simple write function is provided that will copy its buffer and
hand it to the pde->write() method if available (or give an error if not).
The buffer may be modified by the write method.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/proc/generic.c       |   24 ++++++++++++
 fs/proc/internal.h      |    2 +
 fs/proc/proc_net.c      |   92 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/proc_fs.h |   12 ++++++
 4 files changed, 130 insertions(+)

diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 02bb1914f5f7..d0e5a68ae14a 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -741,3 +741,27 @@ void *PDE_DATA(const struct inode *inode)
 	return __PDE_DATA(inode);
 }
 EXPORT_SYMBOL(PDE_DATA);
+
+/*
+ * Pull a user buffer into memory and pass it to the file's write handler if
+ * one is supplied.  The ->write() method is permitted to modify the
+ * kernel-side buffer.
+ */
+ssize_t proc_simple_write(struct file *f, const char __user *ubuf, size_t size,
+			  loff_t *_pos)
+{
+	struct proc_dir_entry *pde = PDE(file_inode(f));
+	char *buf;
+	int ret;
+
+	if (!pde->write)
+		return -EACCES;
+	if (size == 0 || size > PAGE_SIZE - 1)
+		return -EINVAL;
+	buf = memdup_user_nul(ubuf, size);
+	if (IS_ERR(buf))
+		return PTR_ERR(buf);
+	ret = pde->write(f, buf, size);
+	kfree(buf);
+	return ret == 0 ? size : ret;
+}
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index a318ae5b36b4..916ccc39073d 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -48,6 +48,7 @@ struct proc_dir_entry {
 		const struct seq_operations *seq_ops;
 		int (*single_show)(struct seq_file *, void *);
 	};
+	proc_write_t write;
 	void *data;
 	unsigned int state_size;
 	unsigned int low_ino;
@@ -187,6 +188,7 @@ static inline bool is_empty_pde(const struct proc_dir_entry *pde)
 {
 	return S_ISDIR(pde->mode) && !pde->proc_iops;
 }
+extern ssize_t proc_simple_write(struct file *, const char __user *, size_t, loff_t *);
 
 /*
  * inode.c
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
index 7d94fa005b0d..d5e0fcb3439e 100644
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -46,6 +46,9 @@ static int seq_open_net(struct inode *inode, struct file *file)
 
 	WARN_ON_ONCE(state_size < sizeof(*p));
 
+	if (file->f_mode & FMODE_WRITE && !PDE(inode)->write)
+		return -EACCES;
+
 	net = get_proc_net(inode);
 	if (!net)
 		return -ENXIO;
@@ -73,6 +76,7 @@ static int seq_release_net(struct inode *ino, struct file *f)
 static const struct file_operations proc_net_seq_fops = {
 	.open		= seq_open_net,
 	.read		= seq_read,
+	.write		= proc_simple_write,
 	.llseek		= seq_lseek,
 	.release	= seq_release_net,
 };
@@ -93,6 +97,50 @@ struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode,
 }
 EXPORT_SYMBOL_GPL(proc_create_net_data);
 
+/**
+ * proc_create_net_data_write - Create a writable net_ns-specific proc file
+ * @name: The name of the file.
+ * @mode: The file's access mode.
+ * @parent: The parent directory in which to create.
+ * @ops: The seq_file ops with which to read the file.
+ * @write: The write method which which to 'modify' the file.
+ * @data: Data for retrieval by PDE_DATA().
+ *
+ * Create a network namespaced proc file in the @parent directory with the
+ * specified @name and @mode that allows reading of a file that displays a
+ * series of elements and also provides for the file accepting writes that have
+ * some arbitrary effect.
+ *
+ * The functions in the @ops table are used to iterate over items to be
+ * presented and extract the readable content using the seq_file interface.
+ *
+ * The @write function is called with the data copied into a kernel space
+ * scratch buffer and has a NUL appended for convenience.  The buffer may be
+ * modified by the @write function.  @write should return 0 on success.
+ *
+ * The @data value is accessible from the @show and @write functions by calling
+ * PDE_DATA() on the file inode.  The network namespace must be accessed by
+ * calling seq_file_net() on the seq_file struct.
+ */
+struct proc_dir_entry *proc_create_net_data_write(const char *name, umode_t mode,
+						  struct proc_dir_entry *parent,
+						  const struct seq_operations *ops,
+						  proc_write_t write,
+						  unsigned int state_size, void *data)
+{
+	struct proc_dir_entry *p;
+
+	p = proc_create_reg(name, mode, &parent, data);
+	if (!p)
+		return NULL;
+	p->proc_fops = &proc_net_seq_fops;
+	p->seq_ops = ops;
+	p->state_size = state_size;
+	p->write = write;
+	return proc_register(parent, p);
+}
+EXPORT_SYMBOL_GPL(proc_create_net_data_write);
+
 static int single_open_net(struct inode *inode, struct file *file)
 {
 	struct proc_dir_entry *de = PDE(inode);
@@ -119,6 +167,7 @@ static int single_release_net(struct inode *ino, struct file *f)
 static const struct file_operations proc_net_single_fops = {
 	.open		= single_open_net,
 	.read		= seq_read,
+	.write		= proc_simple_write,
 	.llseek		= seq_lseek,
 	.release	= single_release_net,
 };
@@ -138,6 +187,49 @@ struct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode,
 }
 EXPORT_SYMBOL_GPL(proc_create_net_single);
 
+/**
+ * proc_create_net_single_write - Create a writable net_ns-specific proc file
+ * @name: The name of the file.
+ * @mode: The file's access mode.
+ * @parent: The parent directory in which to create.
+ * @show: The seqfile show method with which to read the file.
+ * @write: The write method which which to 'modify' the file.
+ * @data: Data for retrieval by PDE_DATA().
+ *
+ * Create a network-namespaced proc file in the @parent directory with the
+ * specified @name and @mode that allows reading of a file that displays a
+ * single element rather than a series and also provides for the file accepting
+ * writes that have some arbitrary effect.
+ *
+ * The @show function is called to extract the readable content via the
+ * seq_file interface.
+ *
+ * The @write function is called with the data copied into a kernel space
+ * scratch buffer and has a NUL appended for convenience.  The buffer may be
+ * modified by the @write function.  @write should return 0 on success.
+ *
+ * The @data value is accessible from the @show and @write functions by calling
+ * PDE_DATA() on the file inode.  The network namespace must be accessed by
+ * calling seq_file_single_net() on the seq_file struct.
+ */
+struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mode,
+						    struct proc_dir_entry *parent,
+						    int (*show)(struct seq_file *, void *),
+						    proc_write_t write,
+						    void *data)
+{
+	struct proc_dir_entry *p;
+
+	p = proc_create_reg(name, mode, &parent, data);
+	if (!p)
+		return NULL;
+	p->proc_fops = &proc_net_single_fops;
+	p->single_show = show;
+	p->write = write;
+	return proc_register(parent, p);
+}
+EXPORT_SYMBOL_GPL(proc_create_net_single_write);
+
 static struct net *get_proc_task_net(struct inode *dir)
 {
 	struct task_struct *task;
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index e518352137e7..626fc65c4336 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -14,6 +14,8 @@ struct seq_operations;
 
 #ifdef CONFIG_PROC_FS
 
+typedef int (*proc_write_t)(struct file *, char *, size_t);
+
 extern void proc_root_init(void);
 extern void proc_flush_task(struct task_struct *);
 
@@ -61,6 +63,16 @@ struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode,
 struct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode,
 		struct proc_dir_entry *parent,
 		int (*show)(struct seq_file *, void *), void *data);
+struct proc_dir_entry *proc_create_net_data_write(const char *name, umode_t mode,
+						  struct proc_dir_entry *parent,
+						  const struct seq_operations *ops,
+						  proc_write_t write,
+						  unsigned int state_size, void *data);
+struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mode,
+						    struct proc_dir_entry *parent,
+						    int (*show)(struct seq_file *, void *),
+						    proc_write_t write,
+						    void *data);
 
 #else /* CONFIG_PROC_FS */
 

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 6/8] afs: Fix a Sparse warning in xdr_decode_AFSFetchStatus()
  2018-05-23 12:16 [PATCH 0/8] afs: Network-namespacing David Howells
                   ` (4 preceding siblings ...)
  2018-05-23 12:17 ` [PATCH 5/8] proc: Add a way to make network proc files writable David Howells
@ 2018-05-23 12:17 ` David Howells
  2018-05-23 12:17 ` [PATCH 7/8] afs: Mark afs_net::ws_cell as __rcu and set using rcu functions David Howells
  2018-05-23 12:17 ` [PATCH 8/8] afs: Implement network namespacing David Howells
  7 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2018-05-23 12:17 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, linux-kernel

Sparse doesn't appear able to handle the conditionally-taken locks in
xdr_decode_AFSFetchStatus(), even though the lock and unlock are both
contingent on the same unvarying function argument.

Deal with this by interpolating a wrapper function that takes the lock if
needed and calls xdr_decode_AFSFetchStatus() on two separate branches, one
with the lock held and one without.

This allows Sparse to work out the locking.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/fsclient.c |   97 ++++++++++++++++++++++++++++++-----------------------
 1 file changed, 55 insertions(+), 42 deletions(-)

diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index efacdb7c1dee..b695d9e16c65 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -137,10 +137,6 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
 	u64 data_version, size;
 	u32 type, abort_code;
 	u8 flags = 0;
-	int ret;
-
-	if (vnode)
-		write_seqlock(&vnode->cb_lock);
 
 	if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
 		pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
@@ -168,8 +164,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
 	case AFS_FTYPE_INVALID:
 		if (abort_code != 0) {
 			status->abort_code = abort_code;
-			ret = 0;
-			goto out;
+			return 0;
 		}
 		/* Fall through */
 	default:
@@ -222,17 +217,35 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
 					     flags);
 	}
 
-	ret = 0;
-
-out:
-	if (vnode)
-		write_sequnlock(&vnode->cb_lock);
-	return ret;
+	return 0;
 
 bad:
 	xdr_dump_bad(*_bp);
-	ret = afs_protocol_error(call, -EBADMSG);
-	goto out;
+	return afs_protocol_error(call, -EBADMSG);
+}
+
+/*
+ * Decode the file status.  We need to lock the target vnode if we're going to
+ * update its status so that stat() sees the attributes update atomically.
+ */
+static int afs_decode_status(struct afs_call *call,
+			     const __be32 **_bp,
+			     struct afs_file_status *status,
+			     struct afs_vnode *vnode,
+			     const afs_dataversion_t *expected_version,
+			     struct afs_read *read_req)
+{
+	int ret;
+
+	if (!vnode)
+		return xdr_decode_AFSFetchStatus(call, _bp, status, vnode,
+						 expected_version, read_req);
+
+	write_seqlock(&vnode->cb_lock);
+	ret = xdr_decode_AFSFetchStatus(call, _bp, status, vnode,
+					expected_version, read_req);
+	write_sequnlock(&vnode->cb_lock);
+	return ret;
 }
 
 /*
@@ -374,8 +387,8 @@ static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
 
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
-	if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-				      &call->expected_version, NULL) < 0)
+	if (afs_decode_status(call, &bp, &vnode->status, vnode,
+			      &call->expected_version, NULL) < 0)
 		return afs_protocol_error(call, -EBADMSG);
 	xdr_decode_AFSCallBack(call, vnode, &bp);
 	if (call->reply[1])
@@ -555,8 +568,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 			return ret;
 
 		bp = call->buffer;
-		if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-					      &vnode->status.data_version, req) < 0)
+		if (afs_decode_status(call, &bp, &vnode->status, vnode,
+				      &vnode->status.data_version, req) < 0)
 			return afs_protocol_error(call, -EBADMSG);
 		xdr_decode_AFSCallBack(call, vnode, &bp);
 		if (call->reply[1])
@@ -708,9 +721,9 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call)
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
 	xdr_decode_AFSFid(&bp, call->reply[1]);
-	if (xdr_decode_AFSFetchStatus(call, &bp, call->reply[2], NULL, NULL, NULL) < 0 ||
-	    xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-				      &call->expected_version, NULL) < 0)
+	if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) < 0 ||
+	    afs_decode_status(call, &bp, &vnode->status, vnode,
+			      &call->expected_version, NULL) < 0)
 		return afs_protocol_error(call, -EBADMSG);
 	xdr_decode_AFSCallBack_raw(&bp, call->reply[3]);
 	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
@@ -814,8 +827,8 @@ static int afs_deliver_fs_remove(struct afs_call *call)
 
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
-	if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-				      &call->expected_version, NULL) < 0)
+	if (afs_decode_status(call, &bp, &vnode->status, vnode,
+			      &call->expected_version, NULL) < 0)
 		return afs_protocol_error(call, -EBADMSG);
 	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -904,9 +917,9 @@ static int afs_deliver_fs_link(struct afs_call *call)
 
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
-	if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, NULL, NULL) < 0 ||
-	    xdr_decode_AFSFetchStatus(call, &bp, &dvnode->status, dvnode,
-				      &call->expected_version, NULL) < 0)
+	if (afs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL) < 0 ||
+	    afs_decode_status(call, &bp, &dvnode->status, dvnode,
+			      &call->expected_version, NULL) < 0)
 		return afs_protocol_error(call, -EBADMSG);
 	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -991,9 +1004,9 @@ static int afs_deliver_fs_symlink(struct afs_call *call)
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
 	xdr_decode_AFSFid(&bp, call->reply[1]);
-	if (xdr_decode_AFSFetchStatus(call, &bp, call->reply[2], NULL, NULL, NULL) ||
-	    xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-				      &call->expected_version, NULL) < 0)
+	if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) ||
+	    afs_decode_status(call, &bp, &vnode->status, vnode,
+			      &call->expected_version, NULL) < 0)
 		return afs_protocol_error(call, -EBADMSG);
 	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -1097,12 +1110,12 @@ static int afs_deliver_fs_rename(struct afs_call *call)
 
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
-	if (xdr_decode_AFSFetchStatus(call, &bp, &orig_dvnode->status, orig_dvnode,
-				      &call->expected_version, NULL) < 0)
+	if (afs_decode_status(call, &bp, &orig_dvnode->status, orig_dvnode,
+			      &call->expected_version, NULL) < 0)
 		return afs_protocol_error(call, -EBADMSG);
 	if (new_dvnode != orig_dvnode &&
-	    xdr_decode_AFSFetchStatus(call, &bp, &new_dvnode->status, new_dvnode,
-				      &call->expected_version_2, NULL) < 0)
+	    afs_decode_status(call, &bp, &new_dvnode->status, new_dvnode,
+			      &call->expected_version_2, NULL) < 0)
 		return afs_protocol_error(call, -EBADMSG);
 	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -1206,8 +1219,8 @@ static int afs_deliver_fs_store_data(struct afs_call *call)
 
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
-	if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-				      &call->expected_version, NULL) < 0)
+	if (afs_decode_status(call, &bp, &vnode->status, vnode,
+			      &call->expected_version, NULL) < 0)
 		return afs_protocol_error(call, -EBADMSG);
 	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -1382,8 +1395,8 @@ static int afs_deliver_fs_store_status(struct afs_call *call)
 
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
-	if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-				      &call->expected_version, NULL) < 0)
+	if (afs_decode_status(call, &bp, &vnode->status, vnode,
+			      &call->expected_version, NULL) < 0)
 		return afs_protocol_error(call, -EBADMSG);
 	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -2084,8 +2097,8 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call)
 
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
-	xdr_decode_AFSFetchStatus(call, &bp, status, vnode,
-				  &call->expected_version, NULL);
+	afs_decode_status(call, &bp, status, vnode,
+			  &call->expected_version, NULL);
 	callback[call->count].version	= ntohl(bp[0]);
 	callback[call->count].expiry	= ntohl(bp[1]);
 	callback[call->count].type	= ntohl(bp[2]);
@@ -2196,9 +2209,9 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
 
 		bp = call->buffer;
 		statuses = call->reply[1];
-		if (xdr_decode_AFSFetchStatus(call, &bp, &statuses[call->count],
-					      call->count == 0 ? vnode : NULL,
-					      NULL, NULL) < 0)
+		if (afs_decode_status(call, &bp, &statuses[call->count],
+				      call->count == 0 ? vnode : NULL,
+				      NULL, NULL) < 0)
 			return afs_protocol_error(call, -EBADMSG);
 
 		call->count++;

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 7/8] afs: Mark afs_net::ws_cell as __rcu and set using rcu functions
  2018-05-23 12:16 [PATCH 0/8] afs: Network-namespacing David Howells
                   ` (5 preceding siblings ...)
  2018-05-23 12:17 ` [PATCH 6/8] afs: Fix a Sparse warning in xdr_decode_AFSFetchStatus() David Howells
@ 2018-05-23 12:17 ` David Howells
  2018-05-23 12:17 ` [PATCH 8/8] afs: Implement network namespacing David Howells
  7 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2018-05-23 12:17 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, linux-kernel

The afs_net::ws_cell member is sometimes used under RCU conditions from
within an seq-readlock.  It isn't, however, marked __rcu and it isn't set
using the proper RCU barrier-imposing functions.

Fix this by annotating it with __rcu and using appropriate barriers to
make sure accesses are correctly ordered.

Without this, the code can produce the following warning:

>> fs/afs/proc.c:151:24: sparse: incompatible types in comparison expression (different address spaces)

Fixes: f044c8847bb6 ("afs: Lay the groundwork for supporting network namespaces")
Reported-by: kbuild test robot <lkp@intel.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/afs/cell.c     |    8 ++++----
 fs/afs/internal.h |    2 +-
 fs/afs/proc.c     |    2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index fdf4c36cff79..80fd127239ce 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -341,8 +341,8 @@ int afs_cell_init(struct afs_net *net, const char *rootcell)
 
 	/* install the new cell */
 	write_seqlock(&net->cells_lock);
-	old_root = net->ws_cell;
-	net->ws_cell = new_root;
+	old_root = rcu_access_pointer(net->ws_cell);
+	rcu_assign_pointer(net->ws_cell, new_root);
 	write_sequnlock(&net->cells_lock);
 
 	afs_put_cell(net, old_root);
@@ -755,8 +755,8 @@ void afs_cell_purge(struct afs_net *net)
 	_enter("");
 
 	write_seqlock(&net->cells_lock);
-	ws = net->ws_cell;
-	net->ws_cell = NULL;
+	ws = rcu_access_pointer(net->ws_cell);
+	RCU_INIT_POINTER(net->ws_cell, NULL);
 	write_sequnlock(&net->cells_lock);
 	afs_put_cell(net, ws);
 
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index f8086ec95e24..5d922ad148a8 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -231,7 +231,7 @@ struct afs_net {
 
 	/* Cell database */
 	struct rb_root		cells;
-	struct afs_cell		*ws_cell;
+	struct afs_cell __rcu	*ws_cell;
 	struct work_struct	cells_manager;
 	struct timer_list	cells_timer;
 	atomic_t		cells_outstanding;
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index b45ee7576aa8..362f281b1b16 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -173,7 +173,7 @@ static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
 
 	if (*_pos > 0)
 		return 0;
-	if (!net->ws_cell)
+	if (!rcu_access_pointer(net->ws_cell))
 		return 0;
 
 	rcu_read_lock();

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 8/8] afs: Implement network namespacing
  2018-05-23 12:16 [PATCH 0/8] afs: Network-namespacing David Howells
                   ` (6 preceding siblings ...)
  2018-05-23 12:17 ` [PATCH 7/8] afs: Mark afs_net::ws_cell as __rcu and set using rcu functions David Howells
@ 2018-05-23 12:17 ` David Howells
  7 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2018-05-23 12:17 UTC (permalink / raw)
  To: viro; +Cc: dhowells, linux-fsdevel, linux-afs, linux-kernel

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       |    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       |  358 +++++++++++++++------------------------------------
 fs/afs/rxrpc.c      |    2 
 fs/afs/super.c      |   20 ++-
 8 files changed, 173 insertions(+), 295 deletions(-)

diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index 80fd127239ce..bb92b54d2a4a 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 5d922ad148a8..e6cef5702ae2 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 362f281b1b16..3512b9b66caf 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,59 +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)
-{
-	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 @@ 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("");
 }
 
@@ -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;
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);

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-05-23 12:20 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-23 12:16 [PATCH 0/8] afs: Network-namespacing David Howells
2018-05-23 12:16 ` [PATCH 1/8] afs: Move /proc management functions to the end of the file David Howells
2018-05-23 12:16 ` [PATCH 2/8] afs: Rearrange fs/afs/proc.c by moving fops and open functions down David Howells
2018-05-23 12:17 ` [PATCH 3/8] afs: Rearrange fs/afs/proc.c to move the show routines up David Howells
2018-05-23 12:17 ` [PATCH 4/8] afs: Rearrange fs/afs/proc.c to remove remaining predeclarations David Howells
2018-05-23 12:17 ` [PATCH 5/8] proc: Add a way to make network proc files writable David Howells
2018-05-23 12:17 ` [PATCH 6/8] afs: Fix a Sparse warning in xdr_decode_AFSFetchStatus() David Howells
2018-05-23 12:17 ` [PATCH 7/8] afs: Mark afs_net::ws_cell as __rcu and set using rcu functions David Howells
2018-05-23 12:17 ` [PATCH 8/8] afs: Implement network namespacing David Howells

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.