linux/fs/nfsd/nfssvc.c
<<
>>
Prefs
   1/*
   2 * Central processing for nfsd.
   3 *
   4 * Authors:     Olaf Kirch (okir@monad.swb.de)
   5 *
   6 * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
   7 */
   8
   9#include <linux/sched.h>
  10#include <linux/freezer.h>
  11#include <linux/module.h>
  12#include <linux/fs_struct.h>
  13#include <linux/swap.h>
  14
  15#include <linux/sunrpc/stats.h>
  16#include <linux/sunrpc/svcsock.h>
  17#include <linux/lockd/bind.h>
  18#include <linux/nfsacl.h>
  19#include <linux/seq_file.h>
  20#include <net/net_namespace.h>
  21#include "nfsd.h"
  22#include "cache.h"
  23#include "vfs.h"
  24#include "netns.h"
  25
  26#define NFSDDBG_FACILITY        NFSDDBG_SVC
  27
  28extern struct svc_program       nfsd_program;
  29static int                      nfsd(void *vrqstp);
  30
  31/*
  32 * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members
  33 * of the svc_serv struct. In particular, ->sv_nrthreads but also to some
  34 * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt
  35 *
  36 * If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a
  37 * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number
  38 * of nfsd threads must exist and each must listed in ->sp_all_threads in each
  39 * entry of ->sv_pools[].
  40 *
  41 * Transitions of the thread count between zero and non-zero are of particular
  42 * interest since the svc_serv needs to be created and initialized at that
  43 * point, or freed.
  44 *
  45 * Finally, the nfsd_mutex also protects some of the global variables that are
  46 * accessed when nfsd starts and that are settable via the write_* routines in
  47 * nfsctl.c. In particular:
  48 *
  49 *      user_recovery_dirname
  50 *      user_lease_time
  51 *      nfsd_versions
  52 */
  53DEFINE_MUTEX(nfsd_mutex);
  54
  55/*
  56 * nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used.
  57 * nfsd_drc_max_pages limits the total amount of memory available for
  58 * version 4.1 DRC caches.
  59 * nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage.
  60 */
  61spinlock_t      nfsd_drc_lock;
  62unsigned long   nfsd_drc_max_mem;
  63unsigned long   nfsd_drc_mem_used;
  64
  65#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  66static struct svc_stat  nfsd_acl_svcstats;
  67static struct svc_version *     nfsd_acl_version[] = {
  68        [2] = &nfsd_acl_version2,
  69        [3] = &nfsd_acl_version3,
  70};
  71
  72#define NFSD_ACL_MINVERS            2
  73#define NFSD_ACL_NRVERS         ARRAY_SIZE(nfsd_acl_version)
  74static struct svc_version *nfsd_acl_versions[NFSD_ACL_NRVERS];
  75
  76static struct svc_program       nfsd_acl_program = {
  77        .pg_prog                = NFS_ACL_PROGRAM,
  78        .pg_nvers               = NFSD_ACL_NRVERS,
  79        .pg_vers                = nfsd_acl_versions,
  80        .pg_name                = "nfsacl",
  81        .pg_class               = "nfsd",
  82        .pg_stats               = &nfsd_acl_svcstats,
  83        .pg_authenticate        = &svc_set_client,
  84};
  85
  86static struct svc_stat  nfsd_acl_svcstats = {
  87        .program        = &nfsd_acl_program,
  88};
  89#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
  90
  91static struct svc_version *     nfsd_version[] = {
  92        [2] = &nfsd_version2,
  93#if defined(CONFIG_NFSD_V3)
  94        [3] = &nfsd_version3,
  95#endif
  96#if defined(CONFIG_NFSD_V4)
  97        [4] = &nfsd_version4,
  98#endif
  99};
 100
 101#define NFSD_MINVERS            2
 102#define NFSD_NRVERS             ARRAY_SIZE(nfsd_version)
 103static struct svc_version *nfsd_versions[NFSD_NRVERS];
 104
 105struct svc_program              nfsd_program = {
 106#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 107        .pg_next                = &nfsd_acl_program,
 108#endif
 109        .pg_prog                = NFS_PROGRAM,          /* program number */
 110        .pg_nvers               = NFSD_NRVERS,          /* nr of entries in nfsd_version */
 111        .pg_vers                = nfsd_versions,        /* version table */
 112        .pg_name                = "nfsd",               /* program name */
 113        .pg_class               = "nfsd",               /* authentication class */
 114        .pg_stats               = &nfsd_svcstats,       /* version table */
 115        .pg_authenticate        = &svc_set_client,      /* export authentication */
 116
 117};
 118
 119static bool nfsd_supported_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1] = {
 120        [0] = 1,
 121        [1] = 1,
 122        [2] = 1,
 123};
 124
 125int nfsd_vers(int vers, enum vers_op change)
 126{
 127        if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
 128                return 0;
 129        switch(change) {
 130        case NFSD_SET:
 131                nfsd_versions[vers] = nfsd_version[vers];
 132#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 133                if (vers < NFSD_ACL_NRVERS)
 134                        nfsd_acl_versions[vers] = nfsd_acl_version[vers];
 135#endif
 136                break;
 137        case NFSD_CLEAR:
 138                nfsd_versions[vers] = NULL;
 139#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 140                if (vers < NFSD_ACL_NRVERS)
 141                        nfsd_acl_versions[vers] = NULL;
 142#endif
 143                break;
 144        case NFSD_TEST:
 145                return nfsd_versions[vers] != NULL;
 146        case NFSD_AVAIL:
 147                return nfsd_version[vers] != NULL;
 148        }
 149        return 0;
 150}
 151
 152int nfsd_minorversion(u32 minorversion, enum vers_op change)
 153{
 154        if (minorversion > NFSD_SUPPORTED_MINOR_VERSION)
 155                return -1;
 156        switch(change) {
 157        case NFSD_SET:
 158                nfsd_supported_minorversions[minorversion] = true;
 159                break;
 160        case NFSD_CLEAR:
 161                nfsd_supported_minorversions[minorversion] = false;
 162                break;
 163        case NFSD_TEST:
 164                return nfsd_supported_minorversions[minorversion];
 165        case NFSD_AVAIL:
 166                return minorversion <= NFSD_SUPPORTED_MINOR_VERSION;
 167        }
 168        return 0;
 169}
 170
 171/*
 172 * Maximum number of nfsd processes
 173 */
 174#define NFSD_MAXSERVS           8192
 175
 176int nfsd_nrthreads(struct net *net)
 177{
 178        int rv = 0;
 179        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 180
 181        mutex_lock(&nfsd_mutex);
 182        if (nn->nfsd_serv)
 183                rv = nn->nfsd_serv->sv_nrthreads;
 184        mutex_unlock(&nfsd_mutex);
 185        return rv;
 186}
 187
 188static int nfsd_init_socks(struct net *net)
 189{
 190        int error;
 191        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 192
 193        if (!list_empty(&nn->nfsd_serv->sv_permsocks))
 194                return 0;
 195
 196        error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT,
 197                                        SVC_SOCK_DEFAULTS);
 198        if (error < 0)
 199                return error;
 200
 201        error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT,
 202                                        SVC_SOCK_DEFAULTS);
 203        if (error < 0)
 204                return error;
 205
 206        return 0;
 207}
 208
 209static int nfsd_users = 0;
 210
 211static int nfsd_startup_generic(int nrservs)
 212{
 213        int ret;
 214
 215        if (nfsd_users++)
 216                return 0;
 217
 218        /*
 219         * Readahead param cache - will no-op if it already exists.
 220         * (Note therefore results will be suboptimal if number of
 221         * threads is modified after nfsd start.)
 222         */
 223        ret = nfsd_racache_init(2*nrservs);
 224        if (ret)
 225                goto dec_users;
 226
 227        ret = nfs4_state_start();
 228        if (ret)
 229                goto out_racache;
 230        return 0;
 231
 232out_racache:
 233        nfsd_racache_shutdown();
 234dec_users:
 235        nfsd_users--;
 236        return ret;
 237}
 238
 239static void nfsd_shutdown_generic(void)
 240{
 241        if (--nfsd_users)
 242                return;
 243
 244        nfs4_state_shutdown();
 245        nfsd_racache_shutdown();
 246}
 247
 248static bool nfsd_needs_lockd(void)
 249{
 250#if defined(CONFIG_NFSD_V3)
 251        return (nfsd_versions[2] != NULL) || (nfsd_versions[3] != NULL);
 252#else
 253        return (nfsd_versions[2] != NULL);
 254#endif
 255}
 256
 257static int nfsd_startup_net(int nrservs, struct net *net)
 258{
 259        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 260        int ret;
 261
 262        if (nn->nfsd_net_up)
 263                return 0;
 264
 265        ret = nfsd_startup_generic(nrservs);
 266        if (ret)
 267                return ret;
 268        ret = nfsd_init_socks(net);
 269        if (ret)
 270                goto out_socks;
 271
 272        if (nfsd_needs_lockd() && !nn->lockd_up) {
 273                ret = lockd_up(net);
 274                if (ret)
 275                        goto out_socks;
 276                nn->lockd_up = 1;
 277        }
 278
 279        ret = nfs4_state_start_net(net);
 280        if (ret)
 281                goto out_lockd;
 282
 283        nn->nfsd_net_up = true;
 284        return 0;
 285
 286out_lockd:
 287        if (nn->lockd_up) {
 288                lockd_down(net);
 289                nn->lockd_up = 0;
 290        }
 291out_socks:
 292        nfsd_shutdown_generic();
 293        return ret;
 294}
 295
 296static void nfsd_shutdown_net(struct net *net)
 297{
 298        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 299
 300        nfs4_state_shutdown_net(net);
 301        if (nn->lockd_up) {
 302                lockd_down(net);
 303                nn->lockd_up = 0;
 304        }
 305        nn->nfsd_net_up = false;
 306        nfsd_shutdown_generic();
 307}
 308
 309static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
 310{
 311        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 312
 313        /*
 314         * write_ports can create the server without actually starting
 315         * any threads--if we get shut down before any threads are
 316         * started, then nfsd_last_thread will be run before any of this
 317         * other initialization has been done.
 318         */
 319        if (!nn->nfsd_net_up)
 320                return;
 321        nfsd_shutdown_net(net);
 322
 323        svc_rpcb_cleanup(serv, net);
 324
 325        printk(KERN_WARNING "nfsd: last server has exited, flushing export "
 326                            "cache\n");
 327        nfsd_export_flush(net);
 328}
 329
 330void nfsd_reset_versions(void)
 331{
 332        int found_one = 0;
 333        int i;
 334
 335        for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
 336                if (nfsd_program.pg_vers[i])
 337                        found_one = 1;
 338        }
 339
 340        if (!found_one) {
 341                for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
 342                        nfsd_program.pg_vers[i] = nfsd_version[i];
 343#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 344                for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++)
 345                        nfsd_acl_program.pg_vers[i] =
 346                                nfsd_acl_version[i];
 347#endif
 348        }
 349}
 350
 351/*
 352 * Each session guarantees a negotiated per slot memory cache for replies
 353 * which in turn consumes memory beyond the v2/v3/v4.0 server. A dedicated
 354 * NFSv4.1 server might want to use more memory for a DRC than a machine
 355 * with mutiple services.
 356 *
 357 * Impose a hard limit on the number of pages for the DRC which varies
 358 * according to the machines free pages. This is of course only a default.
 359 *
 360 * For now this is a #defined shift which could be under admin control
 361 * in the future.
 362 */
 363static void set_max_drc(void)
 364{
 365        #define NFSD_DRC_SIZE_SHIFT     10
 366        nfsd_drc_max_mem = (nr_free_buffer_pages()
 367                                        >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE;
 368        nfsd_drc_mem_used = 0;
 369        spin_lock_init(&nfsd_drc_lock);
 370        dprintk("%s nfsd_drc_max_mem %lu \n", __func__, nfsd_drc_max_mem);
 371}
 372
 373static int nfsd_get_default_max_blksize(void)
 374{
 375        struct sysinfo i;
 376        unsigned long long target;
 377        unsigned long ret;
 378
 379        si_meminfo(&i);
 380        target = (i.totalram - i.totalhigh) << PAGE_SHIFT;
 381        /*
 382         * Aim for 1/4096 of memory per thread This gives 1MB on 4Gig
 383         * machines, but only uses 32K on 128M machines.  Bottom out at
 384         * 8K on 32M and smaller.  Of course, this is only a default.
 385         */
 386        target >>= 12;
 387
 388        ret = NFSSVC_MAXBLKSIZE;
 389        while (ret > target && ret >= 8*1024*2)
 390                ret /= 2;
 391        return ret;
 392}
 393
 394static struct svc_serv_ops nfsd_thread_sv_ops = {
 395        .svo_shutdown           = nfsd_last_thread,
 396        .svo_function           = nfsd,
 397        .svo_enqueue_xprt       = svc_xprt_do_enqueue,
 398        .svo_setup              = svc_set_num_threads,
 399        .svo_module             = THIS_MODULE,
 400};
 401
 402int nfsd_create_serv(struct net *net)
 403{
 404        int error;
 405        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 406
 407        WARN_ON(!mutex_is_locked(&nfsd_mutex));
 408        if (nn->nfsd_serv) {
 409                svc_get(nn->nfsd_serv);
 410                return 0;
 411        }
 412        if (nfsd_max_blksize == 0)
 413                nfsd_max_blksize = nfsd_get_default_max_blksize();
 414        nfsd_reset_versions();
 415        nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
 416                                                &nfsd_thread_sv_ops);
 417        if (nn->nfsd_serv == NULL)
 418                return -ENOMEM;
 419
 420        nn->nfsd_serv->sv_maxconn = nn->max_connections;
 421        error = svc_bind(nn->nfsd_serv, net);
 422        if (error < 0) {
 423                svc_destroy(nn->nfsd_serv);
 424                return error;
 425        }
 426
 427        set_max_drc();
 428        do_gettimeofday(&nn->nfssvc_boot);              /* record boot time */
 429        return 0;
 430}
 431
 432int nfsd_nrpools(struct net *net)
 433{
 434        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 435
 436        if (nn->nfsd_serv == NULL)
 437                return 0;
 438        else
 439                return nn->nfsd_serv->sv_nrpools;
 440}
 441
 442int nfsd_get_nrthreads(int n, int *nthreads, struct net *net)
 443{
 444        int i = 0;
 445        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 446
 447        if (nn->nfsd_serv != NULL) {
 448                for (i = 0; i < nn->nfsd_serv->sv_nrpools && i < n; i++)
 449                        nthreads[i] = nn->nfsd_serv->sv_pools[i].sp_nrthreads;
 450        }
 451
 452        return 0;
 453}
 454
 455void nfsd_destroy(struct net *net)
 456{
 457        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 458        int destroy = (nn->nfsd_serv->sv_nrthreads == 1);
 459
 460        if (destroy)
 461                svc_shutdown_net(nn->nfsd_serv, net);
 462        svc_destroy(nn->nfsd_serv);
 463        if (destroy)
 464                nn->nfsd_serv = NULL;
 465}
 466
 467int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
 468{
 469        int i = 0;
 470        int tot = 0;
 471        int err = 0;
 472        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 473
 474        WARN_ON(!mutex_is_locked(&nfsd_mutex));
 475
 476        if (nn->nfsd_serv == NULL || n <= 0)
 477                return 0;
 478
 479        if (n > nn->nfsd_serv->sv_nrpools)
 480                n = nn->nfsd_serv->sv_nrpools;
 481
 482        /* enforce a global maximum number of threads */
 483        tot = 0;
 484        for (i = 0; i < n; i++) {
 485                nthreads[i] = min(nthreads[i], NFSD_MAXSERVS);
 486                tot += nthreads[i];
 487        }
 488        if (tot > NFSD_MAXSERVS) {
 489                /* total too large: scale down requested numbers */
 490                for (i = 0; i < n && tot > 0; i++) {
 491                        int new = nthreads[i] * NFSD_MAXSERVS / tot;
 492                        tot -= (nthreads[i] - new);
 493                        nthreads[i] = new;
 494                }
 495                for (i = 0; i < n && tot > 0; i++) {
 496                        nthreads[i]--;
 497                        tot--;
 498                }
 499        }
 500
 501        /*
 502         * There must always be a thread in pool 0; the admin
 503         * can't shut down NFS completely using pool_threads.
 504         */
 505        if (nthreads[0] == 0)
 506                nthreads[0] = 1;
 507
 508        /* apply the new numbers */
 509        svc_get(nn->nfsd_serv);
 510        for (i = 0; i < n; i++) {
 511                err = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv,
 512                                &nn->nfsd_serv->sv_pools[i], nthreads[i]);
 513                if (err)
 514                        break;
 515        }
 516        nfsd_destroy(net);
 517        return err;
 518}
 519
 520/*
 521 * Adjust the number of threads and return the new number of threads.
 522 * This is also the function that starts the server if necessary, if
 523 * this is the first time nrservs is nonzero.
 524 */
 525int
 526nfsd_svc(int nrservs, struct net *net)
 527{
 528        int     error;
 529        bool    nfsd_up_before;
 530        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 531
 532        mutex_lock(&nfsd_mutex);
 533        dprintk("nfsd: creating service\n");
 534
 535        nrservs = max(nrservs, 0);
 536        nrservs = min(nrservs, NFSD_MAXSERVS);
 537        error = 0;
 538
 539        if (nrservs == 0 && nn->nfsd_serv == NULL)
 540                goto out;
 541
 542        error = nfsd_create_serv(net);
 543        if (error)
 544                goto out;
 545
 546        nfsd_up_before = nn->nfsd_net_up;
 547
 548        error = nfsd_startup_net(nrservs, net);
 549        if (error)
 550                goto out_destroy;
 551        error = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv,
 552                        NULL, nrservs);
 553        if (error)
 554                goto out_shutdown;
 555        /* We are holding a reference to nn->nfsd_serv which
 556         * we don't want to count in the return value,
 557         * so subtract 1
 558         */
 559        error = nn->nfsd_serv->sv_nrthreads - 1;
 560out_shutdown:
 561        if (error < 0 && !nfsd_up_before)
 562                nfsd_shutdown_net(net);
 563out_destroy:
 564        nfsd_destroy(net);              /* Release server */
 565out:
 566        mutex_unlock(&nfsd_mutex);
 567        return error;
 568}
 569
 570
 571/*
 572 * This is the NFS server kernel thread
 573 */
 574static int
 575nfsd(void *vrqstp)
 576{
 577        struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
 578        struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list);
 579        struct net *net = perm_sock->xpt_net;
 580        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 581        int err;
 582
 583        /* Lock module and set up kernel thread */
 584        mutex_lock(&nfsd_mutex);
 585
 586        /* At this point, the thread shares current->fs
 587         * with the init process. We need to create files with a
 588         * umask of 0 instead of init's umask. */
 589        if (unshare_fs_struct() < 0) {
 590                printk("Unable to start nfsd thread: out of memory\n");
 591                goto out;
 592        }
 593
 594        current->fs->umask = 0;
 595
 596        /*
 597         * thread is spawned with all signals set to SIG_IGN, re-enable
 598         * the ones that will bring down the thread
 599         */
 600        allow_signal(SIGKILL);
 601        allow_signal(SIGHUP);
 602        allow_signal(SIGINT);
 603        allow_signal(SIGQUIT);
 604
 605        nfsdstats.th_cnt++;
 606        mutex_unlock(&nfsd_mutex);
 607
 608        set_freezable();
 609
 610        /*
 611         * The main request loop
 612         */
 613        for (;;) {
 614                /* Update sv_maxconn if it has changed */
 615                rqstp->rq_server->sv_maxconn = nn->max_connections;
 616
 617                /*
 618                 * Find a socket with data available and call its
 619                 * recvfrom routine.
 620                 */
 621                while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
 622                        ;
 623                if (err == -EINTR)
 624                        break;
 625                validate_process_creds();
 626                svc_process(rqstp);
 627                validate_process_creds();
 628        }
 629
 630        /* Clear signals before calling svc_exit_thread() */
 631        flush_signals(current);
 632
 633        mutex_lock(&nfsd_mutex);
 634        nfsdstats.th_cnt --;
 635
 636out:
 637        rqstp->rq_server = NULL;
 638
 639        /* Release the thread */
 640        svc_exit_thread(rqstp);
 641
 642        nfsd_destroy(net);
 643
 644        /* Release module */
 645        mutex_unlock(&nfsd_mutex);
 646        module_put_and_exit(0);
 647        return 0;
 648}
 649
 650static __be32 map_new_errors(u32 vers, __be32 nfserr)
 651{
 652        if (nfserr == nfserr_jukebox && vers == 2)
 653                return nfserr_dropit;
 654        if (nfserr == nfserr_wrongsec && vers < 4)
 655                return nfserr_acces;
 656        return nfserr;
 657}
 658
 659int
 660nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
 661{
 662        struct svc_procedure    *proc;
 663        kxdrproc_t              xdr;
 664        __be32                  nfserr;
 665        __be32                  *nfserrp;
 666
 667        dprintk("nfsd_dispatch: vers %d proc %d\n",
 668                                rqstp->rq_vers, rqstp->rq_proc);
 669        proc = rqstp->rq_procinfo;
 670
 671        /*
 672         * Give the xdr decoder a chance to change this if it wants
 673         * (necessary in the NFSv4.0 compound case)
 674         */
 675        rqstp->rq_cachetype = proc->pc_cachetype;
 676        /* Decode arguments */
 677        xdr = proc->pc_decode;
 678        if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base,
 679                        rqstp->rq_argp)) {
 680                dprintk("nfsd: failed to decode arguments!\n");
 681                *statp = rpc_garbage_args;
 682                return 1;
 683        }
 684
 685        /* Check whether we have this call in the cache. */
 686        switch (nfsd_cache_lookup(rqstp)) {
 687        case RC_DROPIT:
 688                return 0;
 689        case RC_REPLY:
 690                return 1;
 691        case RC_DOIT:;
 692                /* do it */
 693        }
 694
 695        /* need to grab the location to store the status, as
 696         * nfsv4 does some encoding while processing 
 697         */
 698        nfserrp = rqstp->rq_res.head[0].iov_base
 699                + rqstp->rq_res.head[0].iov_len;
 700        rqstp->rq_res.head[0].iov_len += sizeof(__be32);
 701
 702        /* Now call the procedure handler, and encode NFS status. */
 703        nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
 704        nfserr = map_new_errors(rqstp->rq_vers, nfserr);
 705        if (nfserr == nfserr_dropit || test_bit(RQ_DROPME, &rqstp->rq_flags)) {
 706                dprintk("nfsd: Dropping request; may be revisited later\n");
 707                nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
 708                return 0;
 709        }
 710
 711        if (rqstp->rq_proc != 0)
 712                *nfserrp++ = nfserr;
 713
 714        /* Encode result.
 715         * For NFSv2, additional info is never returned in case of an error.
 716         */
 717        if (!(nfserr && rqstp->rq_vers == 2)) {
 718                xdr = proc->pc_encode;
 719                if (xdr && !xdr(rqstp, nfserrp,
 720                                rqstp->rq_resp)) {
 721                        /* Failed to encode result. Release cache entry */
 722                        dprintk("nfsd: failed to encode result!\n");
 723                        nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
 724                        *statp = rpc_system_err;
 725                        return 1;
 726                }
 727        }
 728
 729        /* Store reply in cache. */
 730        nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1);
 731        return 1;
 732}
 733
 734int nfsd_pool_stats_open(struct inode *inode, struct file *file)
 735{
 736        int ret;
 737        struct nfsd_net *nn = net_generic(inode->i_sb->s_fs_info, nfsd_net_id);
 738
 739        mutex_lock(&nfsd_mutex);
 740        if (nn->nfsd_serv == NULL) {
 741                mutex_unlock(&nfsd_mutex);
 742                return -ENODEV;
 743        }
 744        /* bump up the psudo refcount while traversing */
 745        svc_get(nn->nfsd_serv);
 746        ret = svc_pool_stats_open(nn->nfsd_serv, file);
 747        mutex_unlock(&nfsd_mutex);
 748        return ret;
 749}
 750
 751int nfsd_pool_stats_release(struct inode *inode, struct file *file)
 752{
 753        int ret = seq_release(inode, file);
 754        struct net *net = inode->i_sb->s_fs_info;
 755
 756        mutex_lock(&nfsd_mutex);
 757        /* this function really, really should have been called svc_put() */
 758        nfsd_destroy(net);
 759        mutex_unlock(&nfsd_mutex);
 760        return ret;
 761}
 762