OSDN Git Service

Merge tag 'ceph-for-4.18-rc1' of git://github.com/ceph/ceph-client
[uclinux-h8/linux.git] / fs / afs / proc.c
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 }