162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* /proc interface for AFS 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/proc_fs.h> 1162306a36Sopenharmony_ci#include <linux/seq_file.h> 1262306a36Sopenharmony_ci#include <linux/sched.h> 1362306a36Sopenharmony_ci#include <linux/uaccess.h> 1462306a36Sopenharmony_ci#include "internal.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct afs_vl_seq_net_private { 1762306a36Sopenharmony_ci struct seq_net_private seq; /* Must be first */ 1862306a36Sopenharmony_ci struct afs_vlserver_list *vllist; 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic inline struct afs_net *afs_seq2net(struct seq_file *m) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci return afs_net(seq_file_net(m)); 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic inline struct afs_net *afs_seq2net_single(struct seq_file *m) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci return afs_net(seq_file_single_net(m)); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * Display the list of cells known to the namespace. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cistatic int afs_proc_cells_show(struct seq_file *m, void *v) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct afs_vlserver_list *vllist; 3762306a36Sopenharmony_ci struct afs_cell *cell; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) { 4062306a36Sopenharmony_ci /* display header on line 1 */ 4162306a36Sopenharmony_ci seq_puts(m, "USE ACT TTL SV ST NAME\n"); 4262306a36Sopenharmony_ci return 0; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci cell = list_entry(v, struct afs_cell, proc_link); 4662306a36Sopenharmony_ci vllist = rcu_dereference(cell->vl_servers); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* display one cell per line on subsequent lines */ 4962306a36Sopenharmony_ci seq_printf(m, "%3u %3u %6lld %2u %2u %s\n", 5062306a36Sopenharmony_ci refcount_read(&cell->ref), 5162306a36Sopenharmony_ci atomic_read(&cell->active), 5262306a36Sopenharmony_ci cell->dns_expiry - ktime_get_real_seconds(), 5362306a36Sopenharmony_ci vllist ? vllist->nr_servers : 0, 5462306a36Sopenharmony_ci cell->state, 5562306a36Sopenharmony_ci cell->name); 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos) 6062306a36Sopenharmony_ci __acquires(rcu) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci rcu_read_lock(); 6362306a36Sopenharmony_ci return seq_hlist_start_head_rcu(&afs_seq2net(m)->proc_cells, *_pos); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci return seq_hlist_next_rcu(v, &afs_seq2net(m)->proc_cells, pos); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void afs_proc_cells_stop(struct seq_file *m, void *v) 7262306a36Sopenharmony_ci __releases(rcu) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci rcu_read_unlock(); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic const struct seq_operations afs_proc_cells_ops = { 7862306a36Sopenharmony_ci .start = afs_proc_cells_start, 7962306a36Sopenharmony_ci .next = afs_proc_cells_next, 8062306a36Sopenharmony_ci .stop = afs_proc_cells_stop, 8162306a36Sopenharmony_ci .show = afs_proc_cells_show, 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci * handle writes to /proc/fs/afs/cells 8662306a36Sopenharmony_ci * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]" 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistatic int afs_proc_cells_write(struct file *file, char *buf, size_t size) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct seq_file *m = file->private_data; 9162306a36Sopenharmony_ci struct afs_net *net = afs_seq2net(m); 9262306a36Sopenharmony_ci char *name, *args; 9362306a36Sopenharmony_ci int ret; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* trim to first NL */ 9662306a36Sopenharmony_ci name = memchr(buf, '\n', size); 9762306a36Sopenharmony_ci if (name) 9862306a36Sopenharmony_ci *name = 0; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* split into command, name and argslist */ 10162306a36Sopenharmony_ci name = strchr(buf, ' '); 10262306a36Sopenharmony_ci if (!name) 10362306a36Sopenharmony_ci goto inval; 10462306a36Sopenharmony_ci do { 10562306a36Sopenharmony_ci *name++ = 0; 10662306a36Sopenharmony_ci } while(*name == ' '); 10762306a36Sopenharmony_ci if (!*name) 10862306a36Sopenharmony_ci goto inval; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci args = strchr(name, ' '); 11162306a36Sopenharmony_ci if (args) { 11262306a36Sopenharmony_ci do { 11362306a36Sopenharmony_ci *args++ = 0; 11462306a36Sopenharmony_ci } while(*args == ' '); 11562306a36Sopenharmony_ci if (!*args) 11662306a36Sopenharmony_ci goto inval; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* determine command to perform */ 12062306a36Sopenharmony_ci _debug("cmd=%s name=%s args=%s", buf, name, args); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (strcmp(buf, "add") == 0) { 12362306a36Sopenharmony_ci struct afs_cell *cell; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci cell = afs_lookup_cell(net, name, strlen(name), args, true); 12662306a36Sopenharmony_ci if (IS_ERR(cell)) { 12762306a36Sopenharmony_ci ret = PTR_ERR(cell); 12862306a36Sopenharmony_ci goto done; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags)) 13262306a36Sopenharmony_ci afs_unuse_cell(net, cell, afs_cell_trace_unuse_no_pin); 13362306a36Sopenharmony_ci } else { 13462306a36Sopenharmony_ci goto inval; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ret = 0; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cidone: 14062306a36Sopenharmony_ci _leave(" = %d", ret); 14162306a36Sopenharmony_ci return ret; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ciinval: 14462306a36Sopenharmony_ci ret = -EINVAL; 14562306a36Sopenharmony_ci printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n"); 14662306a36Sopenharmony_ci goto done; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* 15062306a36Sopenharmony_ci * Display the name of the current workstation cell. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_cistatic int afs_proc_rootcell_show(struct seq_file *m, void *v) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct afs_cell *cell; 15562306a36Sopenharmony_ci struct afs_net *net; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci net = afs_seq2net_single(m); 15862306a36Sopenharmony_ci down_read(&net->cells_lock); 15962306a36Sopenharmony_ci cell = net->ws_cell; 16062306a36Sopenharmony_ci if (cell) 16162306a36Sopenharmony_ci seq_printf(m, "%s\n", cell->name); 16262306a36Sopenharmony_ci up_read(&net->cells_lock); 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* 16762306a36Sopenharmony_ci * Set the current workstation cell and optionally supply its list of volume 16862306a36Sopenharmony_ci * location servers. 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_cistatic int afs_proc_rootcell_write(struct file *file, char *buf, size_t size) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct seq_file *m = file->private_data; 17562306a36Sopenharmony_ci struct afs_net *net = afs_seq2net_single(m); 17662306a36Sopenharmony_ci char *s; 17762306a36Sopenharmony_ci int ret; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci ret = -EINVAL; 18062306a36Sopenharmony_ci if (buf[0] == '.') 18162306a36Sopenharmony_ci goto out; 18262306a36Sopenharmony_ci if (memchr(buf, '/', size)) 18362306a36Sopenharmony_ci goto out; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* trim to first NL */ 18662306a36Sopenharmony_ci s = memchr(buf, '\n', size); 18762306a36Sopenharmony_ci if (s) 18862306a36Sopenharmony_ci *s = 0; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* determine command to perform */ 19162306a36Sopenharmony_ci _debug("rootcell=%s", buf); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci ret = afs_cell_init(net, buf); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ciout: 19662306a36Sopenharmony_ci _leave(" = %d", ret); 19762306a36Sopenharmony_ci return ret; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic const char afs_vol_types[3][3] = { 20162306a36Sopenharmony_ci [AFSVL_RWVOL] = "RW", 20262306a36Sopenharmony_ci [AFSVL_ROVOL] = "RO", 20362306a36Sopenharmony_ci [AFSVL_BACKVOL] = "BK", 20462306a36Sopenharmony_ci}; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* 20762306a36Sopenharmony_ci * Display the list of volumes known to a cell. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_cistatic int afs_proc_cell_volumes_show(struct seq_file *m, void *v) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct afs_volume *vol = hlist_entry(v, struct afs_volume, proc_link); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* Display header on line 1 */ 21462306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) { 21562306a36Sopenharmony_ci seq_puts(m, "USE VID TY NAME\n"); 21662306a36Sopenharmony_ci return 0; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci seq_printf(m, "%3d %08llx %s %s\n", 22062306a36Sopenharmony_ci refcount_read(&vol->ref), vol->vid, 22162306a36Sopenharmony_ci afs_vol_types[vol->type], 22262306a36Sopenharmony_ci vol->name); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) 22862306a36Sopenharmony_ci __acquires(cell->proc_lock) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct afs_cell *cell = pde_data(file_inode(m->file)); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci rcu_read_lock(); 23362306a36Sopenharmony_ci return seq_hlist_start_head_rcu(&cell->proc_volumes, *_pos); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void *afs_proc_cell_volumes_next(struct seq_file *m, void *v, 23762306a36Sopenharmony_ci loff_t *_pos) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct afs_cell *cell = pde_data(file_inode(m->file)); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return seq_hlist_next_rcu(v, &cell->proc_volumes, _pos); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic void afs_proc_cell_volumes_stop(struct seq_file *m, void *v) 24562306a36Sopenharmony_ci __releases(cell->proc_lock) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci rcu_read_unlock(); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic const struct seq_operations afs_proc_cell_volumes_ops = { 25162306a36Sopenharmony_ci .start = afs_proc_cell_volumes_start, 25262306a36Sopenharmony_ci .next = afs_proc_cell_volumes_next, 25362306a36Sopenharmony_ci .stop = afs_proc_cell_volumes_stop, 25462306a36Sopenharmony_ci .show = afs_proc_cell_volumes_show, 25562306a36Sopenharmony_ci}; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic const char *const dns_record_sources[NR__dns_record_source + 1] = { 25862306a36Sopenharmony_ci [DNS_RECORD_UNAVAILABLE] = "unav", 25962306a36Sopenharmony_ci [DNS_RECORD_FROM_CONFIG] = "cfg", 26062306a36Sopenharmony_ci [DNS_RECORD_FROM_DNS_A] = "A", 26162306a36Sopenharmony_ci [DNS_RECORD_FROM_DNS_AFSDB] = "AFSDB", 26262306a36Sopenharmony_ci [DNS_RECORD_FROM_DNS_SRV] = "SRV", 26362306a36Sopenharmony_ci [DNS_RECORD_FROM_NSS] = "nss", 26462306a36Sopenharmony_ci [NR__dns_record_source] = "[weird]" 26562306a36Sopenharmony_ci}; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic const char *const dns_lookup_statuses[NR__dns_lookup_status + 1] = { 26862306a36Sopenharmony_ci [DNS_LOOKUP_NOT_DONE] = "no-lookup", 26962306a36Sopenharmony_ci [DNS_LOOKUP_GOOD] = "good", 27062306a36Sopenharmony_ci [DNS_LOOKUP_GOOD_WITH_BAD] = "good/bad", 27162306a36Sopenharmony_ci [DNS_LOOKUP_BAD] = "bad", 27262306a36Sopenharmony_ci [DNS_LOOKUP_GOT_NOT_FOUND] = "not-found", 27362306a36Sopenharmony_ci [DNS_LOOKUP_GOT_LOCAL_FAILURE] = "local-failure", 27462306a36Sopenharmony_ci [DNS_LOOKUP_GOT_TEMP_FAILURE] = "temp-failure", 27562306a36Sopenharmony_ci [DNS_LOOKUP_GOT_NS_FAILURE] = "ns-failure", 27662306a36Sopenharmony_ci [NR__dns_lookup_status] = "[weird]" 27762306a36Sopenharmony_ci}; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci/* 28062306a36Sopenharmony_ci * Display the list of Volume Location servers we're using for a cell. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_cistatic int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci const struct afs_vl_seq_net_private *priv = m->private; 28562306a36Sopenharmony_ci const struct afs_vlserver_list *vllist = priv->vllist; 28662306a36Sopenharmony_ci const struct afs_vlserver_entry *entry; 28762306a36Sopenharmony_ci const struct afs_vlserver *vlserver; 28862306a36Sopenharmony_ci const struct afs_addr_list *alist; 28962306a36Sopenharmony_ci int i; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) { 29262306a36Sopenharmony_ci seq_printf(m, "# source %s, status %s\n", 29362306a36Sopenharmony_ci dns_record_sources[vllist ? vllist->source : 0], 29462306a36Sopenharmony_ci dns_lookup_statuses[vllist ? vllist->status : 0]); 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci entry = v; 29962306a36Sopenharmony_ci vlserver = entry->server; 30062306a36Sopenharmony_ci alist = rcu_dereference(vlserver->addresses); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci seq_printf(m, "%s [p=%hu w=%hu s=%s,%s]:\n", 30362306a36Sopenharmony_ci vlserver->name, entry->priority, entry->weight, 30462306a36Sopenharmony_ci dns_record_sources[alist ? alist->source : entry->source], 30562306a36Sopenharmony_ci dns_lookup_statuses[alist ? alist->status : entry->status]); 30662306a36Sopenharmony_ci if (alist) { 30762306a36Sopenharmony_ci for (i = 0; i < alist->nr_addrs; i++) 30862306a36Sopenharmony_ci seq_printf(m, " %c %pISpc\n", 30962306a36Sopenharmony_ci alist->preferred == i ? '>' : '-', 31062306a36Sopenharmony_ci &alist->addrs[i].transport); 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci seq_printf(m, " info: fl=%lx rtt=%d\n", vlserver->flags, vlserver->rtt); 31362306a36Sopenharmony_ci seq_printf(m, " probe: fl=%x e=%d ac=%d out=%d\n", 31462306a36Sopenharmony_ci vlserver->probe.flags, vlserver->probe.error, 31562306a36Sopenharmony_ci vlserver->probe.abort_code, 31662306a36Sopenharmony_ci atomic_read(&vlserver->probe_outstanding)); 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) 32162306a36Sopenharmony_ci __acquires(rcu) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct afs_vl_seq_net_private *priv = m->private; 32462306a36Sopenharmony_ci struct afs_vlserver_list *vllist; 32562306a36Sopenharmony_ci struct afs_cell *cell = pde_data(file_inode(m->file)); 32662306a36Sopenharmony_ci loff_t pos = *_pos; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci rcu_read_lock(); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci vllist = rcu_dereference(cell->vl_servers); 33162306a36Sopenharmony_ci priv->vllist = vllist; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (pos < 0) 33462306a36Sopenharmony_ci *_pos = pos = 0; 33562306a36Sopenharmony_ci if (pos == 0) 33662306a36Sopenharmony_ci return SEQ_START_TOKEN; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (pos - 1 >= vllist->nr_servers) 33962306a36Sopenharmony_ci return NULL; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci return &vllist->servers[pos - 1]; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v, 34562306a36Sopenharmony_ci loff_t *_pos) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci struct afs_vl_seq_net_private *priv = m->private; 34862306a36Sopenharmony_ci struct afs_vlserver_list *vllist = priv->vllist; 34962306a36Sopenharmony_ci loff_t pos; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci pos = *_pos; 35262306a36Sopenharmony_ci pos++; 35362306a36Sopenharmony_ci *_pos = pos; 35462306a36Sopenharmony_ci if (!vllist || pos - 1 >= vllist->nr_servers) 35562306a36Sopenharmony_ci return NULL; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci return &vllist->servers[pos - 1]; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v) 36162306a36Sopenharmony_ci __releases(rcu) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci rcu_read_unlock(); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic const struct seq_operations afs_proc_cell_vlservers_ops = { 36762306a36Sopenharmony_ci .start = afs_proc_cell_vlservers_start, 36862306a36Sopenharmony_ci .next = afs_proc_cell_vlservers_next, 36962306a36Sopenharmony_ci .stop = afs_proc_cell_vlservers_stop, 37062306a36Sopenharmony_ci .show = afs_proc_cell_vlservers_show, 37162306a36Sopenharmony_ci}; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/* 37462306a36Sopenharmony_ci * Display the list of fileservers we're using within a namespace. 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_cistatic int afs_proc_servers_show(struct seq_file *m, void *v) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct afs_server *server; 37962306a36Sopenharmony_ci struct afs_addr_list *alist; 38062306a36Sopenharmony_ci int i; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) { 38362306a36Sopenharmony_ci seq_puts(m, "UUID REF ACT\n"); 38462306a36Sopenharmony_ci return 0; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci server = list_entry(v, struct afs_server, proc_link); 38862306a36Sopenharmony_ci alist = rcu_dereference(server->addresses); 38962306a36Sopenharmony_ci seq_printf(m, "%pU %3d %3d\n", 39062306a36Sopenharmony_ci &server->uuid, 39162306a36Sopenharmony_ci refcount_read(&server->ref), 39262306a36Sopenharmony_ci atomic_read(&server->active)); 39362306a36Sopenharmony_ci seq_printf(m, " - info: fl=%lx rtt=%u brk=%x\n", 39462306a36Sopenharmony_ci server->flags, server->rtt, server->cb_s_break); 39562306a36Sopenharmony_ci seq_printf(m, " - probe: last=%d out=%d\n", 39662306a36Sopenharmony_ci (int)(jiffies - server->probed_at) / HZ, 39762306a36Sopenharmony_ci atomic_read(&server->probe_outstanding)); 39862306a36Sopenharmony_ci seq_printf(m, " - ALIST v=%u rsp=%lx f=%lx\n", 39962306a36Sopenharmony_ci alist->version, alist->responded, alist->failed); 40062306a36Sopenharmony_ci for (i = 0; i < alist->nr_addrs; i++) 40162306a36Sopenharmony_ci seq_printf(m, " [%x] %pISpc%s\n", 40262306a36Sopenharmony_ci i, &alist->addrs[i].transport, 40362306a36Sopenharmony_ci alist->preferred == i ? "*" : ""); 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos) 40862306a36Sopenharmony_ci __acquires(rcu) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci rcu_read_lock(); 41162306a36Sopenharmony_ci return seq_hlist_start_head_rcu(&afs_seq2net(m)->fs_proc, *_pos); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci return seq_hlist_next_rcu(v, &afs_seq2net(m)->fs_proc, _pos); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic void afs_proc_servers_stop(struct seq_file *m, void *v) 42062306a36Sopenharmony_ci __releases(rcu) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci rcu_read_unlock(); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic const struct seq_operations afs_proc_servers_ops = { 42662306a36Sopenharmony_ci .start = afs_proc_servers_start, 42762306a36Sopenharmony_ci .next = afs_proc_servers_next, 42862306a36Sopenharmony_ci .stop = afs_proc_servers_stop, 42962306a36Sopenharmony_ci .show = afs_proc_servers_show, 43062306a36Sopenharmony_ci}; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci/* 43362306a36Sopenharmony_ci * Display the list of strings that may be substituted for the @sys pathname 43462306a36Sopenharmony_ci * macro. 43562306a36Sopenharmony_ci */ 43662306a36Sopenharmony_cistatic int afs_proc_sysname_show(struct seq_file *m, void *v) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct afs_net *net = afs_seq2net(m); 43962306a36Sopenharmony_ci struct afs_sysnames *sysnames = net->sysnames; 44062306a36Sopenharmony_ci unsigned int i = (unsigned long)v - 1; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (i < sysnames->nr) 44362306a36Sopenharmony_ci seq_printf(m, "%s\n", sysnames->subs[i]); 44462306a36Sopenharmony_ci return 0; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos) 44862306a36Sopenharmony_ci __acquires(&net->sysnames_lock) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct afs_net *net = afs_seq2net(m); 45162306a36Sopenharmony_ci struct afs_sysnames *names; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci read_lock(&net->sysnames_lock); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci names = net->sysnames; 45662306a36Sopenharmony_ci if (*pos >= names->nr) 45762306a36Sopenharmony_ci return NULL; 45862306a36Sopenharmony_ci return (void *)(unsigned long)(*pos + 1); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct afs_net *net = afs_seq2net(m); 46462306a36Sopenharmony_ci struct afs_sysnames *names = net->sysnames; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci *pos += 1; 46762306a36Sopenharmony_ci if (*pos >= names->nr) 46862306a36Sopenharmony_ci return NULL; 46962306a36Sopenharmony_ci return (void *)(unsigned long)(*pos + 1); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic void afs_proc_sysname_stop(struct seq_file *m, void *v) 47362306a36Sopenharmony_ci __releases(&net->sysnames_lock) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct afs_net *net = afs_seq2net(m); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci read_unlock(&net->sysnames_lock); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic const struct seq_operations afs_proc_sysname_ops = { 48162306a36Sopenharmony_ci .start = afs_proc_sysname_start, 48262306a36Sopenharmony_ci .next = afs_proc_sysname_next, 48362306a36Sopenharmony_ci .stop = afs_proc_sysname_stop, 48462306a36Sopenharmony_ci .show = afs_proc_sysname_show, 48562306a36Sopenharmony_ci}; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci/* 48862306a36Sopenharmony_ci * Allow the @sys substitution to be configured. 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_cistatic int afs_proc_sysname_write(struct file *file, char *buf, size_t size) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct afs_sysnames *sysnames, *kill; 49362306a36Sopenharmony_ci struct seq_file *m = file->private_data; 49462306a36Sopenharmony_ci struct afs_net *net = afs_seq2net(m); 49562306a36Sopenharmony_ci char *s, *p, *sub; 49662306a36Sopenharmony_ci int ret, len; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL); 49962306a36Sopenharmony_ci if (!sysnames) 50062306a36Sopenharmony_ci return -ENOMEM; 50162306a36Sopenharmony_ci refcount_set(&sysnames->usage, 1); 50262306a36Sopenharmony_ci kill = sysnames; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci p = buf; 50562306a36Sopenharmony_ci while ((s = strsep(&p, " \t\n"))) { 50662306a36Sopenharmony_ci len = strlen(s); 50762306a36Sopenharmony_ci if (len == 0) 50862306a36Sopenharmony_ci continue; 50962306a36Sopenharmony_ci ret = -ENAMETOOLONG; 51062306a36Sopenharmony_ci if (len >= AFSNAMEMAX) 51162306a36Sopenharmony_ci goto error; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (len >= 4 && 51462306a36Sopenharmony_ci s[len - 4] == '@' && 51562306a36Sopenharmony_ci s[len - 3] == 's' && 51662306a36Sopenharmony_ci s[len - 2] == 'y' && 51762306a36Sopenharmony_ci s[len - 1] == 's') 51862306a36Sopenharmony_ci /* Protect against recursion */ 51962306a36Sopenharmony_ci goto invalid; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (s[0] == '.' && 52262306a36Sopenharmony_ci (len < 2 || (len == 2 && s[1] == '.'))) 52362306a36Sopenharmony_ci goto invalid; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (memchr(s, '/', len)) 52662306a36Sopenharmony_ci goto invalid; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci ret = -EFBIG; 52962306a36Sopenharmony_ci if (sysnames->nr >= AFS_NR_SYSNAME) 53062306a36Sopenharmony_ci goto out; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (strcmp(s, afs_init_sysname) == 0) { 53362306a36Sopenharmony_ci sub = (char *)afs_init_sysname; 53462306a36Sopenharmony_ci } else { 53562306a36Sopenharmony_ci ret = -ENOMEM; 53662306a36Sopenharmony_ci sub = kmemdup(s, len + 1, GFP_KERNEL); 53762306a36Sopenharmony_ci if (!sub) 53862306a36Sopenharmony_ci goto out; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci sysnames->subs[sysnames->nr] = sub; 54262306a36Sopenharmony_ci sysnames->nr++; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (sysnames->nr == 0) { 54662306a36Sopenharmony_ci sysnames->subs[0] = sysnames->blank; 54762306a36Sopenharmony_ci sysnames->nr++; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci write_lock(&net->sysnames_lock); 55162306a36Sopenharmony_ci kill = net->sysnames; 55262306a36Sopenharmony_ci net->sysnames = sysnames; 55362306a36Sopenharmony_ci write_unlock(&net->sysnames_lock); 55462306a36Sopenharmony_ci ret = 0; 55562306a36Sopenharmony_ciout: 55662306a36Sopenharmony_ci afs_put_sysnames(kill); 55762306a36Sopenharmony_ci return ret; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ciinvalid: 56062306a36Sopenharmony_ci ret = -EINVAL; 56162306a36Sopenharmony_cierror: 56262306a36Sopenharmony_ci goto out; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_civoid afs_put_sysnames(struct afs_sysnames *sysnames) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci int i; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (sysnames && refcount_dec_and_test(&sysnames->usage)) { 57062306a36Sopenharmony_ci for (i = 0; i < sysnames->nr; i++) 57162306a36Sopenharmony_ci if (sysnames->subs[i] != afs_init_sysname && 57262306a36Sopenharmony_ci sysnames->subs[i] != sysnames->blank) 57362306a36Sopenharmony_ci kfree(sysnames->subs[i]); 57462306a36Sopenharmony_ci kfree(sysnames); 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci/* 57962306a36Sopenharmony_ci * Display general per-net namespace statistics 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_cistatic int afs_proc_stats_show(struct seq_file *m, void *v) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct afs_net *net = afs_seq2net_single(m); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci seq_puts(m, "kAFS statistics\n"); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n", 58862306a36Sopenharmony_ci atomic_read(&net->n_lookup), 58962306a36Sopenharmony_ci atomic_read(&net->n_reval), 59062306a36Sopenharmony_ci atomic_read(&net->n_inval), 59162306a36Sopenharmony_ci atomic_read(&net->n_relpg)); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci seq_printf(m, "dir-data: rdpg=%u\n", 59462306a36Sopenharmony_ci atomic_read(&net->n_read_dir)); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci seq_printf(m, "dir-edit: cr=%u rm=%u\n", 59762306a36Sopenharmony_ci atomic_read(&net->n_dir_cr), 59862306a36Sopenharmony_ci atomic_read(&net->n_dir_rm)); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci seq_printf(m, "file-rd : n=%u nb=%lu\n", 60162306a36Sopenharmony_ci atomic_read(&net->n_fetches), 60262306a36Sopenharmony_ci atomic_long_read(&net->n_fetch_bytes)); 60362306a36Sopenharmony_ci seq_printf(m, "file-wr : n=%u nb=%lu\n", 60462306a36Sopenharmony_ci atomic_read(&net->n_stores), 60562306a36Sopenharmony_ci atomic_long_read(&net->n_store_bytes)); 60662306a36Sopenharmony_ci return 0; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci/* 61062306a36Sopenharmony_ci * initialise /proc/fs/afs/<cell>/ 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_ciint afs_proc_cell_setup(struct afs_cell *cell) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct proc_dir_entry *dir; 61562306a36Sopenharmony_ci struct afs_net *net = cell->net; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci _enter("%p{%s},%p", cell, cell->name, net->proc_afs); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci dir = proc_net_mkdir(net->net, cell->name, net->proc_afs); 62062306a36Sopenharmony_ci if (!dir) 62162306a36Sopenharmony_ci goto error_dir; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (!proc_create_net_data("vlservers", 0444, dir, 62462306a36Sopenharmony_ci &afs_proc_cell_vlservers_ops, 62562306a36Sopenharmony_ci sizeof(struct afs_vl_seq_net_private), 62662306a36Sopenharmony_ci cell) || 62762306a36Sopenharmony_ci !proc_create_net_data("volumes", 0444, dir, 62862306a36Sopenharmony_ci &afs_proc_cell_volumes_ops, 62962306a36Sopenharmony_ci sizeof(struct seq_net_private), 63062306a36Sopenharmony_ci cell)) 63162306a36Sopenharmony_ci goto error_tree; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci _leave(" = 0"); 63462306a36Sopenharmony_ci return 0; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cierror_tree: 63762306a36Sopenharmony_ci remove_proc_subtree(cell->name, net->proc_afs); 63862306a36Sopenharmony_cierror_dir: 63962306a36Sopenharmony_ci _leave(" = -ENOMEM"); 64062306a36Sopenharmony_ci return -ENOMEM; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci/* 64462306a36Sopenharmony_ci * remove /proc/fs/afs/<cell>/ 64562306a36Sopenharmony_ci */ 64662306a36Sopenharmony_civoid afs_proc_cell_remove(struct afs_cell *cell) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci struct afs_net *net = cell->net; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci _enter(""); 65162306a36Sopenharmony_ci remove_proc_subtree(cell->name, net->proc_afs); 65262306a36Sopenharmony_ci _leave(""); 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci/* 65662306a36Sopenharmony_ci * initialise the /proc/fs/afs/ directory 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_ciint afs_proc_init(struct afs_net *net) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct proc_dir_entry *p; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci _enter(""); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci p = proc_net_mkdir(net->net, "afs", net->net->proc_net); 66562306a36Sopenharmony_ci if (!p) 66662306a36Sopenharmony_ci goto error_dir; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (!proc_create_net_data_write("cells", 0644, p, 66962306a36Sopenharmony_ci &afs_proc_cells_ops, 67062306a36Sopenharmony_ci afs_proc_cells_write, 67162306a36Sopenharmony_ci sizeof(struct seq_net_private), 67262306a36Sopenharmony_ci NULL) || 67362306a36Sopenharmony_ci !proc_create_net_single_write("rootcell", 0644, p, 67462306a36Sopenharmony_ci afs_proc_rootcell_show, 67562306a36Sopenharmony_ci afs_proc_rootcell_write, 67662306a36Sopenharmony_ci NULL) || 67762306a36Sopenharmony_ci !proc_create_net("servers", 0444, p, &afs_proc_servers_ops, 67862306a36Sopenharmony_ci sizeof(struct seq_net_private)) || 67962306a36Sopenharmony_ci !proc_create_net_single("stats", 0444, p, afs_proc_stats_show, NULL) || 68062306a36Sopenharmony_ci !proc_create_net_data_write("sysname", 0644, p, 68162306a36Sopenharmony_ci &afs_proc_sysname_ops, 68262306a36Sopenharmony_ci afs_proc_sysname_write, 68362306a36Sopenharmony_ci sizeof(struct seq_net_private), 68462306a36Sopenharmony_ci NULL)) 68562306a36Sopenharmony_ci goto error_tree; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci net->proc_afs = p; 68862306a36Sopenharmony_ci _leave(" = 0"); 68962306a36Sopenharmony_ci return 0; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cierror_tree: 69262306a36Sopenharmony_ci proc_remove(p); 69362306a36Sopenharmony_cierror_dir: 69462306a36Sopenharmony_ci _leave(" = -ENOMEM"); 69562306a36Sopenharmony_ci return -ENOMEM; 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci/* 69962306a36Sopenharmony_ci * clean up the /proc/fs/afs/ directory 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_civoid afs_proc_cleanup(struct afs_net *net) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci proc_remove(net->proc_afs); 70462306a36Sopenharmony_ci net->proc_afs = NULL; 70562306a36Sopenharmony_ci} 706