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
);
37 if (v
== SEQ_START_TOKEN
) {
38 /* display header on line 1 */
39 seq_puts(m
, "USE NAME\n");
43 /* display one cell per line on subsequent lines */
44 seq_printf(m
, "%3u %s\n", atomic_read(&cell
->usage
), cell
->name
);
48 static void *afs_proc_cells_start(struct seq_file
*m
, loff_t
*_pos
)
52 return seq_hlist_start_head_rcu(&afs_seq2net(m
)->proc_cells
, *_pos
);
55 static void *afs_proc_cells_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
57 return seq_hlist_next_rcu(v
, &afs_seq2net(m
)->proc_cells
, pos
);
60 static void afs_proc_cells_stop(struct seq_file
*m
, void *v
)
66 static const struct seq_operations afs_proc_cells_ops
= {
67 .start
= afs_proc_cells_start
,
68 .next
= afs_proc_cells_next
,
69 .stop
= afs_proc_cells_stop
,
70 .show
= afs_proc_cells_show
,
74 * handle writes to /proc/fs/afs/cells
75 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
77 static int afs_proc_cells_write(struct file
*file
, char *buf
, size_t size
)
79 struct seq_file
*m
= file
->private_data
;
80 struct afs_net
*net
= afs_seq2net(m
);
84 /* trim to first NL */
85 name
= memchr(buf
, '\n', size
);
89 /* split into command, name and argslist */
90 name
= strchr(buf
, ' ');
95 } while(*name
== ' ');
99 args
= strchr(name
, ' ');
103 } while(*args
== ' ');
108 /* determine command to perform */
109 _debug("cmd=%s name=%s args=%s", buf
, name
, args
);
111 if (strcmp(buf
, "add") == 0) {
112 struct afs_cell
*cell
;
114 cell
= afs_lookup_cell(net
, name
, strlen(name
), args
, true);
120 if (test_and_set_bit(AFS_CELL_FL_NO_GC
, &cell
->flags
))
121 afs_put_cell(net
, cell
);
129 _leave(" = %d", ret
);
134 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
139 * Display the name of the current workstation cell.
141 static int afs_proc_rootcell_show(struct seq_file
*m
, void *v
)
143 struct afs_cell
*cell
;
146 net
= afs_seq2net_single(m
);
147 if (rcu_access_pointer(net
->ws_cell
)) {
149 cell
= rcu_dereference(net
->ws_cell
);
151 seq_printf(m
, "%s\n", cell
->name
);
158 * Set the current workstation cell and optionally supply its list of volume
161 * echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell
163 static int afs_proc_rootcell_write(struct file
*file
, char *buf
, size_t size
)
165 struct seq_file
*m
= file
->private_data
;
166 struct afs_net
*net
= afs_seq2net_single(m
);
173 if (memchr(buf
, '/', size
))
176 /* trim to first NL */
177 s
= memchr(buf
, '\n', size
);
181 /* determine command to perform */
182 _debug("rootcell=%s", buf
);
184 ret
= afs_cell_init(net
, buf
);
187 _leave(" = %d", ret
);
191 static const char afs_vol_types
[3][3] = {
192 [AFSVL_RWVOL
] = "RW",
193 [AFSVL_ROVOL
] = "RO",
194 [AFSVL_BACKVOL
] = "BK",
198 * Display the list of volumes known to a cell.
200 static int afs_proc_cell_volumes_show(struct seq_file
*m
, void *v
)
202 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
203 struct afs_volume
*vol
= list_entry(v
, struct afs_volume
, proc_link
);
205 /* Display header on line 1 */
206 if (v
== &cell
->proc_volumes
) {
207 seq_puts(m
, "USE VID TY\n");
211 seq_printf(m
, "%3d %08x %s\n",
212 atomic_read(&vol
->usage
), vol
->vid
,
213 afs_vol_types
[vol
->type
]);
218 static void *afs_proc_cell_volumes_start(struct seq_file
*m
, loff_t
*_pos
)
219 __acquires(cell
->proc_lock
)
221 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
223 read_lock(&cell
->proc_lock
);
224 return seq_list_start_head(&cell
->proc_volumes
, *_pos
);
227 static void *afs_proc_cell_volumes_next(struct seq_file
*m
, void *v
,
230 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
232 return seq_list_next(v
, &cell
->proc_volumes
, _pos
);
235 static void afs_proc_cell_volumes_stop(struct seq_file
*m
, void *v
)
236 __releases(cell
->proc_lock
)
238 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
240 read_unlock(&cell
->proc_lock
);
243 static const struct seq_operations afs_proc_cell_volumes_ops
= {
244 .start
= afs_proc_cell_volumes_start
,
245 .next
= afs_proc_cell_volumes_next
,
246 .stop
= afs_proc_cell_volumes_stop
,
247 .show
= afs_proc_cell_volumes_show
,
251 * Display the list of Volume Location servers we're using for a cell.
253 static int afs_proc_cell_vlservers_show(struct seq_file
*m
, void *v
)
255 struct sockaddr_rxrpc
*addr
= v
;
257 /* display header on line 1 */
258 if (v
== (void *)1) {
259 seq_puts(m
, "ADDRESS\n");
263 /* display one cell per line on subsequent lines */
264 seq_printf(m
, "%pISp\n", &addr
->transport
);
268 static void *afs_proc_cell_vlservers_start(struct seq_file
*m
, loff_t
*_pos
)
271 struct afs_addr_list
*alist
;
272 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
277 alist
= rcu_dereference(cell
->vl_addrs
);
279 /* allow for the header line */
284 if (!alist
|| pos
>= alist
->nr_addrs
)
287 return alist
->addrs
+ pos
;
290 static void *afs_proc_cell_vlservers_next(struct seq_file
*m
, void *v
,
293 struct afs_addr_list
*alist
;
294 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
297 alist
= rcu_dereference(cell
->vl_addrs
);
301 if (!alist
|| pos
>= alist
->nr_addrs
)
304 return alist
->addrs
+ pos
;
307 static void afs_proc_cell_vlservers_stop(struct seq_file
*m
, void *v
)
313 static const struct seq_operations afs_proc_cell_vlservers_ops
= {
314 .start
= afs_proc_cell_vlservers_start
,
315 .next
= afs_proc_cell_vlservers_next
,
316 .stop
= afs_proc_cell_vlservers_stop
,
317 .show
= afs_proc_cell_vlservers_show
,
321 * Display the list of fileservers we're using within a namespace.
323 static int afs_proc_servers_show(struct seq_file
*m
, void *v
)
325 struct afs_server
*server
;
326 struct afs_addr_list
*alist
;
329 if (v
== SEQ_START_TOKEN
) {
330 seq_puts(m
, "UUID USE ADDR\n");
334 server
= list_entry(v
, struct afs_server
, proc_link
);
335 alist
= rcu_dereference(server
->addresses
);
336 seq_printf(m
, "%pU %3d %pISpc%s\n",
338 atomic_read(&server
->usage
),
339 &alist
->addrs
[0].transport
,
340 alist
->index
== 0 ? "*" : "");
341 for (i
= 1; i
< alist
->nr_addrs
; i
++)
342 seq_printf(m
, " %pISpc%s\n",
343 &alist
->addrs
[i
].transport
,
344 alist
->index
== i
? "*" : "");
348 static void *afs_proc_servers_start(struct seq_file
*m
, loff_t
*_pos
)
352 return seq_hlist_start_head_rcu(&afs_seq2net(m
)->fs_proc
, *_pos
);
355 static void *afs_proc_servers_next(struct seq_file
*m
, void *v
, loff_t
*_pos
)
357 return seq_hlist_next_rcu(v
, &afs_seq2net(m
)->fs_proc
, _pos
);
360 static void afs_proc_servers_stop(struct seq_file
*m
, void *v
)
366 static const struct seq_operations afs_proc_servers_ops
= {
367 .start
= afs_proc_servers_start
,
368 .next
= afs_proc_servers_next
,
369 .stop
= afs_proc_servers_stop
,
370 .show
= afs_proc_servers_show
,
374 * Display the list of strings that may be substituted for the @sys pathname
377 static int afs_proc_sysname_show(struct seq_file
*m
, void *v
)
379 struct afs_net
*net
= afs_seq2net(m
);
380 struct afs_sysnames
*sysnames
= net
->sysnames
;
381 unsigned int i
= (unsigned long)v
- 1;
383 if (i
< sysnames
->nr
)
384 seq_printf(m
, "%s\n", sysnames
->subs
[i
]);
388 static void *afs_proc_sysname_start(struct seq_file
*m
, loff_t
*pos
)
389 __acquires(&net
->sysnames_lock
)
391 struct afs_net
*net
= afs_seq2net(m
);
392 struct afs_sysnames
*names
;
394 read_lock(&net
->sysnames_lock
);
396 names
= net
->sysnames
;
397 if (*pos
>= names
->nr
)
399 return (void *)(unsigned long)(*pos
+ 1);
402 static void *afs_proc_sysname_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
404 struct afs_net
*net
= afs_seq2net(m
);
405 struct afs_sysnames
*names
= net
->sysnames
;
408 if (*pos
>= names
->nr
)
410 return (void *)(unsigned long)(*pos
+ 1);
413 static void afs_proc_sysname_stop(struct seq_file
*m
, void *v
)
414 __releases(&net
->sysnames_lock
)
416 struct afs_net
*net
= afs_seq2net(m
);
418 read_unlock(&net
->sysnames_lock
);
421 static const struct seq_operations afs_proc_sysname_ops
= {
422 .start
= afs_proc_sysname_start
,
423 .next
= afs_proc_sysname_next
,
424 .stop
= afs_proc_sysname_stop
,
425 .show
= afs_proc_sysname_show
,
429 * Allow the @sys substitution to be configured.
431 static int afs_proc_sysname_write(struct file
*file
, char *buf
, size_t size
)
433 struct afs_sysnames
*sysnames
, *kill
;
434 struct seq_file
*m
= file
->private_data
;
435 struct afs_net
*net
= afs_seq2net(m
);
439 sysnames
= kzalloc(sizeof(*sysnames
), GFP_KERNEL
);
442 refcount_set(&sysnames
->usage
, 1);
446 while ((s
= strsep(&p
, " \t\n"))) {
451 if (len
>= AFSNAMEMAX
)
459 /* Protect against recursion */
463 (len
< 2 || (len
== 2 && s
[1] == '.')))
466 if (memchr(s
, '/', len
))
470 if (sysnames
->nr
>= AFS_NR_SYSNAME
)
473 if (strcmp(s
, afs_init_sysname
) == 0) {
474 sub
= (char *)afs_init_sysname
;
477 sub
= kmemdup(s
, len
+ 1, GFP_KERNEL
);
482 sysnames
->subs
[sysnames
->nr
] = sub
;
486 if (sysnames
->nr
== 0) {
487 sysnames
->subs
[0] = sysnames
->blank
;
491 write_lock(&net
->sysnames_lock
);
492 kill
= net
->sysnames
;
493 net
->sysnames
= sysnames
;
494 write_unlock(&net
->sysnames_lock
);
497 afs_put_sysnames(kill
);
506 void afs_put_sysnames(struct afs_sysnames
*sysnames
)
510 if (sysnames
&& refcount_dec_and_test(&sysnames
->usage
)) {
511 for (i
= 0; i
< sysnames
->nr
; i
++)
512 if (sysnames
->subs
[i
] != afs_init_sysname
&&
513 sysnames
->subs
[i
] != sysnames
->blank
)
514 kfree(sysnames
->subs
[i
]);
519 * Display general per-net namespace statistics
521 static int afs_proc_stats_show(struct seq_file
*m
, void *v
)
523 struct afs_net
*net
= afs_seq2net_single(m
);
525 seq_puts(m
, "kAFS statistics\n");
527 seq_printf(m
, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
528 atomic_read(&net
->n_lookup
),
529 atomic_read(&net
->n_reval
),
530 atomic_read(&net
->n_inval
),
531 atomic_read(&net
->n_relpg
));
533 seq_printf(m
, "dir-data: rdpg=%u\n",
534 atomic_read(&net
->n_read_dir
));
536 seq_printf(m
, "dir-edit: cr=%u rm=%u\n",
537 atomic_read(&net
->n_dir_cr
),
538 atomic_read(&net
->n_dir_rm
));
540 seq_printf(m
, "file-rd : n=%u nb=%lu\n",
541 atomic_read(&net
->n_fetches
),
542 atomic_long_read(&net
->n_fetch_bytes
));
543 seq_printf(m
, "file-wr : n=%u nb=%lu\n",
544 atomic_read(&net
->n_stores
),
545 atomic_long_read(&net
->n_store_bytes
));
550 * initialise /proc/fs/afs/<cell>/
552 int afs_proc_cell_setup(struct afs_cell
*cell
)
554 struct proc_dir_entry
*dir
;
555 struct afs_net
*net
= cell
->net
;
557 _enter("%p{%s},%p", cell
, cell
->name
, net
->proc_afs
);
559 dir
= proc_net_mkdir(net
->net
, cell
->name
, net
->proc_afs
);
563 if (!proc_create_net_data("vlservers", 0444, dir
,
564 &afs_proc_cell_vlservers_ops
,
565 sizeof(struct seq_net_private
),
567 !proc_create_net_data("volumes", 0444, dir
,
568 &afs_proc_cell_volumes_ops
,
569 sizeof(struct seq_net_private
),
577 remove_proc_subtree(cell
->name
, net
->proc_afs
);
579 _leave(" = -ENOMEM");
584 * remove /proc/fs/afs/<cell>/
586 void afs_proc_cell_remove(struct afs_cell
*cell
)
588 struct afs_net
*net
= cell
->net
;
591 remove_proc_subtree(cell
->name
, net
->proc_afs
);
596 * initialise the /proc/fs/afs/ directory
598 int afs_proc_init(struct afs_net
*net
)
600 struct proc_dir_entry
*p
;
604 p
= proc_net_mkdir(net
->net
, "afs", net
->net
->proc_net
);
608 if (!proc_create_net_data_write("cells", 0644, p
,
610 afs_proc_cells_write
,
611 sizeof(struct seq_net_private
),
613 !proc_create_net_single_write("rootcell", 0644, p
,
614 afs_proc_rootcell_show
,
615 afs_proc_rootcell_write
,
617 !proc_create_net("servers", 0444, p
, &afs_proc_servers_ops
,
618 sizeof(struct seq_net_private
)) ||
619 !proc_create_net_single("stats", 0444, p
, afs_proc_stats_show
, NULL
) ||
620 !proc_create_net_data_write("sysname", 0644, p
,
621 &afs_proc_sysname_ops
,
622 afs_proc_sysname_write
,
623 sizeof(struct seq_net_private
),
634 _leave(" = -ENOMEM");
639 * clean up the /proc/fs/afs/ directory
641 void afs_proc_cleanup(struct afs_net
*net
)
643 proc_remove(net
->proc_afs
);
644 net
->proc_afs
= NULL
;