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 inline struct afs_net
*afs_seq2net(struct seq_file
*m
)
22 return afs_net(seq_file_net(m
));
25 static inline struct afs_net
*afs_seq2net_single(struct seq_file
*m
)
27 return afs_net(seq_file_single_net(m
));
31 * Display the list of cells known to the namespace.
33 static int afs_proc_cells_show(struct seq_file
*m
, void *v
)
35 struct afs_cell
*cell
= list_entry(v
, struct afs_cell
, proc_link
);
36 struct afs_net
*net
= afs_seq2net(m
);
38 if (v
== &net
->proc_cells
) {
39 /* display header on line 1 */
40 seq_puts(m
, "USE NAME\n");
44 /* display one cell per line on subsequent lines */
45 seq_printf(m
, "%3u %s\n", atomic_read(&cell
->usage
), cell
->name
);
49 static void *afs_proc_cells_start(struct seq_file
*m
, loff_t
*_pos
)
53 return seq_list_start_head(&afs_seq2net(m
)->proc_cells
, *_pos
);
56 static void *afs_proc_cells_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
58 return seq_list_next(v
, &afs_seq2net(m
)->proc_cells
, pos
);
61 static void afs_proc_cells_stop(struct seq_file
*m
, void *v
)
67 static const struct seq_operations afs_proc_cells_ops
= {
68 .start
= afs_proc_cells_start
,
69 .next
= afs_proc_cells_next
,
70 .stop
= afs_proc_cells_stop
,
71 .show
= afs_proc_cells_show
,
75 * handle writes to /proc/fs/afs/cells
76 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
78 static int afs_proc_cells_write(struct file
*file
, char *buf
, size_t size
)
80 struct seq_file
*m
= file
->private_data
;
81 struct afs_net
*net
= afs_seq2net(m
);
85 /* trim to first NL */
86 name
= memchr(buf
, '\n', size
);
90 /* split into command, name and argslist */
91 name
= strchr(buf
, ' ');
96 } while(*name
== ' ');
100 args
= strchr(name
, ' ');
104 } while(*args
== ' ');
109 /* determine command to perform */
110 _debug("cmd=%s name=%s args=%s", buf
, name
, args
);
112 if (strcmp(buf
, "add") == 0) {
113 struct afs_cell
*cell
;
115 cell
= afs_lookup_cell(net
, name
, strlen(name
), args
, true);
121 if (test_and_set_bit(AFS_CELL_FL_NO_GC
, &cell
->flags
))
122 afs_put_cell(net
, cell
);
130 _leave(" = %d", ret
);
135 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
140 * Display the name of the current workstation cell.
142 static int afs_proc_rootcell_show(struct seq_file
*m
, void *v
)
144 struct afs_cell
*cell
;
147 net
= afs_seq2net_single(m
);
148 if (rcu_access_pointer(net
->ws_cell
)) {
150 cell
= rcu_dereference(net
->ws_cell
);
152 seq_printf(m
, "%s\n", cell
->name
);
159 * Set the current workstation cell and optionally supply its list of volume
162 * echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell
164 static int afs_proc_rootcell_write(struct file
*file
, char *buf
, size_t size
)
166 struct seq_file
*m
= file
->private_data
;
167 struct afs_net
*net
= afs_seq2net_single(m
);
174 if (memchr(buf
, '/', size
))
177 /* trim to first NL */
178 s
= memchr(buf
, '\n', size
);
182 /* determine command to perform */
183 _debug("rootcell=%s", buf
);
185 ret
= afs_cell_init(net
, buf
);
188 _leave(" = %d", ret
);
192 static const char afs_vol_types
[3][3] = {
193 [AFSVL_RWVOL
] = "RW",
194 [AFSVL_ROVOL
] = "RO",
195 [AFSVL_BACKVOL
] = "BK",
199 * Display the list of volumes known to a cell.
201 static int afs_proc_cell_volumes_show(struct seq_file
*m
, void *v
)
203 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
204 struct afs_volume
*vol
= list_entry(v
, struct afs_volume
, proc_link
);
206 /* Display header on line 1 */
207 if (v
== &cell
->proc_volumes
) {
208 seq_puts(m
, "USE VID TY\n");
212 seq_printf(m
, "%3d %08x %s\n",
213 atomic_read(&vol
->usage
), vol
->vid
,
214 afs_vol_types
[vol
->type
]);
219 static void *afs_proc_cell_volumes_start(struct seq_file
*m
, loff_t
*_pos
)
220 __acquires(cell
->proc_lock
)
222 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
224 read_lock(&cell
->proc_lock
);
225 return seq_list_start_head(&cell
->proc_volumes
, *_pos
);
228 static void *afs_proc_cell_volumes_next(struct seq_file
*m
, void *v
,
231 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
233 return seq_list_next(v
, &cell
->proc_volumes
, _pos
);
236 static void afs_proc_cell_volumes_stop(struct seq_file
*m
, void *v
)
237 __releases(cell
->proc_lock
)
239 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
241 read_unlock(&cell
->proc_lock
);
244 static const struct seq_operations afs_proc_cell_volumes_ops
= {
245 .start
= afs_proc_cell_volumes_start
,
246 .next
= afs_proc_cell_volumes_next
,
247 .stop
= afs_proc_cell_volumes_stop
,
248 .show
= afs_proc_cell_volumes_show
,
252 * Display the list of Volume Location servers we're using for a cell.
254 static int afs_proc_cell_vlservers_show(struct seq_file
*m
, void *v
)
256 struct sockaddr_rxrpc
*addr
= v
;
258 /* display header on line 1 */
259 if (v
== (void *)1) {
260 seq_puts(m
, "ADDRESS\n");
264 /* display one cell per line on subsequent lines */
265 seq_printf(m
, "%pISp\n", &addr
->transport
);
269 static void *afs_proc_cell_vlservers_start(struct seq_file
*m
, loff_t
*_pos
)
272 struct afs_addr_list
*alist
;
273 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
278 alist
= rcu_dereference(cell
->vl_addrs
);
280 /* allow for the header line */
285 if (!alist
|| pos
>= alist
->nr_addrs
)
288 return alist
->addrs
+ pos
;
291 static void *afs_proc_cell_vlservers_next(struct seq_file
*m
, void *v
,
294 struct afs_addr_list
*alist
;
295 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
298 alist
= rcu_dereference(cell
->vl_addrs
);
302 if (!alist
|| pos
>= alist
->nr_addrs
)
305 return alist
->addrs
+ pos
;
308 static void afs_proc_cell_vlservers_stop(struct seq_file
*m
, void *v
)
314 static const struct seq_operations afs_proc_cell_vlservers_ops
= {
315 .start
= afs_proc_cell_vlservers_start
,
316 .next
= afs_proc_cell_vlservers_next
,
317 .stop
= afs_proc_cell_vlservers_stop
,
318 .show
= afs_proc_cell_vlservers_show
,
322 * Display the list of fileservers we're using within a namespace.
324 static int afs_proc_servers_show(struct seq_file
*m
, void *v
)
326 struct afs_server
*server
;
327 struct afs_addr_list
*alist
;
330 if (v
== SEQ_START_TOKEN
) {
331 seq_puts(m
, "UUID USE ADDR\n");
335 server
= list_entry(v
, struct afs_server
, proc_link
);
336 alist
= rcu_dereference(server
->addresses
);
337 seq_printf(m
, "%pU %3d %pISpc%s\n",
339 atomic_read(&server
->usage
),
340 &alist
->addrs
[0].transport
,
341 alist
->index
== 0 ? "*" : "");
342 for (i
= 1; i
< alist
->nr_addrs
; i
++)
343 seq_printf(m
, " %pISpc%s\n",
344 &alist
->addrs
[i
].transport
,
345 alist
->index
== i
? "*" : "");
349 static void *afs_proc_servers_start(struct seq_file
*m
, loff_t
*_pos
)
353 return seq_hlist_start_head_rcu(&afs_seq2net(m
)->fs_proc
, *_pos
);
356 static void *afs_proc_servers_next(struct seq_file
*m
, void *v
, loff_t
*_pos
)
358 return seq_hlist_next_rcu(v
, &afs_seq2net(m
)->fs_proc
, _pos
);
361 static void afs_proc_servers_stop(struct seq_file
*m
, void *v
)
367 static const struct seq_operations afs_proc_servers_ops
= {
368 .start
= afs_proc_servers_start
,
369 .next
= afs_proc_servers_next
,
370 .stop
= afs_proc_servers_stop
,
371 .show
= afs_proc_servers_show
,
375 * Display the list of strings that may be substituted for the @sys pathname
378 static int afs_proc_sysname_show(struct seq_file
*m
, void *v
)
380 struct afs_net
*net
= afs_seq2net(m
);
381 struct afs_sysnames
*sysnames
= net
->sysnames
;
382 unsigned int i
= (unsigned long)v
- 1;
384 if (i
< sysnames
->nr
)
385 seq_printf(m
, "%s\n", sysnames
->subs
[i
]);
389 static void *afs_proc_sysname_start(struct seq_file
*m
, loff_t
*pos
)
390 __acquires(&net
->sysnames_lock
)
392 struct afs_net
*net
= afs_seq2net(m
);
393 struct afs_sysnames
*names
;
395 read_lock(&net
->sysnames_lock
);
397 names
= net
->sysnames
;
398 if (*pos
>= names
->nr
)
400 return (void *)(unsigned long)(*pos
+ 1);
403 static void *afs_proc_sysname_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
405 struct afs_net
*net
= afs_seq2net(m
);
406 struct afs_sysnames
*names
= net
->sysnames
;
409 if (*pos
>= names
->nr
)
411 return (void *)(unsigned long)(*pos
+ 1);
414 static void afs_proc_sysname_stop(struct seq_file
*m
, void *v
)
415 __releases(&net
->sysnames_lock
)
417 struct afs_net
*net
= afs_seq2net(m
);
419 read_unlock(&net
->sysnames_lock
);
422 static const struct seq_operations afs_proc_sysname_ops
= {
423 .start
= afs_proc_sysname_start
,
424 .next
= afs_proc_sysname_next
,
425 .stop
= afs_proc_sysname_stop
,
426 .show
= afs_proc_sysname_show
,
430 * Allow the @sys substitution to be configured.
432 static int afs_proc_sysname_write(struct file
*file
, char *buf
, size_t size
)
434 struct afs_sysnames
*sysnames
, *kill
;
435 struct seq_file
*m
= file
->private_data
;
436 struct afs_net
*net
= afs_seq2net(m
);
440 sysnames
= kzalloc(sizeof(*sysnames
), GFP_KERNEL
);
443 refcount_set(&sysnames
->usage
, 1);
447 while ((s
= strsep(&p
, " \t\n"))) {
452 if (len
>= AFSNAMEMAX
)
460 /* Protect against recursion */
464 (len
< 2 || (len
== 2 && s
[1] == '.')))
467 if (memchr(s
, '/', len
))
471 if (sysnames
->nr
>= AFS_NR_SYSNAME
)
474 if (strcmp(s
, afs_init_sysname
) == 0) {
475 sub
= (char *)afs_init_sysname
;
478 sub
= kmemdup(s
, len
+ 1, GFP_KERNEL
);
483 sysnames
->subs
[sysnames
->nr
] = sub
;
487 if (sysnames
->nr
== 0) {
488 sysnames
->subs
[0] = sysnames
->blank
;
492 write_lock(&net
->sysnames_lock
);
493 kill
= net
->sysnames
;
494 net
->sysnames
= sysnames
;
495 write_unlock(&net
->sysnames_lock
);
498 afs_put_sysnames(kill
);
507 void afs_put_sysnames(struct afs_sysnames
*sysnames
)
511 if (sysnames
&& refcount_dec_and_test(&sysnames
->usage
)) {
512 for (i
= 0; i
< sysnames
->nr
; i
++)
513 if (sysnames
->subs
[i
] != afs_init_sysname
&&
514 sysnames
->subs
[i
] != sysnames
->blank
)
515 kfree(sysnames
->subs
[i
]);
520 * Display general per-net namespace statistics
522 static int afs_proc_stats_show(struct seq_file
*m
, void *v
)
524 struct afs_net
*net
= afs_seq2net_single(m
);
526 seq_puts(m
, "kAFS statistics\n");
528 seq_printf(m
, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
529 atomic_read(&net
->n_lookup
),
530 atomic_read(&net
->n_reval
),
531 atomic_read(&net
->n_inval
),
532 atomic_read(&net
->n_relpg
));
534 seq_printf(m
, "dir-data: rdpg=%u\n",
535 atomic_read(&net
->n_read_dir
));
537 seq_printf(m
, "dir-edit: cr=%u rm=%u\n",
538 atomic_read(&net
->n_dir_cr
),
539 atomic_read(&net
->n_dir_rm
));
541 seq_printf(m
, "file-rd : n=%u nb=%lu\n",
542 atomic_read(&net
->n_fetches
),
543 atomic_long_read(&net
->n_fetch_bytes
));
544 seq_printf(m
, "file-wr : n=%u nb=%lu\n",
545 atomic_read(&net
->n_stores
),
546 atomic_long_read(&net
->n_store_bytes
));
551 * initialise /proc/fs/afs/<cell>/
553 int afs_proc_cell_setup(struct afs_cell
*cell
)
555 struct proc_dir_entry
*dir
;
556 struct afs_net
*net
= cell
->net
;
558 _enter("%p{%s},%p", cell
, cell
->name
, net
->proc_afs
);
560 dir
= proc_net_mkdir(net
->net
, cell
->name
, net
->proc_afs
);
564 if (!proc_create_net_data("vlservers", 0444, dir
,
565 &afs_proc_cell_vlservers_ops
,
566 sizeof(struct seq_net_private
),
568 !proc_create_net_data("volumes", 0444, dir
,
569 &afs_proc_cell_volumes_ops
,
570 sizeof(struct seq_net_private
),
578 remove_proc_subtree(cell
->name
, net
->proc_afs
);
580 _leave(" = -ENOMEM");
585 * remove /proc/fs/afs/<cell>/
587 void afs_proc_cell_remove(struct afs_cell
*cell
)
589 struct afs_net
*net
= cell
->net
;
592 remove_proc_subtree(cell
->name
, net
->proc_afs
);
597 * initialise the /proc/fs/afs/ directory
599 int afs_proc_init(struct afs_net
*net
)
601 struct proc_dir_entry
*p
;
605 p
= proc_net_mkdir(net
->net
, "afs", net
->net
->proc_net
);
609 if (!proc_create_net_data_write("cells", 0644, p
,
611 afs_proc_cells_write
,
612 sizeof(struct seq_net_private
),
614 !proc_create_net_single_write("rootcell", 0644, p
,
615 afs_proc_rootcell_show
,
616 afs_proc_rootcell_write
,
618 !proc_create_net("servers", 0444, p
, &afs_proc_servers_ops
,
619 sizeof(struct seq_net_private
)) ||
620 !proc_create_net_single("stats", 0444, p
, afs_proc_stats_show
, NULL
) ||
621 !proc_create_net_data_write("sysname", 0644, p
,
622 &afs_proc_sysname_ops
,
623 afs_proc_sysname_write
,
624 sizeof(struct seq_net_private
),
635 _leave(" = -ENOMEM");
640 * clean up the /proc/fs/afs/ directory
642 void afs_proc_cleanup(struct afs_net
*net
)
644 proc_remove(net
->proc_afs
);
645 net
->proc_afs
= NULL
;