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 /* lock the list against modification */ 205 down_read(&afs_proc_cells_sem); 206 return seq_list_start_head(&afs_proc_cells, *_pos); 207 } 208 209 /* 210 * move to next cell in cells list 211 */ 212 static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos) 213 { 214 return seq_list_next(v, &afs_proc_cells, pos); 215 } 216 217 /* 218 * clean up after reading from the cells list 219 */ 220 static void afs_proc_cells_stop(struct seq_file *p, void *v) 221 { 222 up_read(&afs_proc_cells_sem); 223 } 224 225 /* 226 * display a header line followed by a load of cell lines 227 */ 228 static int afs_proc_cells_show(struct seq_file *m, void *v) 229 { 230 struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link); 231 232 if (v == &afs_proc_cells) { 233 /* display header on line 1 */ 234 seq_puts(m, "USE NAME\n"); 235 return 0; 236 } 237 238 /* display one cell per line on subsequent lines */ 239 seq_printf(m, "%3d %s\n", 240 atomic_read(&cell->usage), cell->name); 241 return 0; 242 } 243 244 /* 245 * handle writes to /proc/fs/afs/cells 246 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]" 247 */ 248 static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, 249 size_t size, loff_t *_pos) 250 { 251 char *kbuf, *name, *args; 252 int ret; 253 254 /* start by dragging the command into memory */ 255 if (size <= 1 || size >= PAGE_SIZE) 256 return -EINVAL; 257 258 kbuf = kmalloc(size + 1, GFP_KERNEL); 259 if (!kbuf) 260 return -ENOMEM; 261 262 ret = -EFAULT; 263 if (copy_from_user(kbuf, buf, size) != 0) 264 goto done; 265 kbuf[size] = 0; 266 267 /* trim to first NL */ 268 name = memchr(kbuf, '\n', size); 269 if (name) 270 *name = 0; 271 272 /* split into command, name and argslist */ 273 name = strchr(kbuf, ' '); 274 if (!name) 275 goto inval; 276 do { 277 *name++ = 0; 278 } while(*name == ' '); 279 if (!*name) 280 goto inval; 281 282 args = strchr(name, ' '); 283 if (!args) 284 goto inval; 285 do { 286 *args++ = 0; 287 } while(*args == ' '); 288 if (!*args) 289 goto inval; 290 291 /* determine command to perform */ 292 _debug("cmd=%s name=%s args=%s", kbuf, name, args); 293 294 if (strcmp(kbuf, "add") == 0) { 295 struct afs_cell *cell; 296 297 cell = afs_cell_create(name, args); 298 if (IS_ERR(cell)) { 299 ret = PTR_ERR(cell); 300 goto done; 301 } 302 303 afs_put_cell(cell); 304 printk("kAFS: Added new cell '%s'\n", name); 305 } else { 306 goto inval; 307 } 308 309 ret = size; 310 311 done: 312 kfree(kbuf); 313 _leave(" = %d", ret); 314 return ret; 315 316 inval: 317 ret = -EINVAL; 318 printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n"); 319 goto done; 320 } 321 322 /* 323 * Stubs for /proc/fs/afs/rootcell 324 */ 325 static int afs_proc_rootcell_open(struct inode *inode, struct file *file) 326 { 327 return 0; 328 } 329 330 static int afs_proc_rootcell_release(struct inode *inode, struct file *file) 331 { 332 return 0; 333 } 334 335 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, 336 size_t size, loff_t *_pos) 337 { 338 return 0; 339 } 340 341 /* 342 * handle writes to /proc/fs/afs/rootcell 343 * - to initialize rootcell: echo "cell.name:192.168.231.14" 344 */ 345 static ssize_t afs_proc_rootcell_write(struct file *file, 346 const char __user *buf, 347 size_t size, loff_t *_pos) 348 { 349 char *kbuf, *s; 350 int ret; 351 352 /* start by dragging the command into memory */ 353 if (size <= 1 || size >= PAGE_SIZE) 354 return -EINVAL; 355 356 ret = -ENOMEM; 357 kbuf = kmalloc(size + 1, GFP_KERNEL); 358 if (!kbuf) 359 goto nomem; 360 361 ret = -EFAULT; 362 if (copy_from_user(kbuf, buf, size) != 0) 363 goto infault; 364 kbuf[size] = 0; 365 366 /* trim to first NL */ 367 s = memchr(kbuf, '\n', size); 368 if (s) 369 *s = 0; 370 371 /* determine command to perform */ 372 _debug("rootcell=%s", kbuf); 373 374 ret = afs_cell_init(kbuf); 375 if (ret >= 0) 376 ret = size; /* consume everything, always */ 377 378 infault: 379 kfree(kbuf); 380 nomem: 381 _leave(" = %d", ret); 382 return ret; 383 } 384 385 /* 386 * initialise /proc/fs/afs/<cell>/ 387 */ 388 int afs_proc_cell_setup(struct afs_cell *cell) 389 { 390 struct proc_dir_entry *p; 391 392 _enter("%p{%s}", cell, cell->name); 393 394 cell->proc_dir = proc_mkdir(cell->name, proc_afs); 395 if (!cell->proc_dir) 396 goto error_dir; 397 398 p = create_proc_entry("servers", 0, cell->proc_dir); 399 if (!p) 400 goto error_servers; 401 p->proc_fops = &afs_proc_cell_servers_fops; 402 p->owner = THIS_MODULE; 403 p->data = cell; 404 405 p = create_proc_entry("vlservers", 0, cell->proc_dir); 406 if (!p) 407 goto error_vlservers; 408 p->proc_fops = &afs_proc_cell_vlservers_fops; 409 p->owner = THIS_MODULE; 410 p->data = cell; 411 412 p = create_proc_entry("volumes", 0, cell->proc_dir); 413 if (!p) 414 goto error_volumes; 415 p->proc_fops = &afs_proc_cell_volumes_fops; 416 p->owner = THIS_MODULE; 417 p->data = cell; 418 419 _leave(" = 0"); 420 return 0; 421 422 error_volumes: 423 remove_proc_entry("vlservers", cell->proc_dir); 424 error_vlservers: 425 remove_proc_entry("servers", cell->proc_dir); 426 error_servers: 427 remove_proc_entry(cell->name, proc_afs); 428 error_dir: 429 _leave(" = -ENOMEM"); 430 return -ENOMEM; 431 } 432 433 /* 434 * remove /proc/fs/afs/<cell>/ 435 */ 436 void afs_proc_cell_remove(struct afs_cell *cell) 437 { 438 _enter(""); 439 440 remove_proc_entry("volumes", cell->proc_dir); 441 remove_proc_entry("vlservers", cell->proc_dir); 442 remove_proc_entry("servers", cell->proc_dir); 443 remove_proc_entry(cell->name, proc_afs); 444 445 _leave(""); 446 } 447 448 /* 449 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells 450 */ 451 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file) 452 { 453 struct afs_cell *cell; 454 struct seq_file *m; 455 int ret; 456 457 cell = PDE(inode)->data; 458 if (!cell) 459 return -ENOENT; 460 461 ret = seq_open(file, &afs_proc_cell_volumes_ops); 462 if (ret < 0) 463 return ret; 464 465 m = file->private_data; 466 m->private = cell; 467 468 return 0; 469 } 470 471 /* 472 * close the file and release the ref to the cell 473 */ 474 static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file) 475 { 476 return seq_release(inode, file); 477 } 478 479 /* 480 * set up the iterator to start reading from the cells list and return the 481 * first item 482 */ 483 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) 484 { 485 struct afs_cell *cell = m->private; 486 487 _enter("cell=%p pos=%Ld", cell, *_pos); 488 489 /* lock the list against modification */ 490 down_read(&cell->vl_sem); 491 return seq_list_start_head(&cell->vl_list, *_pos); 492 } 493 494 /* 495 * move to next cell in cells list 496 */ 497 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, 498 loff_t *_pos) 499 { 500 struct afs_cell *cell = p->private; 501 502 _enter("cell=%p pos=%Ld", cell, *_pos); 503 return seq_list_next(v, &cell->vl_list, _pos); 504 } 505 506 /* 507 * clean up after reading from the cells list 508 */ 509 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v) 510 { 511 struct afs_cell *cell = p->private; 512 513 up_read(&cell->vl_sem); 514 } 515 516 const char afs_vlocation_states[][4] = { 517 [AFS_VL_NEW] = "New", 518 [AFS_VL_CREATING] = "Crt", 519 [AFS_VL_VALID] = "Val", 520 [AFS_VL_NO_VOLUME] = "NoV", 521 [AFS_VL_UPDATING] = "Upd", 522 [AFS_VL_VOLUME_DELETED] = "Del", 523 [AFS_VL_UNCERTAIN] = "Unc", 524 }; 525 526 /* 527 * display a header line followed by a load of volume lines 528 */ 529 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v) 530 { 531 struct afs_cell *cell = m->private; 532 struct afs_vlocation *vlocation = 533 list_entry(v, struct afs_vlocation, link); 534 535 /* display header on line 1 */ 536 if (v == &cell->vl_list) { 537 seq_puts(m, "USE STT VLID[0] VLID[1] VLID[2] NAME\n"); 538 return 0; 539 } 540 541 /* display one cell per line on subsequent lines */ 542 seq_printf(m, "%3d %s %08x %08x %08x %s\n", 543 atomic_read(&vlocation->usage), 544 afs_vlocation_states[vlocation->state], 545 vlocation->vldb.vid[0], 546 vlocation->vldb.vid[1], 547 vlocation->vldb.vid[2], 548 vlocation->vldb.name); 549 550 return 0; 551 } 552 553 /* 554 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume 555 * location server 556 */ 557 static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file) 558 { 559 struct afs_cell *cell; 560 struct seq_file *m; 561 int ret; 562 563 cell = PDE(inode)->data; 564 if (!cell) 565 return -ENOENT; 566 567 ret = seq_open(file, &afs_proc_cell_vlservers_ops); 568 if (ret<0) 569 return ret; 570 571 m = file->private_data; 572 m->private = cell; 573 574 return 0; 575 } 576 577 /* 578 * close the file and release the ref to the cell 579 */ 580 static int afs_proc_cell_vlservers_release(struct inode *inode, 581 struct file *file) 582 { 583 return seq_release(inode, file); 584 } 585 586 /* 587 * set up the iterator to start reading from the cells list and return the 588 * first item 589 */ 590 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) 591 { 592 struct afs_cell *cell = m->private; 593 loff_t pos = *_pos; 594 595 _enter("cell=%p pos=%Ld", cell, *_pos); 596 597 /* lock the list against modification */ 598 down_read(&cell->vl_sem); 599 600 /* allow for the header line */ 601 if (!pos) 602 return (void *) 1; 603 pos--; 604 605 if (pos >= cell->vl_naddrs) 606 return NULL; 607 608 return &cell->vl_addrs[pos]; 609 } 610 611 /* 612 * move to next cell in cells list 613 */ 614 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, 615 loff_t *_pos) 616 { 617 struct afs_cell *cell = p->private; 618 loff_t pos; 619 620 _enter("cell=%p{nad=%u} pos=%Ld", cell, cell->vl_naddrs, *_pos); 621 622 pos = *_pos; 623 (*_pos)++; 624 if (pos >= cell->vl_naddrs) 625 return NULL; 626 627 return &cell->vl_addrs[pos]; 628 } 629 630 /* 631 * clean up after reading from the cells list 632 */ 633 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v) 634 { 635 struct afs_cell *cell = p->private; 636 637 up_read(&cell->vl_sem); 638 } 639 640 /* 641 * display a header line followed by a load of volume lines 642 */ 643 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) 644 { 645 struct in_addr *addr = v; 646 647 /* display header on line 1 */ 648 if (v == (struct in_addr *) 1) { 649 seq_puts(m, "ADDRESS\n"); 650 return 0; 651 } 652 653 /* display one cell per line on subsequent lines */ 654 seq_printf(m, "%u.%u.%u.%u\n", NIPQUAD(addr->s_addr)); 655 return 0; 656 } 657 658 /* 659 * open "/proc/fs/afs/<cell>/servers" which provides a summary of active 660 * servers 661 */ 662 static int afs_proc_cell_servers_open(struct inode *inode, struct file *file) 663 { 664 struct afs_cell *cell; 665 struct seq_file *m; 666 int ret; 667 668 cell = PDE(inode)->data; 669 if (!cell) 670 return -ENOENT; 671 672 ret = seq_open(file, &afs_proc_cell_servers_ops); 673 if (ret < 0) 674 return ret; 675 676 m = file->private_data; 677 m->private = cell; 678 return 0; 679 } 680 681 /* 682 * close the file and release the ref to the cell 683 */ 684 static int afs_proc_cell_servers_release(struct inode *inode, 685 struct file *file) 686 { 687 return seq_release(inode, file); 688 } 689 690 /* 691 * set up the iterator to start reading from the cells list and return the 692 * first item 693 */ 694 static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos) 695 __acquires(m->private->servers_lock) 696 { 697 struct afs_cell *cell = m->private; 698 699 _enter("cell=%p pos=%Ld", cell, *_pos); 700 701 /* lock the list against modification */ 702 read_lock(&cell->servers_lock); 703 return seq_list_start_head(&cell->servers, *_pos); 704 } 705 706 /* 707 * move to next cell in cells list 708 */ 709 static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, 710 loff_t *_pos) 711 { 712 struct afs_cell *cell = p->private; 713 714 _enter("cell=%p pos=%Ld", cell, *_pos); 715 return seq_list_next(v, &cell->servers, _pos); 716 } 717 718 /* 719 * clean up after reading from the cells list 720 */ 721 static void afs_proc_cell_servers_stop(struct seq_file *p, void *v) 722 __releases(p->private->servers_lock) 723 { 724 struct afs_cell *cell = p->private; 725 726 read_unlock(&cell->servers_lock); 727 } 728 729 /* 730 * display a header line followed by a load of volume lines 731 */ 732 static int afs_proc_cell_servers_show(struct seq_file *m, void *v) 733 { 734 struct afs_cell *cell = m->private; 735 struct afs_server *server = list_entry(v, struct afs_server, link); 736 char ipaddr[20]; 737 738 /* display header on line 1 */ 739 if (v == &cell->servers) { 740 seq_puts(m, "USE ADDR STATE\n"); 741 return 0; 742 } 743 744 /* display one cell per line on subsequent lines */ 745 sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(server->addr)); 746 seq_printf(m, "%3d %-15.15s %5d\n", 747 atomic_read(&server->usage), ipaddr, server->fs_state); 748 749 return 0; 750 } 751