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 refcount_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 list of addr_prefs known to the namespace.
152 static int afs_proc_addr_prefs_show(struct seq_file
*m
, void *v
)
154 struct afs_addr_preference_list
*preflist
;
155 struct afs_addr_preference
*pref
;
156 struct afs_net
*net
= afs_seq2net_single(m
);
158 struct sockaddr_in sin
;
159 struct sockaddr_in6 sin6
;
162 char buf
[44]; /* Maximum ipv6 + max subnet is 43 */
165 preflist
= rcu_dereference(net
->address_prefs
);
168 seq_puts(m
, "NO PREFS\n");
172 seq_printf(m
, "PROT SUBNET PRIOR (v=%u n=%u/%u/%u)\n",
173 preflist
->version
, preflist
->ipv6_off
, preflist
->nr
, preflist
->max_prefs
);
175 memset(&addr
, 0, sizeof(addr
));
177 for (i
= 0; i
< preflist
->nr
; i
++) {
178 pref
= &preflist
->prefs
[i
];
180 addr
.sin
.sin_family
= pref
->family
;
181 if (pref
->family
== AF_INET
) {
182 memcpy(&addr
.sin
.sin_addr
, &pref
->ipv4_addr
,
183 sizeof(addr
.sin
.sin_addr
));
184 snprintf(buf
, sizeof(buf
), "%pISc/%u", &addr
.sin
, pref
->subnet_mask
);
185 seq_printf(m
, "UDP %-43.43s %5u\n", buf
, pref
->prio
);
187 memcpy(&addr
.sin6
.sin6_addr
, &pref
->ipv6_addr
,
188 sizeof(addr
.sin6
.sin6_addr
));
189 snprintf(buf
, sizeof(buf
), "%pISc/%u", &addr
.sin6
, pref
->subnet_mask
);
190 seq_printf(m
, "UDP %-43.43s %5u\n", buf
, pref
->prio
);
200 * Display the name of the current workstation cell.
202 static int afs_proc_rootcell_show(struct seq_file
*m
, void *v
)
204 struct afs_cell
*cell
;
207 net
= afs_seq2net_single(m
);
208 down_read(&net
->cells_lock
);
211 seq_printf(m
, "%s\n", cell
->name
);
212 up_read(&net
->cells_lock
);
217 * Set the current workstation cell and optionally supply its list of volume
220 * echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell
222 static int afs_proc_rootcell_write(struct file
*file
, char *buf
, size_t size
)
224 struct seq_file
*m
= file
->private_data
;
225 struct afs_net
*net
= afs_seq2net_single(m
);
232 if (memchr(buf
, '/', size
))
235 /* trim to first NL */
236 s
= memchr(buf
, '\n', size
);
240 /* determine command to perform */
241 _debug("rootcell=%s", buf
);
243 ret
= afs_cell_init(net
, buf
);
246 _leave(" = %d", ret
);
250 static const char afs_vol_types
[3][3] = {
251 [AFSVL_RWVOL
] = "RW",
252 [AFSVL_ROVOL
] = "RO",
253 [AFSVL_BACKVOL
] = "BK",
257 * Display the list of volumes known to a cell.
259 static int afs_proc_cell_volumes_show(struct seq_file
*m
, void *v
)
261 struct afs_volume
*vol
= hlist_entry(v
, struct afs_volume
, proc_link
);
263 /* Display header on line 1 */
264 if (v
== SEQ_START_TOKEN
) {
265 seq_puts(m
, "USE VID TY NAME\n");
269 seq_printf(m
, "%3d %08llx %s %s\n",
270 refcount_read(&vol
->ref
), vol
->vid
,
271 afs_vol_types
[vol
->type
],
277 static void *afs_proc_cell_volumes_start(struct seq_file
*m
, loff_t
*_pos
)
278 __acquires(cell
->proc_lock
)
280 struct afs_cell
*cell
= pde_data(file_inode(m
->file
));
283 return seq_hlist_start_head_rcu(&cell
->proc_volumes
, *_pos
);
286 static void *afs_proc_cell_volumes_next(struct seq_file
*m
, void *v
,
289 struct afs_cell
*cell
= pde_data(file_inode(m
->file
));
291 return seq_hlist_next_rcu(v
, &cell
->proc_volumes
, _pos
);
294 static void afs_proc_cell_volumes_stop(struct seq_file
*m
, void *v
)
295 __releases(cell
->proc_lock
)
300 static const struct seq_operations afs_proc_cell_volumes_ops
= {
301 .start
= afs_proc_cell_volumes_start
,
302 .next
= afs_proc_cell_volumes_next
,
303 .stop
= afs_proc_cell_volumes_stop
,
304 .show
= afs_proc_cell_volumes_show
,
307 static const char *const dns_record_sources
[NR__dns_record_source
+ 1] = {
308 [DNS_RECORD_UNAVAILABLE
] = "unav",
309 [DNS_RECORD_FROM_CONFIG
] = "cfg",
310 [DNS_RECORD_FROM_DNS_A
] = "A",
311 [DNS_RECORD_FROM_DNS_AFSDB
] = "AFSDB",
312 [DNS_RECORD_FROM_DNS_SRV
] = "SRV",
313 [DNS_RECORD_FROM_NSS
] = "nss",
314 [NR__dns_record_source
] = "[weird]"
317 static const char *const dns_lookup_statuses
[NR__dns_lookup_status
+ 1] = {
318 [DNS_LOOKUP_NOT_DONE
] = "no-lookup",
319 [DNS_LOOKUP_GOOD
] = "good",
320 [DNS_LOOKUP_GOOD_WITH_BAD
] = "good/bad",
321 [DNS_LOOKUP_BAD
] = "bad",
322 [DNS_LOOKUP_GOT_NOT_FOUND
] = "not-found",
323 [DNS_LOOKUP_GOT_LOCAL_FAILURE
] = "local-failure",
324 [DNS_LOOKUP_GOT_TEMP_FAILURE
] = "temp-failure",
325 [DNS_LOOKUP_GOT_NS_FAILURE
] = "ns-failure",
326 [NR__dns_lookup_status
] = "[weird]"
330 * Display the list of Volume Location servers we're using for a cell.
332 static int afs_proc_cell_vlservers_show(struct seq_file
*m
, void *v
)
334 const struct afs_vl_seq_net_private
*priv
= m
->private;
335 const struct afs_vlserver_list
*vllist
= priv
->vllist
;
336 const struct afs_vlserver_entry
*entry
;
337 const struct afs_vlserver
*vlserver
;
338 const struct afs_addr_list
*alist
;
341 if (v
== SEQ_START_TOKEN
) {
342 seq_printf(m
, "# source %s, status %s\n",
343 dns_record_sources
[vllist
? vllist
->source
: 0],
344 dns_lookup_statuses
[vllist
? vllist
->status
: 0]);
349 vlserver
= entry
->server
;
350 alist
= rcu_dereference(vlserver
->addresses
);
352 seq_printf(m
, "%s [p=%hu w=%hu s=%s,%s]:\n",
353 vlserver
->name
, entry
->priority
, entry
->weight
,
354 dns_record_sources
[alist
? alist
->source
: entry
->source
],
355 dns_lookup_statuses
[alist
? alist
->status
: entry
->status
]);
357 for (i
= 0; i
< alist
->nr_addrs
; i
++)
358 seq_printf(m
, " %c %pISpc\n",
359 alist
->preferred
== i
? '>' : '-',
360 rxrpc_kernel_remote_addr(alist
->addrs
[i
].peer
));
362 seq_printf(m
, " info: fl=%lx rtt=%d\n", vlserver
->flags
, vlserver
->rtt
);
363 seq_printf(m
, " probe: fl=%x e=%d ac=%d out=%d\n",
364 vlserver
->probe
.flags
, vlserver
->probe
.error
,
365 vlserver
->probe
.abort_code
,
366 atomic_read(&vlserver
->probe_outstanding
));
370 static void *afs_proc_cell_vlservers_start(struct seq_file
*m
, loff_t
*_pos
)
373 struct afs_vl_seq_net_private
*priv
= m
->private;
374 struct afs_vlserver_list
*vllist
;
375 struct afs_cell
*cell
= pde_data(file_inode(m
->file
));
380 vllist
= rcu_dereference(cell
->vl_servers
);
381 priv
->vllist
= vllist
;
386 return SEQ_START_TOKEN
;
388 if (pos
- 1 >= vllist
->nr_servers
)
391 return &vllist
->servers
[pos
- 1];
394 static void *afs_proc_cell_vlservers_next(struct seq_file
*m
, void *v
,
397 struct afs_vl_seq_net_private
*priv
= m
->private;
398 struct afs_vlserver_list
*vllist
= priv
->vllist
;
404 if (!vllist
|| pos
- 1 >= vllist
->nr_servers
)
407 return &vllist
->servers
[pos
- 1];
410 static void afs_proc_cell_vlservers_stop(struct seq_file
*m
, void *v
)
416 static const struct seq_operations afs_proc_cell_vlservers_ops
= {
417 .start
= afs_proc_cell_vlservers_start
,
418 .next
= afs_proc_cell_vlservers_next
,
419 .stop
= afs_proc_cell_vlservers_stop
,
420 .show
= afs_proc_cell_vlservers_show
,
424 * Display the list of fileservers we're using within a namespace.
426 static int afs_proc_servers_show(struct seq_file
*m
, void *v
)
428 struct afs_endpoint_state
*estate
;
429 struct afs_addr_list
*alist
;
430 struct afs_server
*server
;
431 unsigned long failed
;
434 if (v
== SEQ_START_TOKEN
) {
435 seq_puts(m
, "UUID REF ACT CELL\n");
439 server
= list_entry(v
, struct afs_server
, proc_link
);
440 estate
= rcu_dereference(server
->endpoint_state
);
441 alist
= estate
->addresses
;
442 seq_printf(m
, "%pU %3d %3d %s\n",
444 refcount_read(&server
->ref
),
445 atomic_read(&server
->active
),
447 seq_printf(m
, " - info: fl=%lx rtt=%u\n",
448 server
->flags
, server
->rtt
);
449 seq_printf(m
, " - probe: last=%d\n",
450 (int)(jiffies
- server
->probed_at
) / HZ
);
451 failed
= estate
->failed_set
;
452 seq_printf(m
, " - ESTATE pq=%x np=%u rsp=%lx f=%lx\n",
453 estate
->probe_seq
, atomic_read(&estate
->nr_probing
),
454 estate
->responsive_set
, estate
->failed_set
);
455 seq_printf(m
, " - ALIST v=%u ap=%u\n",
456 alist
->version
, alist
->addr_pref_version
);
457 for (i
= 0; i
< alist
->nr_addrs
; i
++) {
458 const struct afs_address
*addr
= &alist
->addrs
[i
];
460 seq_printf(m
, " [%x] %pISpc%s rtt=%d err=%d p=%u\n",
461 i
, rxrpc_kernel_remote_addr(addr
->peer
),
462 alist
->preferred
== i
? "*" :
463 test_bit(i
, &failed
) ? "!" : "",
464 rxrpc_kernel_get_srtt(addr
->peer
),
465 addr
->last_error
, addr
->prio
);
470 static void *afs_proc_servers_start(struct seq_file
*m
, loff_t
*_pos
)
474 return seq_hlist_start_head_rcu(&afs_seq2net(m
)->fs_proc
, *_pos
);
477 static void *afs_proc_servers_next(struct seq_file
*m
, void *v
, loff_t
*_pos
)
479 return seq_hlist_next_rcu(v
, &afs_seq2net(m
)->fs_proc
, _pos
);
482 static void afs_proc_servers_stop(struct seq_file
*m
, void *v
)
488 static const struct seq_operations afs_proc_servers_ops
= {
489 .start
= afs_proc_servers_start
,
490 .next
= afs_proc_servers_next
,
491 .stop
= afs_proc_servers_stop
,
492 .show
= afs_proc_servers_show
,
496 * Display the list of strings that may be substituted for the @sys pathname
499 static int afs_proc_sysname_show(struct seq_file
*m
, void *v
)
501 struct afs_net
*net
= afs_seq2net(m
);
502 struct afs_sysnames
*sysnames
= net
->sysnames
;
503 unsigned int i
= (unsigned long)v
- 1;
505 if (i
< sysnames
->nr
)
506 seq_printf(m
, "%s\n", sysnames
->subs
[i
]);
510 static void *afs_proc_sysname_start(struct seq_file
*m
, loff_t
*pos
)
511 __acquires(&net
->sysnames_lock
)
513 struct afs_net
*net
= afs_seq2net(m
);
514 struct afs_sysnames
*names
;
516 read_lock(&net
->sysnames_lock
);
518 names
= net
->sysnames
;
519 if (*pos
>= names
->nr
)
521 return (void *)(unsigned long)(*pos
+ 1);
524 static void *afs_proc_sysname_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
526 struct afs_net
*net
= afs_seq2net(m
);
527 struct afs_sysnames
*names
= net
->sysnames
;
530 if (*pos
>= names
->nr
)
532 return (void *)(unsigned long)(*pos
+ 1);
535 static void afs_proc_sysname_stop(struct seq_file
*m
, void *v
)
536 __releases(&net
->sysnames_lock
)
538 struct afs_net
*net
= afs_seq2net(m
);
540 read_unlock(&net
->sysnames_lock
);
543 static const struct seq_operations afs_proc_sysname_ops
= {
544 .start
= afs_proc_sysname_start
,
545 .next
= afs_proc_sysname_next
,
546 .stop
= afs_proc_sysname_stop
,
547 .show
= afs_proc_sysname_show
,
551 * Allow the @sys substitution to be configured.
553 static int afs_proc_sysname_write(struct file
*file
, char *buf
, size_t size
)
555 struct afs_sysnames
*sysnames
, *kill
;
556 struct seq_file
*m
= file
->private_data
;
557 struct afs_net
*net
= afs_seq2net(m
);
561 sysnames
= kzalloc(sizeof(*sysnames
), GFP_KERNEL
);
564 refcount_set(&sysnames
->usage
, 1);
568 while ((s
= strsep(&p
, " \t\n"))) {
573 if (len
>= AFSNAMEMAX
)
581 /* Protect against recursion */
585 (len
< 2 || (len
== 2 && s
[1] == '.')))
588 if (memchr(s
, '/', len
))
592 if (sysnames
->nr
>= AFS_NR_SYSNAME
)
595 if (strcmp(s
, afs_init_sysname
) == 0) {
596 sub
= (char *)afs_init_sysname
;
599 sub
= kmemdup(s
, len
+ 1, GFP_KERNEL
);
604 sysnames
->subs
[sysnames
->nr
] = sub
;
608 if (sysnames
->nr
== 0) {
609 sysnames
->subs
[0] = sysnames
->blank
;
613 write_lock(&net
->sysnames_lock
);
614 kill
= net
->sysnames
;
615 net
->sysnames
= sysnames
;
616 write_unlock(&net
->sysnames_lock
);
619 afs_put_sysnames(kill
);
628 void afs_put_sysnames(struct afs_sysnames
*sysnames
)
632 if (sysnames
&& refcount_dec_and_test(&sysnames
->usage
)) {
633 for (i
= 0; i
< sysnames
->nr
; i
++)
634 if (sysnames
->subs
[i
] != afs_init_sysname
&&
635 sysnames
->subs
[i
] != sysnames
->blank
)
636 kfree(sysnames
->subs
[i
]);
642 * Display general per-net namespace statistics
644 static int afs_proc_stats_show(struct seq_file
*m
, void *v
)
646 struct afs_net
*net
= afs_seq2net_single(m
);
648 seq_puts(m
, "kAFS statistics\n");
650 seq_printf(m
, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
651 atomic_read(&net
->n_lookup
),
652 atomic_read(&net
->n_reval
),
653 atomic_read(&net
->n_inval
),
654 atomic_read(&net
->n_relpg
));
656 seq_printf(m
, "dir-data: rdpg=%u\n",
657 atomic_read(&net
->n_read_dir
));
659 seq_printf(m
, "dir-edit: cr=%u rm=%u\n",
660 atomic_read(&net
->n_dir_cr
),
661 atomic_read(&net
->n_dir_rm
));
663 seq_printf(m
, "file-rd : n=%u nb=%lu\n",
664 atomic_read(&net
->n_fetches
),
665 atomic_long_read(&net
->n_fetch_bytes
));
666 seq_printf(m
, "file-wr : n=%u nb=%lu\n",
667 atomic_read(&net
->n_stores
),
668 atomic_long_read(&net
->n_store_bytes
));
673 * initialise /proc/fs/afs/<cell>/
675 int afs_proc_cell_setup(struct afs_cell
*cell
)
677 struct proc_dir_entry
*dir
;
678 struct afs_net
*net
= cell
->net
;
680 _enter("%p{%s},%p", cell
, cell
->name
, net
->proc_afs
);
682 dir
= proc_net_mkdir(net
->net
, cell
->name
, net
->proc_afs
);
686 if (!proc_create_net_data("vlservers", 0444, dir
,
687 &afs_proc_cell_vlservers_ops
,
688 sizeof(struct afs_vl_seq_net_private
),
690 !proc_create_net_data("volumes", 0444, dir
,
691 &afs_proc_cell_volumes_ops
,
692 sizeof(struct seq_net_private
),
700 remove_proc_subtree(cell
->name
, net
->proc_afs
);
702 _leave(" = -ENOMEM");
707 * remove /proc/fs/afs/<cell>/
709 void afs_proc_cell_remove(struct afs_cell
*cell
)
711 struct afs_net
*net
= cell
->net
;
714 remove_proc_subtree(cell
->name
, net
->proc_afs
);
719 * initialise the /proc/fs/afs/ directory
721 int afs_proc_init(struct afs_net
*net
)
723 struct proc_dir_entry
*p
;
727 p
= proc_net_mkdir(net
->net
, "afs", net
->net
->proc_net
);
731 if (!proc_create_net_data_write("cells", 0644, p
,
733 afs_proc_cells_write
,
734 sizeof(struct seq_net_private
),
736 !proc_create_net_single_write("rootcell", 0644, p
,
737 afs_proc_rootcell_show
,
738 afs_proc_rootcell_write
,
740 !proc_create_net("servers", 0444, p
, &afs_proc_servers_ops
,
741 sizeof(struct seq_net_private
)) ||
742 !proc_create_net_single("stats", 0444, p
, afs_proc_stats_show
, NULL
) ||
743 !proc_create_net_data_write("sysname", 0644, p
,
744 &afs_proc_sysname_ops
,
745 afs_proc_sysname_write
,
746 sizeof(struct seq_net_private
),
748 !proc_create_net_single_write("addr_prefs", 0644, p
,
749 afs_proc_addr_prefs_show
,
750 afs_proc_addr_prefs_write
,
761 _leave(" = -ENOMEM");
766 * clean up the /proc/fs/afs/ directory
768 void afs_proc_cleanup(struct afs_net
*net
)
770 proc_remove(net
->proc_afs
);
771 net
->proc_afs
= NULL
;