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 const 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 const 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 const 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 const 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 150 p = proc_create("cells", 0, proc_afs, &afs_proc_cells_fops); 151 if (!p) 152 goto error_cells; 153 154 p = proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops); 155 if (!p) 156 goto error_rootcell; 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, strlen(name), args, false); 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 = proc_create_data("servers", 0, cell->proc_dir, 399 &afs_proc_cell_servers_fops, cell); 400 if (!p) 401 goto error_servers; 402 403 p = proc_create_data("vlservers", 0, cell->proc_dir, 404 &afs_proc_cell_vlservers_fops, cell); 405 if (!p) 406 goto error_vlservers; 407 408 p = proc_create_data("volumes", 0, cell->proc_dir, 409 &afs_proc_cell_volumes_fops, cell); 410 if (!p) 411 goto error_volumes; 412 413 _leave(" = 0"); 414 return 0; 415 416 error_volumes: 417 remove_proc_entry("vlservers", cell->proc_dir); 418 error_vlservers: 419 remove_proc_entry("servers", cell->proc_dir); 420 error_servers: 421 remove_proc_entry(cell->name, proc_afs); 422 error_dir: 423 _leave(" = -ENOMEM"); 424 return -ENOMEM; 425 } 426 427 /* 428 * remove /proc/fs/afs/<cell>/ 429 */ 430 void afs_proc_cell_remove(struct afs_cell *cell) 431 { 432 _enter(""); 433 434 remove_proc_entry("volumes", cell->proc_dir); 435 remove_proc_entry("vlservers", cell->proc_dir); 436 remove_proc_entry("servers", cell->proc_dir); 437 remove_proc_entry(cell->name, proc_afs); 438 439 _leave(""); 440 } 441 442 /* 443 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells 444 */ 445 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file) 446 { 447 struct afs_cell *cell; 448 struct seq_file *m; 449 int ret; 450 451 cell = PDE(inode)->data; 452 if (!cell) 453 return -ENOENT; 454 455 ret = seq_open(file, &afs_proc_cell_volumes_ops); 456 if (ret < 0) 457 return ret; 458 459 m = file->private_data; 460 m->private = cell; 461 462 return 0; 463 } 464 465 /* 466 * close the file and release the ref to the cell 467 */ 468 static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file) 469 { 470 return seq_release(inode, file); 471 } 472 473 /* 474 * set up the iterator to start reading from the cells list and return the 475 * first item 476 */ 477 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) 478 { 479 struct afs_cell *cell = m->private; 480 481 _enter("cell=%p pos=%Ld", cell, *_pos); 482 483 /* lock the list against modification */ 484 down_read(&cell->vl_sem); 485 return seq_list_start_head(&cell->vl_list, *_pos); 486 } 487 488 /* 489 * move to next cell in cells list 490 */ 491 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, 492 loff_t *_pos) 493 { 494 struct afs_cell *cell = p->private; 495 496 _enter("cell=%p pos=%Ld", cell, *_pos); 497 return seq_list_next(v, &cell->vl_list, _pos); 498 } 499 500 /* 501 * clean up after reading from the cells list 502 */ 503 static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v) 504 { 505 struct afs_cell *cell = p->private; 506 507 up_read(&cell->vl_sem); 508 } 509 510 static const char afs_vlocation_states[][4] = { 511 [AFS_VL_NEW] = "New", 512 [AFS_VL_CREATING] = "Crt", 513 [AFS_VL_VALID] = "Val", 514 [AFS_VL_NO_VOLUME] = "NoV", 515 [AFS_VL_UPDATING] = "Upd", 516 [AFS_VL_VOLUME_DELETED] = "Del", 517 [AFS_VL_UNCERTAIN] = "Unc", 518 }; 519 520 /* 521 * display a header line followed by a load of volume lines 522 */ 523 static int afs_proc_cell_volumes_show(struct seq_file *m, void *v) 524 { 525 struct afs_cell *cell = m->private; 526 struct afs_vlocation *vlocation = 527 list_entry(v, struct afs_vlocation, link); 528 529 /* display header on line 1 */ 530 if (v == &cell->vl_list) { 531 seq_puts(m, "USE STT VLID[0] VLID[1] VLID[2] NAME\n"); 532 return 0; 533 } 534 535 /* display one cell per line on subsequent lines */ 536 seq_printf(m, "%3d %s %08x %08x %08x %s\n", 537 atomic_read(&vlocation->usage), 538 afs_vlocation_states[vlocation->state], 539 vlocation->vldb.vid[0], 540 vlocation->vldb.vid[1], 541 vlocation->vldb.vid[2], 542 vlocation->vldb.name); 543 544 return 0; 545 } 546 547 /* 548 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume 549 * location server 550 */ 551 static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file) 552 { 553 struct afs_cell *cell; 554 struct seq_file *m; 555 int ret; 556 557 cell = PDE(inode)->data; 558 if (!cell) 559 return -ENOENT; 560 561 ret = seq_open(file, &afs_proc_cell_vlservers_ops); 562 if (ret<0) 563 return ret; 564 565 m = file->private_data; 566 m->private = cell; 567 568 return 0; 569 } 570 571 /* 572 * close the file and release the ref to the cell 573 */ 574 static int afs_proc_cell_vlservers_release(struct inode *inode, 575 struct file *file) 576 { 577 return seq_release(inode, file); 578 } 579 580 /* 581 * set up the iterator to start reading from the cells list and return the 582 * first item 583 */ 584 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) 585 { 586 struct afs_cell *cell = m->private; 587 loff_t pos = *_pos; 588 589 _enter("cell=%p pos=%Ld", cell, *_pos); 590 591 /* lock the list against modification */ 592 down_read(&cell->vl_sem); 593 594 /* allow for the header line */ 595 if (!pos) 596 return (void *) 1; 597 pos--; 598 599 if (pos >= cell->vl_naddrs) 600 return NULL; 601 602 return &cell->vl_addrs[pos]; 603 } 604 605 /* 606 * move to next cell in cells list 607 */ 608 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, 609 loff_t *_pos) 610 { 611 struct afs_cell *cell = p->private; 612 loff_t pos; 613 614 _enter("cell=%p{nad=%u} pos=%Ld", cell, cell->vl_naddrs, *_pos); 615 616 pos = *_pos; 617 (*_pos)++; 618 if (pos >= cell->vl_naddrs) 619 return NULL; 620 621 return &cell->vl_addrs[pos]; 622 } 623 624 /* 625 * clean up after reading from the cells list 626 */ 627 static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v) 628 { 629 struct afs_cell *cell = p->private; 630 631 up_read(&cell->vl_sem); 632 } 633 634 /* 635 * display a header line followed by a load of volume lines 636 */ 637 static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) 638 { 639 struct in_addr *addr = v; 640 641 /* display header on line 1 */ 642 if (v == (struct in_addr *) 1) { 643 seq_puts(m, "ADDRESS\n"); 644 return 0; 645 } 646 647 /* display one cell per line on subsequent lines */ 648 seq_printf(m, "%pI4\n", &addr->s_addr); 649 return 0; 650 } 651 652 /* 653 * open "/proc/fs/afs/<cell>/servers" which provides a summary of active 654 * servers 655 */ 656 static int afs_proc_cell_servers_open(struct inode *inode, struct file *file) 657 { 658 struct afs_cell *cell; 659 struct seq_file *m; 660 int ret; 661 662 cell = PDE(inode)->data; 663 if (!cell) 664 return -ENOENT; 665 666 ret = seq_open(file, &afs_proc_cell_servers_ops); 667 if (ret < 0) 668 return ret; 669 670 m = file->private_data; 671 m->private = cell; 672 return 0; 673 } 674 675 /* 676 * close the file and release the ref to the cell 677 */ 678 static int afs_proc_cell_servers_release(struct inode *inode, 679 struct file *file) 680 { 681 return seq_release(inode, file); 682 } 683 684 /* 685 * set up the iterator to start reading from the cells list and return the 686 * first item 687 */ 688 static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos) 689 __acquires(m->private->servers_lock) 690 { 691 struct afs_cell *cell = m->private; 692 693 _enter("cell=%p pos=%Ld", cell, *_pos); 694 695 /* lock the list against modification */ 696 read_lock(&cell->servers_lock); 697 return seq_list_start_head(&cell->servers, *_pos); 698 } 699 700 /* 701 * move to next cell in cells list 702 */ 703 static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, 704 loff_t *_pos) 705 { 706 struct afs_cell *cell = p->private; 707 708 _enter("cell=%p pos=%Ld", cell, *_pos); 709 return seq_list_next(v, &cell->servers, _pos); 710 } 711 712 /* 713 * clean up after reading from the cells list 714 */ 715 static void afs_proc_cell_servers_stop(struct seq_file *p, void *v) 716 __releases(p->private->servers_lock) 717 { 718 struct afs_cell *cell = p->private; 719 720 read_unlock(&cell->servers_lock); 721 } 722 723 /* 724 * display a header line followed by a load of volume lines 725 */ 726 static int afs_proc_cell_servers_show(struct seq_file *m, void *v) 727 { 728 struct afs_cell *cell = m->private; 729 struct afs_server *server = list_entry(v, struct afs_server, link); 730 char ipaddr[20]; 731 732 /* display header on line 1 */ 733 if (v == &cell->servers) { 734 seq_puts(m, "USE ADDR STATE\n"); 735 return 0; 736 } 737 738 /* display one cell per line on subsequent lines */ 739 sprintf(ipaddr, "%pI4", &server->addr); 740 seq_printf(m, "%3d %-15.15s %5d\n", 741 atomic_read(&server->usage), ipaddr, server->fs_state); 742 743 return 0; 744 } 745