1 /* proc.c: /proc interface for AFS
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/sched.h>
13 #include <linux/slab.h>
14 #include <linux/module.h>
15 #include <linux/proc_fs.h>
16 #include <linux/seq_file.h>
19 #include <asm/uaccess.h>
22 static struct proc_dir_entry *proc_afs;
25 static int afs_proc_cells_open(struct inode *inode, struct file *file);
26 static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
27 static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
28 static void afs_proc_cells_stop(struct seq_file *p, void *v);
29 static int afs_proc_cells_show(struct seq_file *m, void *v);
30 static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
31 size_t size, loff_t *_pos);
33 static struct seq_operations afs_proc_cells_ops = {
34 .start = afs_proc_cells_start,
35 .next = afs_proc_cells_next,
36 .stop = afs_proc_cells_stop,
37 .show = afs_proc_cells_show,
40 static const struct file_operations afs_proc_cells_fops = {
41 .open = afs_proc_cells_open,
43 .write = afs_proc_cells_write,
45 .release = seq_release,
48 static int afs_proc_rootcell_open(struct inode *inode, struct file *file);
49 static int afs_proc_rootcell_release(struct inode *inode, struct file *file);
50 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
51 size_t size, loff_t *_pos);
52 static ssize_t afs_proc_rootcell_write(struct file *file,
53 const char __user *buf,
54 size_t size, loff_t *_pos);
56 static const struct file_operations afs_proc_rootcell_fops = {
57 .open = afs_proc_rootcell_open,
58 .read = afs_proc_rootcell_read,
59 .write = afs_proc_rootcell_write,
61 .release = afs_proc_rootcell_release
64 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
65 static int afs_proc_cell_volumes_release(struct inode *inode,
67 static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
68 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
70 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
71 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
73 static struct seq_operations afs_proc_cell_volumes_ops = {
74 .start = afs_proc_cell_volumes_start,
75 .next = afs_proc_cell_volumes_next,
76 .stop = afs_proc_cell_volumes_stop,
77 .show = afs_proc_cell_volumes_show,
80 static const struct file_operations afs_proc_cell_volumes_fops = {
81 .open = afs_proc_cell_volumes_open,
84 .release = afs_proc_cell_volumes_release,
87 static int afs_proc_cell_vlservers_open(struct inode *inode,
89 static int afs_proc_cell_vlservers_release(struct inode *inode,
91 static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
92 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
94 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
95 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
97 static struct seq_operations afs_proc_cell_vlservers_ops = {
98 .start = afs_proc_cell_vlservers_start,
99 .next = afs_proc_cell_vlservers_next,
100 .stop = afs_proc_cell_vlservers_stop,
101 .show = afs_proc_cell_vlservers_show,
104 static const struct file_operations afs_proc_cell_vlservers_fops = {
105 .open = afs_proc_cell_vlservers_open,
108 .release = afs_proc_cell_vlservers_release,
111 static int afs_proc_cell_servers_open(struct inode *inode, struct file *file);
112 static int afs_proc_cell_servers_release(struct inode *inode,
114 static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos);
115 static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
117 static void afs_proc_cell_servers_stop(struct seq_file *p, void *v);
118 static int afs_proc_cell_servers_show(struct seq_file *m, void *v);
120 static struct seq_operations afs_proc_cell_servers_ops = {
121 .start = afs_proc_cell_servers_start,
122 .next = afs_proc_cell_servers_next,
123 .stop = afs_proc_cell_servers_stop,
124 .show = afs_proc_cell_servers_show,
127 static const struct file_operations afs_proc_cell_servers_fops = {
128 .open = afs_proc_cell_servers_open,
131 .release = afs_proc_cell_servers_release,
134 /*****************************************************************************/
136 * initialise the /proc/fs/afs/ directory
138 int afs_proc_init(void)
140 struct proc_dir_entry *p;
144 proc_afs = proc_mkdir("fs/afs", NULL);
147 proc_afs->owner = THIS_MODULE;
149 p = create_proc_entry("cells", 0, proc_afs);
152 p->proc_fops = &afs_proc_cells_fops;
153 p->owner = THIS_MODULE;
155 p = create_proc_entry("rootcell", 0, proc_afs);
158 p->proc_fops = &afs_proc_rootcell_fops;
159 p->owner = THIS_MODULE;
165 remove_proc_entry("cells", proc_afs);
167 remove_proc_entry("fs/afs", NULL);
169 _leave(" = -ENOMEM");
172 } /* end afs_proc_init() */
174 /*****************************************************************************/
176 * clean up the /proc/fs/afs/ directory
178 void afs_proc_cleanup(void)
180 remove_proc_entry("rootcell", proc_afs);
181 remove_proc_entry("cells", proc_afs);
183 remove_proc_entry("fs/afs", NULL);
185 } /* end afs_proc_cleanup() */
187 /*****************************************************************************/
189 * open "/proc/fs/afs/cells" which provides a summary of extant cells
191 static int afs_proc_cells_open(struct inode *inode, struct file *file)
196 ret = seq_open(file, &afs_proc_cells_ops);
200 m = file->private_data;
201 m->private = PDE(inode)->data;
204 } /* end afs_proc_cells_open() */
206 /*****************************************************************************/
208 * set up the iterator to start reading from the cells list and return the
211 static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
213 struct list_head *_p;
216 /* lock the list against modification */
217 down_read(&afs_proc_cells_sem);
219 /* allow for the header line */
224 /* find the n'th element in the list */
225 list_for_each(_p, &afs_proc_cells)
229 return _p != &afs_proc_cells ? _p : NULL;
230 } /* end afs_proc_cells_start() */
232 /*****************************************************************************/
234 * move to next cell in cells list
236 static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos)
238 struct list_head *_p;
243 _p = v == (void *) 1 ? afs_proc_cells.next : _p->next;
245 return _p != &afs_proc_cells ? _p : NULL;
246 } /* end afs_proc_cells_next() */
248 /*****************************************************************************/
250 * clean up after reading from the cells list
252 static void afs_proc_cells_stop(struct seq_file *p, void *v)
254 up_read(&afs_proc_cells_sem);
256 } /* end afs_proc_cells_stop() */
258 /*****************************************************************************/
260 * display a header line followed by a load of cell lines
262 static int afs_proc_cells_show(struct seq_file *m, void *v)
264 struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
266 /* display header on line 1 */
267 if (v == (void *) 1) {
268 seq_puts(m, "USE NAME\n");
272 /* display one cell per line on subsequent lines */
273 seq_printf(m, "%3d %s\n", atomic_read(&cell->usage), cell->name);
276 } /* end afs_proc_cells_show() */
278 /*****************************************************************************/
280 * handle writes to /proc/fs/afs/cells
281 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
283 static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
284 size_t size, loff_t *_pos)
286 char *kbuf, *name, *args;
289 /* start by dragging the command into memory */
290 if (size <= 1 || size >= PAGE_SIZE)
293 kbuf = kmalloc(size + 1, GFP_KERNEL);
298 if (copy_from_user(kbuf, buf, size) != 0)
302 /* trim to first NL */
303 name = memchr(kbuf, '\n', size);
307 /* split into command, name and argslist */
308 name = strchr(kbuf, ' ');
313 } while(*name == ' ');
317 args = strchr(name, ' ');
322 } while(*args == ' ');
326 /* determine command to perform */
327 _debug("cmd=%s name=%s args=%s", kbuf, name, args);
329 if (strcmp(kbuf, "add") == 0) {
330 struct afs_cell *cell;
331 ret = afs_cell_create(name, args, &cell);
335 printk("kAFS: Added new cell '%s'\n", name);
345 _leave(" = %d", ret);
350 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
352 } /* end afs_proc_cells_write() */
354 /*****************************************************************************/
356 * Stubs for /proc/fs/afs/rootcell
358 static int afs_proc_rootcell_open(struct inode *inode, struct file *file)
363 static int afs_proc_rootcell_release(struct inode *inode, struct file *file)
368 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
369 size_t size, loff_t *_pos)
374 /*****************************************************************************/
376 * handle writes to /proc/fs/afs/rootcell
377 * - to initialize rootcell: echo "cell.name:192.168.231.14"
379 static ssize_t afs_proc_rootcell_write(struct file *file,
380 const char __user *buf,
381 size_t size, loff_t *_pos)
386 /* start by dragging the command into memory */
387 if (size <= 1 || size >= PAGE_SIZE)
391 kbuf = kmalloc(size + 1, GFP_KERNEL);
396 if (copy_from_user(kbuf, buf, size) != 0)
400 /* trim to first NL */
401 s = memchr(kbuf, '\n', size);
405 /* determine command to perform */
406 _debug("rootcell=%s", kbuf);
408 ret = afs_cell_init(kbuf);
410 ret = size; /* consume everything, always */
415 _leave(" = %d", ret);
417 } /* end afs_proc_rootcell_write() */
419 /*****************************************************************************/
421 * initialise /proc/fs/afs/<cell>/
423 int afs_proc_cell_setup(struct afs_cell *cell)
425 struct proc_dir_entry *p;
427 _enter("%p{%s}", cell, cell->name);
429 cell->proc_dir = proc_mkdir(cell->name, proc_afs);
433 p = create_proc_entry("servers", 0, cell->proc_dir);
436 p->proc_fops = &afs_proc_cell_servers_fops;
437 p->owner = THIS_MODULE;
440 p = create_proc_entry("vlservers", 0, cell->proc_dir);
443 p->proc_fops = &afs_proc_cell_vlservers_fops;
444 p->owner = THIS_MODULE;
447 p = create_proc_entry("volumes", 0, cell->proc_dir);
449 goto error_vlservers;
450 p->proc_fops = &afs_proc_cell_volumes_fops;
451 p->owner = THIS_MODULE;
458 remove_proc_entry("vlservers", cell->proc_dir);
460 remove_proc_entry("servers", cell->proc_dir);
462 remove_proc_entry(cell->name, proc_afs);
463 _leave(" = -ENOMEM");
465 } /* end afs_proc_cell_setup() */
467 /*****************************************************************************/
469 * remove /proc/fs/afs/<cell>/
471 void afs_proc_cell_remove(struct afs_cell *cell)
475 remove_proc_entry("volumes", cell->proc_dir);
476 remove_proc_entry("vlservers", cell->proc_dir);
477 remove_proc_entry("servers", cell->proc_dir);
478 remove_proc_entry(cell->name, proc_afs);
481 } /* end afs_proc_cell_remove() */
483 /*****************************************************************************/
485 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
487 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)
489 struct afs_cell *cell;
493 cell = afs_get_cell_maybe((struct afs_cell **) &PDE(inode)->data);
497 ret = seq_open(file, &afs_proc_cell_volumes_ops);
501 m = file->private_data;
505 } /* end afs_proc_cell_volumes_open() */
507 /*****************************************************************************/
509 * close the file and release the ref to the cell
511 static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file)
513 struct afs_cell *cell = PDE(inode)->data;
516 ret = seq_release(inode,file);
521 } /* end afs_proc_cell_volumes_release() */
523 /*****************************************************************************/
525 * set up the iterator to start reading from the cells list and return the
528 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
530 struct list_head *_p;
531 struct afs_cell *cell = m->private;
534 _enter("cell=%p pos=%Ld", cell, *_pos);
536 /* lock the list against modification */
537 down_read(&cell->vl_sem);
539 /* allow for the header line */
544 /* find the n'th element in the list */
545 list_for_each(_p, &cell->vl_list)
549 return _p != &cell->vl_list ? _p : NULL;
550 } /* end afs_proc_cell_volumes_start() */
552 /*****************************************************************************/
554 * move to next cell in cells list
556 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
559 struct list_head *_p;
560 struct afs_cell *cell = p->private;
562 _enter("cell=%p pos=%Ld", cell, *_pos);
567 _p = v == (void *) 1 ? cell->vl_list.next : _p->next;
569 return _p != &cell->vl_list ? _p : NULL;
570 } /* end afs_proc_cell_volumes_next() */
572 /*****************************************************************************/
574 * clean up after reading from the cells list
576 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
578 struct afs_cell *cell = p->private;
580 up_read(&cell->vl_sem);
582 } /* end afs_proc_cell_volumes_stop() */
584 /*****************************************************************************/
586 * display a header line followed by a load of volume lines
588 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
590 struct afs_vlocation *vlocation =
591 list_entry(v, struct afs_vlocation, link);
593 /* display header on line 1 */
594 if (v == (void *) 1) {
595 seq_puts(m, "USE VLID[0] VLID[1] VLID[2] NAME\n");
599 /* display one cell per line on subsequent lines */
600 seq_printf(m, "%3d %08x %08x %08x %s\n",
601 atomic_read(&vlocation->usage),
602 vlocation->vldb.vid[0],
603 vlocation->vldb.vid[1],
604 vlocation->vldb.vid[2],
609 } /* end afs_proc_cell_volumes_show() */
611 /*****************************************************************************/
613 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
616 static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)
618 struct afs_cell *cell;
622 cell = afs_get_cell_maybe((struct afs_cell**)&PDE(inode)->data);
626 ret = seq_open(file,&afs_proc_cell_vlservers_ops);
630 m = file->private_data;
634 } /* end afs_proc_cell_vlservers_open() */
636 /*****************************************************************************/
638 * close the file and release the ref to the cell
640 static int afs_proc_cell_vlservers_release(struct inode *inode,
643 struct afs_cell *cell = PDE(inode)->data;
646 ret = seq_release(inode,file);
651 } /* end afs_proc_cell_vlservers_release() */
653 /*****************************************************************************/
655 * set up the iterator to start reading from the cells list and return the
658 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
660 struct afs_cell *cell = m->private;
663 _enter("cell=%p pos=%Ld", cell, *_pos);
665 /* lock the list against modification */
666 down_read(&cell->vl_sem);
668 /* allow for the header line */
673 if (pos >= cell->vl_naddrs)
676 return &cell->vl_addrs[pos];
677 } /* end afs_proc_cell_vlservers_start() */
679 /*****************************************************************************/
681 * move to next cell in cells list
683 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
686 struct afs_cell *cell = p->private;
689 _enter("cell=%p{nad=%u} pos=%Ld", cell, cell->vl_naddrs, *_pos);
693 if (pos >= cell->vl_naddrs)
696 return &cell->vl_addrs[pos];
697 } /* end afs_proc_cell_vlservers_next() */
699 /*****************************************************************************/
701 * clean up after reading from the cells list
703 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
705 struct afs_cell *cell = p->private;
707 up_read(&cell->vl_sem);
709 } /* end afs_proc_cell_vlservers_stop() */
711 /*****************************************************************************/
713 * display a header line followed by a load of volume lines
715 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
717 struct in_addr *addr = v;
719 /* display header on line 1 */
720 if (v == (struct in_addr *) 1) {
721 seq_puts(m, "ADDRESS\n");
725 /* display one cell per line on subsequent lines */
726 seq_printf(m, "%u.%u.%u.%u\n", NIPQUAD(addr->s_addr));
729 } /* end afs_proc_cell_vlservers_show() */
731 /*****************************************************************************/
733 * open "/proc/fs/afs/<cell>/servers" which provides a summary of active
736 static int afs_proc_cell_servers_open(struct inode *inode, struct file *file)
738 struct afs_cell *cell;
742 cell = afs_get_cell_maybe((struct afs_cell **) &PDE(inode)->data);
746 ret = seq_open(file, &afs_proc_cell_servers_ops);
750 m = file->private_data;
754 } /* end afs_proc_cell_servers_open() */
756 /*****************************************************************************/
758 * close the file and release the ref to the cell
760 static int afs_proc_cell_servers_release(struct inode *inode,
763 struct afs_cell *cell = PDE(inode)->data;
766 ret = seq_release(inode, file);
771 } /* end afs_proc_cell_servers_release() */
773 /*****************************************************************************/
775 * set up the iterator to start reading from the cells list and return the
778 static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
780 struct list_head *_p;
781 struct afs_cell *cell = m->private;
784 _enter("cell=%p pos=%Ld", cell, *_pos);
786 /* lock the list against modification */
787 read_lock(&cell->sv_lock);
789 /* allow for the header line */
794 /* find the n'th element in the list */
795 list_for_each(_p, &cell->sv_list)
799 return _p != &cell->sv_list ? _p : NULL;
800 } /* end afs_proc_cell_servers_start() */
802 /*****************************************************************************/
804 * move to next cell in cells list
806 static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
809 struct list_head *_p;
810 struct afs_cell *cell = p->private;
812 _enter("cell=%p pos=%Ld", cell, *_pos);
817 _p = v == (void *) 1 ? cell->sv_list.next : _p->next;
819 return _p != &cell->sv_list ? _p : NULL;
820 } /* end afs_proc_cell_servers_next() */
822 /*****************************************************************************/
824 * clean up after reading from the cells list
826 static void afs_proc_cell_servers_stop(struct seq_file *p, void *v)
828 struct afs_cell *cell = p->private;
830 read_unlock(&cell->sv_lock);
832 } /* end afs_proc_cell_servers_stop() */
834 /*****************************************************************************/
836 * display a header line followed by a load of volume lines
838 static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
840 struct afs_server *server = list_entry(v, struct afs_server, link);
843 /* display header on line 1 */
844 if (v == (void *) 1) {
845 seq_puts(m, "USE ADDR STATE\n");
849 /* display one cell per line on subsequent lines */
850 sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(server->addr));
851 seq_printf(m, "%3d %-15.15s %5d\n",
852 atomic_read(&server->usage),
858 } /* end afs_proc_cell_servers_show() */