1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* /proc interface for AFS 3 * 4 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. 5 * Written by David Howells (dhowells@redhat.com) 6 */ 7 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> 14 #include "internal.h" 15 16 struct afs_vl_seq_net_private { 17 struct seq_net_private seq; /* Must be first */ 18 struct afs_vlserver_list *vllist; 19 }; 20 21 static inline struct afs_net *afs_seq2net(struct seq_file *m) 22 { 23 return afs_net(seq_file_net(m)); 24 } 25 26 static inline struct afs_net *afs_seq2net_single(struct seq_file *m) 27 { 28 return afs_net(seq_file_single_net(m)); 29 } 30 31 /* 32 * Display the list of cells known to the namespace. 33 */ 34 static int afs_proc_cells_show(struct seq_file *m, void *v) 35 { 36 struct afs_vlserver_list *vllist; 37 struct afs_cell *cell; 38 39 if (v == SEQ_START_TOKEN) { 40 /* display header on line 1 */ 41 seq_puts(m, "USE TTL SV NAME\n"); 42 return 0; 43 } 44 45 cell = list_entry(v, struct afs_cell, proc_link); 46 vllist = rcu_dereference(cell->vl_servers); 47 48 /* display one cell per line on subsequent lines */ 49 seq_printf(m, "%3u %6lld %2u %s\n", 50 atomic_read(&cell->usage), 51 cell->dns_expiry - ktime_get_real_seconds(), 52 vllist->nr_servers, 53 cell->name); 54 return 0; 55 } 56 57 static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos) 58 __acquires(rcu) 59 { 60 rcu_read_lock(); 61 return seq_hlist_start_head_rcu(&afs_seq2net(m)->proc_cells, *_pos); 62 } 63 64 static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos) 65 { 66 return seq_hlist_next_rcu(v, &afs_seq2net(m)->proc_cells, pos); 67 } 68 69 static void afs_proc_cells_stop(struct seq_file *m, void *v) 70 __releases(rcu) 71 { 72 rcu_read_unlock(); 73 } 74 75 static const struct seq_operations afs_proc_cells_ops = { 76 .start = afs_proc_cells_start, 77 .next = afs_proc_cells_next, 78 .stop = afs_proc_cells_stop, 79 .show = afs_proc_cells_show, 80 }; 81 82 /* 83 * handle writes to /proc/fs/afs/cells 84 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]" 85 */ 86 static int afs_proc_cells_write(struct file *file, char *buf, size_t size) 87 { 88 struct seq_file *m = file->private_data; 89 struct afs_net *net = afs_seq2net(m); 90 char *name, *args; 91 int ret; 92 93 /* trim to first NL */ 94 name = memchr(buf, '\n', size); 95 if (name) 96 *name = 0; 97 98 /* split into command, name and argslist */ 99 name = strchr(buf, ' '); 100 if (!name) 101 goto inval; 102 do { 103 *name++ = 0; 104 } while(*name == ' '); 105 if (!*name) 106 goto inval; 107 108 args = strchr(name, ' '); 109 if (args) { 110 do { 111 *args++ = 0; 112 } while(*args == ' '); 113 if (!*args) 114 goto inval; 115 } 116 117 /* determine command to perform */ 118 _debug("cmd=%s name=%s args=%s", buf, name, args); 119 120 if (strcmp(buf, "add") == 0) { 121 struct afs_cell *cell; 122 123 cell = afs_lookup_cell(net, name, strlen(name), args, true); 124 if (IS_ERR(cell)) { 125 ret = PTR_ERR(cell); 126 goto done; 127 } 128 129 if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags)) 130 afs_put_cell(net, cell); 131 } else { 132 goto inval; 133 } 134 135 ret = 0; 136 137 done: 138 _leave(" = %d", ret); 139 return ret; 140 141 inval: 142 ret = -EINVAL; 143 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n"); 144 goto done; 145 } 146 147 /* 148 * Display the name of the current workstation cell. 149 */ 150 static int afs_proc_rootcell_show(struct seq_file *m, void *v) 151 { 152 struct afs_cell *cell; 153 struct afs_net *net; 154 155 net = afs_seq2net_single(m); 156 if (rcu_access_pointer(net->ws_cell)) { 157 rcu_read_lock(); 158 cell = rcu_dereference(net->ws_cell); 159 if (cell) 160 seq_printf(m, "%s\n", cell->name); 161 rcu_read_unlock(); 162 } 163 return 0; 164 } 165 166 /* 167 * Set the current workstation cell and optionally supply its list of volume 168 * location servers. 169 * 170 * echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell 171 */ 172 static int afs_proc_rootcell_write(struct file *file, char *buf, size_t size) 173 { 174 struct seq_file *m = file->private_data; 175 struct afs_net *net = afs_seq2net_single(m); 176 char *s; 177 int ret; 178 179 ret = -EINVAL; 180 if (buf[0] == '.') 181 goto out; 182 if (memchr(buf, '/', size)) 183 goto out; 184 185 /* trim to first NL */ 186 s = memchr(buf, '\n', size); 187 if (s) 188 *s = 0; 189 190 /* determine command to perform */ 191 _debug("rootcell=%s", buf); 192 193 ret = afs_cell_init(net, buf); 194 195 out: 196 _leave(" = %d", ret); 197 return ret; 198 } 199 200 static const char afs_vol_types[3][3] = { 201 [AFSVL_RWVOL] = "RW", 202 [AFSVL_ROVOL] = "RO", 203 [AFSVL_BACKVOL] = "BK", 204 }; 205 206 /* 207 * Display the list of volumes known to a cell. 208 */ 209 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v) 210 { 211 struct afs_cell *cell = PDE_DATA(file_inode(m->file)); 212 struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link); 213 214 /* Display header on line 1 */ 215 if (v == &cell->proc_volumes) { 216 seq_puts(m, "USE VID TY NAME\n"); 217 return 0; 218 } 219 220 seq_printf(m, "%3d %08llx %s %s\n", 221 atomic_read(&vol->usage), vol->vid, 222 afs_vol_types[vol->type], 223 vol->name); 224 225 return 0; 226 } 227 228 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) 229 __acquires(cell->proc_lock) 230 { 231 struct afs_cell *cell = PDE_DATA(file_inode(m->file)); 232 233 read_lock(&cell->proc_lock); 234 return seq_list_start_head(&cell->proc_volumes, *_pos); 235 } 236 237 static void *afs_proc_cell_volumes_next(struct seq_file *m, void *v, 238 loff_t *_pos) 239 { 240 struct afs_cell *cell = PDE_DATA(file_inode(m->file)); 241 242 return seq_list_next(v, &cell->proc_volumes, _pos); 243 } 244 245 static void afs_proc_cell_volumes_stop(struct seq_file *m, void *v) 246 __releases(cell->proc_lock) 247 { 248 struct afs_cell *cell = PDE_DATA(file_inode(m->file)); 249 250 read_unlock(&cell->proc_lock); 251 } 252 253 static const struct seq_operations afs_proc_cell_volumes_ops = { 254 .start = afs_proc_cell_volumes_start, 255 .next = afs_proc_cell_volumes_next, 256 .stop = afs_proc_cell_volumes_stop, 257 .show = afs_proc_cell_volumes_show, 258 }; 259 260 static const char *const dns_record_sources[NR__dns_record_source + 1] = { 261 [DNS_RECORD_UNAVAILABLE] = "unav", 262 [DNS_RECORD_FROM_CONFIG] = "cfg", 263 [DNS_RECORD_FROM_DNS_A] = "A", 264 [DNS_RECORD_FROM_DNS_AFSDB] = "AFSDB", 265 [DNS_RECORD_FROM_DNS_SRV] = "SRV", 266 [DNS_RECORD_FROM_NSS] = "nss", 267 [NR__dns_record_source] = "[weird]" 268 }; 269 270 static const char *const dns_lookup_statuses[NR__dns_lookup_status + 1] = { 271 [DNS_LOOKUP_NOT_DONE] = "no-lookup", 272 [DNS_LOOKUP_GOOD] = "good", 273 [DNS_LOOKUP_GOOD_WITH_BAD] = "good/bad", 274 [DNS_LOOKUP_BAD] = "bad", 275 [DNS_LOOKUP_GOT_NOT_FOUND] = "not-found", 276 [DNS_LOOKUP_GOT_LOCAL_FAILURE] = "local-failure", 277 [DNS_LOOKUP_GOT_TEMP_FAILURE] = "temp-failure", 278 [DNS_LOOKUP_GOT_NS_FAILURE] = "ns-failure", 279 [NR__dns_lookup_status] = "[weird]" 280 }; 281 282 /* 283 * Display the list of Volume Location servers we're using for a cell. 284 */ 285 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) 286 { 287 const struct afs_vl_seq_net_private *priv = m->private; 288 const struct afs_vlserver_list *vllist = priv->vllist; 289 const struct afs_vlserver_entry *entry; 290 const struct afs_vlserver *vlserver; 291 const struct afs_addr_list *alist; 292 int i; 293 294 if (v == SEQ_START_TOKEN) { 295 seq_printf(m, "# source %s, status %s\n", 296 dns_record_sources[vllist ? vllist->source : 0], 297 dns_lookup_statuses[vllist ? vllist->status : 0]); 298 return 0; 299 } 300 301 entry = v; 302 vlserver = entry->server; 303 alist = rcu_dereference(vlserver->addresses); 304 305 seq_printf(m, "%s [p=%hu w=%hu s=%s,%s]:\n", 306 vlserver->name, entry->priority, entry->weight, 307 dns_record_sources[alist ? alist->source : entry->source], 308 dns_lookup_statuses[alist ? alist->status : entry->status]); 309 if (alist) { 310 for (i = 0; i < alist->nr_addrs; i++) 311 seq_printf(m, " %c %pISpc\n", 312 alist->preferred == i ? '>' : '-', 313 &alist->addrs[i].transport); 314 } 315 return 0; 316 } 317 318 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) 319 __acquires(rcu) 320 { 321 struct afs_vl_seq_net_private *priv = m->private; 322 struct afs_vlserver_list *vllist; 323 struct afs_cell *cell = PDE_DATA(file_inode(m->file)); 324 loff_t pos = *_pos; 325 326 rcu_read_lock(); 327 328 vllist = rcu_dereference(cell->vl_servers); 329 priv->vllist = vllist; 330 331 if (pos < 0) 332 *_pos = pos = 0; 333 if (pos == 0) 334 return SEQ_START_TOKEN; 335 336 if (pos - 1 >= vllist->nr_servers) 337 return NULL; 338 339 return &vllist->servers[pos - 1]; 340 } 341 342 static void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v, 343 loff_t *_pos) 344 { 345 struct afs_vl_seq_net_private *priv = m->private; 346 struct afs_vlserver_list *vllist = priv->vllist; 347 loff_t pos; 348 349 pos = *_pos; 350 pos++; 351 *_pos = pos; 352 if (!vllist || pos - 1 >= vllist->nr_servers) 353 return NULL; 354 355 return &vllist->servers[pos - 1]; 356 } 357 358 static void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v) 359 __releases(rcu) 360 { 361 rcu_read_unlock(); 362 } 363 364 static const struct seq_operations afs_proc_cell_vlservers_ops = { 365 .start = afs_proc_cell_vlservers_start, 366 .next = afs_proc_cell_vlservers_next, 367 .stop = afs_proc_cell_vlservers_stop, 368 .show = afs_proc_cell_vlservers_show, 369 }; 370 371 /* 372 * Display the list of fileservers we're using within a namespace. 373 */ 374 static int afs_proc_servers_show(struct seq_file *m, void *v) 375 { 376 struct afs_server *server; 377 struct afs_addr_list *alist; 378 int i; 379 380 if (v == SEQ_START_TOKEN) { 381 seq_puts(m, "UUID USE ADDR\n"); 382 return 0; 383 } 384 385 server = list_entry(v, struct afs_server, proc_link); 386 alist = rcu_dereference(server->addresses); 387 seq_printf(m, "%pU %3d %pISpc%s\n", 388 &server->uuid, 389 atomic_read(&server->usage), 390 &alist->addrs[0].transport, 391 alist->preferred == 0 ? "*" : ""); 392 for (i = 1; i < alist->nr_addrs; i++) 393 seq_printf(m, " %pISpc%s\n", 394 &alist->addrs[i].transport, 395 alist->preferred == i ? "*" : ""); 396 return 0; 397 } 398 399 static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos) 400 __acquires(rcu) 401 { 402 rcu_read_lock(); 403 return seq_hlist_start_head_rcu(&afs_seq2net(m)->fs_proc, *_pos); 404 } 405 406 static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos) 407 { 408 return seq_hlist_next_rcu(v, &afs_seq2net(m)->fs_proc, _pos); 409 } 410 411 static void afs_proc_servers_stop(struct seq_file *m, void *v) 412 __releases(rcu) 413 { 414 rcu_read_unlock(); 415 } 416 417 static const struct seq_operations afs_proc_servers_ops = { 418 .start = afs_proc_servers_start, 419 .next = afs_proc_servers_next, 420 .stop = afs_proc_servers_stop, 421 .show = afs_proc_servers_show, 422 }; 423 424 /* 425 * Display the list of strings that may be substituted for the @sys pathname 426 * macro. 427 */ 428 static int afs_proc_sysname_show(struct seq_file *m, void *v) 429 { 430 struct afs_net *net = afs_seq2net(m); 431 struct afs_sysnames *sysnames = net->sysnames; 432 unsigned int i = (unsigned long)v - 1; 433 434 if (i < sysnames->nr) 435 seq_printf(m, "%s\n", sysnames->subs[i]); 436 return 0; 437 } 438 439 static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos) 440 __acquires(&net->sysnames_lock) 441 { 442 struct afs_net *net = afs_seq2net(m); 443 struct afs_sysnames *names; 444 445 read_lock(&net->sysnames_lock); 446 447 names = net->sysnames; 448 if (*pos >= names->nr) 449 return NULL; 450 return (void *)(unsigned long)(*pos + 1); 451 } 452 453 static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos) 454 { 455 struct afs_net *net = afs_seq2net(m); 456 struct afs_sysnames *names = net->sysnames; 457 458 *pos += 1; 459 if (*pos >= names->nr) 460 return NULL; 461 return (void *)(unsigned long)(*pos + 1); 462 } 463 464 static void afs_proc_sysname_stop(struct seq_file *m, void *v) 465 __releases(&net->sysnames_lock) 466 { 467 struct afs_net *net = afs_seq2net(m); 468 469 read_unlock(&net->sysnames_lock); 470 } 471 472 static const struct seq_operations afs_proc_sysname_ops = { 473 .start = afs_proc_sysname_start, 474 .next = afs_proc_sysname_next, 475 .stop = afs_proc_sysname_stop, 476 .show = afs_proc_sysname_show, 477 }; 478 479 /* 480 * Allow the @sys substitution to be configured. 481 */ 482 static int afs_proc_sysname_write(struct file *file, char *buf, size_t size) 483 { 484 struct afs_sysnames *sysnames, *kill; 485 struct seq_file *m = file->private_data; 486 struct afs_net *net = afs_seq2net(m); 487 char *s, *p, *sub; 488 int ret, len; 489 490 sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL); 491 if (!sysnames) 492 return -ENOMEM; 493 refcount_set(&sysnames->usage, 1); 494 kill = sysnames; 495 496 p = buf; 497 while ((s = strsep(&p, " \t\n"))) { 498 len = strlen(s); 499 if (len == 0) 500 continue; 501 ret = -ENAMETOOLONG; 502 if (len >= AFSNAMEMAX) 503 goto error; 504 505 if (len >= 4 && 506 s[len - 4] == '@' && 507 s[len - 3] == 's' && 508 s[len - 2] == 'y' && 509 s[len - 1] == 's') 510 /* Protect against recursion */ 511 goto invalid; 512 513 if (s[0] == '.' && 514 (len < 2 || (len == 2 && s[1] == '.'))) 515 goto invalid; 516 517 if (memchr(s, '/', len)) 518 goto invalid; 519 520 ret = -EFBIG; 521 if (sysnames->nr >= AFS_NR_SYSNAME) 522 goto out; 523 524 if (strcmp(s, afs_init_sysname) == 0) { 525 sub = (char *)afs_init_sysname; 526 } else { 527 ret = -ENOMEM; 528 sub = kmemdup(s, len + 1, GFP_KERNEL); 529 if (!sub) 530 goto out; 531 } 532 533 sysnames->subs[sysnames->nr] = sub; 534 sysnames->nr++; 535 } 536 537 if (sysnames->nr == 0) { 538 sysnames->subs[0] = sysnames->blank; 539 sysnames->nr++; 540 } 541 542 write_lock(&net->sysnames_lock); 543 kill = net->sysnames; 544 net->sysnames = sysnames; 545 write_unlock(&net->sysnames_lock); 546 ret = 0; 547 out: 548 afs_put_sysnames(kill); 549 return ret; 550 551 invalid: 552 ret = -EINVAL; 553 error: 554 goto out; 555 } 556 557 void afs_put_sysnames(struct afs_sysnames *sysnames) 558 { 559 int i; 560 561 if (sysnames && refcount_dec_and_test(&sysnames->usage)) { 562 for (i = 0; i < sysnames->nr; i++) 563 if (sysnames->subs[i] != afs_init_sysname && 564 sysnames->subs[i] != sysnames->blank) 565 kfree(sysnames->subs[i]); 566 } 567 } 568 569 /* 570 * Display general per-net namespace statistics 571 */ 572 static int afs_proc_stats_show(struct seq_file *m, void *v) 573 { 574 struct afs_net *net = afs_seq2net_single(m); 575 576 seq_puts(m, "kAFS statistics\n"); 577 578 seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n", 579 atomic_read(&net->n_lookup), 580 atomic_read(&net->n_reval), 581 atomic_read(&net->n_inval), 582 atomic_read(&net->n_relpg)); 583 584 seq_printf(m, "dir-data: rdpg=%u\n", 585 atomic_read(&net->n_read_dir)); 586 587 seq_printf(m, "dir-edit: cr=%u rm=%u\n", 588 atomic_read(&net->n_dir_cr), 589 atomic_read(&net->n_dir_rm)); 590 591 seq_printf(m, "file-rd : n=%u nb=%lu\n", 592 atomic_read(&net->n_fetches), 593 atomic_long_read(&net->n_fetch_bytes)); 594 seq_printf(m, "file-wr : n=%u nb=%lu\n", 595 atomic_read(&net->n_stores), 596 atomic_long_read(&net->n_store_bytes)); 597 return 0; 598 } 599 600 /* 601 * initialise /proc/fs/afs/<cell>/ 602 */ 603 int afs_proc_cell_setup(struct afs_cell *cell) 604 { 605 struct proc_dir_entry *dir; 606 struct afs_net *net = cell->net; 607 608 _enter("%p{%s},%p", cell, cell->name, net->proc_afs); 609 610 dir = proc_net_mkdir(net->net, cell->name, net->proc_afs); 611 if (!dir) 612 goto error_dir; 613 614 if (!proc_create_net_data("vlservers", 0444, dir, 615 &afs_proc_cell_vlservers_ops, 616 sizeof(struct afs_vl_seq_net_private), 617 cell) || 618 !proc_create_net_data("volumes", 0444, dir, 619 &afs_proc_cell_volumes_ops, 620 sizeof(struct seq_net_private), 621 cell)) 622 goto error_tree; 623 624 _leave(" = 0"); 625 return 0; 626 627 error_tree: 628 remove_proc_subtree(cell->name, net->proc_afs); 629 error_dir: 630 _leave(" = -ENOMEM"); 631 return -ENOMEM; 632 } 633 634 /* 635 * remove /proc/fs/afs/<cell>/ 636 */ 637 void afs_proc_cell_remove(struct afs_cell *cell) 638 { 639 struct afs_net *net = cell->net; 640 641 _enter(""); 642 remove_proc_subtree(cell->name, net->proc_afs); 643 _leave(""); 644 } 645 646 /* 647 * initialise the /proc/fs/afs/ directory 648 */ 649 int afs_proc_init(struct afs_net *net) 650 { 651 struct proc_dir_entry *p; 652 653 _enter(""); 654 655 p = proc_net_mkdir(net->net, "afs", net->net->proc_net); 656 if (!p) 657 goto error_dir; 658 659 if (!proc_create_net_data_write("cells", 0644, p, 660 &afs_proc_cells_ops, 661 afs_proc_cells_write, 662 sizeof(struct seq_net_private), 663 NULL) || 664 !proc_create_net_single_write("rootcell", 0644, p, 665 afs_proc_rootcell_show, 666 afs_proc_rootcell_write, 667 NULL) || 668 !proc_create_net("servers", 0444, p, &afs_proc_servers_ops, 669 sizeof(struct seq_net_private)) || 670 !proc_create_net_single("stats", 0444, p, afs_proc_stats_show, NULL) || 671 !proc_create_net_data_write("sysname", 0644, p, 672 &afs_proc_sysname_ops, 673 afs_proc_sysname_write, 674 sizeof(struct seq_net_private), 675 NULL)) 676 goto error_tree; 677 678 net->proc_afs = p; 679 _leave(" = 0"); 680 return 0; 681 682 error_tree: 683 proc_remove(p); 684 error_dir: 685 _leave(" = -ENOMEM"); 686 return -ENOMEM; 687 } 688 689 /* 690 * clean up the /proc/fs/afs/ directory 691 */ 692 void afs_proc_cleanup(struct afs_net *net) 693 { 694 proc_remove(net->proc_afs); 695 net->proc_afs = NULL; 696 } 697