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 <asm/uaccess.h> 17 #include "internal.h" 18 19 static struct proc_dir_entry *proc_afs; 20 21 22 static int afs_proc_cells_open(struct inode *inode, struct file *file); 23 static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos); 24 static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos); 25 static void afs_proc_cells_stop(struct seq_file *p, void *v); 26 static int afs_proc_cells_show(struct seq_file *m, void *v); 27 static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, 28 size_t size, loff_t *_pos); 29 30 static struct seq_operations afs_proc_cells_ops = { 31 .start = afs_proc_cells_start, 32 .next = afs_proc_cells_next, 33 .stop = afs_proc_cells_stop, 34 .show = afs_proc_cells_show, 35 }; 36 37 static const struct file_operations afs_proc_cells_fops = { 38 .open = afs_proc_cells_open, 39 .read = seq_read, 40 .write = afs_proc_cells_write, 41 .llseek = seq_lseek, 42 .release = seq_release, 43 }; 44 45 static int afs_proc_rootcell_open(struct inode *inode, struct file *file); 46 static int afs_proc_rootcell_release(struct inode *inode, struct file *file); 47 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, 48 size_t size, loff_t *_pos); 49 static ssize_t afs_proc_rootcell_write(struct file *file, 50 const char __user *buf, 51 size_t size, loff_t *_pos); 52 53 static const struct file_operations afs_proc_rootcell_fops = { 54 .open = afs_proc_rootcell_open, 55 .read = afs_proc_rootcell_read, 56 .write = afs_proc_rootcell_write, 57 .llseek = no_llseek, 58 .release = afs_proc_rootcell_release 59 }; 60 61 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file); 62 static int afs_proc_cell_volumes_release(struct inode *inode, 63 struct file *file); 64 static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos); 65 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, 66 loff_t *pos); 67 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v); 68 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v); 69 70 static struct seq_operations afs_proc_cell_volumes_ops = { 71 .start = afs_proc_cell_volumes_start, 72 .next = afs_proc_cell_volumes_next, 73 .stop = afs_proc_cell_volumes_stop, 74 .show = afs_proc_cell_volumes_show, 75 }; 76 77 static const struct file_operations afs_proc_cell_volumes_fops = { 78 .open = afs_proc_cell_volumes_open, 79 .read = seq_read, 80 .llseek = seq_lseek, 81 .release = afs_proc_cell_volumes_release, 82 }; 83 84 static int afs_proc_cell_vlservers_open(struct inode *inode, 85 struct file *file); 86 static int afs_proc_cell_vlservers_release(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 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 = afs_proc_cell_vlservers_release, 106 }; 107 108 static int afs_proc_cell_servers_open(struct inode *inode, struct file *file); 109 static int afs_proc_cell_servers_release(struct inode *inode, 110 struct file *file); 111 static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos); 112 static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, 113 loff_t *pos); 114 static void afs_proc_cell_servers_stop(struct seq_file *p, void *v); 115 static int afs_proc_cell_servers_show(struct seq_file *m, void *v); 116 117 static struct seq_operations afs_proc_cell_servers_ops = { 118 .start = afs_proc_cell_servers_start, 119 .next = afs_proc_cell_servers_next, 120 .stop = afs_proc_cell_servers_stop, 121 .show = afs_proc_cell_servers_show, 122 }; 123 124 static const struct file_operations afs_proc_cell_servers_fops = { 125 .open = afs_proc_cell_servers_open, 126 .read = seq_read, 127 .llseek = seq_lseek, 128 .release = afs_proc_cell_servers_release, 129 }; 130 131 /* 132 * initialise the /proc/fs/afs/ directory 133 */ 134 int afs_proc_init(void) 135 { 136 struct proc_dir_entry *p; 137 138 _enter(""); 139 140 proc_afs = proc_mkdir("fs/afs", NULL); 141 if (!proc_afs) 142 goto error_dir; 143 proc_afs->owner = THIS_MODULE; 144 145 p = create_proc_entry("cells", 0, proc_afs); 146 if (!p) 147 goto error_cells; 148 p->proc_fops = &afs_proc_cells_fops; 149 p->owner = THIS_MODULE; 150 151 p = create_proc_entry("rootcell", 0, proc_afs); 152 if (!p) 153 goto error_rootcell; 154 p->proc_fops = &afs_proc_rootcell_fops; 155 p->owner = THIS_MODULE; 156 157 _leave(" = 0"); 158 return 0; 159 160 error_rootcell: 161 remove_proc_entry("cells", proc_afs); 162 error_cells: 163 remove_proc_entry("fs/afs", NULL); 164 error_dir: 165 _leave(" = -ENOMEM"); 166 return -ENOMEM; 167 } 168 169 /* 170 * clean up the /proc/fs/afs/ directory 171 */ 172 void afs_proc_cleanup(void) 173 { 174 remove_proc_entry("rootcell", proc_afs); 175 remove_proc_entry("cells", proc_afs); 176 remove_proc_entry("fs/afs", NULL); 177 } 178 179 /* 180 * open "/proc/fs/afs/cells" which provides a summary of extant cells 181 */ 182 static int afs_proc_cells_open(struct inode *inode, struct file *file) 183 { 184 struct seq_file *m; 185 int ret; 186 187 ret = seq_open(file, &afs_proc_cells_ops); 188 if (ret < 0) 189 return ret; 190 191 m = file->private_data; 192 m->private = PDE(inode)->data; 193 194 return 0; 195 } 196 197 /* 198 * set up the iterator to start reading from the cells list and return the 199 * first item 200 */ 201 static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos) 202 { 203 struct list_head *_p; 204 loff_t pos = *_pos; 205 206 /* lock the list against modification */ 207 down_read(&afs_proc_cells_sem); 208 209 /* allow for the header line */ 210 if (!pos) 211 return (void *) 1; 212 pos--; 213 214 /* find the n'th element in the list */ 215 list_for_each(_p, &afs_proc_cells) 216 if (!pos--) 217 break; 218 219 return _p != &afs_proc_cells ? _p : NULL; 220 } 221 222 /* 223 * move to next cell in cells list 224 */ 225 static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos) 226 { 227 struct list_head *_p; 228 229 (*pos)++; 230 231 _p = v; 232 _p = v == (void *) 1 ? afs_proc_cells.next : _p->next; 233 234 return _p != &afs_proc_cells ? _p : NULL; 235 } 236 237 /* 238 * clean up after reading from the cells list 239 */ 240 static void afs_proc_cells_stop(struct seq_file *p, void *v) 241 { 242 up_read(&afs_proc_cells_sem); 243 } 244 245 /* 246 * display a header line followed by a load of cell lines 247 */ 248 static int afs_proc_cells_show(struct seq_file *m, void *v) 249 { 250 struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link); 251 252 if (v == (void *) 1) { 253 /* display header on line 1 */ 254 seq_puts(m, "USE NAME\n"); 255 return 0; 256 } 257 258 /* display one cell per line on subsequent lines */ 259 seq_printf(m, "%3d %s\n", 260 atomic_read(&cell->usage), cell->name); 261 return 0; 262 } 263 264 /* 265 * handle writes to /proc/fs/afs/cells 266 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]" 267 */ 268 static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, 269 size_t size, loff_t *_pos) 270 { 271 char *kbuf, *name, *args; 272 int ret; 273 274 /* start by dragging the command into memory */ 275 if (size <= 1 || size >= PAGE_SIZE) 276 return -EINVAL; 277 278 kbuf = kmalloc(size + 1, GFP_KERNEL); 279 if (!kbuf) 280 return -ENOMEM; 281 282 ret = -EFAULT; 283 if (copy_from_user(kbuf, buf, size) != 0) 284 goto done; 285 kbuf[size] = 0; 286 287 /* trim to first NL */ 288 name = memchr(kbuf, '\n', size); 289 if (name) 290 *name = 0; 291 292 /* split into command, name and argslist */ 293 name = strchr(kbuf, ' '); 294 if (!name) 295 goto inval; 296 do { 297 *name++ = 0; 298 } while(*name == ' '); 299 if (!*name) 300 goto inval; 301 302 args = strchr(name, ' '); 303 if (!args) 304 goto inval; 305 do { 306 *args++ = 0; 307 } while(*args == ' '); 308 if (!*args) 309 goto inval; 310 311 /* determine command to perform */ 312 _debug("cmd=%s name=%s args=%s", kbuf, name, args); 313 314 if (strcmp(kbuf, "add") == 0) { 315 struct afs_cell *cell; 316 317 cell = afs_cell_create(name, args); 318 if (IS_ERR(cell)) { 319 ret = PTR_ERR(cell); 320 goto done; 321 } 322 323 afs_put_cell(cell); 324 printk("kAFS: Added new cell '%s'\n", name); 325 } else { 326 goto inval; 327 } 328 329 ret = size; 330 331 done: 332 kfree(kbuf); 333 _leave(" = %d", ret); 334 return ret; 335 336 inval: 337 ret = -EINVAL; 338 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n"); 339 goto done; 340 } 341 342 /* 343 * Stubs for /proc/fs/afs/rootcell 344 */ 345 static int afs_proc_rootcell_open(struct inode *inode, struct file *file) 346 { 347 return 0; 348 } 349 350 static int afs_proc_rootcell_release(struct inode *inode, struct file *file) 351 { 352 return 0; 353 } 354 355 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, 356 size_t size, loff_t *_pos) 357 { 358 return 0; 359 } 360 361 /* 362 * handle writes to /proc/fs/afs/rootcell 363 * - to initialize rootcell: echo "cell.name:192.168.231.14" 364 */ 365 static ssize_t afs_proc_rootcell_write(struct file *file, 366 const char __user *buf, 367 size_t size, loff_t *_pos) 368 { 369 char *kbuf, *s; 370 int ret; 371 372 /* start by dragging the command into memory */ 373 if (size <= 1 || size >= PAGE_SIZE) 374 return -EINVAL; 375 376 ret = -ENOMEM; 377 kbuf = kmalloc(size + 1, GFP_KERNEL); 378 if (!kbuf) 379 goto nomem; 380 381 ret = -EFAULT; 382 if (copy_from_user(kbuf, buf, size) != 0) 383 goto infault; 384 kbuf[size] = 0; 385 386 /* trim to first NL */ 387 s = memchr(kbuf, '\n', size); 388 if (s) 389 *s = 0; 390 391 /* determine command to perform */ 392 _debug("rootcell=%s", kbuf); 393 394 ret = afs_cell_init(kbuf); 395 if (ret >= 0) 396 ret = size; /* consume everything, always */ 397 398 infault: 399 kfree(kbuf); 400 nomem: 401 _leave(" = %d", ret); 402 return ret; 403 } 404 405 /* 406 * initialise /proc/fs/afs/<cell>/ 407 */ 408 int afs_proc_cell_setup(struct afs_cell *cell) 409 { 410 struct proc_dir_entry *p; 411 412 _enter("%p{%s}", cell, cell->name); 413 414 cell->proc_dir = proc_mkdir(cell->name, proc_afs); 415 if (!cell->proc_dir) 416 goto error_dir; 417 418 p = create_proc_entry("servers", 0, cell->proc_dir); 419 if (!p) 420 goto error_servers; 421 p->proc_fops = &afs_proc_cell_servers_fops; 422 p->owner = THIS_MODULE; 423 p->data = cell; 424 425 p = create_proc_entry("vlservers", 0, cell->proc_dir); 426 if (!p) 427 goto error_vlservers; 428 p->proc_fops = &afs_proc_cell_vlservers_fops; 429 p->owner = THIS_MODULE; 430 p->data = cell; 431 432 p = create_proc_entry("volumes", 0, cell->proc_dir); 433 if (!p) 434 goto error_volumes; 435 p->proc_fops = &afs_proc_cell_volumes_fops; 436 p->owner = THIS_MODULE; 437 p->data = cell; 438 439 _leave(" = 0"); 440 return 0; 441 442 error_volumes: 443 remove_proc_entry("vlservers", cell->proc_dir); 444 error_vlservers: 445 remove_proc_entry("servers", cell->proc_dir); 446 error_servers: 447 remove_proc_entry(cell->name, proc_afs); 448 error_dir: 449 _leave(" = -ENOMEM"); 450 return -ENOMEM; 451 } 452 453 /* 454 * remove /proc/fs/afs/<cell>/ 455 */ 456 void afs_proc_cell_remove(struct afs_cell *cell) 457 { 458 _enter(""); 459 460 remove_proc_entry("volumes", cell->proc_dir); 461 remove_proc_entry("vlservers", cell->proc_dir); 462 remove_proc_entry("servers", cell->proc_dir); 463 remove_proc_entry(cell->name, proc_afs); 464 465 _leave(""); 466 } 467 468 /* 469 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells 470 */ 471 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file) 472 { 473 struct afs_cell *cell; 474 struct seq_file *m; 475 int ret; 476 477 cell = PDE(inode)->data; 478 if (!cell) 479 return -ENOENT; 480 481 ret = seq_open(file, &afs_proc_cell_volumes_ops); 482 if (ret < 0) 483 return ret; 484 485 m = file->private_data; 486 m->private = cell; 487 488 return 0; 489 } 490 491 /* 492 * close the file and release the ref to the cell 493 */ 494 static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file) 495 { 496 return seq_release(inode, file); 497 } 498 499 /* 500 * set up the iterator to start reading from the cells list and return the 501 * first item 502 */ 503 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) 504 { 505 struct list_head *_p; 506 struct afs_cell *cell = m->private; 507 loff_t pos = *_pos; 508 509 _enter("cell=%p pos=%Ld", cell, *_pos); 510 511 /* lock the list against modification */ 512 down_read(&cell->vl_sem); 513 514 /* allow for the header line */ 515 if (!pos) 516 return (void *) 1; 517 pos--; 518 519 /* find the n'th element in the list */ 520 list_for_each(_p, &cell->vl_list) 521 if (!pos--) 522 break; 523 524 return _p != &cell->vl_list ? _p : NULL; 525 } 526 527 /* 528 * move to next cell in cells list 529 */ 530 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, 531 loff_t *_pos) 532 { 533 struct list_head *_p; 534 struct afs_cell *cell = p->private; 535 536 _enter("cell=%p pos=%Ld", cell, *_pos); 537 538 (*_pos)++; 539 540 _p = v; 541 _p = (v == (void *) 1) ? cell->vl_list.next : _p->next; 542 543 return (_p != &cell->vl_list) ? _p : NULL; 544 } 545 546 /* 547 * clean up after reading from the cells list 548 */ 549 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v) 550 { 551 struct afs_cell *cell = p->private; 552 553 up_read(&cell->vl_sem); 554 } 555 556 const char afs_vlocation_states[][4] = { 557 [AFS_VL_NEW] = "New", 558 [AFS_VL_CREATING] = "Crt", 559 [AFS_VL_VALID] = "Val", 560 [AFS_VL_NO_VOLUME] = "NoV", 561 [AFS_VL_UPDATING] = "Upd", 562 [AFS_VL_VOLUME_DELETED] = "Del", 563 [AFS_VL_UNCERTAIN] = "Unc", 564 }; 565 566 /* 567 * display a header line followed by a load of volume lines 568 */ 569 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v) 570 { 571 struct afs_vlocation *vlocation = 572 list_entry(v, struct afs_vlocation, link); 573 574 /* display header on line 1 */ 575 if (v == (void *) 1) { 576 seq_puts(m, "USE STT VLID[0] VLID[1] VLID[2] NAME\n"); 577 return 0; 578 } 579 580 /* display one cell per line on subsequent lines */ 581 seq_printf(m, "%3d %s %08x %08x %08x %s\n", 582 atomic_read(&vlocation->usage), 583 afs_vlocation_states[vlocation->state], 584 vlocation->vldb.vid[0], 585 vlocation->vldb.vid[1], 586 vlocation->vldb.vid[2], 587 vlocation->vldb.name); 588 589 return 0; 590 } 591 592 /* 593 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume 594 * location server 595 */ 596 static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file) 597 { 598 struct afs_cell *cell; 599 struct seq_file *m; 600 int ret; 601 602 cell = PDE(inode)->data; 603 if (!cell) 604 return -ENOENT; 605 606 ret = seq_open(file, &afs_proc_cell_vlservers_ops); 607 if (ret<0) 608 return ret; 609 610 m = file->private_data; 611 m->private = cell; 612 613 return 0; 614 } 615 616 /* 617 * close the file and release the ref to the cell 618 */ 619 static int afs_proc_cell_vlservers_release(struct inode *inode, 620 struct file *file) 621 { 622 return seq_release(inode, file); 623 } 624 625 /* 626 * set up the iterator to start reading from the cells list and return the 627 * first item 628 */ 629 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) 630 { 631 struct afs_cell *cell = m->private; 632 loff_t pos = *_pos; 633 634 _enter("cell=%p pos=%Ld", cell, *_pos); 635 636 /* lock the list against modification */ 637 down_read(&cell->vl_sem); 638 639 /* allow for the header line */ 640 if (!pos) 641 return (void *) 1; 642 pos--; 643 644 if (pos >= cell->vl_naddrs) 645 return NULL; 646 647 return &cell->vl_addrs[pos]; 648 } 649 650 /* 651 * move to next cell in cells list 652 */ 653 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, 654 loff_t *_pos) 655 { 656 struct afs_cell *cell = p->private; 657 loff_t pos; 658 659 _enter("cell=%p{nad=%u} pos=%Ld", cell, cell->vl_naddrs, *_pos); 660 661 pos = *_pos; 662 (*_pos)++; 663 if (pos >= cell->vl_naddrs) 664 return NULL; 665 666 return &cell->vl_addrs[pos]; 667 } 668 669 /* 670 * clean up after reading from the cells list 671 */ 672 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v) 673 { 674 struct afs_cell *cell = p->private; 675 676 up_read(&cell->vl_sem); 677 } 678 679 /* 680 * display a header line followed by a load of volume lines 681 */ 682 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) 683 { 684 struct in_addr *addr = v; 685 686 /* display header on line 1 */ 687 if (v == (struct in_addr *) 1) { 688 seq_puts(m, "ADDRESS\n"); 689 return 0; 690 } 691 692 /* display one cell per line on subsequent lines */ 693 seq_printf(m, "%u.%u.%u.%u\n", NIPQUAD(addr->s_addr)); 694 return 0; 695 } 696 697 /* 698 * open "/proc/fs/afs/<cell>/servers" which provides a summary of active 699 * servers 700 */ 701 static int afs_proc_cell_servers_open(struct inode *inode, struct file *file) 702 { 703 struct afs_cell *cell; 704 struct seq_file *m; 705 int ret; 706 707 cell = PDE(inode)->data; 708 if (!cell) 709 return -ENOENT; 710 711 ret = seq_open(file, &afs_proc_cell_servers_ops); 712 if (ret < 0) 713 return ret; 714 715 m = file->private_data; 716 m->private = cell; 717 return 0; 718 } 719 720 /* 721 * close the file and release the ref to the cell 722 */ 723 static int afs_proc_cell_servers_release(struct inode *inode, 724 struct file *file) 725 { 726 return seq_release(inode, file); 727 } 728 729 /* 730 * set up the iterator to start reading from the cells list and return the 731 * first item 732 */ 733 static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos) 734 __acquires(m->private->servers_lock) 735 { 736 struct list_head *_p; 737 struct afs_cell *cell = m->private; 738 loff_t pos = *_pos; 739 740 _enter("cell=%p pos=%Ld", cell, *_pos); 741 742 /* lock the list against modification */ 743 read_lock(&cell->servers_lock); 744 745 /* allow for the header line */ 746 if (!pos) 747 return (void *) 1; 748 pos--; 749 750 /* find the n'th element in the list */ 751 list_for_each(_p, &cell->servers) 752 if (!pos--) 753 break; 754 755 return _p != &cell->servers ? _p : NULL; 756 } 757 758 /* 759 * move to next cell in cells list 760 */ 761 static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, 762 loff_t *_pos) 763 { 764 struct list_head *_p; 765 struct afs_cell *cell = p->private; 766 767 _enter("cell=%p pos=%Ld", cell, *_pos); 768 769 (*_pos)++; 770 771 _p = v; 772 _p = v == (void *) 1 ? cell->servers.next : _p->next; 773 774 return _p != &cell->servers ? _p : NULL; 775 } 776 777 /* 778 * clean up after reading from the cells list 779 */ 780 static void afs_proc_cell_servers_stop(struct seq_file *p, void *v) 781 __releases(p->private->servers_lock) 782 { 783 struct afs_cell *cell = p->private; 784 785 read_unlock(&cell->servers_lock); 786 } 787 788 /* 789 * display a header line followed by a load of volume lines 790 */ 791 static int afs_proc_cell_servers_show(struct seq_file *m, void *v) 792 { 793 struct afs_server *server = list_entry(v, struct afs_server, link); 794 char ipaddr[20]; 795 796 /* display header on line 1 */ 797 if (v == (void *) 1) { 798 seq_puts(m, "USE ADDR STATE\n"); 799 return 0; 800 } 801 802 /* display one cell per line on subsequent lines */ 803 sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(server->addr)); 804 seq_printf(m, "%3d %-15.15s %5d\n", 805 atomic_read(&server->usage), ipaddr, server->fs_state); 806 807 return 0; 808 } 809