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