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
);
150 p
= proc_create("cells", 0, proc_afs
, &afs_proc_cells_fops
);
154 p
= proc_create("rootcell", 0, proc_afs
, &afs_proc_rootcell_fops
);
162 remove_proc_entry("cells", proc_afs
);
164 remove_proc_entry("fs/afs", NULL
);
166 _leave(" = -ENOMEM");
171 * clean up the /proc/fs/afs/ directory
173 void afs_proc_cleanup(void)
175 remove_proc_entry("rootcell", proc_afs
);
176 remove_proc_entry("cells", proc_afs
);
177 remove_proc_entry("fs/afs", NULL
);
181 * open "/proc/fs/afs/cells" which provides a summary of extant cells
183 static int afs_proc_cells_open(struct inode
*inode
, struct file
*file
)
188 ret
= seq_open(file
, &afs_proc_cells_ops
);
192 m
= file
->private_data
;
193 m
->private = PDE(inode
)->data
;
199 * set up the iterator to start reading from the cells list and return the
202 static void *afs_proc_cells_start(struct seq_file
*m
, loff_t
*_pos
)
204 /* lock the list against modification */
205 down_read(&afs_proc_cells_sem
);
206 return seq_list_start_head(&afs_proc_cells
, *_pos
);
210 * move to next cell in cells list
212 static void *afs_proc_cells_next(struct seq_file
*p
, void *v
, loff_t
*pos
)
214 return seq_list_next(v
, &afs_proc_cells
, pos
);
218 * clean up after reading from the cells list
220 static void afs_proc_cells_stop(struct seq_file
*p
, void *v
)
222 up_read(&afs_proc_cells_sem
);
226 * display a header line followed by a load of cell lines
228 static int afs_proc_cells_show(struct seq_file
*m
, void *v
)
230 struct afs_cell
*cell
= list_entry(v
, struct afs_cell
, proc_link
);
232 if (v
== &afs_proc_cells
) {
233 /* display header on line 1 */
234 seq_puts(m
, "USE NAME\n");
238 /* display one cell per line on subsequent lines */
239 seq_printf(m
, "%3d %s\n",
240 atomic_read(&cell
->usage
), cell
->name
);
245 * handle writes to /proc/fs/afs/cells
246 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
248 static ssize_t
afs_proc_cells_write(struct file
*file
, const char __user
*buf
,
249 size_t size
, loff_t
*_pos
)
251 char *kbuf
, *name
, *args
;
254 /* start by dragging the command into memory */
255 if (size
<= 1 || size
>= PAGE_SIZE
)
258 kbuf
= kmalloc(size
+ 1, GFP_KERNEL
);
263 if (copy_from_user(kbuf
, buf
, size
) != 0)
267 /* trim to first NL */
268 name
= memchr(kbuf
, '\n', size
);
272 /* split into command, name and argslist */
273 name
= strchr(kbuf
, ' ');
278 } while(*name
== ' ');
282 args
= strchr(name
, ' ');
287 } while(*args
== ' ');
291 /* determine command to perform */
292 _debug("cmd=%s name=%s args=%s", kbuf
, name
, args
);
294 if (strcmp(kbuf
, "add") == 0) {
295 struct afs_cell
*cell
;
297 cell
= afs_cell_create(name
, args
);
304 printk("kAFS: Added new cell '%s'\n", name
);
313 _leave(" = %d", ret
);
318 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
323 * Stubs for /proc/fs/afs/rootcell
325 static int afs_proc_rootcell_open(struct inode
*inode
, struct file
*file
)
330 static int afs_proc_rootcell_release(struct inode
*inode
, struct file
*file
)
335 static ssize_t
afs_proc_rootcell_read(struct file
*file
, char __user
*buf
,
336 size_t size
, loff_t
*_pos
)
342 * handle writes to /proc/fs/afs/rootcell
343 * - to initialize rootcell: echo "cell.name:192.168.231.14"
345 static ssize_t
afs_proc_rootcell_write(struct file
*file
,
346 const char __user
*buf
,
347 size_t size
, loff_t
*_pos
)
352 /* start by dragging the command into memory */
353 if (size
<= 1 || size
>= PAGE_SIZE
)
357 kbuf
= kmalloc(size
+ 1, GFP_KERNEL
);
362 if (copy_from_user(kbuf
, buf
, size
) != 0)
366 /* trim to first NL */
367 s
= memchr(kbuf
, '\n', size
);
371 /* determine command to perform */
372 _debug("rootcell=%s", kbuf
);
374 ret
= afs_cell_init(kbuf
);
376 ret
= size
; /* consume everything, always */
381 _leave(" = %d", ret
);
386 * initialise /proc/fs/afs/<cell>/
388 int afs_proc_cell_setup(struct afs_cell
*cell
)
390 struct proc_dir_entry
*p
;
392 _enter("%p{%s}", cell
, cell
->name
);
394 cell
->proc_dir
= proc_mkdir(cell
->name
, proc_afs
);
398 p
= proc_create_data("servers", 0, cell
->proc_dir
,
399 &afs_proc_cell_servers_fops
, cell
);
403 p
= proc_create_data("vlservers", 0, cell
->proc_dir
,
404 &afs_proc_cell_vlservers_fops
, cell
);
406 goto error_vlservers
;
408 p
= proc_create_data("volumes", 0, cell
->proc_dir
,
409 &afs_proc_cell_volumes_fops
, cell
);
417 remove_proc_entry("vlservers", cell
->proc_dir
);
419 remove_proc_entry("servers", cell
->proc_dir
);
421 remove_proc_entry(cell
->name
, proc_afs
);
423 _leave(" = -ENOMEM");
428 * remove /proc/fs/afs/<cell>/
430 void afs_proc_cell_remove(struct afs_cell
*cell
)
434 remove_proc_entry("volumes", cell
->proc_dir
);
435 remove_proc_entry("vlservers", cell
->proc_dir
);
436 remove_proc_entry("servers", cell
->proc_dir
);
437 remove_proc_entry(cell
->name
, proc_afs
);
443 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
445 static int afs_proc_cell_volumes_open(struct inode
*inode
, struct file
*file
)
447 struct afs_cell
*cell
;
451 cell
= PDE(inode
)->data
;
455 ret
= seq_open(file
, &afs_proc_cell_volumes_ops
);
459 m
= file
->private_data
;
466 * close the file and release the ref to the cell
468 static int afs_proc_cell_volumes_release(struct inode
*inode
, struct file
*file
)
470 return seq_release(inode
, file
);
474 * set up the iterator to start reading from the cells list and return the
477 static void *afs_proc_cell_volumes_start(struct seq_file
*m
, loff_t
*_pos
)
479 struct afs_cell
*cell
= m
->private;
481 _enter("cell=%p pos=%Ld", cell
, *_pos
);
483 /* lock the list against modification */
484 down_read(&cell
->vl_sem
);
485 return seq_list_start_head(&cell
->vl_list
, *_pos
);
489 * move to next cell in cells list
491 static void *afs_proc_cell_volumes_next(struct seq_file
*p
, void *v
,
494 struct afs_cell
*cell
= p
->private;
496 _enter("cell=%p pos=%Ld", cell
, *_pos
);
497 return seq_list_next(v
, &cell
->vl_list
, _pos
);
501 * clean up after reading from the cells list
503 static void afs_proc_cell_volumes_stop(struct seq_file
*p
, void *v
)
505 struct afs_cell
*cell
= p
->private;
507 up_read(&cell
->vl_sem
);
510 static const char afs_vlocation_states
[][4] = {
511 [AFS_VL_NEW
] = "New",
512 [AFS_VL_CREATING
] = "Crt",
513 [AFS_VL_VALID
] = "Val",
514 [AFS_VL_NO_VOLUME
] = "NoV",
515 [AFS_VL_UPDATING
] = "Upd",
516 [AFS_VL_VOLUME_DELETED
] = "Del",
517 [AFS_VL_UNCERTAIN
] = "Unc",
521 * display a header line followed by a load of volume lines
523 static int afs_proc_cell_volumes_show(struct seq_file
*m
, void *v
)
525 struct afs_cell
*cell
= m
->private;
526 struct afs_vlocation
*vlocation
=
527 list_entry(v
, struct afs_vlocation
, link
);
529 /* display header on line 1 */
530 if (v
== &cell
->vl_list
) {
531 seq_puts(m
, "USE STT VLID[0] VLID[1] VLID[2] NAME\n");
535 /* display one cell per line on subsequent lines */
536 seq_printf(m
, "%3d %s %08x %08x %08x %s\n",
537 atomic_read(&vlocation
->usage
),
538 afs_vlocation_states
[vlocation
->state
],
539 vlocation
->vldb
.vid
[0],
540 vlocation
->vldb
.vid
[1],
541 vlocation
->vldb
.vid
[2],
542 vlocation
->vldb
.name
);
548 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
551 static int afs_proc_cell_vlservers_open(struct inode
*inode
, struct file
*file
)
553 struct afs_cell
*cell
;
557 cell
= PDE(inode
)->data
;
561 ret
= seq_open(file
, &afs_proc_cell_vlservers_ops
);
565 m
= file
->private_data
;
572 * close the file and release the ref to the cell
574 static int afs_proc_cell_vlservers_release(struct inode
*inode
,
577 return seq_release(inode
, file
);
581 * set up the iterator to start reading from the cells list and return the
584 static void *afs_proc_cell_vlservers_start(struct seq_file
*m
, loff_t
*_pos
)
586 struct afs_cell
*cell
= m
->private;
589 _enter("cell=%p pos=%Ld", cell
, *_pos
);
591 /* lock the list against modification */
592 down_read(&cell
->vl_sem
);
594 /* allow for the header line */
599 if (pos
>= cell
->vl_naddrs
)
602 return &cell
->vl_addrs
[pos
];
606 * move to next cell in cells list
608 static void *afs_proc_cell_vlservers_next(struct seq_file
*p
, void *v
,
611 struct afs_cell
*cell
= p
->private;
614 _enter("cell=%p{nad=%u} pos=%Ld", cell
, cell
->vl_naddrs
, *_pos
);
618 if (pos
>= cell
->vl_naddrs
)
621 return &cell
->vl_addrs
[pos
];
625 * clean up after reading from the cells list
627 static void afs_proc_cell_vlservers_stop(struct seq_file
*p
, void *v
)
629 struct afs_cell
*cell
= p
->private;
631 up_read(&cell
->vl_sem
);
635 * display a header line followed by a load of volume lines
637 static int afs_proc_cell_vlservers_show(struct seq_file
*m
, void *v
)
639 struct in_addr
*addr
= v
;
641 /* display header on line 1 */
642 if (v
== (struct in_addr
*) 1) {
643 seq_puts(m
, "ADDRESS\n");
647 /* display one cell per line on subsequent lines */
648 seq_printf(m
, "%pI4\n", &addr
->s_addr
);
653 * open "/proc/fs/afs/<cell>/servers" which provides a summary of active
656 static int afs_proc_cell_servers_open(struct inode
*inode
, struct file
*file
)
658 struct afs_cell
*cell
;
662 cell
= PDE(inode
)->data
;
666 ret
= seq_open(file
, &afs_proc_cell_servers_ops
);
670 m
= file
->private_data
;
676 * close the file and release the ref to the cell
678 static int afs_proc_cell_servers_release(struct inode
*inode
,
681 return seq_release(inode
, file
);
685 * set up the iterator to start reading from the cells list and return the
688 static void *afs_proc_cell_servers_start(struct seq_file
*m
, loff_t
*_pos
)
689 __acquires(m
->private->servers_lock
)
691 struct afs_cell
*cell
= m
->private;
693 _enter("cell=%p pos=%Ld", cell
, *_pos
);
695 /* lock the list against modification */
696 read_lock(&cell
->servers_lock
);
697 return seq_list_start_head(&cell
->servers
, *_pos
);
701 * move to next cell in cells list
703 static void *afs_proc_cell_servers_next(struct seq_file
*p
, void *v
,
706 struct afs_cell
*cell
= p
->private;
708 _enter("cell=%p pos=%Ld", cell
, *_pos
);
709 return seq_list_next(v
, &cell
->servers
, _pos
);
713 * clean up after reading from the cells list
715 static void afs_proc_cell_servers_stop(struct seq_file
*p
, void *v
)
716 __releases(p
->private->servers_lock
)
718 struct afs_cell
*cell
= p
->private;
720 read_unlock(&cell
->servers_lock
);
724 * display a header line followed by a load of volume lines
726 static int afs_proc_cell_servers_show(struct seq_file
*m
, void *v
)
728 struct afs_cell
*cell
= m
->private;
729 struct afs_server
*server
= list_entry(v
, struct afs_server
, link
);
732 /* display header on line 1 */
733 if (v
== &cell
->servers
) {
734 seq_puts(m
, "USE ADDR STATE\n");
738 /* display one cell per line on subsequent lines */
739 sprintf(ipaddr
, "%pI4", &server
->addr
);
740 seq_printf(m
, "%3d %-15.15s %5d\n",
741 atomic_read(&server
->usage
), ipaddr
, server
->fs_state
);