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