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 const 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
,
46 static ssize_t
afs_proc_rootcell_read(struct file
*file
, char __user
*buf
,
47 size_t size
, loff_t
*_pos
);
48 static ssize_t
afs_proc_rootcell_write(struct file
*file
,
49 const char __user
*buf
,
50 size_t size
, loff_t
*_pos
);
52 static const struct file_operations afs_proc_rootcell_fops
= {
53 .read
= afs_proc_rootcell_read
,
54 .write
= afs_proc_rootcell_write
,
58 static int afs_proc_cell_volumes_open(struct inode
*inode
, struct file
*file
);
59 static void *afs_proc_cell_volumes_start(struct seq_file
*p
, loff_t
*pos
);
60 static void *afs_proc_cell_volumes_next(struct seq_file
*p
, void *v
,
62 static void afs_proc_cell_volumes_stop(struct seq_file
*p
, void *v
);
63 static int afs_proc_cell_volumes_show(struct seq_file
*m
, void *v
);
65 static const struct seq_operations afs_proc_cell_volumes_ops
= {
66 .start
= afs_proc_cell_volumes_start
,
67 .next
= afs_proc_cell_volumes_next
,
68 .stop
= afs_proc_cell_volumes_stop
,
69 .show
= afs_proc_cell_volumes_show
,
72 static const struct file_operations afs_proc_cell_volumes_fops
= {
73 .open
= afs_proc_cell_volumes_open
,
76 .release
= seq_release
,
79 static int afs_proc_cell_vlservers_open(struct inode
*inode
,
81 static void *afs_proc_cell_vlservers_start(struct seq_file
*p
, loff_t
*pos
);
82 static void *afs_proc_cell_vlservers_next(struct seq_file
*p
, void *v
,
84 static void afs_proc_cell_vlservers_stop(struct seq_file
*p
, void *v
);
85 static int afs_proc_cell_vlservers_show(struct seq_file
*m
, void *v
);
87 static const struct seq_operations afs_proc_cell_vlservers_ops
= {
88 .start
= afs_proc_cell_vlservers_start
,
89 .next
= afs_proc_cell_vlservers_next
,
90 .stop
= afs_proc_cell_vlservers_stop
,
91 .show
= afs_proc_cell_vlservers_show
,
94 static const struct file_operations afs_proc_cell_vlservers_fops
= {
95 .open
= afs_proc_cell_vlservers_open
,
98 .release
= seq_release
,
101 static int afs_proc_cell_servers_open(struct inode
*inode
, struct file
*file
);
102 static void *afs_proc_cell_servers_start(struct seq_file
*p
, loff_t
*pos
);
103 static void *afs_proc_cell_servers_next(struct seq_file
*p
, void *v
,
105 static void afs_proc_cell_servers_stop(struct seq_file
*p
, void *v
);
106 static int afs_proc_cell_servers_show(struct seq_file
*m
, void *v
);
108 static const struct seq_operations afs_proc_cell_servers_ops
= {
109 .start
= afs_proc_cell_servers_start
,
110 .next
= afs_proc_cell_servers_next
,
111 .stop
= afs_proc_cell_servers_stop
,
112 .show
= afs_proc_cell_servers_show
,
115 static const struct file_operations afs_proc_cell_servers_fops
= {
116 .open
= afs_proc_cell_servers_open
,
119 .release
= seq_release
,
123 * initialise the /proc/fs/afs/ directory
125 int afs_proc_init(void)
129 proc_afs
= proc_mkdir("fs/afs", NULL
);
133 if (!proc_create("cells", 0644, proc_afs
, &afs_proc_cells_fops
) ||
134 !proc_create("rootcell", 0644, proc_afs
, &afs_proc_rootcell_fops
))
141 remove_proc_subtree("fs/afs", NULL
);
143 _leave(" = -ENOMEM");
148 * clean up the /proc/fs/afs/ directory
150 void afs_proc_cleanup(void)
152 remove_proc_subtree("fs/afs", NULL
);
156 * open "/proc/fs/afs/cells" which provides a summary of extant cells
158 static int afs_proc_cells_open(struct inode
*inode
, struct file
*file
)
163 ret
= seq_open(file
, &afs_proc_cells_ops
);
167 m
= file
->private_data
;
168 m
->private = PDE_DATA(inode
);
174 * set up the iterator to start reading from the cells list and return the
177 static void *afs_proc_cells_start(struct seq_file
*m
, loff_t
*_pos
)
179 /* lock the list against modification */
180 down_read(&afs_proc_cells_sem
);
181 return seq_list_start_head(&afs_proc_cells
, *_pos
);
185 * move to next cell in cells list
187 static void *afs_proc_cells_next(struct seq_file
*p
, void *v
, loff_t
*pos
)
189 return seq_list_next(v
, &afs_proc_cells
, pos
);
193 * clean up after reading from the cells list
195 static void afs_proc_cells_stop(struct seq_file
*p
, void *v
)
197 up_read(&afs_proc_cells_sem
);
201 * display a header line followed by a load of cell lines
203 static int afs_proc_cells_show(struct seq_file
*m
, void *v
)
205 struct afs_cell
*cell
= list_entry(v
, struct afs_cell
, proc_link
);
207 if (v
== &afs_proc_cells
) {
208 /* display header on line 1 */
209 seq_puts(m
, "USE NAME\n");
213 /* display one cell per line on subsequent lines */
214 seq_printf(m
, "%3d %s\n",
215 atomic_read(&cell
->usage
), cell
->name
);
220 * handle writes to /proc/fs/afs/cells
221 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
223 static ssize_t
afs_proc_cells_write(struct file
*file
, const char __user
*buf
,
224 size_t size
, loff_t
*_pos
)
226 char *kbuf
, *name
, *args
;
229 /* start by dragging the command into memory */
230 if (size
<= 1 || size
>= PAGE_SIZE
)
233 kbuf
= kmalloc(size
+ 1, GFP_KERNEL
);
238 if (copy_from_user(kbuf
, buf
, size
) != 0)
242 /* trim to first NL */
243 name
= memchr(kbuf
, '\n', size
);
247 /* split into command, name and argslist */
248 name
= strchr(kbuf
, ' ');
253 } while(*name
== ' ');
257 args
= strchr(name
, ' ');
262 } while(*args
== ' ');
266 /* determine command to perform */
267 _debug("cmd=%s name=%s args=%s", kbuf
, name
, args
);
269 if (strcmp(kbuf
, "add") == 0) {
270 struct afs_cell
*cell
;
272 cell
= afs_cell_create(name
, strlen(name
), args
, false);
279 printk("kAFS: Added new cell '%s'\n", name
);
288 _leave(" = %d", ret
);
293 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
297 static ssize_t
afs_proc_rootcell_read(struct file
*file
, char __user
*buf
,
298 size_t size
, loff_t
*_pos
)
304 * handle writes to /proc/fs/afs/rootcell
305 * - to initialize rootcell: echo "cell.name:192.168.231.14"
307 static ssize_t
afs_proc_rootcell_write(struct file
*file
,
308 const char __user
*buf
,
309 size_t size
, loff_t
*_pos
)
314 /* start by dragging the command into memory */
315 if (size
<= 1 || size
>= PAGE_SIZE
)
319 kbuf
= kmalloc(size
+ 1, GFP_KERNEL
);
324 if (copy_from_user(kbuf
, buf
, size
) != 0)
328 /* trim to first NL */
329 s
= memchr(kbuf
, '\n', size
);
333 /* determine command to perform */
334 _debug("rootcell=%s", kbuf
);
336 ret
= afs_cell_init(kbuf
);
338 ret
= size
; /* consume everything, always */
343 _leave(" = %d", ret
);
348 * initialise /proc/fs/afs/<cell>/
350 int afs_proc_cell_setup(struct afs_cell
*cell
)
352 struct proc_dir_entry
*dir
;
354 _enter("%p{%s}", cell
, cell
->name
);
356 dir
= proc_mkdir(cell
->name
, proc_afs
);
360 if (!proc_create_data("servers", 0, dir
,
361 &afs_proc_cell_servers_fops
, cell
) ||
362 !proc_create_data("vlservers", 0, dir
,
363 &afs_proc_cell_vlservers_fops
, cell
) ||
364 !proc_create_data("volumes", 0, dir
,
365 &afs_proc_cell_volumes_fops
, cell
))
372 remove_proc_subtree(cell
->name
, proc_afs
);
374 _leave(" = -ENOMEM");
379 * remove /proc/fs/afs/<cell>/
381 void afs_proc_cell_remove(struct afs_cell
*cell
)
385 remove_proc_subtree(cell
->name
, proc_afs
);
391 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
393 static int afs_proc_cell_volumes_open(struct inode
*inode
, struct file
*file
)
395 struct afs_cell
*cell
;
399 cell
= PDE_DATA(inode
);
403 ret
= seq_open(file
, &afs_proc_cell_volumes_ops
);
407 m
= file
->private_data
;
414 * set up the iterator to start reading from the cells list and return the
417 static void *afs_proc_cell_volumes_start(struct seq_file
*m
, loff_t
*_pos
)
419 struct afs_cell
*cell
= m
->private;
421 _enter("cell=%p pos=%Ld", cell
, *_pos
);
423 /* lock the list against modification */
424 down_read(&cell
->vl_sem
);
425 return seq_list_start_head(&cell
->vl_list
, *_pos
);
429 * move to next cell in cells list
431 static void *afs_proc_cell_volumes_next(struct seq_file
*p
, void *v
,
434 struct afs_cell
*cell
= p
->private;
436 _enter("cell=%p pos=%Ld", cell
, *_pos
);
437 return seq_list_next(v
, &cell
->vl_list
, _pos
);
441 * clean up after reading from the cells list
443 static void afs_proc_cell_volumes_stop(struct seq_file
*p
, void *v
)
445 struct afs_cell
*cell
= p
->private;
447 up_read(&cell
->vl_sem
);
450 static const char afs_vlocation_states
[][4] = {
451 [AFS_VL_NEW
] = "New",
452 [AFS_VL_CREATING
] = "Crt",
453 [AFS_VL_VALID
] = "Val",
454 [AFS_VL_NO_VOLUME
] = "NoV",
455 [AFS_VL_UPDATING
] = "Upd",
456 [AFS_VL_VOLUME_DELETED
] = "Del",
457 [AFS_VL_UNCERTAIN
] = "Unc",
461 * display a header line followed by a load of volume lines
463 static int afs_proc_cell_volumes_show(struct seq_file
*m
, void *v
)
465 struct afs_cell
*cell
= m
->private;
466 struct afs_vlocation
*vlocation
=
467 list_entry(v
, struct afs_vlocation
, link
);
469 /* display header on line 1 */
470 if (v
== &cell
->vl_list
) {
471 seq_puts(m
, "USE STT VLID[0] VLID[1] VLID[2] NAME\n");
475 /* display one cell per line on subsequent lines */
476 seq_printf(m
, "%3d %s %08x %08x %08x %s\n",
477 atomic_read(&vlocation
->usage
),
478 afs_vlocation_states
[vlocation
->state
],
479 vlocation
->vldb
.vid
[0],
480 vlocation
->vldb
.vid
[1],
481 vlocation
->vldb
.vid
[2],
482 vlocation
->vldb
.name
);
488 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
491 static int afs_proc_cell_vlservers_open(struct inode
*inode
, struct file
*file
)
493 struct afs_cell
*cell
;
497 cell
= PDE_DATA(inode
);
501 ret
= seq_open(file
, &afs_proc_cell_vlservers_ops
);
505 m
= file
->private_data
;
512 * set up the iterator to start reading from the cells list and return the
515 static void *afs_proc_cell_vlservers_start(struct seq_file
*m
, loff_t
*_pos
)
517 struct afs_cell
*cell
= m
->private;
520 _enter("cell=%p pos=%Ld", cell
, *_pos
);
522 /* lock the list against modification */
523 down_read(&cell
->vl_sem
);
525 /* allow for the header line */
530 if (pos
>= cell
->vl_naddrs
)
533 return &cell
->vl_addrs
[pos
];
537 * move to next cell in cells list
539 static void *afs_proc_cell_vlservers_next(struct seq_file
*p
, void *v
,
542 struct afs_cell
*cell
= p
->private;
545 _enter("cell=%p{nad=%u} pos=%Ld", cell
, cell
->vl_naddrs
, *_pos
);
549 if (pos
>= cell
->vl_naddrs
)
552 return &cell
->vl_addrs
[pos
];
556 * clean up after reading from the cells list
558 static void afs_proc_cell_vlservers_stop(struct seq_file
*p
, void *v
)
560 struct afs_cell
*cell
= p
->private;
562 up_read(&cell
->vl_sem
);
566 * display a header line followed by a load of volume lines
568 static int afs_proc_cell_vlservers_show(struct seq_file
*m
, void *v
)
570 struct in_addr
*addr
= v
;
572 /* display header on line 1 */
573 if (v
== (struct in_addr
*) 1) {
574 seq_puts(m
, "ADDRESS\n");
578 /* display one cell per line on subsequent lines */
579 seq_printf(m
, "%pI4\n", &addr
->s_addr
);
584 * open "/proc/fs/afs/<cell>/servers" which provides a summary of active
587 static int afs_proc_cell_servers_open(struct inode
*inode
, struct file
*file
)
589 struct afs_cell
*cell
;
593 cell
= PDE_DATA(inode
);
597 ret
= seq_open(file
, &afs_proc_cell_servers_ops
);
601 m
= file
->private_data
;
607 * set up the iterator to start reading from the cells list and return the
610 static void *afs_proc_cell_servers_start(struct seq_file
*m
, loff_t
*_pos
)
611 __acquires(m
->private->servers_lock
)
613 struct afs_cell
*cell
= m
->private;
615 _enter("cell=%p pos=%Ld", cell
, *_pos
);
617 /* lock the list against modification */
618 read_lock(&cell
->servers_lock
);
619 return seq_list_start_head(&cell
->servers
, *_pos
);
623 * move to next cell in cells list
625 static void *afs_proc_cell_servers_next(struct seq_file
*p
, void *v
,
628 struct afs_cell
*cell
= p
->private;
630 _enter("cell=%p pos=%Ld", cell
, *_pos
);
631 return seq_list_next(v
, &cell
->servers
, _pos
);
635 * clean up after reading from the cells list
637 static void afs_proc_cell_servers_stop(struct seq_file
*p
, void *v
)
638 __releases(p
->private->servers_lock
)
640 struct afs_cell
*cell
= p
->private;
642 read_unlock(&cell
->servers_lock
);
646 * display a header line followed by a load of volume lines
648 static int afs_proc_cell_servers_show(struct seq_file
*m
, void *v
)
650 struct afs_cell
*cell
= m
->private;
651 struct afs_server
*server
= list_entry(v
, struct afs_server
, link
);
654 /* display header on line 1 */
655 if (v
== &cell
->servers
) {
656 seq_puts(m
, "USE ADDR STATE\n");
660 /* display one cell per line on subsequent lines */
661 sprintf(ipaddr
, "%pI4", &server
->addr
);
662 seq_printf(m
, "%3d %-15.15s %5d\n",
663 atomic_read(&server
->usage
), ipaddr
, server
->fs_state
);