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