at v3.10 18 kB view raw
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 20static struct proc_dir_entry *proc_afs; 21 22 23static int afs_proc_cells_open(struct inode *inode, struct file *file); 24static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos); 25static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos); 26static void afs_proc_cells_stop(struct seq_file *p, void *v); 27static int afs_proc_cells_show(struct seq_file *m, void *v); 28static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, 29 size_t size, loff_t *_pos); 30 31static 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 38static 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 47static int afs_proc_rootcell_open(struct inode *inode, struct file *file); 48static int afs_proc_rootcell_release(struct inode *inode, struct file *file); 49static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, 50 size_t size, loff_t *_pos); 51static ssize_t afs_proc_rootcell_write(struct file *file, 52 const char __user *buf, 53 size_t size, loff_t *_pos); 54 55static 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 64static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file); 65static int afs_proc_cell_volumes_release(struct inode *inode, 66 struct file *file); 67static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos); 68static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, 69 loff_t *pos); 70static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v); 71static int afs_proc_cell_volumes_show(struct seq_file *m, void *v); 72 73static 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 80static 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 88static int afs_proc_cell_vlservers_open(struct inode *inode, 89 struct file *file); 90static int afs_proc_cell_vlservers_release(struct inode *inode, 91 struct file *file); 92static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos); 93static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, 94 loff_t *pos); 95static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v); 96static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v); 97 98static 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 105static 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 113static int afs_proc_cell_servers_open(struct inode *inode, struct file *file); 114static int afs_proc_cell_servers_release(struct inode *inode, 115 struct file *file); 116static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos); 117static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, 118 loff_t *pos); 119static void afs_proc_cell_servers_stop(struct seq_file *p, void *v); 120static int afs_proc_cell_servers_show(struct seq_file *m, void *v); 121 122static 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 129static 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 */ 140int 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 161error_rootcell: 162 remove_proc_entry("cells", proc_afs); 163error_cells: 164 remove_proc_entry("fs/afs", NULL); 165error_dir: 166 _leave(" = -ENOMEM"); 167 return -ENOMEM; 168} 169 170/* 171 * clean up the /proc/fs/afs/ directory 172 */ 173void 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 */ 183static 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_DATA(inode); 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 */ 202static 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 */ 212static 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 */ 220static 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 */ 228static 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 */ 248static 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 311done: 312 kfree(kbuf); 313 _leave(" = %d", ret); 314 return ret; 315 316inval: 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 */ 325static int afs_proc_rootcell_open(struct inode *inode, struct file *file) 326{ 327 return 0; 328} 329 330static int afs_proc_rootcell_release(struct inode *inode, struct file *file) 331{ 332 return 0; 333} 334 335static 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 */ 345static 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 378infault: 379 kfree(kbuf); 380nomem: 381 _leave(" = %d", ret); 382 return ret; 383} 384 385/* 386 * initialise /proc/fs/afs/<cell>/ 387 */ 388int 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 416error_volumes: 417 remove_proc_entry("vlservers", cell->proc_dir); 418error_vlservers: 419 remove_proc_entry("servers", cell->proc_dir); 420error_servers: 421 remove_proc_entry(cell->name, proc_afs); 422error_dir: 423 _leave(" = -ENOMEM"); 424 return -ENOMEM; 425} 426 427/* 428 * remove /proc/fs/afs/<cell>/ 429 */ 430void 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 */ 445static 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_DATA(inode); 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 */ 468static 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 */ 477static 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 */ 491static 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 */ 503static 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 510static 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 */ 523static 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 */ 551static 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_DATA(inode); 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 */ 574static 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 */ 584static 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 */ 608static 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 */ 627static 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 */ 637static 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 */ 656static 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_DATA(inode); 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 */ 678static 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 */ 688static 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 */ 703static 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 */ 715static 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 */ 726static 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}