xref: /openbmc/linux/fs/afs/proc.c (revision a86854d0)
1 /* /proc interface for AFS
2  *
3  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11 
12 #include <linux/slab.h>
13 #include <linux/module.h>
14 #include <linux/proc_fs.h>
15 #include <linux/seq_file.h>
16 #include <linux/sched.h>
17 #include <linux/uaccess.h>
18 #include "internal.h"
19 
20 static inline struct afs_net *afs_proc2net(struct file *f)
21 {
22 	return &__afs_net;
23 }
24 
25 static inline struct afs_net *afs_seq2net(struct seq_file *m)
26 {
27 	return &__afs_net; // TODO: use seq_file_net(m)
28 }
29 
30 static int afs_proc_cells_open(struct inode *inode, struct file *file);
31 static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
32 static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
33 static void afs_proc_cells_stop(struct seq_file *p, void *v);
34 static int afs_proc_cells_show(struct seq_file *m, void *v);
35 static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
36 				    size_t size, loff_t *_pos);
37 
38 static const struct seq_operations afs_proc_cells_ops = {
39 	.start	= afs_proc_cells_start,
40 	.next	= afs_proc_cells_next,
41 	.stop	= afs_proc_cells_stop,
42 	.show	= afs_proc_cells_show,
43 };
44 
45 static const struct file_operations afs_proc_cells_fops = {
46 	.open		= afs_proc_cells_open,
47 	.read		= seq_read,
48 	.write		= afs_proc_cells_write,
49 	.llseek		= seq_lseek,
50 	.release	= seq_release,
51 };
52 
53 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
54 				      size_t size, loff_t *_pos);
55 static ssize_t afs_proc_rootcell_write(struct file *file,
56 				       const char __user *buf,
57 				       size_t size, loff_t *_pos);
58 
59 static const struct file_operations afs_proc_rootcell_fops = {
60 	.read		= afs_proc_rootcell_read,
61 	.write		= afs_proc_rootcell_write,
62 	.llseek		= no_llseek,
63 };
64 
65 static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
66 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
67 					loff_t *pos);
68 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
69 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
70 
71 static const struct seq_operations afs_proc_cell_volumes_ops = {
72 	.start	= afs_proc_cell_volumes_start,
73 	.next	= afs_proc_cell_volumes_next,
74 	.stop	= afs_proc_cell_volumes_stop,
75 	.show	= afs_proc_cell_volumes_show,
76 };
77 
78 static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
79 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
80 					  loff_t *pos);
81 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
82 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
83 
84 static const struct seq_operations afs_proc_cell_vlservers_ops = {
85 	.start	= afs_proc_cell_vlservers_start,
86 	.next	= afs_proc_cell_vlservers_next,
87 	.stop	= afs_proc_cell_vlservers_stop,
88 	.show	= afs_proc_cell_vlservers_show,
89 };
90 
91 static void *afs_proc_servers_start(struct seq_file *p, loff_t *pos);
92 static void *afs_proc_servers_next(struct seq_file *p, void *v,
93 					loff_t *pos);
94 static void afs_proc_servers_stop(struct seq_file *p, void *v);
95 static int afs_proc_servers_show(struct seq_file *m, void *v);
96 
97 static const struct seq_operations afs_proc_servers_ops = {
98 	.start	= afs_proc_servers_start,
99 	.next	= afs_proc_servers_next,
100 	.stop	= afs_proc_servers_stop,
101 	.show	= afs_proc_servers_show,
102 };
103 
104 static int afs_proc_sysname_open(struct inode *inode, struct file *file);
105 static int afs_proc_sysname_release(struct inode *inode, struct file *file);
106 static void *afs_proc_sysname_start(struct seq_file *p, loff_t *pos);
107 static void *afs_proc_sysname_next(struct seq_file *p, void *v,
108 					loff_t *pos);
109 static void afs_proc_sysname_stop(struct seq_file *p, void *v);
110 static int afs_proc_sysname_show(struct seq_file *m, void *v);
111 static ssize_t afs_proc_sysname_write(struct file *file,
112 				      const char __user *buf,
113 				      size_t size, loff_t *_pos);
114 
115 static const struct seq_operations afs_proc_sysname_ops = {
116 	.start	= afs_proc_sysname_start,
117 	.next	= afs_proc_sysname_next,
118 	.stop	= afs_proc_sysname_stop,
119 	.show	= afs_proc_sysname_show,
120 };
121 
122 static const struct file_operations afs_proc_sysname_fops = {
123 	.open		= afs_proc_sysname_open,
124 	.read		= seq_read,
125 	.llseek		= seq_lseek,
126 	.release	= afs_proc_sysname_release,
127 	.write		= afs_proc_sysname_write,
128 };
129 
130 static int afs_proc_stats_show(struct seq_file *m, void *v);
131 
132 /*
133  * initialise the /proc/fs/afs/ directory
134  */
135 int afs_proc_init(struct afs_net *net)
136 {
137 	_enter("");
138 
139 	net->proc_afs = proc_mkdir("fs/afs", NULL);
140 	if (!net->proc_afs)
141 		goto error_dir;
142 
143 	if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) ||
144 	    !proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops) ||
145 	    !proc_create_seq("servers", 0644, net->proc_afs, &afs_proc_servers_ops) ||
146 	    !proc_create_single("stats", 0644, net->proc_afs, afs_proc_stats_show) ||
147 	    !proc_create("sysname", 0644, net->proc_afs, &afs_proc_sysname_fops))
148 		goto error_tree;
149 
150 	_leave(" = 0");
151 	return 0;
152 
153 error_tree:
154 	proc_remove(net->proc_afs);
155 error_dir:
156 	_leave(" = -ENOMEM");
157 	return -ENOMEM;
158 }
159 
160 /*
161  * clean up the /proc/fs/afs/ directory
162  */
163 void afs_proc_cleanup(struct afs_net *net)
164 {
165 	proc_remove(net->proc_afs);
166 	net->proc_afs = NULL;
167 }
168 
169 /*
170  * open "/proc/fs/afs/cells" which provides a summary of extant cells
171  */
172 static int afs_proc_cells_open(struct inode *inode, struct file *file)
173 {
174 	return seq_open(file, &afs_proc_cells_ops);
175 }
176 
177 /*
178  * set up the iterator to start reading from the cells list and return the
179  * first item
180  */
181 static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
182 	__acquires(rcu)
183 {
184 	struct afs_net *net = afs_seq2net(m);
185 
186 	rcu_read_lock();
187 	return seq_list_start_head(&net->proc_cells, *_pos);
188 }
189 
190 /*
191  * move to next cell in cells list
192  */
193 static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
194 {
195 	struct afs_net *net = afs_seq2net(m);
196 
197 	return seq_list_next(v, &net->proc_cells, pos);
198 }
199 
200 /*
201  * clean up after reading from the cells list
202  */
203 static void afs_proc_cells_stop(struct seq_file *m, void *v)
204 	__releases(rcu)
205 {
206 	rcu_read_unlock();
207 }
208 
209 /*
210  * display a header line followed by a load of cell lines
211  */
212 static int afs_proc_cells_show(struct seq_file *m, void *v)
213 {
214 	struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
215 	struct afs_net *net = afs_seq2net(m);
216 
217 	if (v == &net->proc_cells) {
218 		/* display header on line 1 */
219 		seq_puts(m, "USE NAME\n");
220 		return 0;
221 	}
222 
223 	/* display one cell per line on subsequent lines */
224 	seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name);
225 	return 0;
226 }
227 
228 /*
229  * handle writes to /proc/fs/afs/cells
230  * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
231  */
232 static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
233 				    size_t size, loff_t *_pos)
234 {
235 	struct afs_net *net = afs_proc2net(file);
236 	char *kbuf, *name, *args;
237 	int ret;
238 
239 	/* start by dragging the command into memory */
240 	if (size <= 1 || size >= PAGE_SIZE)
241 		return -EINVAL;
242 
243 	kbuf = memdup_user_nul(buf, size);
244 	if (IS_ERR(kbuf))
245 		return PTR_ERR(kbuf);
246 
247 	/* trim to first NL */
248 	name = memchr(kbuf, '\n', size);
249 	if (name)
250 		*name = 0;
251 
252 	/* split into command, name and argslist */
253 	name = strchr(kbuf, ' ');
254 	if (!name)
255 		goto inval;
256 	do {
257 		*name++ = 0;
258 	} while(*name == ' ');
259 	if (!*name)
260 		goto inval;
261 
262 	args = strchr(name, ' ');
263 	if (!args)
264 		goto inval;
265 	do {
266 		*args++ = 0;
267 	} while(*args == ' ');
268 	if (!*args)
269 		goto inval;
270 
271 	/* determine command to perform */
272 	_debug("cmd=%s name=%s args=%s", kbuf, name, args);
273 
274 	if (strcmp(kbuf, "add") == 0) {
275 		struct afs_cell *cell;
276 
277 		cell = afs_lookup_cell(net, name, strlen(name), args, true);
278 		if (IS_ERR(cell)) {
279 			ret = PTR_ERR(cell);
280 			goto done;
281 		}
282 
283 		if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags))
284 			afs_put_cell(net, cell);
285 		printk("kAFS: Added new cell '%s'\n", name);
286 	} else {
287 		goto inval;
288 	}
289 
290 	ret = size;
291 
292 done:
293 	kfree(kbuf);
294 	_leave(" = %d", ret);
295 	return ret;
296 
297 inval:
298 	ret = -EINVAL;
299 	printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
300 	goto done;
301 }
302 
303 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
304 				      size_t size, loff_t *_pos)
305 {
306 	struct afs_cell *cell;
307 	struct afs_net *net = afs_proc2net(file);
308 	unsigned int seq = 0;
309 	char name[AFS_MAXCELLNAME + 1];
310 	int len;
311 
312 	if (*_pos > 0)
313 		return 0;
314 	if (!net->ws_cell)
315 		return 0;
316 
317 	rcu_read_lock();
318 	do {
319 		read_seqbegin_or_lock(&net->cells_lock, &seq);
320 		len = 0;
321 		cell = rcu_dereference_raw(net->ws_cell);
322 		if (cell) {
323 			len = cell->name_len;
324 			memcpy(name, cell->name, len);
325 		}
326 	} while (need_seqretry(&net->cells_lock, seq));
327 	done_seqretry(&net->cells_lock, seq);
328 	rcu_read_unlock();
329 
330 	if (!len)
331 		return 0;
332 
333 	name[len++] = '\n';
334 	if (len > size)
335 		len = size;
336 	if (copy_to_user(buf, name, len) != 0)
337 		return -EFAULT;
338 	*_pos = 1;
339 	return len;
340 }
341 
342 /*
343  * handle writes to /proc/fs/afs/rootcell
344  * - to initialize rootcell: echo "cell.name:192.168.231.14"
345  */
346 static ssize_t afs_proc_rootcell_write(struct file *file,
347 				       const char __user *buf,
348 				       size_t size, loff_t *_pos)
349 {
350 	struct afs_net *net = afs_proc2net(file);
351 	char *kbuf, *s;
352 	int ret;
353 
354 	/* start by dragging the command into memory */
355 	if (size <= 1 || size >= PAGE_SIZE)
356 		return -EINVAL;
357 
358 	kbuf = memdup_user_nul(buf, size);
359 	if (IS_ERR(kbuf))
360 		return PTR_ERR(kbuf);
361 
362 	ret = -EINVAL;
363 	if (kbuf[0] == '.')
364 		goto out;
365 	if (memchr(kbuf, '/', size))
366 		goto out;
367 
368 	/* trim to first NL */
369 	s = memchr(kbuf, '\n', size);
370 	if (s)
371 		*s = 0;
372 
373 	/* determine command to perform */
374 	_debug("rootcell=%s", kbuf);
375 
376 	ret = afs_cell_init(net, kbuf);
377 	if (ret >= 0)
378 		ret = size;	/* consume everything, always */
379 
380 out:
381 	kfree(kbuf);
382 	_leave(" = %d", ret);
383 	return ret;
384 }
385 
386 /*
387  * initialise /proc/fs/afs/<cell>/
388  */
389 int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
390 {
391 	struct proc_dir_entry *dir;
392 
393 	_enter("%p{%s},%p", cell, cell->name, net->proc_afs);
394 
395 	dir = proc_mkdir(cell->name, net->proc_afs);
396 	if (!dir)
397 		goto error_dir;
398 
399 	if (!proc_create_seq_data("vlservers", 0, dir,
400 			&afs_proc_cell_vlservers_ops, cell))
401 		goto error_tree;
402 	if (!proc_create_seq_data("volumes", 0, dir, &afs_proc_cell_volumes_ops,
403 			cell))
404 		goto error_tree;
405 
406 	_leave(" = 0");
407 	return 0;
408 
409 error_tree:
410 	remove_proc_subtree(cell->name, net->proc_afs);
411 error_dir:
412 	_leave(" = -ENOMEM");
413 	return -ENOMEM;
414 }
415 
416 /*
417  * remove /proc/fs/afs/<cell>/
418  */
419 void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
420 {
421 	_enter("");
422 
423 	remove_proc_subtree(cell->name, net->proc_afs);
424 
425 	_leave("");
426 }
427 
428 /*
429  * set up the iterator to start reading from the cells list and return the
430  * first item
431  */
432 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
433 	__acquires(cell->proc_lock)
434 {
435 	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
436 
437 	_enter("cell=%p pos=%Ld", cell, *_pos);
438 
439 	read_lock(&cell->proc_lock);
440 	return seq_list_start_head(&cell->proc_volumes, *_pos);
441 }
442 
443 /*
444  * move to next cell in cells list
445  */
446 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
447 					loff_t *_pos)
448 {
449 	struct afs_cell *cell = PDE_DATA(file_inode(p->file));
450 
451 	_enter("cell=%p pos=%Ld", cell, *_pos);
452 	return seq_list_next(v, &cell->proc_volumes, _pos);
453 }
454 
455 /*
456  * clean up after reading from the cells list
457  */
458 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
459 	__releases(cell->proc_lock)
460 {
461 	struct afs_cell *cell = PDE_DATA(file_inode(p->file));
462 
463 	read_unlock(&cell->proc_lock);
464 }
465 
466 static const char afs_vol_types[3][3] = {
467 	[AFSVL_RWVOL]	= "RW",
468 	[AFSVL_ROVOL]	= "RO",
469 	[AFSVL_BACKVOL]	= "BK",
470 };
471 
472 /*
473  * display a header line followed by a load of volume lines
474  */
475 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
476 {
477 	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
478 	struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
479 
480 	/* Display header on line 1 */
481 	if (v == &cell->proc_volumes) {
482 		seq_puts(m, "USE VID      TY\n");
483 		return 0;
484 	}
485 
486 	seq_printf(m, "%3d %08x %s\n",
487 		   atomic_read(&vol->usage), vol->vid,
488 		   afs_vol_types[vol->type]);
489 
490 	return 0;
491 }
492 
493 /*
494  * set up the iterator to start reading from the cells list and return the
495  * first item
496  */
497 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
498 	__acquires(rcu)
499 {
500 	struct afs_addr_list *alist;
501 	struct afs_cell *cell = PDE_DATA(file_inode(m->file));
502 	loff_t pos = *_pos;
503 
504 	rcu_read_lock();
505 
506 	alist = rcu_dereference(cell->vl_addrs);
507 
508 	/* allow for the header line */
509 	if (!pos)
510 		return (void *) 1;
511 	pos--;
512 
513 	if (!alist || pos >= alist->nr_addrs)
514 		return NULL;
515 
516 	return alist->addrs + pos;
517 }
518 
519 /*
520  * move to next cell in cells list
521  */
522 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
523 					  loff_t *_pos)
524 {
525 	struct afs_addr_list *alist;
526 	struct afs_cell *cell = PDE_DATA(file_inode(p->file));
527 	loff_t pos;
528 
529 	alist = rcu_dereference(cell->vl_addrs);
530 
531 	pos = *_pos;
532 	(*_pos)++;
533 	if (!alist || pos >= alist->nr_addrs)
534 		return NULL;
535 
536 	return alist->addrs + pos;
537 }
538 
539 /*
540  * clean up after reading from the cells list
541  */
542 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
543 	__releases(rcu)
544 {
545 	rcu_read_unlock();
546 }
547 
548 /*
549  * display a header line followed by a load of volume lines
550  */
551 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
552 {
553 	struct sockaddr_rxrpc *addr = v;
554 
555 	/* display header on line 1 */
556 	if (v == (void *)1) {
557 		seq_puts(m, "ADDRESS\n");
558 		return 0;
559 	}
560 
561 	/* display one cell per line on subsequent lines */
562 	seq_printf(m, "%pISp\n", &addr->transport);
563 	return 0;
564 }
565 
566 /*
567  * Set up the iterator to start reading from the server list and return the
568  * first item.
569  */
570 static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos)
571 	__acquires(rcu)
572 {
573 	struct afs_net *net = afs_seq2net(m);
574 
575 	rcu_read_lock();
576 	return seq_hlist_start_head_rcu(&net->fs_proc, *_pos);
577 }
578 
579 /*
580  * move to next cell in cells list
581  */
582 static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
583 {
584 	struct afs_net *net = afs_seq2net(m);
585 
586 	return seq_hlist_next_rcu(v, &net->fs_proc, _pos);
587 }
588 
589 /*
590  * clean up after reading from the cells list
591  */
592 static void afs_proc_servers_stop(struct seq_file *p, void *v)
593 	__releases(rcu)
594 {
595 	rcu_read_unlock();
596 }
597 
598 /*
599  * display a header line followed by a load of volume lines
600  */
601 static int afs_proc_servers_show(struct seq_file *m, void *v)
602 {
603 	struct afs_server *server;
604 	struct afs_addr_list *alist;
605 
606 	if (v == SEQ_START_TOKEN) {
607 		seq_puts(m, "UUID                                 USE ADDR\n");
608 		return 0;
609 	}
610 
611 	server = list_entry(v, struct afs_server, proc_link);
612 	alist = rcu_dereference(server->addresses);
613 	seq_printf(m, "%pU %3d %pISp\n",
614 		   &server->uuid,
615 		   atomic_read(&server->usage),
616 		   &alist->addrs[alist->index].transport);
617 	return 0;
618 }
619 
620 void afs_put_sysnames(struct afs_sysnames *sysnames)
621 {
622 	int i;
623 
624 	if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
625 		for (i = 0; i < sysnames->nr; i++)
626 			if (sysnames->subs[i] != afs_init_sysname &&
627 			    sysnames->subs[i] != sysnames->blank)
628 				kfree(sysnames->subs[i]);
629 	}
630 }
631 
632 /*
633  * Handle opening of /proc/fs/afs/sysname.  If it is opened for writing, we
634  * assume the caller wants to change the substitution list and we allocate a
635  * buffer to hold the list.
636  */
637 static int afs_proc_sysname_open(struct inode *inode, struct file *file)
638 {
639 	struct afs_sysnames *sysnames;
640 	struct seq_file *m;
641 	int ret;
642 
643 	ret = seq_open(file, &afs_proc_sysname_ops);
644 	if (ret < 0)
645 		return ret;
646 
647 	if (file->f_mode & FMODE_WRITE) {
648 		sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
649 		if (!sysnames) {
650 			seq_release(inode, file);
651 			return -ENOMEM;
652 		}
653 
654 		refcount_set(&sysnames->usage, 1);
655 		m = file->private_data;
656 		m->private = sysnames;
657 	}
658 
659 	return 0;
660 }
661 
662 /*
663  * Handle writes to /proc/fs/afs/sysname to set the @sys substitution.
664  */
665 static ssize_t afs_proc_sysname_write(struct file *file,
666 				      const char __user *buf,
667 				      size_t size, loff_t *_pos)
668 {
669 	struct afs_sysnames *sysnames;
670 	struct seq_file *m = file->private_data;
671 	char *kbuf = NULL, *s, *p, *sub;
672 	int ret, len;
673 
674 	sysnames = m->private;
675 	if (!sysnames)
676 		return -EINVAL;
677 	if (sysnames->error)
678 		return sysnames->error;
679 
680 	if (size >= PAGE_SIZE - 1) {
681 		sysnames->error = -EINVAL;
682 		return -EINVAL;
683 	}
684 	if (size == 0)
685 		return 0;
686 
687 	kbuf = memdup_user_nul(buf, size);
688 	if (IS_ERR(kbuf))
689 		return PTR_ERR(kbuf);
690 
691 	inode_lock(file_inode(file));
692 
693 	p = kbuf;
694 	while ((s = strsep(&p, " \t\n"))) {
695 		len = strlen(s);
696 		if (len == 0)
697 			continue;
698 		ret = -ENAMETOOLONG;
699 		if (len >= AFSNAMEMAX)
700 			goto error;
701 
702 		if (len >= 4 &&
703 		    s[len - 4] == '@' &&
704 		    s[len - 3] == 's' &&
705 		    s[len - 2] == 'y' &&
706 		    s[len - 1] == 's')
707 			/* Protect against recursion */
708 			goto invalid;
709 
710 		if (s[0] == '.' &&
711 		    (len < 2 || (len == 2 && s[1] == '.')))
712 			goto invalid;
713 
714 		if (memchr(s, '/', len))
715 			goto invalid;
716 
717 		ret = -EFBIG;
718 		if (sysnames->nr >= AFS_NR_SYSNAME)
719 			goto out;
720 
721 		if (strcmp(s, afs_init_sysname) == 0) {
722 			sub = (char *)afs_init_sysname;
723 		} else {
724 			ret = -ENOMEM;
725 			sub = kmemdup(s, len + 1, GFP_KERNEL);
726 			if (!sub)
727 				goto out;
728 		}
729 
730 		sysnames->subs[sysnames->nr] = sub;
731 		sysnames->nr++;
732 	}
733 
734 	ret = size;	/* consume everything, always */
735 out:
736 	inode_unlock(file_inode(file));
737 	kfree(kbuf);
738 	return ret;
739 
740 invalid:
741 	ret = -EINVAL;
742 error:
743 	sysnames->error = ret;
744 	goto out;
745 }
746 
747 static int afs_proc_sysname_release(struct inode *inode, struct file *file)
748 {
749 	struct afs_sysnames *sysnames, *kill = NULL;
750 	struct seq_file *m = file->private_data;
751 	struct afs_net *net = afs_seq2net(m);
752 
753 	sysnames = m->private;
754 	if (sysnames) {
755 		if (!sysnames->error) {
756 			kill = sysnames;
757 			if (sysnames->nr == 0) {
758 				sysnames->subs[0] = sysnames->blank;
759 				sysnames->nr++;
760 			}
761 			write_lock(&net->sysnames_lock);
762 			kill = net->sysnames;
763 			net->sysnames = sysnames;
764 			write_unlock(&net->sysnames_lock);
765 		}
766 		afs_put_sysnames(kill);
767 	}
768 
769 	return seq_release(inode, file);
770 }
771 
772 static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
773 	__acquires(&net->sysnames_lock)
774 {
775 	struct afs_net *net = afs_seq2net(m);
776 	struct afs_sysnames *names = net->sysnames;
777 
778 	read_lock(&net->sysnames_lock);
779 
780 	if (*pos >= names->nr)
781 		return NULL;
782 	return (void *)(unsigned long)(*pos + 1);
783 }
784 
785 static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
786 {
787 	struct afs_net *net = afs_seq2net(m);
788 	struct afs_sysnames *names = net->sysnames;
789 
790 	*pos += 1;
791 	if (*pos >= names->nr)
792 		return NULL;
793 	return (void *)(unsigned long)(*pos + 1);
794 }
795 
796 static void afs_proc_sysname_stop(struct seq_file *m, void *v)
797 	__releases(&net->sysnames_lock)
798 {
799 	struct afs_net *net = afs_seq2net(m);
800 
801 	read_unlock(&net->sysnames_lock);
802 }
803 
804 static int afs_proc_sysname_show(struct seq_file *m, void *v)
805 {
806 	struct afs_net *net = afs_seq2net(m);
807 	struct afs_sysnames *sysnames = net->sysnames;
808 	unsigned int i = (unsigned long)v - 1;
809 
810 	if (i < sysnames->nr)
811 		seq_printf(m, "%s\n", sysnames->subs[i]);
812 	return 0;
813 }
814 
815 /*
816  * Display general per-net namespace statistics
817  */
818 static int afs_proc_stats_show(struct seq_file *m, void *v)
819 {
820 	struct afs_net *net = afs_seq2net(m);
821 
822 	seq_puts(m, "kAFS statistics\n");
823 
824 	seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
825 		   atomic_read(&net->n_lookup),
826 		   atomic_read(&net->n_reval),
827 		   atomic_read(&net->n_inval),
828 		   atomic_read(&net->n_relpg));
829 
830 	seq_printf(m, "dir-data: rdpg=%u\n",
831 		   atomic_read(&net->n_read_dir));
832 
833 	seq_printf(m, "dir-edit: cr=%u rm=%u\n",
834 		   atomic_read(&net->n_dir_cr),
835 		   atomic_read(&net->n_dir_rm));
836 
837 	seq_printf(m, "file-rd : n=%u nb=%lu\n",
838 		   atomic_read(&net->n_fetches),
839 		   atomic_long_read(&net->n_fetch_bytes));
840 	seq_printf(m, "file-wr : n=%u nb=%lu\n",
841 		   atomic_read(&net->n_stores),
842 		   atomic_long_read(&net->n_store_bytes));
843 	return 0;
844 }
845