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