1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* /proc interface for AFS
4 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
8 #include <linux/slab.h>
9 #include <linux/module.h>
10 #include <linux/proc_fs.h>
11 #include <linux/seq_file.h>
12 #include <linux/sched.h>
13 #include <linux/uaccess.h>
16 struct afs_vl_seq_net_private
{
17 struct seq_net_private seq
; /* Must be first */
18 struct afs_vlserver_list
*vllist
;
21 static inline struct afs_net
*afs_seq2net(struct seq_file
*m
)
23 return afs_net(seq_file_net(m
));
26 static inline struct afs_net
*afs_seq2net_single(struct seq_file
*m
)
28 return afs_net(seq_file_single_net(m
));
32 * Display the list of cells known to the namespace.
34 static int afs_proc_cells_show(struct seq_file
*m
, void *v
)
36 struct afs_vlserver_list
*vllist
;
37 struct afs_cell
*cell
;
39 if (v
== SEQ_START_TOKEN
) {
40 /* display header on line 1 */
41 seq_puts(m
, "USE ACT TTL SV ST NAME\n");
45 cell
= list_entry(v
, struct afs_cell
, proc_link
);
46 vllist
= rcu_dereference(cell
->vl_servers
);
48 /* display one cell per line on subsequent lines */
49 seq_printf(m
, "%3u %3u %6lld %2u %2u %s\n",
50 atomic_read(&cell
->ref
),
51 atomic_read(&cell
->active
),
52 cell
->dns_expiry
- ktime_get_real_seconds(),
53 vllist
? vllist
->nr_servers
: 0,
59 static void *afs_proc_cells_start(struct seq_file
*m
, loff_t
*_pos
)
63 return seq_hlist_start_head_rcu(&afs_seq2net(m
)->proc_cells
, *_pos
);
66 static void *afs_proc_cells_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
68 return seq_hlist_next_rcu(v
, &afs_seq2net(m
)->proc_cells
, pos
);
71 static void afs_proc_cells_stop(struct seq_file
*m
, void *v
)
77 static const struct seq_operations afs_proc_cells_ops
= {
78 .start
= afs_proc_cells_start
,
79 .next
= afs_proc_cells_next
,
80 .stop
= afs_proc_cells_stop
,
81 .show
= afs_proc_cells_show
,
85 * handle writes to /proc/fs/afs/cells
86 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
88 static int afs_proc_cells_write(struct file
*file
, char *buf
, size_t size
)
90 struct seq_file
*m
= file
->private_data
;
91 struct afs_net
*net
= afs_seq2net(m
);
95 /* trim to first NL */
96 name
= memchr(buf
, '\n', size
);
100 /* split into command, name and argslist */
101 name
= strchr(buf
, ' ');
106 } while(*name
== ' ');
110 args
= strchr(name
, ' ');
114 } while(*args
== ' ');
119 /* determine command to perform */
120 _debug("cmd=%s name=%s args=%s", buf
, name
, args
);
122 if (strcmp(buf
, "add") == 0) {
123 struct afs_cell
*cell
;
125 cell
= afs_lookup_cell(net
, name
, strlen(name
), args
, true);
131 if (test_and_set_bit(AFS_CELL_FL_NO_GC
, &cell
->flags
))
132 afs_unuse_cell(net
, cell
, afs_cell_trace_unuse_no_pin
);
140 _leave(" = %d", ret
);
145 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
150 * Display the name of the current workstation cell.
152 static int afs_proc_rootcell_show(struct seq_file
*m
, void *v
)
154 struct afs_cell
*cell
;
157 net
= afs_seq2net_single(m
);
158 down_read(&net
->cells_lock
);
161 seq_printf(m
, "%s\n", cell
->name
);
162 up_read(&net
->cells_lock
);
167 * Set the current workstation cell and optionally supply its list of volume
170 * echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell
172 static int afs_proc_rootcell_write(struct file
*file
, char *buf
, size_t size
)
174 struct seq_file
*m
= file
->private_data
;
175 struct afs_net
*net
= afs_seq2net_single(m
);
182 if (memchr(buf
, '/', size
))
185 /* trim to first NL */
186 s
= memchr(buf
, '\n', size
);
190 /* determine command to perform */
191 _debug("rootcell=%s", buf
);
193 ret
= afs_cell_init(net
, buf
);
196 _leave(" = %d", ret
);
200 static const char afs_vol_types
[3][3] = {
201 [AFSVL_RWVOL
] = "RW",
202 [AFSVL_ROVOL
] = "RO",
203 [AFSVL_BACKVOL
] = "BK",
207 * Display the list of volumes known to a cell.
209 static int afs_proc_cell_volumes_show(struct seq_file
*m
, void *v
)
211 struct afs_volume
*vol
= hlist_entry(v
, struct afs_volume
, proc_link
);
213 /* Display header on line 1 */
214 if (v
== SEQ_START_TOKEN
) {
215 seq_puts(m
, "USE VID TY NAME\n");
219 seq_printf(m
, "%3d %08llx %s %s\n",
220 atomic_read(&vol
->usage
), vol
->vid
,
221 afs_vol_types
[vol
->type
],
227 static void *afs_proc_cell_volumes_start(struct seq_file
*m
, loff_t
*_pos
)
228 __acquires(cell
->proc_lock
)
230 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
233 return seq_hlist_start_head_rcu(&cell
->proc_volumes
, *_pos
);
236 static void *afs_proc_cell_volumes_next(struct seq_file
*m
, void *v
,
239 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
241 return seq_hlist_next_rcu(v
, &cell
->proc_volumes
, _pos
);
244 static void afs_proc_cell_volumes_stop(struct seq_file
*m
, void *v
)
245 __releases(cell
->proc_lock
)
250 static const struct seq_operations afs_proc_cell_volumes_ops
= {
251 .start
= afs_proc_cell_volumes_start
,
252 .next
= afs_proc_cell_volumes_next
,
253 .stop
= afs_proc_cell_volumes_stop
,
254 .show
= afs_proc_cell_volumes_show
,
257 static const char *const dns_record_sources
[NR__dns_record_source
+ 1] = {
258 [DNS_RECORD_UNAVAILABLE
] = "unav",
259 [DNS_RECORD_FROM_CONFIG
] = "cfg",
260 [DNS_RECORD_FROM_DNS_A
] = "A",
261 [DNS_RECORD_FROM_DNS_AFSDB
] = "AFSDB",
262 [DNS_RECORD_FROM_DNS_SRV
] = "SRV",
263 [DNS_RECORD_FROM_NSS
] = "nss",
264 [NR__dns_record_source
] = "[weird]"
267 static const char *const dns_lookup_statuses
[NR__dns_lookup_status
+ 1] = {
268 [DNS_LOOKUP_NOT_DONE
] = "no-lookup",
269 [DNS_LOOKUP_GOOD
] = "good",
270 [DNS_LOOKUP_GOOD_WITH_BAD
] = "good/bad",
271 [DNS_LOOKUP_BAD
] = "bad",
272 [DNS_LOOKUP_GOT_NOT_FOUND
] = "not-found",
273 [DNS_LOOKUP_GOT_LOCAL_FAILURE
] = "local-failure",
274 [DNS_LOOKUP_GOT_TEMP_FAILURE
] = "temp-failure",
275 [DNS_LOOKUP_GOT_NS_FAILURE
] = "ns-failure",
276 [NR__dns_lookup_status
] = "[weird]"
280 * Display the list of Volume Location servers we're using for a cell.
282 static int afs_proc_cell_vlservers_show(struct seq_file
*m
, void *v
)
284 const struct afs_vl_seq_net_private
*priv
= m
->private;
285 const struct afs_vlserver_list
*vllist
= priv
->vllist
;
286 const struct afs_vlserver_entry
*entry
;
287 const struct afs_vlserver
*vlserver
;
288 const struct afs_addr_list
*alist
;
291 if (v
== SEQ_START_TOKEN
) {
292 seq_printf(m
, "# source %s, status %s\n",
293 dns_record_sources
[vllist
? vllist
->source
: 0],
294 dns_lookup_statuses
[vllist
? vllist
->status
: 0]);
299 vlserver
= entry
->server
;
300 alist
= rcu_dereference(vlserver
->addresses
);
302 seq_printf(m
, "%s [p=%hu w=%hu s=%s,%s]:\n",
303 vlserver
->name
, entry
->priority
, entry
->weight
,
304 dns_record_sources
[alist
? alist
->source
: entry
->source
],
305 dns_lookup_statuses
[alist
? alist
->status
: entry
->status
]);
307 for (i
= 0; i
< alist
->nr_addrs
; i
++)
308 seq_printf(m
, " %c %pISpc\n",
309 alist
->preferred
== i
? '>' : '-',
310 &alist
->addrs
[i
].transport
);
312 seq_printf(m
, " info: fl=%lx rtt=%d\n", vlserver
->flags
, vlserver
->rtt
);
313 seq_printf(m
, " probe: fl=%x e=%d ac=%d out=%d\n",
314 vlserver
->probe
.flags
, vlserver
->probe
.error
,
315 vlserver
->probe
.abort_code
,
316 atomic_read(&vlserver
->probe_outstanding
));
320 static void *afs_proc_cell_vlservers_start(struct seq_file
*m
, loff_t
*_pos
)
323 struct afs_vl_seq_net_private
*priv
= m
->private;
324 struct afs_vlserver_list
*vllist
;
325 struct afs_cell
*cell
= PDE_DATA(file_inode(m
->file
));
330 vllist
= rcu_dereference(cell
->vl_servers
);
331 priv
->vllist
= vllist
;
336 return SEQ_START_TOKEN
;
338 if (pos
- 1 >= vllist
->nr_servers
)
341 return &vllist
->servers
[pos
- 1];
344 static void *afs_proc_cell_vlservers_next(struct seq_file
*m
, void *v
,
347 struct afs_vl_seq_net_private
*priv
= m
->private;
348 struct afs_vlserver_list
*vllist
= priv
->vllist
;
354 if (!vllist
|| pos
- 1 >= vllist
->nr_servers
)
357 return &vllist
->servers
[pos
- 1];
360 static void afs_proc_cell_vlservers_stop(struct seq_file
*m
, void *v
)
366 static const struct seq_operations afs_proc_cell_vlservers_ops
= {
367 .start
= afs_proc_cell_vlservers_start
,
368 .next
= afs_proc_cell_vlservers_next
,
369 .stop
= afs_proc_cell_vlservers_stop
,
370 .show
= afs_proc_cell_vlservers_show
,
374 * Display the list of fileservers we're using within a namespace.
376 static int afs_proc_servers_show(struct seq_file
*m
, void *v
)
378 struct afs_server
*server
;
379 struct afs_addr_list
*alist
;
382 if (v
== SEQ_START_TOKEN
) {
383 seq_puts(m
, "UUID REF ACT\n");
387 server
= list_entry(v
, struct afs_server
, proc_link
);
388 alist
= rcu_dereference(server
->addresses
);
389 seq_printf(m
, "%pU %3d %3d\n",
391 atomic_read(&server
->ref
),
392 atomic_read(&server
->active
));
393 seq_printf(m
, " - info: fl=%lx rtt=%u brk=%x\n",
394 server
->flags
, server
->rtt
, server
->cb_s_break
);
395 seq_printf(m
, " - probe: last=%d out=%d\n",
396 (int)(jiffies
- server
->probed_at
) / HZ
,
397 atomic_read(&server
->probe_outstanding
));
398 seq_printf(m
, " - ALIST v=%u rsp=%lx f=%lx\n",
399 alist
->version
, alist
->responded
, alist
->failed
);
400 for (i
= 0; i
< alist
->nr_addrs
; i
++)
401 seq_printf(m
, " [%x] %pISpc%s\n",
402 i
, &alist
->addrs
[i
].transport
,
403 alist
->preferred
== i
? "*" : "");
407 static void *afs_proc_servers_start(struct seq_file
*m
, loff_t
*_pos
)
411 return seq_hlist_start_head_rcu(&afs_seq2net(m
)->fs_proc
, *_pos
);
414 static void *afs_proc_servers_next(struct seq_file
*m
, void *v
, loff_t
*_pos
)
416 return seq_hlist_next_rcu(v
, &afs_seq2net(m
)->fs_proc
, _pos
);
419 static void afs_proc_servers_stop(struct seq_file
*m
, void *v
)
425 static const struct seq_operations afs_proc_servers_ops
= {
426 .start
= afs_proc_servers_start
,
427 .next
= afs_proc_servers_next
,
428 .stop
= afs_proc_servers_stop
,
429 .show
= afs_proc_servers_show
,
433 * Display the list of strings that may be substituted for the @sys pathname
436 static int afs_proc_sysname_show(struct seq_file
*m
, void *v
)
438 struct afs_net
*net
= afs_seq2net(m
);
439 struct afs_sysnames
*sysnames
= net
->sysnames
;
440 unsigned int i
= (unsigned long)v
- 1;
442 if (i
< sysnames
->nr
)
443 seq_printf(m
, "%s\n", sysnames
->subs
[i
]);
447 static void *afs_proc_sysname_start(struct seq_file
*m
, loff_t
*pos
)
448 __acquires(&net
->sysnames_lock
)
450 struct afs_net
*net
= afs_seq2net(m
);
451 struct afs_sysnames
*names
;
453 read_lock(&net
->sysnames_lock
);
455 names
= net
->sysnames
;
456 if (*pos
>= names
->nr
)
458 return (void *)(unsigned long)(*pos
+ 1);
461 static void *afs_proc_sysname_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
463 struct afs_net
*net
= afs_seq2net(m
);
464 struct afs_sysnames
*names
= net
->sysnames
;
467 if (*pos
>= names
->nr
)
469 return (void *)(unsigned long)(*pos
+ 1);
472 static void afs_proc_sysname_stop(struct seq_file
*m
, void *v
)
473 __releases(&net
->sysnames_lock
)
475 struct afs_net
*net
= afs_seq2net(m
);
477 read_unlock(&net
->sysnames_lock
);
480 static const struct seq_operations afs_proc_sysname_ops
= {
481 .start
= afs_proc_sysname_start
,
482 .next
= afs_proc_sysname_next
,
483 .stop
= afs_proc_sysname_stop
,
484 .show
= afs_proc_sysname_show
,
488 * Allow the @sys substitution to be configured.
490 static int afs_proc_sysname_write(struct file
*file
, char *buf
, size_t size
)
492 struct afs_sysnames
*sysnames
, *kill
;
493 struct seq_file
*m
= file
->private_data
;
494 struct afs_net
*net
= afs_seq2net(m
);
498 sysnames
= kzalloc(sizeof(*sysnames
), GFP_KERNEL
);
501 refcount_set(&sysnames
->usage
, 1);
505 while ((s
= strsep(&p
, " \t\n"))) {
510 if (len
>= AFSNAMEMAX
)
518 /* Protect against recursion */
522 (len
< 2 || (len
== 2 && s
[1] == '.')))
525 if (memchr(s
, '/', len
))
529 if (sysnames
->nr
>= AFS_NR_SYSNAME
)
532 if (strcmp(s
, afs_init_sysname
) == 0) {
533 sub
= (char *)afs_init_sysname
;
536 sub
= kmemdup(s
, len
+ 1, GFP_KERNEL
);
541 sysnames
->subs
[sysnames
->nr
] = sub
;
545 if (sysnames
->nr
== 0) {
546 sysnames
->subs
[0] = sysnames
->blank
;
550 write_lock(&net
->sysnames_lock
);
551 kill
= net
->sysnames
;
552 net
->sysnames
= sysnames
;
553 write_unlock(&net
->sysnames_lock
);
556 afs_put_sysnames(kill
);
565 void afs_put_sysnames(struct afs_sysnames
*sysnames
)
569 if (sysnames
&& refcount_dec_and_test(&sysnames
->usage
)) {
570 for (i
= 0; i
< sysnames
->nr
; i
++)
571 if (sysnames
->subs
[i
] != afs_init_sysname
&&
572 sysnames
->subs
[i
] != sysnames
->blank
)
573 kfree(sysnames
->subs
[i
]);
579 * Display general per-net namespace statistics
581 static int afs_proc_stats_show(struct seq_file
*m
, void *v
)
583 struct afs_net
*net
= afs_seq2net_single(m
);
585 seq_puts(m
, "kAFS statistics\n");
587 seq_printf(m
, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
588 atomic_read(&net
->n_lookup
),
589 atomic_read(&net
->n_reval
),
590 atomic_read(&net
->n_inval
),
591 atomic_read(&net
->n_relpg
));
593 seq_printf(m
, "dir-data: rdpg=%u\n",
594 atomic_read(&net
->n_read_dir
));
596 seq_printf(m
, "dir-edit: cr=%u rm=%u\n",
597 atomic_read(&net
->n_dir_cr
),
598 atomic_read(&net
->n_dir_rm
));
600 seq_printf(m
, "file-rd : n=%u nb=%lu\n",
601 atomic_read(&net
->n_fetches
),
602 atomic_long_read(&net
->n_fetch_bytes
));
603 seq_printf(m
, "file-wr : n=%u nb=%lu\n",
604 atomic_read(&net
->n_stores
),
605 atomic_long_read(&net
->n_store_bytes
));
610 * initialise /proc/fs/afs/<cell>/
612 int afs_proc_cell_setup(struct afs_cell
*cell
)
614 struct proc_dir_entry
*dir
;
615 struct afs_net
*net
= cell
->net
;
617 _enter("%p{%s},%p", cell
, cell
->name
, net
->proc_afs
);
619 dir
= proc_net_mkdir(net
->net
, cell
->name
, net
->proc_afs
);
623 if (!proc_create_net_data("vlservers", 0444, dir
,
624 &afs_proc_cell_vlservers_ops
,
625 sizeof(struct afs_vl_seq_net_private
),
627 !proc_create_net_data("volumes", 0444, dir
,
628 &afs_proc_cell_volumes_ops
,
629 sizeof(struct seq_net_private
),
637 remove_proc_subtree(cell
->name
, net
->proc_afs
);
639 _leave(" = -ENOMEM");
644 * remove /proc/fs/afs/<cell>/
646 void afs_proc_cell_remove(struct afs_cell
*cell
)
648 struct afs_net
*net
= cell
->net
;
651 remove_proc_subtree(cell
->name
, net
->proc_afs
);
656 * initialise the /proc/fs/afs/ directory
658 int afs_proc_init(struct afs_net
*net
)
660 struct proc_dir_entry
*p
;
664 p
= proc_net_mkdir(net
->net
, "afs", net
->net
->proc_net
);
668 if (!proc_create_net_data_write("cells", 0644, p
,
670 afs_proc_cells_write
,
671 sizeof(struct seq_net_private
),
673 !proc_create_net_single_write("rootcell", 0644, p
,
674 afs_proc_rootcell_show
,
675 afs_proc_rootcell_write
,
677 !proc_create_net("servers", 0444, p
, &afs_proc_servers_ops
,
678 sizeof(struct seq_net_private
)) ||
679 !proc_create_net_single("stats", 0444, p
, afs_proc_stats_show
, NULL
) ||
680 !proc_create_net_data_write("sysname", 0644, p
,
681 &afs_proc_sysname_ops
,
682 afs_proc_sysname_write
,
683 sizeof(struct seq_net_private
),
694 _leave(" = -ENOMEM");
699 * clean up the /proc/fs/afs/ directory
701 void afs_proc_cleanup(struct afs_net
*net
)
703 proc_remove(net
->proc_afs
);
704 net
->proc_afs
= NULL
;