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 <linux/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
= memdup_user_nul(buf
, size
);
235 return PTR_ERR(kbuf
);
237 /* trim to first NL */
238 name
= memchr(kbuf
, '\n', size
);
242 /* split into command, name and argslist */
243 name
= strchr(kbuf
, ' ');
248 } while(*name
== ' ');
252 args
= strchr(name
, ' ');
257 } while(*args
== ' ');
261 /* determine command to perform */
262 _debug("cmd=%s name=%s args=%s", kbuf
, name
, args
);
264 if (strcmp(kbuf
, "add") == 0) {
265 struct afs_cell
*cell
;
267 cell
= afs_cell_create(name
, strlen(name
), args
, false);
274 printk("kAFS: Added new cell '%s'\n", name
);
283 _leave(" = %d", ret
);
288 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
292 static ssize_t
afs_proc_rootcell_read(struct file
*file
, char __user
*buf
,
293 size_t size
, loff_t
*_pos
)
299 * handle writes to /proc/fs/afs/rootcell
300 * - to initialize rootcell: echo "cell.name:192.168.231.14"
302 static ssize_t
afs_proc_rootcell_write(struct file
*file
,
303 const char __user
*buf
,
304 size_t size
, loff_t
*_pos
)
309 /* start by dragging the command into memory */
310 if (size
<= 1 || size
>= PAGE_SIZE
)
313 kbuf
= memdup_user_nul(buf
, size
);
315 return PTR_ERR(kbuf
);
317 /* trim to first NL */
318 s
= memchr(kbuf
, '\n', size
);
322 /* determine command to perform */
323 _debug("rootcell=%s", kbuf
);
325 ret
= afs_cell_init(kbuf
);
327 ret
= size
; /* consume everything, always */
330 _leave(" = %d", ret
);
335 * initialise /proc/fs/afs/<cell>/
337 int afs_proc_cell_setup(struct afs_cell
*cell
)
339 struct proc_dir_entry
*dir
;
341 _enter("%p{%s}", cell
, cell
->name
);
343 dir
= proc_mkdir(cell
->name
, proc_afs
);
347 if (!proc_create_data("servers", 0, dir
,
348 &afs_proc_cell_servers_fops
, cell
) ||
349 !proc_create_data("vlservers", 0, dir
,
350 &afs_proc_cell_vlservers_fops
, cell
) ||
351 !proc_create_data("volumes", 0, dir
,
352 &afs_proc_cell_volumes_fops
, cell
))
359 remove_proc_subtree(cell
->name
, proc_afs
);
361 _leave(" = -ENOMEM");
366 * remove /proc/fs/afs/<cell>/
368 void afs_proc_cell_remove(struct afs_cell
*cell
)
372 remove_proc_subtree(cell
->name
, proc_afs
);
378 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
380 static int afs_proc_cell_volumes_open(struct inode
*inode
, struct file
*file
)
382 struct afs_cell
*cell
;
386 cell
= PDE_DATA(inode
);
390 ret
= seq_open(file
, &afs_proc_cell_volumes_ops
);
394 m
= file
->private_data
;
401 * set up the iterator to start reading from the cells list and return the
404 static void *afs_proc_cell_volumes_start(struct seq_file
*m
, loff_t
*_pos
)
406 struct afs_cell
*cell
= m
->private;
408 _enter("cell=%p pos=%Ld", cell
, *_pos
);
410 /* lock the list against modification */
411 down_read(&cell
->vl_sem
);
412 return seq_list_start_head(&cell
->vl_list
, *_pos
);
416 * move to next cell in cells list
418 static void *afs_proc_cell_volumes_next(struct seq_file
*p
, void *v
,
421 struct afs_cell
*cell
= p
->private;
423 _enter("cell=%p pos=%Ld", cell
, *_pos
);
424 return seq_list_next(v
, &cell
->vl_list
, _pos
);
428 * clean up after reading from the cells list
430 static void afs_proc_cell_volumes_stop(struct seq_file
*p
, void *v
)
432 struct afs_cell
*cell
= p
->private;
434 up_read(&cell
->vl_sem
);
437 static const char afs_vlocation_states
[][4] = {
438 [AFS_VL_NEW
] = "New",
439 [AFS_VL_CREATING
] = "Crt",
440 [AFS_VL_VALID
] = "Val",
441 [AFS_VL_NO_VOLUME
] = "NoV",
442 [AFS_VL_UPDATING
] = "Upd",
443 [AFS_VL_VOLUME_DELETED
] = "Del",
444 [AFS_VL_UNCERTAIN
] = "Unc",
448 * display a header line followed by a load of volume lines
450 static int afs_proc_cell_volumes_show(struct seq_file
*m
, void *v
)
452 struct afs_cell
*cell
= m
->private;
453 struct afs_vlocation
*vlocation
=
454 list_entry(v
, struct afs_vlocation
, link
);
456 /* display header on line 1 */
457 if (v
== &cell
->vl_list
) {
458 seq_puts(m
, "USE STT VLID[0] VLID[1] VLID[2] NAME\n");
462 /* display one cell per line on subsequent lines */
463 seq_printf(m
, "%3d %s %08x %08x %08x %s\n",
464 atomic_read(&vlocation
->usage
),
465 afs_vlocation_states
[vlocation
->state
],
466 vlocation
->vldb
.vid
[0],
467 vlocation
->vldb
.vid
[1],
468 vlocation
->vldb
.vid
[2],
469 vlocation
->vldb
.name
);
475 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
478 static int afs_proc_cell_vlservers_open(struct inode
*inode
, struct file
*file
)
480 struct afs_cell
*cell
;
484 cell
= PDE_DATA(inode
);
488 ret
= seq_open(file
, &afs_proc_cell_vlservers_ops
);
492 m
= file
->private_data
;
499 * set up the iterator to start reading from the cells list and return the
502 static void *afs_proc_cell_vlservers_start(struct seq_file
*m
, loff_t
*_pos
)
504 struct afs_cell
*cell
= m
->private;
507 _enter("cell=%p pos=%Ld", cell
, *_pos
);
509 /* lock the list against modification */
510 down_read(&cell
->vl_sem
);
512 /* allow for the header line */
517 if (pos
>= cell
->vl_naddrs
)
520 return &cell
->vl_addrs
[pos
];
524 * move to next cell in cells list
526 static void *afs_proc_cell_vlservers_next(struct seq_file
*p
, void *v
,
529 struct afs_cell
*cell
= p
->private;
532 _enter("cell=%p{nad=%u} pos=%Ld", cell
, cell
->vl_naddrs
, *_pos
);
536 if (pos
>= cell
->vl_naddrs
)
539 return &cell
->vl_addrs
[pos
];
543 * clean up after reading from the cells list
545 static void afs_proc_cell_vlservers_stop(struct seq_file
*p
, void *v
)
547 struct afs_cell
*cell
= p
->private;
549 up_read(&cell
->vl_sem
);
553 * display a header line followed by a load of volume lines
555 static int afs_proc_cell_vlservers_show(struct seq_file
*m
, void *v
)
557 struct in_addr
*addr
= v
;
559 /* display header on line 1 */
560 if (v
== (struct in_addr
*) 1) {
561 seq_puts(m
, "ADDRESS\n");
565 /* display one cell per line on subsequent lines */
566 seq_printf(m
, "%pI4\n", &addr
->s_addr
);
571 * open "/proc/fs/afs/<cell>/servers" which provides a summary of active
574 static int afs_proc_cell_servers_open(struct inode
*inode
, struct file
*file
)
576 struct afs_cell
*cell
;
580 cell
= PDE_DATA(inode
);
584 ret
= seq_open(file
, &afs_proc_cell_servers_ops
);
588 m
= file
->private_data
;
594 * set up the iterator to start reading from the cells list and return the
597 static void *afs_proc_cell_servers_start(struct seq_file
*m
, loff_t
*_pos
)
598 __acquires(m
->private->servers_lock
)
600 struct afs_cell
*cell
= m
->private;
602 _enter("cell=%p pos=%Ld", cell
, *_pos
);
604 /* lock the list against modification */
605 read_lock(&cell
->servers_lock
);
606 return seq_list_start_head(&cell
->servers
, *_pos
);
610 * move to next cell in cells list
612 static void *afs_proc_cell_servers_next(struct seq_file
*p
, void *v
,
615 struct afs_cell
*cell
= p
->private;
617 _enter("cell=%p pos=%Ld", cell
, *_pos
);
618 return seq_list_next(v
, &cell
->servers
, _pos
);
622 * clean up after reading from the cells list
624 static void afs_proc_cell_servers_stop(struct seq_file
*p
, void *v
)
625 __releases(p
->private->servers_lock
)
627 struct afs_cell
*cell
= p
->private;
629 read_unlock(&cell
->servers_lock
);
633 * display a header line followed by a load of volume lines
635 static int afs_proc_cell_servers_show(struct seq_file
*m
, void *v
)
637 struct afs_cell
*cell
= m
->private;
638 struct afs_server
*server
= list_entry(v
, struct afs_server
, link
);
641 /* display header on line 1 */
642 if (v
== &cell
->servers
) {
643 seq_puts(m
, "USE ADDR STATE\n");
647 /* display one cell per line on subsequent lines */
648 sprintf(ipaddr
, "%pI4", &server
->addr
);
649 seq_printf(m
, "%3d %-15.15s %5d\n",
650 atomic_read(&server
->usage
), ipaddr
, server
->fs_state
);