0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/slab.h>
0009 #include <linux/module.h>
0010 #include <linux/proc_fs.h>
0011 #include <linux/seq_file.h>
0012 #include <linux/sched.h>
0013 #include <linux/uaccess.h>
0014 #include "internal.h"
0015
0016 struct afs_vl_seq_net_private {
0017 struct seq_net_private seq;
0018 struct afs_vlserver_list *vllist;
0019 };
0020
0021 static inline struct afs_net *afs_seq2net(struct seq_file *m)
0022 {
0023 return afs_net(seq_file_net(m));
0024 }
0025
0026 static inline struct afs_net *afs_seq2net_single(struct seq_file *m)
0027 {
0028 return afs_net(seq_file_single_net(m));
0029 }
0030
0031
0032
0033
0034 static int afs_proc_cells_show(struct seq_file *m, void *v)
0035 {
0036 struct afs_vlserver_list *vllist;
0037 struct afs_cell *cell;
0038
0039 if (v == SEQ_START_TOKEN) {
0040
0041 seq_puts(m, "USE ACT TTL SV ST NAME\n");
0042 return 0;
0043 }
0044
0045 cell = list_entry(v, struct afs_cell, proc_link);
0046 vllist = rcu_dereference(cell->vl_servers);
0047
0048
0049 seq_printf(m, "%3u %3u %6lld %2u %2u %s\n",
0050 refcount_read(&cell->ref),
0051 atomic_read(&cell->active),
0052 cell->dns_expiry - ktime_get_real_seconds(),
0053 vllist ? vllist->nr_servers : 0,
0054 cell->state,
0055 cell->name);
0056 return 0;
0057 }
0058
0059 static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
0060 __acquires(rcu)
0061 {
0062 rcu_read_lock();
0063 return seq_hlist_start_head_rcu(&afs_seq2net(m)->proc_cells, *_pos);
0064 }
0065
0066 static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
0067 {
0068 return seq_hlist_next_rcu(v, &afs_seq2net(m)->proc_cells, pos);
0069 }
0070
0071 static void afs_proc_cells_stop(struct seq_file *m, void *v)
0072 __releases(rcu)
0073 {
0074 rcu_read_unlock();
0075 }
0076
0077 static const struct seq_operations afs_proc_cells_ops = {
0078 .start = afs_proc_cells_start,
0079 .next = afs_proc_cells_next,
0080 .stop = afs_proc_cells_stop,
0081 .show = afs_proc_cells_show,
0082 };
0083
0084
0085
0086
0087
0088 static int afs_proc_cells_write(struct file *file, char *buf, size_t size)
0089 {
0090 struct seq_file *m = file->private_data;
0091 struct afs_net *net = afs_seq2net(m);
0092 char *name, *args;
0093 int ret;
0094
0095
0096 name = memchr(buf, '\n', size);
0097 if (name)
0098 *name = 0;
0099
0100
0101 name = strchr(buf, ' ');
0102 if (!name)
0103 goto inval;
0104 do {
0105 *name++ = 0;
0106 } while(*name == ' ');
0107 if (!*name)
0108 goto inval;
0109
0110 args = strchr(name, ' ');
0111 if (args) {
0112 do {
0113 *args++ = 0;
0114 } while(*args == ' ');
0115 if (!*args)
0116 goto inval;
0117 }
0118
0119
0120 _debug("cmd=%s name=%s args=%s", buf, name, args);
0121
0122 if (strcmp(buf, "add") == 0) {
0123 struct afs_cell *cell;
0124
0125 cell = afs_lookup_cell(net, name, strlen(name), args, true);
0126 if (IS_ERR(cell)) {
0127 ret = PTR_ERR(cell);
0128 goto done;
0129 }
0130
0131 if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags))
0132 afs_unuse_cell(net, cell, afs_cell_trace_unuse_no_pin);
0133 } else {
0134 goto inval;
0135 }
0136
0137 ret = 0;
0138
0139 done:
0140 _leave(" = %d", ret);
0141 return ret;
0142
0143 inval:
0144 ret = -EINVAL;
0145 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
0146 goto done;
0147 }
0148
0149
0150
0151
0152 static int afs_proc_rootcell_show(struct seq_file *m, void *v)
0153 {
0154 struct afs_cell *cell;
0155 struct afs_net *net;
0156
0157 net = afs_seq2net_single(m);
0158 down_read(&net->cells_lock);
0159 cell = net->ws_cell;
0160 if (cell)
0161 seq_printf(m, "%s\n", cell->name);
0162 up_read(&net->cells_lock);
0163 return 0;
0164 }
0165
0166
0167
0168
0169
0170
0171
0172 static int afs_proc_rootcell_write(struct file *file, char *buf, size_t size)
0173 {
0174 struct seq_file *m = file->private_data;
0175 struct afs_net *net = afs_seq2net_single(m);
0176 char *s;
0177 int ret;
0178
0179 ret = -EINVAL;
0180 if (buf[0] == '.')
0181 goto out;
0182 if (memchr(buf, '/', size))
0183 goto out;
0184
0185
0186 s = memchr(buf, '\n', size);
0187 if (s)
0188 *s = 0;
0189
0190
0191 _debug("rootcell=%s", buf);
0192
0193 ret = afs_cell_init(net, buf);
0194
0195 out:
0196 _leave(" = %d", ret);
0197 return ret;
0198 }
0199
0200 static const char afs_vol_types[3][3] = {
0201 [AFSVL_RWVOL] = "RW",
0202 [AFSVL_ROVOL] = "RO",
0203 [AFSVL_BACKVOL] = "BK",
0204 };
0205
0206
0207
0208
0209 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
0210 {
0211 struct afs_volume *vol = hlist_entry(v, struct afs_volume, proc_link);
0212
0213
0214 if (v == SEQ_START_TOKEN) {
0215 seq_puts(m, "USE VID TY NAME\n");
0216 return 0;
0217 }
0218
0219 seq_printf(m, "%3d %08llx %s %s\n",
0220 refcount_read(&vol->ref), vol->vid,
0221 afs_vol_types[vol->type],
0222 vol->name);
0223
0224 return 0;
0225 }
0226
0227 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
0228 __acquires(cell->proc_lock)
0229 {
0230 struct afs_cell *cell = pde_data(file_inode(m->file));
0231
0232 rcu_read_lock();
0233 return seq_hlist_start_head_rcu(&cell->proc_volumes, *_pos);
0234 }
0235
0236 static void *afs_proc_cell_volumes_next(struct seq_file *m, void *v,
0237 loff_t *_pos)
0238 {
0239 struct afs_cell *cell = pde_data(file_inode(m->file));
0240
0241 return seq_hlist_next_rcu(v, &cell->proc_volumes, _pos);
0242 }
0243
0244 static void afs_proc_cell_volumes_stop(struct seq_file *m, void *v)
0245 __releases(cell->proc_lock)
0246 {
0247 rcu_read_unlock();
0248 }
0249
0250 static const struct seq_operations afs_proc_cell_volumes_ops = {
0251 .start = afs_proc_cell_volumes_start,
0252 .next = afs_proc_cell_volumes_next,
0253 .stop = afs_proc_cell_volumes_stop,
0254 .show = afs_proc_cell_volumes_show,
0255 };
0256
0257 static const char *const dns_record_sources[NR__dns_record_source + 1] = {
0258 [DNS_RECORD_UNAVAILABLE] = "unav",
0259 [DNS_RECORD_FROM_CONFIG] = "cfg",
0260 [DNS_RECORD_FROM_DNS_A] = "A",
0261 [DNS_RECORD_FROM_DNS_AFSDB] = "AFSDB",
0262 [DNS_RECORD_FROM_DNS_SRV] = "SRV",
0263 [DNS_RECORD_FROM_NSS] = "nss",
0264 [NR__dns_record_source] = "[weird]"
0265 };
0266
0267 static const char *const dns_lookup_statuses[NR__dns_lookup_status + 1] = {
0268 [DNS_LOOKUP_NOT_DONE] = "no-lookup",
0269 [DNS_LOOKUP_GOOD] = "good",
0270 [DNS_LOOKUP_GOOD_WITH_BAD] = "good/bad",
0271 [DNS_LOOKUP_BAD] = "bad",
0272 [DNS_LOOKUP_GOT_NOT_FOUND] = "not-found",
0273 [DNS_LOOKUP_GOT_LOCAL_FAILURE] = "local-failure",
0274 [DNS_LOOKUP_GOT_TEMP_FAILURE] = "temp-failure",
0275 [DNS_LOOKUP_GOT_NS_FAILURE] = "ns-failure",
0276 [NR__dns_lookup_status] = "[weird]"
0277 };
0278
0279
0280
0281
0282 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
0283 {
0284 const struct afs_vl_seq_net_private *priv = m->private;
0285 const struct afs_vlserver_list *vllist = priv->vllist;
0286 const struct afs_vlserver_entry *entry;
0287 const struct afs_vlserver *vlserver;
0288 const struct afs_addr_list *alist;
0289 int i;
0290
0291 if (v == SEQ_START_TOKEN) {
0292 seq_printf(m, "# source %s, status %s\n",
0293 dns_record_sources[vllist ? vllist->source : 0],
0294 dns_lookup_statuses[vllist ? vllist->status : 0]);
0295 return 0;
0296 }
0297
0298 entry = v;
0299 vlserver = entry->server;
0300 alist = rcu_dereference(vlserver->addresses);
0301
0302 seq_printf(m, "%s [p=%hu w=%hu s=%s,%s]:\n",
0303 vlserver->name, entry->priority, entry->weight,
0304 dns_record_sources[alist ? alist->source : entry->source],
0305 dns_lookup_statuses[alist ? alist->status : entry->status]);
0306 if (alist) {
0307 for (i = 0; i < alist->nr_addrs; i++)
0308 seq_printf(m, " %c %pISpc\n",
0309 alist->preferred == i ? '>' : '-',
0310 &alist->addrs[i].transport);
0311 }
0312 seq_printf(m, " info: fl=%lx rtt=%d\n", vlserver->flags, vlserver->rtt);
0313 seq_printf(m, " probe: fl=%x e=%d ac=%d out=%d\n",
0314 vlserver->probe.flags, vlserver->probe.error,
0315 vlserver->probe.abort_code,
0316 atomic_read(&vlserver->probe_outstanding));
0317 return 0;
0318 }
0319
0320 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
0321 __acquires(rcu)
0322 {
0323 struct afs_vl_seq_net_private *priv = m->private;
0324 struct afs_vlserver_list *vllist;
0325 struct afs_cell *cell = pde_data(file_inode(m->file));
0326 loff_t pos = *_pos;
0327
0328 rcu_read_lock();
0329
0330 vllist = rcu_dereference(cell->vl_servers);
0331 priv->vllist = vllist;
0332
0333 if (pos < 0)
0334 *_pos = pos = 0;
0335 if (pos == 0)
0336 return SEQ_START_TOKEN;
0337
0338 if (pos - 1 >= vllist->nr_servers)
0339 return NULL;
0340
0341 return &vllist->servers[pos - 1];
0342 }
0343
0344 static void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v,
0345 loff_t *_pos)
0346 {
0347 struct afs_vl_seq_net_private *priv = m->private;
0348 struct afs_vlserver_list *vllist = priv->vllist;
0349 loff_t pos;
0350
0351 pos = *_pos;
0352 pos++;
0353 *_pos = pos;
0354 if (!vllist || pos - 1 >= vllist->nr_servers)
0355 return NULL;
0356
0357 return &vllist->servers[pos - 1];
0358 }
0359
0360 static void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v)
0361 __releases(rcu)
0362 {
0363 rcu_read_unlock();
0364 }
0365
0366 static const struct seq_operations afs_proc_cell_vlservers_ops = {
0367 .start = afs_proc_cell_vlservers_start,
0368 .next = afs_proc_cell_vlservers_next,
0369 .stop = afs_proc_cell_vlservers_stop,
0370 .show = afs_proc_cell_vlservers_show,
0371 };
0372
0373
0374
0375
0376 static int afs_proc_servers_show(struct seq_file *m, void *v)
0377 {
0378 struct afs_server *server;
0379 struct afs_addr_list *alist;
0380 int i;
0381
0382 if (v == SEQ_START_TOKEN) {
0383 seq_puts(m, "UUID REF ACT\n");
0384 return 0;
0385 }
0386
0387 server = list_entry(v, struct afs_server, proc_link);
0388 alist = rcu_dereference(server->addresses);
0389 seq_printf(m, "%pU %3d %3d\n",
0390 &server->uuid,
0391 refcount_read(&server->ref),
0392 atomic_read(&server->active));
0393 seq_printf(m, " - info: fl=%lx rtt=%u brk=%x\n",
0394 server->flags, server->rtt, server->cb_s_break);
0395 seq_printf(m, " - probe: last=%d out=%d\n",
0396 (int)(jiffies - server->probed_at) / HZ,
0397 atomic_read(&server->probe_outstanding));
0398 seq_printf(m, " - ALIST v=%u rsp=%lx f=%lx\n",
0399 alist->version, alist->responded, alist->failed);
0400 for (i = 0; i < alist->nr_addrs; i++)
0401 seq_printf(m, " [%x] %pISpc%s\n",
0402 i, &alist->addrs[i].transport,
0403 alist->preferred == i ? "*" : "");
0404 return 0;
0405 }
0406
0407 static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos)
0408 __acquires(rcu)
0409 {
0410 rcu_read_lock();
0411 return seq_hlist_start_head_rcu(&afs_seq2net(m)->fs_proc, *_pos);
0412 }
0413
0414 static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
0415 {
0416 return seq_hlist_next_rcu(v, &afs_seq2net(m)->fs_proc, _pos);
0417 }
0418
0419 static void afs_proc_servers_stop(struct seq_file *m, void *v)
0420 __releases(rcu)
0421 {
0422 rcu_read_unlock();
0423 }
0424
0425 static const struct seq_operations afs_proc_servers_ops = {
0426 .start = afs_proc_servers_start,
0427 .next = afs_proc_servers_next,
0428 .stop = afs_proc_servers_stop,
0429 .show = afs_proc_servers_show,
0430 };
0431
0432
0433
0434
0435
0436 static int afs_proc_sysname_show(struct seq_file *m, void *v)
0437 {
0438 struct afs_net *net = afs_seq2net(m);
0439 struct afs_sysnames *sysnames = net->sysnames;
0440 unsigned int i = (unsigned long)v - 1;
0441
0442 if (i < sysnames->nr)
0443 seq_printf(m, "%s\n", sysnames->subs[i]);
0444 return 0;
0445 }
0446
0447 static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
0448 __acquires(&net->sysnames_lock)
0449 {
0450 struct afs_net *net = afs_seq2net(m);
0451 struct afs_sysnames *names;
0452
0453 read_lock(&net->sysnames_lock);
0454
0455 names = net->sysnames;
0456 if (*pos >= names->nr)
0457 return NULL;
0458 return (void *)(unsigned long)(*pos + 1);
0459 }
0460
0461 static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
0462 {
0463 struct afs_net *net = afs_seq2net(m);
0464 struct afs_sysnames *names = net->sysnames;
0465
0466 *pos += 1;
0467 if (*pos >= names->nr)
0468 return NULL;
0469 return (void *)(unsigned long)(*pos + 1);
0470 }
0471
0472 static void afs_proc_sysname_stop(struct seq_file *m, void *v)
0473 __releases(&net->sysnames_lock)
0474 {
0475 struct afs_net *net = afs_seq2net(m);
0476
0477 read_unlock(&net->sysnames_lock);
0478 }
0479
0480 static const struct seq_operations afs_proc_sysname_ops = {
0481 .start = afs_proc_sysname_start,
0482 .next = afs_proc_sysname_next,
0483 .stop = afs_proc_sysname_stop,
0484 .show = afs_proc_sysname_show,
0485 };
0486
0487
0488
0489
0490 static int afs_proc_sysname_write(struct file *file, char *buf, size_t size)
0491 {
0492 struct afs_sysnames *sysnames, *kill;
0493 struct seq_file *m = file->private_data;
0494 struct afs_net *net = afs_seq2net(m);
0495 char *s, *p, *sub;
0496 int ret, len;
0497
0498 sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
0499 if (!sysnames)
0500 return -ENOMEM;
0501 refcount_set(&sysnames->usage, 1);
0502 kill = sysnames;
0503
0504 p = buf;
0505 while ((s = strsep(&p, " \t\n"))) {
0506 len = strlen(s);
0507 if (len == 0)
0508 continue;
0509 ret = -ENAMETOOLONG;
0510 if (len >= AFSNAMEMAX)
0511 goto error;
0512
0513 if (len >= 4 &&
0514 s[len - 4] == '@' &&
0515 s[len - 3] == 's' &&
0516 s[len - 2] == 'y' &&
0517 s[len - 1] == 's')
0518
0519 goto invalid;
0520
0521 if (s[0] == '.' &&
0522 (len < 2 || (len == 2 && s[1] == '.')))
0523 goto invalid;
0524
0525 if (memchr(s, '/', len))
0526 goto invalid;
0527
0528 ret = -EFBIG;
0529 if (sysnames->nr >= AFS_NR_SYSNAME)
0530 goto out;
0531
0532 if (strcmp(s, afs_init_sysname) == 0) {
0533 sub = (char *)afs_init_sysname;
0534 } else {
0535 ret = -ENOMEM;
0536 sub = kmemdup(s, len + 1, GFP_KERNEL);
0537 if (!sub)
0538 goto out;
0539 }
0540
0541 sysnames->subs[sysnames->nr] = sub;
0542 sysnames->nr++;
0543 }
0544
0545 if (sysnames->nr == 0) {
0546 sysnames->subs[0] = sysnames->blank;
0547 sysnames->nr++;
0548 }
0549
0550 write_lock(&net->sysnames_lock);
0551 kill = net->sysnames;
0552 net->sysnames = sysnames;
0553 write_unlock(&net->sysnames_lock);
0554 ret = 0;
0555 out:
0556 afs_put_sysnames(kill);
0557 return ret;
0558
0559 invalid:
0560 ret = -EINVAL;
0561 error:
0562 goto out;
0563 }
0564
0565 void afs_put_sysnames(struct afs_sysnames *sysnames)
0566 {
0567 int i;
0568
0569 if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
0570 for (i = 0; i < sysnames->nr; i++)
0571 if (sysnames->subs[i] != afs_init_sysname &&
0572 sysnames->subs[i] != sysnames->blank)
0573 kfree(sysnames->subs[i]);
0574 kfree(sysnames);
0575 }
0576 }
0577
0578
0579
0580
0581 static int afs_proc_stats_show(struct seq_file *m, void *v)
0582 {
0583 struct afs_net *net = afs_seq2net_single(m);
0584
0585 seq_puts(m, "kAFS statistics\n");
0586
0587 seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
0588 atomic_read(&net->n_lookup),
0589 atomic_read(&net->n_reval),
0590 atomic_read(&net->n_inval),
0591 atomic_read(&net->n_relpg));
0592
0593 seq_printf(m, "dir-data: rdpg=%u\n",
0594 atomic_read(&net->n_read_dir));
0595
0596 seq_printf(m, "dir-edit: cr=%u rm=%u\n",
0597 atomic_read(&net->n_dir_cr),
0598 atomic_read(&net->n_dir_rm));
0599
0600 seq_printf(m, "file-rd : n=%u nb=%lu\n",
0601 atomic_read(&net->n_fetches),
0602 atomic_long_read(&net->n_fetch_bytes));
0603 seq_printf(m, "file-wr : n=%u nb=%lu\n",
0604 atomic_read(&net->n_stores),
0605 atomic_long_read(&net->n_store_bytes));
0606 return 0;
0607 }
0608
0609
0610
0611
0612 int afs_proc_cell_setup(struct afs_cell *cell)
0613 {
0614 struct proc_dir_entry *dir;
0615 struct afs_net *net = cell->net;
0616
0617 _enter("%p{%s},%p", cell, cell->name, net->proc_afs);
0618
0619 dir = proc_net_mkdir(net->net, cell->name, net->proc_afs);
0620 if (!dir)
0621 goto error_dir;
0622
0623 if (!proc_create_net_data("vlservers", 0444, dir,
0624 &afs_proc_cell_vlservers_ops,
0625 sizeof(struct afs_vl_seq_net_private),
0626 cell) ||
0627 !proc_create_net_data("volumes", 0444, dir,
0628 &afs_proc_cell_volumes_ops,
0629 sizeof(struct seq_net_private),
0630 cell))
0631 goto error_tree;
0632
0633 _leave(" = 0");
0634 return 0;
0635
0636 error_tree:
0637 remove_proc_subtree(cell->name, net->proc_afs);
0638 error_dir:
0639 _leave(" = -ENOMEM");
0640 return -ENOMEM;
0641 }
0642
0643
0644
0645
0646 void afs_proc_cell_remove(struct afs_cell *cell)
0647 {
0648 struct afs_net *net = cell->net;
0649
0650 _enter("");
0651 remove_proc_subtree(cell->name, net->proc_afs);
0652 _leave("");
0653 }
0654
0655
0656
0657
0658 int afs_proc_init(struct afs_net *net)
0659 {
0660 struct proc_dir_entry *p;
0661
0662 _enter("");
0663
0664 p = proc_net_mkdir(net->net, "afs", net->net->proc_net);
0665 if (!p)
0666 goto error_dir;
0667
0668 if (!proc_create_net_data_write("cells", 0644, p,
0669 &afs_proc_cells_ops,
0670 afs_proc_cells_write,
0671 sizeof(struct seq_net_private),
0672 NULL) ||
0673 !proc_create_net_single_write("rootcell", 0644, p,
0674 afs_proc_rootcell_show,
0675 afs_proc_rootcell_write,
0676 NULL) ||
0677 !proc_create_net("servers", 0444, p, &afs_proc_servers_ops,
0678 sizeof(struct seq_net_private)) ||
0679 !proc_create_net_single("stats", 0444, p, afs_proc_stats_show, NULL) ||
0680 !proc_create_net_data_write("sysname", 0644, p,
0681 &afs_proc_sysname_ops,
0682 afs_proc_sysname_write,
0683 sizeof(struct seq_net_private),
0684 NULL))
0685 goto error_tree;
0686
0687 net->proc_afs = p;
0688 _leave(" = 0");
0689 return 0;
0690
0691 error_tree:
0692 proc_remove(p);
0693 error_dir:
0694 _leave(" = -ENOMEM");
0695 return -ENOMEM;
0696 }
0697
0698
0699
0700
0701 void afs_proc_cleanup(struct afs_net *net)
0702 {
0703 proc_remove(net->proc_afs);
0704 net->proc_afs = NULL;
0705 }