1 /* /proc interface for AFS 2 * 3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 #include <linux/slab.h> 13 #include <linux/module.h> 14 #include <linux/proc_fs.h> 15 #include <linux/seq_file.h> 16 #include <linux/sched.h> 17 #include <linux/uaccess.h> 18 #include "internal.h" 19 20 static inline struct afs_net *afs_proc2net(struct file *f) 21 { 22 return &__afs_net; 23 } 24 25 static inline struct afs_net *afs_seq2net(struct seq_file *m) 26 { 27 return &__afs_net; // TODO: use seq_file_net(m) 28 } 29 30 static int afs_proc_cells_open(struct inode *inode, struct file *file); 31 static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos); 32 static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos); 33 static void afs_proc_cells_stop(struct seq_file *p, void *v); 34 static int afs_proc_cells_show(struct seq_file *m, void *v); 35 static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, 36 size_t size, loff_t *_pos); 37 38 static const struct seq_operations afs_proc_cells_ops = { 39 .start = afs_proc_cells_start, 40 .next = afs_proc_cells_next, 41 .stop = afs_proc_cells_stop, 42 .show = afs_proc_cells_show, 43 }; 44 45 static const struct file_operations afs_proc_cells_fops = { 46 .open = afs_proc_cells_open, 47 .read = seq_read, 48 .write = afs_proc_cells_write, 49 .llseek = seq_lseek, 50 .release = seq_release, 51 }; 52 53 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, 54 size_t size, loff_t *_pos); 55 static ssize_t afs_proc_rootcell_write(struct file *file, 56 const char __user *buf, 57 size_t size, loff_t *_pos); 58 59 static const struct file_operations afs_proc_rootcell_fops = { 60 .read = afs_proc_rootcell_read, 61 .write = afs_proc_rootcell_write, 62 .llseek = no_llseek, 63 }; 64 65 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file); 66 static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos); 67 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, 68 loff_t *pos); 69 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v); 70 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v); 71 72 static const struct seq_operations afs_proc_cell_volumes_ops = { 73 .start = afs_proc_cell_volumes_start, 74 .next = afs_proc_cell_volumes_next, 75 .stop = afs_proc_cell_volumes_stop, 76 .show = afs_proc_cell_volumes_show, 77 }; 78 79 static const struct file_operations afs_proc_cell_volumes_fops = { 80 .open = afs_proc_cell_volumes_open, 81 .read = seq_read, 82 .llseek = seq_lseek, 83 .release = seq_release, 84 }; 85 86 static int afs_proc_cell_vlservers_open(struct inode *inode, 87 struct file *file); 88 static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos); 89 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, 90 loff_t *pos); 91 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v); 92 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v); 93 94 static const struct seq_operations afs_proc_cell_vlservers_ops = { 95 .start = afs_proc_cell_vlservers_start, 96 .next = afs_proc_cell_vlservers_next, 97 .stop = afs_proc_cell_vlservers_stop, 98 .show = afs_proc_cell_vlservers_show, 99 }; 100 101 static const struct file_operations afs_proc_cell_vlservers_fops = { 102 .open = afs_proc_cell_vlservers_open, 103 .read = seq_read, 104 .llseek = seq_lseek, 105 .release = seq_release, 106 }; 107 108 static int afs_proc_servers_open(struct inode *inode, struct file *file); 109 static void *afs_proc_servers_start(struct seq_file *p, loff_t *pos); 110 static void *afs_proc_servers_next(struct seq_file *p, void *v, 111 loff_t *pos); 112 static void afs_proc_servers_stop(struct seq_file *p, void *v); 113 static int afs_proc_servers_show(struct seq_file *m, void *v); 114 115 static const struct seq_operations afs_proc_servers_ops = { 116 .start = afs_proc_servers_start, 117 .next = afs_proc_servers_next, 118 .stop = afs_proc_servers_stop, 119 .show = afs_proc_servers_show, 120 }; 121 122 static const struct file_operations afs_proc_servers_fops = { 123 .open = afs_proc_servers_open, 124 .read = seq_read, 125 .llseek = seq_lseek, 126 .release = seq_release, 127 }; 128 129 static int afs_proc_sysname_open(struct inode *inode, struct file *file); 130 static int afs_proc_sysname_release(struct inode *inode, struct file *file); 131 static void *afs_proc_sysname_start(struct seq_file *p, loff_t *pos); 132 static void *afs_proc_sysname_next(struct seq_file *p, void *v, 133 loff_t *pos); 134 static void afs_proc_sysname_stop(struct seq_file *p, void *v); 135 static int afs_proc_sysname_show(struct seq_file *m, void *v); 136 static ssize_t afs_proc_sysname_write(struct file *file, 137 const char __user *buf, 138 size_t size, loff_t *_pos); 139 140 static const struct seq_operations afs_proc_sysname_ops = { 141 .start = afs_proc_sysname_start, 142 .next = afs_proc_sysname_next, 143 .stop = afs_proc_sysname_stop, 144 .show = afs_proc_sysname_show, 145 }; 146 147 static const struct file_operations afs_proc_sysname_fops = { 148 .open = afs_proc_sysname_open, 149 .read = seq_read, 150 .llseek = seq_lseek, 151 .release = afs_proc_sysname_release, 152 .write = afs_proc_sysname_write, 153 }; 154 155 static const struct file_operations afs_proc_stats_fops; 156 157 /* 158 * initialise the /proc/fs/afs/ directory 159 */ 160 int afs_proc_init(struct afs_net *net) 161 { 162 _enter(""); 163 164 net->proc_afs = proc_mkdir("fs/afs", NULL); 165 if (!net->proc_afs) 166 goto error_dir; 167 168 if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) || 169 !proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops) || 170 !proc_create("servers", 0644, net->proc_afs, &afs_proc_servers_fops) || 171 !proc_create("stats", 0644, net->proc_afs, &afs_proc_stats_fops) || 172 !proc_create("sysname", 0644, net->proc_afs, &afs_proc_sysname_fops)) 173 goto error_tree; 174 175 _leave(" = 0"); 176 return 0; 177 178 error_tree: 179 proc_remove(net->proc_afs); 180 error_dir: 181 _leave(" = -ENOMEM"); 182 return -ENOMEM; 183 } 184 185 /* 186 * clean up the /proc/fs/afs/ directory 187 */ 188 void afs_proc_cleanup(struct afs_net *net) 189 { 190 proc_remove(net->proc_afs); 191 net->proc_afs = NULL; 192 } 193 194 /* 195 * open "/proc/fs/afs/cells" which provides a summary of extant cells 196 */ 197 static int afs_proc_cells_open(struct inode *inode, struct file *file) 198 { 199 struct seq_file *m; 200 int ret; 201 202 ret = seq_open(file, &afs_proc_cells_ops); 203 if (ret < 0) 204 return ret; 205 206 m = file->private_data; 207 m->private = PDE_DATA(inode); 208 return 0; 209 } 210 211 /* 212 * set up the iterator to start reading from the cells list and return the 213 * first item 214 */ 215 static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos) 216 __acquires(rcu) 217 { 218 struct afs_net *net = afs_seq2net(m); 219 220 rcu_read_lock(); 221 return seq_list_start_head(&net->proc_cells, *_pos); 222 } 223 224 /* 225 * move to next cell in cells list 226 */ 227 static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos) 228 { 229 struct afs_net *net = afs_seq2net(m); 230 231 return seq_list_next(v, &net->proc_cells, pos); 232 } 233 234 /* 235 * clean up after reading from the cells list 236 */ 237 static void afs_proc_cells_stop(struct seq_file *m, void *v) 238 __releases(rcu) 239 { 240 rcu_read_unlock(); 241 } 242 243 /* 244 * display a header line followed by a load of cell lines 245 */ 246 static int afs_proc_cells_show(struct seq_file *m, void *v) 247 { 248 struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link); 249 struct afs_net *net = afs_seq2net(m); 250 251 if (v == &net->proc_cells) { 252 /* display header on line 1 */ 253 seq_puts(m, "USE NAME\n"); 254 return 0; 255 } 256 257 /* display one cell per line on subsequent lines */ 258 seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name); 259 return 0; 260 } 261 262 /* 263 * handle writes to /proc/fs/afs/cells 264 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]" 265 */ 266 static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, 267 size_t size, loff_t *_pos) 268 { 269 struct afs_net *net = afs_proc2net(file); 270 char *kbuf, *name, *args; 271 int ret; 272 273 /* start by dragging the command into memory */ 274 if (size <= 1 || size >= PAGE_SIZE) 275 return -EINVAL; 276 277 kbuf = memdup_user_nul(buf, size); 278 if (IS_ERR(kbuf)) 279 return PTR_ERR(kbuf); 280 281 /* trim to first NL */ 282 name = memchr(kbuf, '\n', size); 283 if (name) 284 *name = 0; 285 286 /* split into command, name and argslist */ 287 name = strchr(kbuf, ' '); 288 if (!name) 289 goto inval; 290 do { 291 *name++ = 0; 292 } while(*name == ' '); 293 if (!*name) 294 goto inval; 295 296 args = strchr(name, ' '); 297 if (!args) 298 goto inval; 299 do { 300 *args++ = 0; 301 } while(*args == ' '); 302 if (!*args) 303 goto inval; 304 305 /* determine command to perform */ 306 _debug("cmd=%s name=%s args=%s", kbuf, name, args); 307 308 if (strcmp(kbuf, "add") == 0) { 309 struct afs_cell *cell; 310 311 cell = afs_lookup_cell(net, name, strlen(name), args, true); 312 if (IS_ERR(cell)) { 313 ret = PTR_ERR(cell); 314 goto done; 315 } 316 317 if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags)) 318 afs_put_cell(net, cell); 319 printk("kAFS: Added new cell '%s'\n", name); 320 } else { 321 goto inval; 322 } 323 324 ret = size; 325 326 done: 327 kfree(kbuf); 328 _leave(" = %d", ret); 329 return ret; 330 331 inval: 332 ret = -EINVAL; 333 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n"); 334 goto done; 335 } 336 337 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, 338 size_t size, loff_t *_pos) 339 { 340 struct afs_cell *cell; 341 struct afs_net *net = afs_proc2net(file); 342 unsigned int seq = 0; 343 char name[AFS_MAXCELLNAME + 1]; 344 int len; 345 346 if (*_pos > 0) 347 return 0; 348 if (!net->ws_cell) 349 return 0; 350 351 rcu_read_lock(); 352 do { 353 read_seqbegin_or_lock(&net->cells_lock, &seq); 354 len = 0; 355 cell = rcu_dereference_raw(net->ws_cell); 356 if (cell) { 357 len = cell->name_len; 358 memcpy(name, cell->name, len); 359 } 360 } while (need_seqretry(&net->cells_lock, seq)); 361 done_seqretry(&net->cells_lock, seq); 362 rcu_read_unlock(); 363 364 if (!len) 365 return 0; 366 367 name[len++] = '\n'; 368 if (len > size) 369 len = size; 370 if (copy_to_user(buf, name, len) != 0) 371 return -EFAULT; 372 *_pos = 1; 373 return len; 374 } 375 376 /* 377 * handle writes to /proc/fs/afs/rootcell 378 * - to initialize rootcell: echo "cell.name:192.168.231.14" 379 */ 380 static ssize_t afs_proc_rootcell_write(struct file *file, 381 const char __user *buf, 382 size_t size, loff_t *_pos) 383 { 384 struct afs_net *net = afs_proc2net(file); 385 char *kbuf, *s; 386 int ret; 387 388 /* start by dragging the command into memory */ 389 if (size <= 1 || size >= PAGE_SIZE) 390 return -EINVAL; 391 392 kbuf = memdup_user_nul(buf, size); 393 if (IS_ERR(kbuf)) 394 return PTR_ERR(kbuf); 395 396 ret = -EINVAL; 397 if (kbuf[0] == '.') 398 goto out; 399 if (memchr(kbuf, '/', size)) 400 goto out; 401 402 /* trim to first NL */ 403 s = memchr(kbuf, '\n', size); 404 if (s) 405 *s = 0; 406 407 /* determine command to perform */ 408 _debug("rootcell=%s", kbuf); 409 410 ret = afs_cell_init(net, kbuf); 411 if (ret >= 0) 412 ret = size; /* consume everything, always */ 413 414 out: 415 kfree(kbuf); 416 _leave(" = %d", ret); 417 return ret; 418 } 419 420 /* 421 * initialise /proc/fs/afs/<cell>/ 422 */ 423 int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell) 424 { 425 struct proc_dir_entry *dir; 426 427 _enter("%p{%s},%p", cell, cell->name, net->proc_afs); 428 429 dir = proc_mkdir(cell->name, net->proc_afs); 430 if (!dir) 431 goto error_dir; 432 433 if (!proc_create_data("vlservers", 0, dir, 434 &afs_proc_cell_vlservers_fops, cell) || 435 !proc_create_data("volumes", 0, dir, 436 &afs_proc_cell_volumes_fops, cell)) 437 goto error_tree; 438 439 _leave(" = 0"); 440 return 0; 441 442 error_tree: 443 remove_proc_subtree(cell->name, net->proc_afs); 444 error_dir: 445 _leave(" = -ENOMEM"); 446 return -ENOMEM; 447 } 448 449 /* 450 * remove /proc/fs/afs/<cell>/ 451 */ 452 void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell) 453 { 454 _enter(""); 455 456 remove_proc_subtree(cell->name, net->proc_afs); 457 458 _leave(""); 459 } 460 461 /* 462 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells 463 */ 464 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file) 465 { 466 struct afs_cell *cell; 467 struct seq_file *m; 468 int ret; 469 470 cell = PDE_DATA(inode); 471 if (!cell) 472 return -ENOENT; 473 474 ret = seq_open(file, &afs_proc_cell_volumes_ops); 475 if (ret < 0) 476 return ret; 477 478 m = file->private_data; 479 m->private = cell; 480 481 return 0; 482 } 483 484 /* 485 * set up the iterator to start reading from the cells list and return the 486 * first item 487 */ 488 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) 489 __acquires(cell->proc_lock) 490 { 491 struct afs_cell *cell = m->private; 492 493 _enter("cell=%p pos=%Ld", cell, *_pos); 494 495 read_lock(&cell->proc_lock); 496 return seq_list_start_head(&cell->proc_volumes, *_pos); 497 } 498 499 /* 500 * move to next cell in cells list 501 */ 502 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, 503 loff_t *_pos) 504 { 505 struct afs_cell *cell = p->private; 506 507 _enter("cell=%p pos=%Ld", cell, *_pos); 508 return seq_list_next(v, &cell->proc_volumes, _pos); 509 } 510 511 /* 512 * clean up after reading from the cells list 513 */ 514 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v) 515 __releases(cell->proc_lock) 516 { 517 struct afs_cell *cell = p->private; 518 519 read_unlock(&cell->proc_lock); 520 } 521 522 static const char afs_vol_types[3][3] = { 523 [AFSVL_RWVOL] = "RW", 524 [AFSVL_ROVOL] = "RO", 525 [AFSVL_BACKVOL] = "BK", 526 }; 527 528 /* 529 * display a header line followed by a load of volume lines 530 */ 531 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v) 532 { 533 struct afs_cell *cell = m->private; 534 struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link); 535 536 /* Display header on line 1 */ 537 if (v == &cell->proc_volumes) { 538 seq_puts(m, "USE VID TY\n"); 539 return 0; 540 } 541 542 seq_printf(m, "%3d %08x %s\n", 543 atomic_read(&vol->usage), vol->vid, 544 afs_vol_types[vol->type]); 545 546 return 0; 547 } 548 549 /* 550 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume 551 * location server 552 */ 553 static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file) 554 { 555 struct afs_cell *cell; 556 struct seq_file *m; 557 int ret; 558 559 cell = PDE_DATA(inode); 560 if (!cell) 561 return -ENOENT; 562 563 ret = seq_open(file, &afs_proc_cell_vlservers_ops); 564 if (ret<0) 565 return ret; 566 567 m = file->private_data; 568 m->private = cell; 569 570 return 0; 571 } 572 573 /* 574 * set up the iterator to start reading from the cells list and return the 575 * first item 576 */ 577 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) 578 __acquires(rcu) 579 { 580 struct afs_addr_list *alist; 581 struct afs_cell *cell = m->private; 582 loff_t pos = *_pos; 583 584 rcu_read_lock(); 585 586 alist = rcu_dereference(cell->vl_addrs); 587 588 /* allow for the header line */ 589 if (!pos) 590 return (void *) 1; 591 pos--; 592 593 if (!alist || pos >= alist->nr_addrs) 594 return NULL; 595 596 return alist->addrs + pos; 597 } 598 599 /* 600 * move to next cell in cells list 601 */ 602 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, 603 loff_t *_pos) 604 { 605 struct afs_addr_list *alist; 606 struct afs_cell *cell = p->private; 607 loff_t pos; 608 609 alist = rcu_dereference(cell->vl_addrs); 610 611 pos = *_pos; 612 (*_pos)++; 613 if (!alist || pos >= alist->nr_addrs) 614 return NULL; 615 616 return alist->addrs + pos; 617 } 618 619 /* 620 * clean up after reading from the cells list 621 */ 622 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v) 623 __releases(rcu) 624 { 625 rcu_read_unlock(); 626 } 627 628 /* 629 * display a header line followed by a load of volume lines 630 */ 631 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) 632 { 633 struct sockaddr_rxrpc *addr = v; 634 635 /* display header on line 1 */ 636 if (v == (void *)1) { 637 seq_puts(m, "ADDRESS\n"); 638 return 0; 639 } 640 641 /* display one cell per line on subsequent lines */ 642 seq_printf(m, "%pISp\n", &addr->transport); 643 return 0; 644 } 645 646 /* 647 * open "/proc/fs/afs/servers" which provides a summary of active 648 * servers 649 */ 650 static int afs_proc_servers_open(struct inode *inode, struct file *file) 651 { 652 return seq_open(file, &afs_proc_servers_ops); 653 } 654 655 /* 656 * Set up the iterator to start reading from the server list and return the 657 * first item. 658 */ 659 static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos) 660 __acquires(rcu) 661 { 662 struct afs_net *net = afs_seq2net(m); 663 664 rcu_read_lock(); 665 return seq_hlist_start_head_rcu(&net->fs_proc, *_pos); 666 } 667 668 /* 669 * move to next cell in cells list 670 */ 671 static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos) 672 { 673 struct afs_net *net = afs_seq2net(m); 674 675 return seq_hlist_next_rcu(v, &net->fs_proc, _pos); 676 } 677 678 /* 679 * clean up after reading from the cells list 680 */ 681 static void afs_proc_servers_stop(struct seq_file *p, void *v) 682 __releases(rcu) 683 { 684 rcu_read_unlock(); 685 } 686 687 /* 688 * display a header line followed by a load of volume lines 689 */ 690 static int afs_proc_servers_show(struct seq_file *m, void *v) 691 { 692 struct afs_server *server; 693 struct afs_addr_list *alist; 694 695 if (v == SEQ_START_TOKEN) { 696 seq_puts(m, "UUID USE ADDR\n"); 697 return 0; 698 } 699 700 server = list_entry(v, struct afs_server, proc_link); 701 alist = rcu_dereference(server->addresses); 702 seq_printf(m, "%pU %3d %pISp\n", 703 &server->uuid, 704 atomic_read(&server->usage), 705 &alist->addrs[alist->index].transport); 706 return 0; 707 } 708 709 void afs_put_sysnames(struct afs_sysnames *sysnames) 710 { 711 int i; 712 713 if (sysnames && refcount_dec_and_test(&sysnames->usage)) { 714 for (i = 0; i < sysnames->nr; i++) 715 if (sysnames->subs[i] != afs_init_sysname && 716 sysnames->subs[i] != sysnames->blank) 717 kfree(sysnames->subs[i]); 718 } 719 } 720 721 /* 722 * Handle opening of /proc/fs/afs/sysname. If it is opened for writing, we 723 * assume the caller wants to change the substitution list and we allocate a 724 * buffer to hold the list. 725 */ 726 static int afs_proc_sysname_open(struct inode *inode, struct file *file) 727 { 728 struct afs_sysnames *sysnames; 729 struct seq_file *m; 730 int ret; 731 732 ret = seq_open(file, &afs_proc_sysname_ops); 733 if (ret < 0) 734 return ret; 735 736 if (file->f_mode & FMODE_WRITE) { 737 sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL); 738 if (!sysnames) { 739 seq_release(inode, file); 740 return -ENOMEM; 741 } 742 743 refcount_set(&sysnames->usage, 1); 744 m = file->private_data; 745 m->private = sysnames; 746 } 747 748 return 0; 749 } 750 751 /* 752 * Handle writes to /proc/fs/afs/sysname to set the @sys substitution. 753 */ 754 static ssize_t afs_proc_sysname_write(struct file *file, 755 const char __user *buf, 756 size_t size, loff_t *_pos) 757 { 758 struct afs_sysnames *sysnames; 759 struct seq_file *m = file->private_data; 760 char *kbuf = NULL, *s, *p, *sub; 761 int ret, len; 762 763 sysnames = m->private; 764 if (!sysnames) 765 return -EINVAL; 766 if (sysnames->error) 767 return sysnames->error; 768 769 if (size >= PAGE_SIZE - 1) { 770 sysnames->error = -EINVAL; 771 return -EINVAL; 772 } 773 if (size == 0) 774 return 0; 775 776 kbuf = memdup_user_nul(buf, size); 777 if (IS_ERR(kbuf)) 778 return PTR_ERR(kbuf); 779 780 inode_lock(file_inode(file)); 781 782 p = kbuf; 783 while ((s = strsep(&p, " \t\n"))) { 784 len = strlen(s); 785 if (len == 0) 786 continue; 787 ret = -ENAMETOOLONG; 788 if (len >= AFSNAMEMAX) 789 goto error; 790 791 if (len >= 4 && 792 s[len - 4] == '@' && 793 s[len - 3] == 's' && 794 s[len - 2] == 'y' && 795 s[len - 1] == 's') 796 /* Protect against recursion */ 797 goto invalid; 798 799 if (s[0] == '.' && 800 (len < 2 || (len == 2 && s[1] == '.'))) 801 goto invalid; 802 803 if (memchr(s, '/', len)) 804 goto invalid; 805 806 ret = -EFBIG; 807 if (sysnames->nr >= AFS_NR_SYSNAME) 808 goto out; 809 810 if (strcmp(s, afs_init_sysname) == 0) { 811 sub = (char *)afs_init_sysname; 812 } else { 813 ret = -ENOMEM; 814 sub = kmemdup(s, len + 1, GFP_KERNEL); 815 if (!sub) 816 goto out; 817 } 818 819 sysnames->subs[sysnames->nr] = sub; 820 sysnames->nr++; 821 } 822 823 ret = size; /* consume everything, always */ 824 out: 825 inode_unlock(file_inode(file)); 826 kfree(kbuf); 827 return ret; 828 829 invalid: 830 ret = -EINVAL; 831 error: 832 sysnames->error = ret; 833 goto out; 834 } 835 836 static int afs_proc_sysname_release(struct inode *inode, struct file *file) 837 { 838 struct afs_sysnames *sysnames, *kill = NULL; 839 struct seq_file *m = file->private_data; 840 struct afs_net *net = afs_seq2net(m); 841 842 sysnames = m->private; 843 if (sysnames) { 844 if (!sysnames->error) { 845 kill = sysnames; 846 if (sysnames->nr == 0) { 847 sysnames->subs[0] = sysnames->blank; 848 sysnames->nr++; 849 } 850 write_lock(&net->sysnames_lock); 851 kill = net->sysnames; 852 net->sysnames = sysnames; 853 write_unlock(&net->sysnames_lock); 854 } 855 afs_put_sysnames(kill); 856 } 857 858 return seq_release(inode, file); 859 } 860 861 static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos) 862 __acquires(&net->sysnames_lock) 863 { 864 struct afs_net *net = afs_seq2net(m); 865 struct afs_sysnames *names = net->sysnames; 866 867 read_lock(&net->sysnames_lock); 868 869 if (*pos >= names->nr) 870 return NULL; 871 return (void *)(unsigned long)(*pos + 1); 872 } 873 874 static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos) 875 { 876 struct afs_net *net = afs_seq2net(m); 877 struct afs_sysnames *names = net->sysnames; 878 879 *pos += 1; 880 if (*pos >= names->nr) 881 return NULL; 882 return (void *)(unsigned long)(*pos + 1); 883 } 884 885 static void afs_proc_sysname_stop(struct seq_file *m, void *v) 886 __releases(&net->sysnames_lock) 887 { 888 struct afs_net *net = afs_seq2net(m); 889 890 read_unlock(&net->sysnames_lock); 891 } 892 893 static int afs_proc_sysname_show(struct seq_file *m, void *v) 894 { 895 struct afs_net *net = afs_seq2net(m); 896 struct afs_sysnames *sysnames = net->sysnames; 897 unsigned int i = (unsigned long)v - 1; 898 899 if (i < sysnames->nr) 900 seq_printf(m, "%s\n", sysnames->subs[i]); 901 return 0; 902 } 903 904 /* 905 * Display general per-net namespace statistics 906 */ 907 static int afs_proc_stats_show(struct seq_file *m, void *v) 908 { 909 struct afs_net *net = afs_seq2net(m); 910 911 seq_puts(m, "kAFS statistics\n"); 912 913 seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n", 914 atomic_read(&net->n_lookup), 915 atomic_read(&net->n_reval), 916 atomic_read(&net->n_inval), 917 atomic_read(&net->n_relpg)); 918 919 seq_printf(m, "dir-data: rdpg=%u\n", 920 atomic_read(&net->n_read_dir)); 921 922 seq_printf(m, "dir-edit: cr=%u rm=%u\n", 923 atomic_read(&net->n_dir_cr), 924 atomic_read(&net->n_dir_rm)); 925 926 seq_printf(m, "file-rd : n=%u nb=%lu\n", 927 atomic_read(&net->n_fetches), 928 atomic_long_read(&net->n_fetch_bytes)); 929 seq_printf(m, "file-wr : n=%u nb=%lu\n", 930 atomic_read(&net->n_stores), 931 atomic_long_read(&net->n_store_bytes)); 932 return 0; 933 } 934 935 /* 936 * Open "/proc/fs/afs/stats" to allow reading of the stat counters. 937 */ 938 static int afs_proc_stats_open(struct inode *inode, struct file *file) 939 { 940 return single_open(file, afs_proc_stats_show, NULL); 941 } 942 943 static const struct file_operations afs_proc_stats_fops = { 944 .open = afs_proc_stats_open, 945 .read = seq_read, 946 .llseek = seq_lseek, 947 .release = single_release, 948 }; 949