linux/fs/afs/proc.c
<<
>>
Prefs
   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 <linux/uaccess.h>
  18#include "internal.h"
  19
  20static inline struct afs_net *afs_proc2net(struct file *f)
  21{
  22        return &__afs_net;
  23}
  24
  25static inline struct afs_net *afs_seq2net(struct seq_file *m)
  26{
  27        return &__afs_net; // TODO: use seq_file_net(m)
  28}
  29
  30static int afs_proc_cells_open(struct inode *inode, struct file *file);
  31static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
  32static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
  33static void afs_proc_cells_stop(struct seq_file *p, void *v);
  34static int afs_proc_cells_show(struct seq_file *m, void *v);
  35static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
  36                                    size_t size, loff_t *_pos);
  37
  38static const struct seq_operations afs_proc_cells_ops = {
  39        .start  = afs_proc_cells_start,
  40        .next   = afs_proc_cells_next,
  41        .stop   = afs_proc_cells_stop,
  42        .show   = afs_proc_cells_show,
  43};
  44
  45static const struct file_operations afs_proc_cells_fops = {
  46        .open           = afs_proc_cells_open,
  47        .read           = seq_read,
  48        .write          = afs_proc_cells_write,
  49        .llseek         = seq_lseek,
  50        .release        = seq_release,
  51};
  52
  53static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
  54                                      size_t size, loff_t *_pos);
  55static ssize_t afs_proc_rootcell_write(struct file *file,
  56                                       const char __user *buf,
  57                                       size_t size, loff_t *_pos);
  58
  59static const struct file_operations afs_proc_rootcell_fops = {
  60        .read           = afs_proc_rootcell_read,
  61        .write          = afs_proc_rootcell_write,
  62        .llseek         = no_llseek,
  63};
  64
  65static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
  66static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
  67static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
  68                                        loff_t *pos);
  69static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
  70static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
  71
  72static const struct seq_operations afs_proc_cell_volumes_ops = {
  73        .start  = afs_proc_cell_volumes_start,
  74        .next   = afs_proc_cell_volumes_next,
  75        .stop   = afs_proc_cell_volumes_stop,
  76        .show   = afs_proc_cell_volumes_show,
  77};
  78
  79static const struct file_operations afs_proc_cell_volumes_fops = {
  80        .open           = afs_proc_cell_volumes_open,
  81        .read           = seq_read,
  82        .llseek         = seq_lseek,
  83        .release        = seq_release,
  84};
  85
  86static int afs_proc_cell_vlservers_open(struct inode *inode,
  87                                        struct file *file);
  88static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
  89static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
  90                                          loff_t *pos);
  91static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
  92static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
  93
  94static const struct seq_operations afs_proc_cell_vlservers_ops = {
  95        .start  = afs_proc_cell_vlservers_start,
  96        .next   = afs_proc_cell_vlservers_next,
  97        .stop   = afs_proc_cell_vlservers_stop,
  98        .show   = afs_proc_cell_vlservers_show,
  99};
 100
 101static const struct file_operations afs_proc_cell_vlservers_fops = {
 102        .open           = afs_proc_cell_vlservers_open,
 103        .read           = seq_read,
 104        .llseek         = seq_lseek,
 105        .release        = seq_release,
 106};
 107
 108static int afs_proc_servers_open(struct inode *inode, struct file *file);
 109static void *afs_proc_servers_start(struct seq_file *p, loff_t *pos);
 110static void *afs_proc_servers_next(struct seq_file *p, void *v,
 111                                        loff_t *pos);
 112static void afs_proc_servers_stop(struct seq_file *p, void *v);
 113static int afs_proc_servers_show(struct seq_file *m, void *v);
 114
 115static const struct seq_operations afs_proc_servers_ops = {
 116        .start  = afs_proc_servers_start,
 117        .next   = afs_proc_servers_next,
 118        .stop   = afs_proc_servers_stop,
 119        .show   = afs_proc_servers_show,
 120};
 121
 122static const struct file_operations afs_proc_servers_fops = {
 123        .open           = afs_proc_servers_open,
 124        .read           = seq_read,
 125        .llseek         = seq_lseek,
 126        .release        = seq_release,
 127};
 128
 129static int afs_proc_sysname_open(struct inode *inode, struct file *file);
 130static int afs_proc_sysname_release(struct inode *inode, struct file *file);
 131static void *afs_proc_sysname_start(struct seq_file *p, loff_t *pos);
 132static void *afs_proc_sysname_next(struct seq_file *p, void *v,
 133                                        loff_t *pos);
 134static void afs_proc_sysname_stop(struct seq_file *p, void *v);
 135static int afs_proc_sysname_show(struct seq_file *m, void *v);
 136static ssize_t afs_proc_sysname_write(struct file *file,
 137                                      const char __user *buf,
 138                                      size_t size, loff_t *_pos);
 139
 140static const struct seq_operations afs_proc_sysname_ops = {
 141        .start  = afs_proc_sysname_start,
 142        .next   = afs_proc_sysname_next,
 143        .stop   = afs_proc_sysname_stop,
 144        .show   = afs_proc_sysname_show,
 145};
 146
 147static const struct file_operations afs_proc_sysname_fops = {
 148        .open           = afs_proc_sysname_open,
 149        .read           = seq_read,
 150        .llseek         = seq_lseek,
 151        .release        = afs_proc_sysname_release,
 152        .write          = afs_proc_sysname_write,
 153};
 154
 155static const struct file_operations afs_proc_stats_fops;
 156
 157/*
 158 * initialise the /proc/fs/afs/ directory
 159 */
 160int afs_proc_init(struct afs_net *net)
 161{
 162        _enter("");
 163
 164        net->proc_afs = proc_mkdir("fs/afs", NULL);
 165        if (!net->proc_afs)
 166                goto error_dir;
 167
 168        if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) ||
 169            !proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops) ||
 170            !proc_create("servers", 0644, net->proc_afs, &afs_proc_servers_fops) ||
 171            !proc_create("stats", 0644, net->proc_afs, &afs_proc_stats_fops) ||
 172            !proc_create("sysname", 0644, net->proc_afs, &afs_proc_sysname_fops))
 173                goto error_tree;
 174
 175        _leave(" = 0");
 176        return 0;
 177
 178error_tree:
 179        proc_remove(net->proc_afs);
 180error_dir:
 181        _leave(" = -ENOMEM");
 182        return -ENOMEM;
 183}
 184
 185/*
 186 * clean up the /proc/fs/afs/ directory
 187 */
 188void afs_proc_cleanup(struct afs_net *net)
 189{
 190        proc_remove(net->proc_afs);
 191        net->proc_afs = NULL;
 192}
 193
 194/*
 195 * open "/proc/fs/afs/cells" which provides a summary of extant cells
 196 */
 197static int afs_proc_cells_open(struct inode *inode, struct file *file)
 198{
 199        struct seq_file *m;
 200        int ret;
 201
 202        ret = seq_open(file, &afs_proc_cells_ops);
 203        if (ret < 0)
 204                return ret;
 205
 206        m = file->private_data;
 207        m->private = PDE_DATA(inode);
 208        return 0;
 209}
 210
 211/*
 212 * set up the iterator to start reading from the cells list and return the
 213 * first item
 214 */
 215static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
 216        __acquires(rcu)
 217{
 218        struct afs_net *net = afs_seq2net(m);
 219
 220        rcu_read_lock();
 221        return seq_list_start_head(&net->proc_cells, *_pos);
 222}
 223
 224/*
 225 * move to next cell in cells list
 226 */
 227static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
 228{
 229        struct afs_net *net = afs_seq2net(m);
 230
 231        return seq_list_next(v, &net->proc_cells, pos);
 232}
 233
 234/*
 235 * clean up after reading from the cells list
 236 */
 237static void afs_proc_cells_stop(struct seq_file *m, void *v)
 238        __releases(rcu)
 239{
 240        rcu_read_unlock();
 241}
 242
 243/*
 244 * display a header line followed by a load of cell lines
 245 */
 246static int afs_proc_cells_show(struct seq_file *m, void *v)
 247{
 248        struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
 249        struct afs_net *net = afs_seq2net(m);
 250
 251        if (v == &net->proc_cells) {
 252                /* display header on line 1 */
 253                seq_puts(m, "USE NAME\n");
 254                return 0;
 255        }
 256
 257        /* display one cell per line on subsequent lines */
 258        seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name);
 259        return 0;
 260}
 261
 262/*
 263 * handle writes to /proc/fs/afs/cells
 264 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
 265 */
 266static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
 267                                    size_t size, loff_t *_pos)
 268{
 269        struct afs_net *net = afs_proc2net(file);
 270        char *kbuf, *name, *args;
 271        int ret;
 272
 273        /* start by dragging the command into memory */
 274        if (size <= 1 || size >= PAGE_SIZE)
 275                return -EINVAL;
 276
 277        kbuf = memdup_user_nul(buf, size);
 278        if (IS_ERR(kbuf))
 279                return PTR_ERR(kbuf);
 280
 281        /* trim to first NL */
 282        name = memchr(kbuf, '\n', size);
 283        if (name)
 284                *name = 0;
 285
 286        /* split into command, name and argslist */
 287        name = strchr(kbuf, ' ');
 288        if (!name)
 289                goto inval;
 290        do {
 291                *name++ = 0;
 292        } while(*name == ' ');
 293        if (!*name)
 294                goto inval;
 295
 296        args = strchr(name, ' ');
 297        if (!args)
 298                goto inval;
 299        do {
 300                *args++ = 0;
 301        } while(*args == ' ');
 302        if (!*args)
 303                goto inval;
 304
 305        /* determine command to perform */
 306        _debug("cmd=%s name=%s args=%s", kbuf, name, args);
 307
 308        if (strcmp(kbuf, "add") == 0) {
 309                struct afs_cell *cell;
 310
 311                cell = afs_lookup_cell(net, name, strlen(name), args, true);
 312                if (IS_ERR(cell)) {
 313                        ret = PTR_ERR(cell);
 314                        goto done;
 315                }
 316
 317                if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags))
 318                        afs_put_cell(net, cell);
 319                printk("kAFS: Added new cell '%s'\n", name);
 320        } else {
 321                goto inval;
 322        }
 323
 324        ret = size;
 325
 326done:
 327        kfree(kbuf);
 328        _leave(" = %d", ret);
 329        return ret;
 330
 331inval:
 332        ret = -EINVAL;
 333        printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
 334        goto done;
 335}
 336
 337static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
 338                                      size_t size, loff_t *_pos)
 339{
 340        struct afs_cell *cell;
 341        struct afs_net *net = afs_proc2net(file);
 342        unsigned int seq = 0;
 343        char name[AFS_MAXCELLNAME + 1];
 344        int len;
 345
 346        if (*_pos > 0)
 347                return 0;
 348        if (!net->ws_cell)
 349                return 0;
 350
 351        rcu_read_lock();
 352        do {
 353                read_seqbegin_or_lock(&net->cells_lock, &seq);
 354                len = 0;
 355                cell = rcu_dereference_raw(net->ws_cell);
 356                if (cell) {
 357                        len = cell->name_len;
 358                        memcpy(name, cell->name, len);
 359                }
 360        } while (need_seqretry(&net->cells_lock, seq));
 361        done_seqretry(&net->cells_lock, seq);
 362        rcu_read_unlock();
 363
 364        if (!len)
 365                return 0;
 366
 367        name[len++] = '\n';
 368        if (len > size)
 369                len = size;
 370        if (copy_to_user(buf, name, len) != 0)
 371                return -EFAULT;
 372        *_pos = 1;
 373        return len;
 374}
 375
 376/*
 377 * handle writes to /proc/fs/afs/rootcell
 378 * - to initialize rootcell: echo "cell.name:192.168.231.14"
 379 */
 380static ssize_t afs_proc_rootcell_write(struct file *file,
 381                                       const char __user *buf,
 382                                       size_t size, loff_t *_pos)
 383{
 384        struct afs_net *net = afs_proc2net(file);
 385        char *kbuf, *s;
 386        int ret;
 387
 388        /* start by dragging the command into memory */
 389        if (size <= 1 || size >= PAGE_SIZE)
 390                return -EINVAL;
 391
 392        kbuf = memdup_user_nul(buf, size);
 393        if (IS_ERR(kbuf))
 394                return PTR_ERR(kbuf);
 395
 396        ret = -EINVAL;
 397        if (kbuf[0] == '.')
 398                goto out;
 399        if (memchr(kbuf, '/', size))
 400                goto out;
 401
 402        /* trim to first NL */
 403        s = memchr(kbuf, '\n', size);
 404        if (s)
 405                *s = 0;
 406
 407        /* determine command to perform */
 408        _debug("rootcell=%s", kbuf);
 409
 410        ret = afs_cell_init(net, kbuf);
 411        if (ret >= 0)
 412                ret = size;     /* consume everything, always */
 413
 414out:
 415        kfree(kbuf);
 416        _leave(" = %d", ret);
 417        return ret;
 418}
 419
 420/*
 421 * initialise /proc/fs/afs/<cell>/
 422 */
 423int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
 424{
 425        struct proc_dir_entry *dir;
 426
 427        _enter("%p{%s},%p", cell, cell->name, net->proc_afs);
 428
 429        dir = proc_mkdir(cell->name, net->proc_afs);
 430        if (!dir)
 431                goto error_dir;
 432
 433        if (!proc_create_data("vlservers", 0, dir,
 434                              &afs_proc_cell_vlservers_fops, cell) ||
 435            !proc_create_data("volumes", 0, dir,
 436                              &afs_proc_cell_volumes_fops, cell))
 437                goto error_tree;
 438
 439        _leave(" = 0");
 440        return 0;
 441
 442error_tree:
 443        remove_proc_subtree(cell->name, net->proc_afs);
 444error_dir:
 445        _leave(" = -ENOMEM");
 446        return -ENOMEM;
 447}
 448
 449/*
 450 * remove /proc/fs/afs/<cell>/
 451 */
 452void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
 453{
 454        _enter("");
 455
 456        remove_proc_subtree(cell->name, net->proc_afs);
 457
 458        _leave("");
 459}
 460
 461/*
 462 * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
 463 */
 464static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)
 465{
 466        struct afs_cell *cell;
 467        struct seq_file *m;
 468        int ret;
 469
 470        cell = PDE_DATA(inode);
 471        if (!cell)
 472                return -ENOENT;
 473
 474        ret = seq_open(file, &afs_proc_cell_volumes_ops);
 475        if (ret < 0)
 476                return ret;
 477
 478        m = file->private_data;
 479        m->private = cell;
 480
 481        return 0;
 482}
 483
 484/*
 485 * set up the iterator to start reading from the cells list and return the
 486 * first item
 487 */
 488static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
 489        __acquires(cell->proc_lock)
 490{
 491        struct afs_cell *cell = m->private;
 492
 493        _enter("cell=%p pos=%Ld", cell, *_pos);
 494
 495        read_lock(&cell->proc_lock);
 496        return seq_list_start_head(&cell->proc_volumes, *_pos);
 497}
 498
 499/*
 500 * move to next cell in cells list
 501 */
 502static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
 503                                        loff_t *_pos)
 504{
 505        struct afs_cell *cell = p->private;
 506
 507        _enter("cell=%p pos=%Ld", cell, *_pos);
 508        return seq_list_next(v, &cell->proc_volumes, _pos);
 509}
 510
 511/*
 512 * clean up after reading from the cells list
 513 */
 514static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
 515        __releases(cell->proc_lock)
 516{
 517        struct afs_cell *cell = p->private;
 518
 519        read_unlock(&cell->proc_lock);
 520}
 521
 522static const char afs_vol_types[3][3] = {
 523        [AFSVL_RWVOL]   = "RW",
 524        [AFSVL_ROVOL]   = "RO",
 525        [AFSVL_BACKVOL] = "BK",
 526};
 527
 528/*
 529 * display a header line followed by a load of volume lines
 530 */
 531static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
 532{
 533        struct afs_cell *cell = m->private;
 534        struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
 535
 536        /* Display header on line 1 */
 537        if (v == &cell->proc_volumes) {
 538                seq_puts(m, "USE VID      TY\n");
 539                return 0;
 540        }
 541
 542        seq_printf(m, "%3d %08x %s\n",
 543                   atomic_read(&vol->usage), vol->vid,
 544                   afs_vol_types[vol->type]);
 545
 546        return 0;
 547}
 548
 549/*
 550 * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
 551 * location server
 552 */
 553static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)
 554{
 555        struct afs_cell *cell;
 556        struct seq_file *m;
 557        int ret;
 558
 559        cell = PDE_DATA(inode);
 560        if (!cell)
 561                return -ENOENT;
 562
 563        ret = seq_open(file, &afs_proc_cell_vlservers_ops);
 564        if (ret<0)
 565                return ret;
 566
 567        m = file->private_data;
 568        m->private = cell;
 569
 570        return 0;
 571}
 572
 573/*
 574 * set up the iterator to start reading from the cells list and return the
 575 * first item
 576 */
 577static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
 578        __acquires(rcu)
 579{
 580        struct afs_addr_list *alist;
 581        struct afs_cell *cell = m->private;
 582        loff_t pos = *_pos;
 583
 584        rcu_read_lock();
 585
 586        alist = rcu_dereference(cell->vl_addrs);
 587
 588        /* allow for the header line */
 589        if (!pos)
 590                return (void *) 1;
 591        pos--;
 592
 593        if (!alist || pos >= alist->nr_addrs)
 594                return NULL;
 595
 596        return alist->addrs + pos;
 597}
 598
 599/*
 600 * move to next cell in cells list
 601 */
 602static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
 603                                          loff_t *_pos)
 604{
 605        struct afs_addr_list *alist;
 606        struct afs_cell *cell = p->private;
 607        loff_t pos;
 608
 609        alist = rcu_dereference(cell->vl_addrs);
 610
 611        pos = *_pos;
 612        (*_pos)++;
 613        if (!alist || pos >= alist->nr_addrs)
 614                return NULL;
 615
 616        return alist->addrs + pos;
 617}
 618
 619/*
 620 * clean up after reading from the cells list
 621 */
 622static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
 623        __releases(rcu)
 624{
 625        rcu_read_unlock();
 626}
 627
 628/*
 629 * display a header line followed by a load of volume lines
 630 */
 631static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
 632{
 633        struct sockaddr_rxrpc *addr = v;
 634
 635        /* display header on line 1 */
 636        if (v == (void *)1) {
 637                seq_puts(m, "ADDRESS\n");
 638                return 0;
 639        }
 640
 641        /* display one cell per line on subsequent lines */
 642        seq_printf(m, "%pISp\n", &addr->transport);
 643        return 0;
 644}
 645
 646/*
 647 * open "/proc/fs/afs/servers" which provides a summary of active
 648 * servers
 649 */
 650static int afs_proc_servers_open(struct inode *inode, struct file *file)
 651{
 652        return seq_open(file, &afs_proc_servers_ops);
 653}
 654
 655/*
 656 * Set up the iterator to start reading from the server list and return the
 657 * first item.
 658 */
 659static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos)
 660        __acquires(rcu)
 661{
 662        struct afs_net *net = afs_seq2net(m);
 663
 664        rcu_read_lock();
 665        return seq_hlist_start_head_rcu(&net->fs_proc, *_pos);
 666}
 667
 668/*
 669 * move to next cell in cells list
 670 */
 671static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
 672{
 673        struct afs_net *net = afs_seq2net(m);
 674
 675        return seq_hlist_next_rcu(v, &net->fs_proc, _pos);
 676}
 677
 678/*
 679 * clean up after reading from the cells list
 680 */
 681static void afs_proc_servers_stop(struct seq_file *p, void *v)
 682        __releases(rcu)
 683{
 684        rcu_read_unlock();
 685}
 686
 687/*
 688 * display a header line followed by a load of volume lines
 689 */
 690static int afs_proc_servers_show(struct seq_file *m, void *v)
 691{
 692        struct afs_server *server;
 693        struct afs_addr_list *alist;
 694
 695        if (v == SEQ_START_TOKEN) {
 696                seq_puts(m, "UUID                                 USE ADDR\n");
 697                return 0;
 698        }
 699
 700        server = list_entry(v, struct afs_server, proc_link);
 701        alist = rcu_dereference(server->addresses);
 702        seq_printf(m, "%pU %3d %pISp\n",
 703                   &server->uuid,
 704                   atomic_read(&server->usage),
 705                   &alist->addrs[alist->index].transport);
 706        return 0;
 707}
 708
 709void afs_put_sysnames(struct afs_sysnames *sysnames)
 710{
 711        int i;
 712
 713        if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
 714                for (i = 0; i < sysnames->nr; i++)
 715                        if (sysnames->subs[i] != afs_init_sysname &&
 716                            sysnames->subs[i] != sysnames->blank)
 717                                kfree(sysnames->subs[i]);
 718        }
 719}
 720
 721/*
 722 * Handle opening of /proc/fs/afs/sysname.  If it is opened for writing, we
 723 * assume the caller wants to change the substitution list and we allocate a
 724 * buffer to hold the list.
 725 */
 726static int afs_proc_sysname_open(struct inode *inode, struct file *file)
 727{
 728        struct afs_sysnames *sysnames;
 729        struct seq_file *m;
 730        int ret;
 731
 732        ret = seq_open(file, &afs_proc_sysname_ops);
 733        if (ret < 0)
 734                return ret;
 735
 736        if (file->f_mode & FMODE_WRITE) {
 737                sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
 738                if (!sysnames) {
 739                        seq_release(inode, file);
 740                        return -ENOMEM;
 741                }
 742
 743                refcount_set(&sysnames->usage, 1);
 744                m = file->private_data;
 745                m->private = sysnames;
 746        }
 747
 748        return 0;
 749}
 750
 751/*
 752 * Handle writes to /proc/fs/afs/sysname to set the @sys substitution.
 753 */
 754static ssize_t afs_proc_sysname_write(struct file *file,
 755                                      const char __user *buf,
 756                                      size_t size, loff_t *_pos)
 757{
 758        struct afs_sysnames *sysnames;
 759        struct seq_file *m = file->private_data;
 760        char *kbuf = NULL, *s, *p, *sub;
 761        int ret, len;
 762
 763        sysnames = m->private;
 764        if (!sysnames)
 765                return -EINVAL;
 766        if (sysnames->error)
 767                return sysnames->error;
 768
 769        if (size >= PAGE_SIZE - 1) {
 770                sysnames->error = -EINVAL;
 771                return -EINVAL;
 772        }
 773        if (size == 0)
 774                return 0;
 775
 776        kbuf = memdup_user_nul(buf, size);
 777        if (IS_ERR(kbuf))
 778                return PTR_ERR(kbuf);
 779
 780        inode_lock(file_inode(file));
 781
 782        p = kbuf;
 783        while ((s = strsep(&p, " \t\n"))) {
 784                len = strlen(s);
 785                if (len == 0)
 786                        continue;
 787                ret = -ENAMETOOLONG;
 788                if (len >= AFSNAMEMAX)
 789                        goto error;
 790
 791                if (len >= 4 &&
 792                    s[len - 4] == '@' &&
 793                    s[len - 3] == 's' &&
 794                    s[len - 2] == 'y' &&
 795                    s[len - 1] == 's')
 796                        /* Protect against recursion */
 797                        goto invalid;
 798
 799                if (s[0] == '.' &&
 800                    (len < 2 || (len == 2 && s[1] == '.')))
 801                        goto invalid;
 802
 803                if (memchr(s, '/', len))
 804                        goto invalid;
 805
 806                ret = -EFBIG;
 807                if (sysnames->nr >= AFS_NR_SYSNAME)
 808                        goto out;
 809
 810                if (strcmp(s, afs_init_sysname) == 0) {
 811                        sub = (char *)afs_init_sysname;
 812                } else {
 813                        ret = -ENOMEM;
 814                        sub = kmemdup(s, len + 1, GFP_KERNEL);
 815                        if (!sub)
 816                                goto out;
 817                }
 818
 819                sysnames->subs[sysnames->nr] = sub;
 820                sysnames->nr++;
 821        }
 822
 823        ret = size;     /* consume everything, always */
 824out:
 825        inode_unlock(file_inode(file));
 826        kfree(kbuf);
 827        return ret;
 828
 829invalid:
 830        ret = -EINVAL;
 831error:
 832        sysnames->error = ret;
 833        goto out;
 834}
 835
 836static int afs_proc_sysname_release(struct inode *inode, struct file *file)
 837{
 838        struct afs_sysnames *sysnames, *kill = NULL;
 839        struct seq_file *m = file->private_data;
 840        struct afs_net *net = afs_seq2net(m);
 841
 842        sysnames = m->private;
 843        if (sysnames) {
 844                if (!sysnames->error) {
 845                        kill = sysnames;
 846                        if (sysnames->nr == 0) {
 847                                sysnames->subs[0] = sysnames->blank;
 848                                sysnames->nr++;
 849                        }
 850                        write_lock(&net->sysnames_lock);
 851                        kill = net->sysnames;
 852                        net->sysnames = sysnames;
 853                        write_unlock(&net->sysnames_lock);
 854                }
 855                afs_put_sysnames(kill);
 856        }
 857
 858        return seq_release(inode, file);
 859}
 860
 861static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
 862        __acquires(&net->sysnames_lock)
 863{
 864        struct afs_net *net = afs_seq2net(m);
 865        struct afs_sysnames *names = net->sysnames;
 866
 867        read_lock(&net->sysnames_lock);
 868
 869        if (*pos >= names->nr)
 870                return NULL;
 871        return (void *)(unsigned long)(*pos + 1);
 872}
 873
 874static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
 875{
 876        struct afs_net *net = afs_seq2net(m);
 877        struct afs_sysnames *names = net->sysnames;
 878
 879        *pos += 1;
 880        if (*pos >= names->nr)
 881                return NULL;
 882        return (void *)(unsigned long)(*pos + 1);
 883}
 884
 885static void afs_proc_sysname_stop(struct seq_file *m, void *v)
 886        __releases(&net->sysnames_lock)
 887{
 888        struct afs_net *net = afs_seq2net(m);
 889
 890        read_unlock(&net->sysnames_lock);
 891}
 892
 893static int afs_proc_sysname_show(struct seq_file *m, void *v)
 894{
 895        struct afs_net *net = afs_seq2net(m);
 896        struct afs_sysnames *sysnames = net->sysnames;
 897        unsigned int i = (unsigned long)v - 1;
 898
 899        if (i < sysnames->nr)
 900                seq_printf(m, "%s\n", sysnames->subs[i]);
 901        return 0;
 902}
 903
 904/*
 905 * Display general per-net namespace statistics
 906 */
 907static int afs_proc_stats_show(struct seq_file *m, void *v)
 908{
 909        struct afs_net *net = afs_seq2net(m);
 910
 911        seq_puts(m, "kAFS statistics\n");
 912
 913        seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
 914                   atomic_read(&net->n_lookup),
 915                   atomic_read(&net->n_reval),
 916                   atomic_read(&net->n_inval),
 917                   atomic_read(&net->n_relpg));
 918
 919        seq_printf(m, "dir-data: rdpg=%u\n",
 920                   atomic_read(&net->n_read_dir));
 921
 922        seq_printf(m, "dir-edit: cr=%u rm=%u\n",
 923                   atomic_read(&net->n_dir_cr),
 924                   atomic_read(&net->n_dir_rm));
 925
 926        seq_printf(m, "file-rd : n=%u nb=%lu\n",
 927                   atomic_read(&net->n_fetches),
 928                   atomic_long_read(&net->n_fetch_bytes));
 929        seq_printf(m, "file-wr : n=%u nb=%lu\n",
 930                   atomic_read(&net->n_stores),
 931                   atomic_long_read(&net->n_store_bytes));
 932        return 0;
 933}
 934
 935/*
 936 * Open "/proc/fs/afs/stats" to allow reading of the stat counters.
 937 */
 938static int afs_proc_stats_open(struct inode *inode, struct file *file)
 939{
 940        return single_open(file, afs_proc_stats_show, NULL);
 941}
 942
 943static const struct file_operations afs_proc_stats_fops = {
 944        .open           = afs_proc_stats_open,
 945        .read           = seq_read,
 946        .llseek         = seq_lseek,
 947        .release        = single_release,
 948};
 949