1 /* /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/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 <asm/uaccess.h>
20 static struct proc_dir_entry
*proc_afs
;
23 static int afs_proc_cells_open(struct inode
*inode
, struct file
*file
);
24 static void *afs_proc_cells_start(struct seq_file
*p
, loff_t
*pos
);
25 static void *afs_proc_cells_next(struct seq_file
*p
, void *v
, loff_t
*pos
);
26 static void afs_proc_cells_stop(struct seq_file
*p
, void *v
);
27 static int afs_proc_cells_show(struct seq_file
*m
, void *v
);
28 static ssize_t
afs_proc_cells_write(struct file
*file
, const char __user
*buf
,
29 size_t size
, loff_t
*_pos
);
31 static struct seq_operations afs_proc_cells_ops
= {
32 .start
= afs_proc_cells_start
,
33 .next
= afs_proc_cells_next
,
34 .stop
= afs_proc_cells_stop
,
35 .show
= afs_proc_cells_show
,
38 static const struct file_operations afs_proc_cells_fops
= {
39 .open
= afs_proc_cells_open
,
41 .write
= afs_proc_cells_write
,
43 .release
= seq_release
,
47 static int afs_proc_rootcell_open(struct inode
*inode
, struct file
*file
);
48 static int afs_proc_rootcell_release(struct inode
*inode
, struct file
*file
);
49 static ssize_t
afs_proc_rootcell_read(struct file
*file
, char __user
*buf
,
50 size_t size
, loff_t
*_pos
);
51 static ssize_t
afs_proc_rootcell_write(struct file
*file
,
52 const char __user
*buf
,
53 size_t size
, loff_t
*_pos
);
55 static const struct file_operations afs_proc_rootcell_fops
= {
56 .open
= afs_proc_rootcell_open
,
57 .read
= afs_proc_rootcell_read
,
58 .write
= afs_proc_rootcell_write
,
60 .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
,
88 static int afs_proc_cell_vlservers_open(struct inode
*inode
,
90 static int afs_proc_cell_vlservers_release(struct inode
*inode
,
92 static void *afs_proc_cell_vlservers_start(struct seq_file
*p
, loff_t
*pos
);
93 static void *afs_proc_cell_vlservers_next(struct seq_file
*p
, void *v
,
95 static void afs_proc_cell_vlservers_stop(struct seq_file
*p
, void *v
);
96 static int afs_proc_cell_vlservers_show(struct seq_file
*m
, void *v
);
98 static struct seq_operations afs_proc_cell_vlservers_ops
= {
99 .start
= afs_proc_cell_vlservers_start
,
100 .next
= afs_proc_cell_vlservers_next
,
101 .stop
= afs_proc_cell_vlservers_stop
,
102 .show
= afs_proc_cell_vlservers_show
,
105 static const struct file_operations afs_proc_cell_vlservers_fops
= {
106 .open
= afs_proc_cell_vlservers_open
,
109 .release
= afs_proc_cell_vlservers_release
,
110 .owner
= THIS_MODULE
,
113 static int afs_proc_cell_servers_open(struct inode
*inode
, struct file
*file
);
114 static int afs_proc_cell_servers_release(struct inode
*inode
,
116 static void *afs_proc_cell_servers_start(struct seq_file
*p
, loff_t
*pos
);
117 static void *afs_proc_cell_servers_next(struct seq_file
*p
, void *v
,
119 static void afs_proc_cell_servers_stop(struct seq_file
*p
, void *v
);
120 static int afs_proc_cell_servers_show(struct seq_file
*m
, void *v
);
122 static struct seq_operations afs_proc_cell_servers_ops
= {
123 .start
= afs_proc_cell_servers_start
,
124 .next
= afs_proc_cell_servers_next
,
125 .stop
= afs_proc_cell_servers_stop
,
126 .show
= afs_proc_cell_servers_show
,
129 static const struct file_operations afs_proc_cell_servers_fops
= {
130 .open
= afs_proc_cell_servers_open
,
133 .release
= afs_proc_cell_servers_release
,
134 .owner
= THIS_MODULE
,
138 * initialise the /proc/fs/afs/ directory
140 int afs_proc_init(void)
142 struct proc_dir_entry
*p
;
146 proc_afs
= proc_mkdir("fs/afs", NULL
);
149 proc_afs
->owner
= THIS_MODULE
;
151 p
= proc_create("cells", 0, proc_afs
, &afs_proc_cells_fops
);
155 p
= proc_create("rootcell", 0, proc_afs
, &afs_proc_rootcell_fops
);
163 remove_proc_entry("cells", proc_afs
);
165 remove_proc_entry("fs/afs", NULL
);
167 _leave(" = -ENOMEM");
172 * clean up the /proc/fs/afs/ directory
174 void afs_proc_cleanup(void)
176 remove_proc_entry("rootcell", proc_afs
);
177 remove_proc_entry("cells", proc_afs
);
178 remove_proc_entry("fs/afs", NULL
);
182 * open "/proc/fs/afs/cells" which provides a summary of extant cells
184 static int afs_proc_cells_open(struct inode
*inode
, struct file
*file
)
189 ret
= seq_open(file
, &afs_proc_cells_ops
);
193 m
= file
->private_data
;
194 m
->private = PDE(inode
)->data
;
200 * set up the iterator to start reading from the cells list and return the
203 static void *afs_proc_cells_start(struct seq_file
*m
, loff_t
*_pos
)
205 /* lock the list against modification */
206 down_read(&afs_proc_cells_sem
);
207 return seq_list_start_head(&afs_proc_cells
, *_pos
);
211 * move to next cell in cells list
213 static void *afs_proc_cells_next(struct seq_file
*p
, void *v
, loff_t
*pos
)
215 return seq_list_next(v
, &afs_proc_cells
, pos
);
219 * clean up after reading from the cells list
221 static void afs_proc_cells_stop(struct seq_file
*p
, void *v
)
223 up_read(&afs_proc_cells_sem
);
227 * display a header line followed by a load of cell lines
229 static int afs_proc_cells_show(struct seq_file
*m
, void *v
)
231 struct afs_cell
*cell
= list_entry(v
, struct afs_cell
, proc_link
);
233 if (v
== &afs_proc_cells
) {
234 /* display header on line 1 */
235 seq_puts(m
, "USE NAME\n");
239 /* display one cell per line on subsequent lines */
240 seq_printf(m
, "%3d %s\n",
241 atomic_read(&cell
->usage
), cell
->name
);
246 * handle writes to /proc/fs/afs/cells
247 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
249 static ssize_t
afs_proc_cells_write(struct file
*file
, const char __user
*buf
,
250 size_t size
, loff_t
*_pos
)
252 char *kbuf
, *name
, *args
;
255 /* start by dragging the command into memory */
256 if (size
<= 1 || size
>= PAGE_SIZE
)
259 kbuf
= kmalloc(size
+ 1, GFP_KERNEL
);
264 if (copy_from_user(kbuf
, buf
, size
) != 0)
268 /* trim to first NL */
269 name
= memchr(kbuf
, '\n', size
);
273 /* split into command, name and argslist */
274 name
= strchr(kbuf
, ' ');
279 } while(*name
== ' ');
283 args
= strchr(name
, ' ');
288 } while(*args
== ' ');
292 /* determine command to perform */
293 _debug("cmd=%s name=%s args=%s", kbuf
, name
, args
);
295 if (strcmp(kbuf
, "add") == 0) {
296 struct afs_cell
*cell
;
298 cell
= afs_cell_create(name
, args
);
305 printk("kAFS: Added new cell '%s'\n", name
);
314 _leave(" = %d", ret
);
319 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
324 * Stubs for /proc/fs/afs/rootcell
326 static int afs_proc_rootcell_open(struct inode
*inode
, struct file
*file
)
331 static int afs_proc_rootcell_release(struct inode
*inode
, struct file
*file
)
336 static ssize_t
afs_proc_rootcell_read(struct file
*file
, char __user
*buf
,
337 size_t size
, loff_t
*_pos
)
343 * handle writes to /proc/fs/afs/rootcell
344 * - to initialize rootcell: echo "cell.name:192.168.231.14"
346 static ssize_t
afs_proc_rootcell_write(struct file
*file
,
347 const char __user
*buf
,
348 size_t size
, loff_t
*_pos
)
353 /* start by dragging the command into memory */
354 if (size
<= 1 || size
>= PAGE_SIZE
)
358 kbuf
= kmalloc(size
+ 1, GFP_KERNEL
);
363 if (copy_from_user(kbuf
, buf
, size
) != 0)
367 /* trim to first NL */
368 s
= memchr(kbuf
, '\n', size
);
372 /* determine command to perform */
373 _debug("rootcell=%s", kbuf
);
375 ret
= afs_cell_init(kbuf
);
377 ret
= size
; /* consume everything, always */
382 _leave(" = %d", ret
);
387 * initialise /proc/fs/afs/<cell>/
389 int afs_proc_cell_setup(struct afs_cell
*cell
)
391 struct proc_dir_entry
*p
;
393 _enter("%p{%s}", cell
, cell
->name
);
395 cell
->proc_dir
= proc_mkdir(cell
->name
, proc_afs
);
399 p
= proc_create_data("servers", 0, cell
->proc_dir
,
400 &afs_proc_cell_servers_fops
, cell
);
404 p
= proc_create_data("vlservers", 0, cell
->proc_dir
,
405 &afs_proc_cell_vlservers_fops
, cell
);
407 goto error_vlservers
;
409 p
= proc_create_data("volumes", 0, cell
->proc_dir
,
410 &afs_proc_cell_volumes_fops
, cell
);
418 remove_proc_entry("vlservers", cell
->proc_dir
);
420 remove_proc_entry("servers", cell
->proc_dir
);
422 remove_proc_entry(cell
->name
, proc_afs
);
424 _leave(" = -ENOMEM");
429 * remove /proc/fs/afs/<cell>/
431 void afs_proc_cell_remove(struct afs_cell
*cell
)
435 remove_proc_entry("volumes", cell
->proc_dir
);
436 remove_proc_entry("vlservers", cell
->proc_dir
);
437 remove_proc_entry("servers", cell
->proc_dir
);
438 remove_proc_entry(cell
->name
, proc_afs
);
444 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
446 static int afs_proc_cell_volumes_open(struct inode
*inode
, struct file
*file
)
448 struct afs_cell
*cell
;
452 cell
= PDE(inode
)->data
;
456 ret
= seq_open(file
, &afs_proc_cell_volumes_ops
);
460 m
= file
->private_data
;
467 * close the file and release the ref to the cell
469 static int afs_proc_cell_volumes_release(struct inode
*inode
, struct file
*file
)
471 return seq_release(inode
, file
);
475 * set up the iterator to start reading from the cells list and return the
478 static void *afs_proc_cell_volumes_start(struct seq_file
*m
, loff_t
*_pos
)
480 struct afs_cell
*cell
= m
->private;
482 _enter("cell=%p pos=%Ld", cell
, *_pos
);
484 /* lock the list against modification */
485 down_read(&cell
->vl_sem
);
486 return seq_list_start_head(&cell
->vl_list
, *_pos
);
490 * move to next cell in cells list
492 static void *afs_proc_cell_volumes_next(struct seq_file
*p
, void *v
,
495 struct afs_cell
*cell
= p
->private;
497 _enter("cell=%p pos=%Ld", cell
, *_pos
);
498 return seq_list_next(v
, &cell
->vl_list
, _pos
);
502 * clean up after reading from the cells list
504 static void afs_proc_cell_volumes_stop(struct seq_file
*p
, void *v
)
506 struct afs_cell
*cell
= p
->private;
508 up_read(&cell
->vl_sem
);
511 static const char afs_vlocation_states
[][4] = {
512 [AFS_VL_NEW
] = "New",
513 [AFS_VL_CREATING
] = "Crt",
514 [AFS_VL_VALID
] = "Val",
515 [AFS_VL_NO_VOLUME
] = "NoV",
516 [AFS_VL_UPDATING
] = "Upd",
517 [AFS_VL_VOLUME_DELETED
] = "Del",
518 [AFS_VL_UNCERTAIN
] = "Unc",
522 * display a header line followed by a load of volume lines
524 static int afs_proc_cell_volumes_show(struct seq_file
*m
, void *v
)
526 struct afs_cell
*cell
= m
->private;
527 struct afs_vlocation
*vlocation
=
528 list_entry(v
, struct afs_vlocation
, link
);
530 /* display header on line 1 */
531 if (v
== &cell
->vl_list
) {
532 seq_puts(m
, "USE STT VLID[0] VLID[1] VLID[2] NAME\n");
536 /* display one cell per line on subsequent lines */
537 seq_printf(m
, "%3d %s %08x %08x %08x %s\n",
538 atomic_read(&vlocation
->usage
),
539 afs_vlocation_states
[vlocation
->state
],
540 vlocation
->vldb
.vid
[0],
541 vlocation
->vldb
.vid
[1],
542 vlocation
->vldb
.vid
[2],
543 vlocation
->vldb
.name
);
549 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
552 static int afs_proc_cell_vlservers_open(struct inode
*inode
, struct file
*file
)
554 struct afs_cell
*cell
;
558 cell
= PDE(inode
)->data
;
562 ret
= seq_open(file
, &afs_proc_cell_vlservers_ops
);
566 m
= file
->private_data
;
573 * close the file and release the ref to the cell
575 static int afs_proc_cell_vlservers_release(struct inode
*inode
,
578 return seq_release(inode
, file
);
582 * set up the iterator to start reading from the cells list and return the
585 static void *afs_proc_cell_vlservers_start(struct seq_file
*m
, loff_t
*_pos
)
587 struct afs_cell
*cell
= m
->private;
590 _enter("cell=%p pos=%Ld", cell
, *_pos
);
592 /* lock the list against modification */
593 down_read(&cell
->vl_sem
);
595 /* allow for the header line */
600 if (pos
>= cell
->vl_naddrs
)
603 return &cell
->vl_addrs
[pos
];
607 * move to next cell in cells list
609 static void *afs_proc_cell_vlservers_next(struct seq_file
*p
, void *v
,
612 struct afs_cell
*cell
= p
->private;
615 _enter("cell=%p{nad=%u} pos=%Ld", cell
, cell
->vl_naddrs
, *_pos
);
619 if (pos
>= cell
->vl_naddrs
)
622 return &cell
->vl_addrs
[pos
];
626 * clean up after reading from the cells list
628 static void afs_proc_cell_vlservers_stop(struct seq_file
*p
, void *v
)
630 struct afs_cell
*cell
= p
->private;
632 up_read(&cell
->vl_sem
);
636 * display a header line followed by a load of volume lines
638 static int afs_proc_cell_vlservers_show(struct seq_file
*m
, void *v
)
640 struct in_addr
*addr
= v
;
642 /* display header on line 1 */
643 if (v
== (struct in_addr
*) 1) {
644 seq_puts(m
, "ADDRESS\n");
648 /* display one cell per line on subsequent lines */
649 seq_printf(m
, "%pI4\n", &addr
->s_addr
);
654 * open "/proc/fs/afs/<cell>/servers" which provides a summary of active
657 static int afs_proc_cell_servers_open(struct inode
*inode
, struct file
*file
)
659 struct afs_cell
*cell
;
663 cell
= PDE(inode
)->data
;
667 ret
= seq_open(file
, &afs_proc_cell_servers_ops
);
671 m
= file
->private_data
;
677 * close the file and release the ref to the cell
679 static int afs_proc_cell_servers_release(struct inode
*inode
,
682 return seq_release(inode
, file
);
686 * set up the iterator to start reading from the cells list and return the
689 static void *afs_proc_cell_servers_start(struct seq_file
*m
, loff_t
*_pos
)
690 __acquires(m
->private->servers_lock
)
692 struct afs_cell
*cell
= m
->private;
694 _enter("cell=%p pos=%Ld", cell
, *_pos
);
696 /* lock the list against modification */
697 read_lock(&cell
->servers_lock
);
698 return seq_list_start_head(&cell
->servers
, *_pos
);
702 * move to next cell in cells list
704 static void *afs_proc_cell_servers_next(struct seq_file
*p
, void *v
,
707 struct afs_cell
*cell
= p
->private;
709 _enter("cell=%p pos=%Ld", cell
, *_pos
);
710 return seq_list_next(v
, &cell
->servers
, _pos
);
714 * clean up after reading from the cells list
716 static void afs_proc_cell_servers_stop(struct seq_file
*p
, void *v
)
717 __releases(p
->private->servers_lock
)
719 struct afs_cell
*cell
= p
->private;
721 read_unlock(&cell
->servers_lock
);
725 * display a header line followed by a load of volume lines
727 static int afs_proc_cell_servers_show(struct seq_file
*m
, void *v
)
729 struct afs_cell
*cell
= m
->private;
730 struct afs_server
*server
= list_entry(v
, struct afs_server
, link
);
733 /* display header on line 1 */
734 if (v
== &cell
->servers
) {
735 seq_puts(m
, "USE ADDR STATE\n");
739 /* display one cell per line on subsequent lines */
740 sprintf(ipaddr
, "%pI4", &server
->addr
);
741 seq_printf(m
, "%3d %-15.15s %5d\n",
742 atomic_read(&server
->usage
), ipaddr
, server
->fs_state
);