linux/fs/nfsd/nfsctl.c
<<
>>
Prefs
   1/*
   2 * Syscall interface to knfsd.
   3 *
   4 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   5 */
   6
   7#include <linux/slab.h>
   8#include <linux/namei.h>
   9#include <linux/ctype.h>
  10
  11#include <linux/sunrpc/svcsock.h>
  12#include <linux/lockd/lockd.h>
  13#include <linux/sunrpc/clnt.h>
  14#include <linux/sunrpc/gss_api.h>
  15#include <linux/sunrpc/gss_krb5_enctypes.h>
  16#include <linux/module.h>
  17
  18#include "idmap.h"
  19#include "nfsd.h"
  20#include "cache.h"
  21
  22/*
  23 *      We have a single directory with several nodes in it.
  24 */
  25enum {
  26        NFSD_Root = 1,
  27        NFSD_List,
  28        NFSD_Export_features,
  29        NFSD_Fh,
  30        NFSD_FO_UnlockIP,
  31        NFSD_FO_UnlockFS,
  32        NFSD_Threads,
  33        NFSD_Pool_Threads,
  34        NFSD_Pool_Stats,
  35        NFSD_Versions,
  36        NFSD_Ports,
  37        NFSD_MaxBlkSize,
  38        NFSD_SupportedEnctypes,
  39        /*
  40         * The below MUST come last.  Otherwise we leave a hole in nfsd_files[]
  41         * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
  42         */
  43#ifdef CONFIG_NFSD_V4
  44        NFSD_Leasetime,
  45        NFSD_Gracetime,
  46        NFSD_RecoveryDir,
  47#endif
  48};
  49
  50/*
  51 * write() for these nodes.
  52 */
  53static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
  54static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
  55static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
  56static ssize_t write_threads(struct file *file, char *buf, size_t size);
  57static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
  58static ssize_t write_versions(struct file *file, char *buf, size_t size);
  59static ssize_t write_ports(struct file *file, char *buf, size_t size);
  60static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
  61#ifdef CONFIG_NFSD_V4
  62static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
  63static ssize_t write_gracetime(struct file *file, char *buf, size_t size);
  64static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
  65#endif
  66
  67static ssize_t (*write_op[])(struct file *, char *, size_t) = {
  68        [NFSD_Fh] = write_filehandle,
  69        [NFSD_FO_UnlockIP] = write_unlock_ip,
  70        [NFSD_FO_UnlockFS] = write_unlock_fs,
  71        [NFSD_Threads] = write_threads,
  72        [NFSD_Pool_Threads] = write_pool_threads,
  73        [NFSD_Versions] = write_versions,
  74        [NFSD_Ports] = write_ports,
  75        [NFSD_MaxBlkSize] = write_maxblksize,
  76#ifdef CONFIG_NFSD_V4
  77        [NFSD_Leasetime] = write_leasetime,
  78        [NFSD_Gracetime] = write_gracetime,
  79        [NFSD_RecoveryDir] = write_recoverydir,
  80#endif
  81};
  82
  83static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
  84{
  85        ino_t ino =  file->f_path.dentry->d_inode->i_ino;
  86        char *data;
  87        ssize_t rv;
  88
  89        if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
  90                return -EINVAL;
  91
  92        data = simple_transaction_get(file, buf, size);
  93        if (IS_ERR(data))
  94                return PTR_ERR(data);
  95
  96        rv =  write_op[ino](file, data, size);
  97        if (rv >= 0) {
  98                simple_transaction_set(file, rv);
  99                rv = size;
 100        }
 101        return rv;
 102}
 103
 104static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
 105{
 106        if (! file->private_data) {
 107                /* An attempt to read a transaction file without writing
 108                 * causes a 0-byte write so that the file can return
 109                 * state information
 110                 */
 111                ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
 112                if (rv < 0)
 113                        return rv;
 114        }
 115        return simple_transaction_read(file, buf, size, pos);
 116}
 117
 118static const struct file_operations transaction_ops = {
 119        .write          = nfsctl_transaction_write,
 120        .read           = nfsctl_transaction_read,
 121        .release        = simple_transaction_release,
 122        .llseek         = default_llseek,
 123};
 124
 125static int exports_open(struct inode *inode, struct file *file)
 126{
 127        return seq_open(file, &nfs_exports_op);
 128}
 129
 130static const struct file_operations exports_operations = {
 131        .open           = exports_open,
 132        .read           = seq_read,
 133        .llseek         = seq_lseek,
 134        .release        = seq_release,
 135        .owner          = THIS_MODULE,
 136};
 137
 138static int export_features_show(struct seq_file *m, void *v)
 139{
 140        seq_printf(m, "0x%x 0x%x\n", NFSEXP_ALLFLAGS, NFSEXP_SECINFO_FLAGS);
 141        return 0;
 142}
 143
 144static int export_features_open(struct inode *inode, struct file *file)
 145{
 146        return single_open(file, export_features_show, NULL);
 147}
 148
 149static struct file_operations export_features_operations = {
 150        .open           = export_features_open,
 151        .read           = seq_read,
 152        .llseek         = seq_lseek,
 153        .release        = single_release,
 154};
 155
 156#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
 157static int supported_enctypes_show(struct seq_file *m, void *v)
 158{
 159        seq_printf(m, KRB5_SUPPORTED_ENCTYPES);
 160        return 0;
 161}
 162
 163static int supported_enctypes_open(struct inode *inode, struct file *file)
 164{
 165        return single_open(file, supported_enctypes_show, NULL);
 166}
 167
 168static struct file_operations supported_enctypes_ops = {
 169        .open           = supported_enctypes_open,
 170        .read           = seq_read,
 171        .llseek         = seq_lseek,
 172        .release        = single_release,
 173};
 174#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
 175
 176extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
 177extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
 178
 179static const struct file_operations pool_stats_operations = {
 180        .open           = nfsd_pool_stats_open,
 181        .read           = seq_read,
 182        .llseek         = seq_lseek,
 183        .release        = nfsd_pool_stats_release,
 184        .owner          = THIS_MODULE,
 185};
 186
 187/*----------------------------------------------------------------------------*/
 188/*
 189 * payload - write methods
 190 */
 191
 192
 193/**
 194 * write_unlock_ip - Release all locks used by a client
 195 *
 196 * Experimental.
 197 *
 198 * Input:
 199 *                      buf:    '\n'-terminated C string containing a
 200 *                              presentation format IP address
 201 *                      size:   length of C string in @buf
 202 * Output:
 203 *      On success:     returns zero if all specified locks were released;
 204 *                      returns one if one or more locks were not released
 205 *      On error:       return code is negative errno value
 206 */
 207static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
 208{
 209        struct sockaddr_storage address;
 210        struct sockaddr *sap = (struct sockaddr *)&address;
 211        size_t salen = sizeof(address);
 212        char *fo_path;
 213
 214        /* sanity check */
 215        if (size == 0)
 216                return -EINVAL;
 217
 218        if (buf[size-1] != '\n')
 219                return -EINVAL;
 220
 221        fo_path = buf;
 222        if (qword_get(&buf, fo_path, size) < 0)
 223                return -EINVAL;
 224
 225        if (rpc_pton(fo_path, size, sap, salen) == 0)
 226                return -EINVAL;
 227
 228        return nlmsvc_unlock_all_by_ip(sap);
 229}
 230
 231/**
 232 * write_unlock_fs - Release all locks on a local file system
 233 *
 234 * Experimental.
 235 *
 236 * Input:
 237 *                      buf:    '\n'-terminated C string containing the
 238 *                              absolute pathname of a local file system
 239 *                      size:   length of C string in @buf
 240 * Output:
 241 *      On success:     returns zero if all specified locks were released;
 242 *                      returns one if one or more locks were not released
 243 *      On error:       return code is negative errno value
 244 */
 245static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
 246{
 247        struct path path;
 248        char *fo_path;
 249        int error;
 250
 251        /* sanity check */
 252        if (size == 0)
 253                return -EINVAL;
 254
 255        if (buf[size-1] != '\n')
 256                return -EINVAL;
 257
 258        fo_path = buf;
 259        if (qword_get(&buf, fo_path, size) < 0)
 260                return -EINVAL;
 261
 262        error = kern_path(fo_path, 0, &path);
 263        if (error)
 264                return error;
 265
 266        /*
 267         * XXX: Needs better sanity checking.  Otherwise we could end up
 268         * releasing locks on the wrong file system.
 269         *
 270         * For example:
 271         * 1.  Does the path refer to a directory?
 272         * 2.  Is that directory a mount point, or
 273         * 3.  Is that directory the root of an exported file system?
 274         */
 275        error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb);
 276
 277        path_put(&path);
 278        return error;
 279}
 280
 281/**
 282 * write_filehandle - Get a variable-length NFS file handle by path
 283 *
 284 * On input, the buffer contains a '\n'-terminated C string comprised of
 285 * three alphanumeric words separated by whitespace.  The string may
 286 * contain escape sequences.
 287 *
 288 * Input:
 289 *                      buf:
 290 *                              domain:         client domain name
 291 *                              path:           export pathname
 292 *                              maxsize:        numeric maximum size of
 293 *                                              @buf
 294 *                      size:   length of C string in @buf
 295 * Output:
 296 *      On success:     passed-in buffer filled with '\n'-terminated C
 297 *                      string containing a ASCII hex text version
 298 *                      of the NFS file handle;
 299 *                      return code is the size in bytes of the string
 300 *      On error:       return code is negative errno value
 301 */
 302static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
 303{
 304        char *dname, *path;
 305        int uninitialized_var(maxsize);
 306        char *mesg = buf;
 307        int len;
 308        struct auth_domain *dom;
 309        struct knfsd_fh fh;
 310
 311        if (size == 0)
 312                return -EINVAL;
 313
 314        if (buf[size-1] != '\n')
 315                return -EINVAL;
 316        buf[size-1] = 0;
 317
 318        dname = mesg;
 319        len = qword_get(&mesg, dname, size);
 320        if (len <= 0)
 321                return -EINVAL;
 322        
 323        path = dname+len+1;
 324        len = qword_get(&mesg, path, size);
 325        if (len <= 0)
 326                return -EINVAL;
 327
 328        len = get_int(&mesg, &maxsize);
 329        if (len)
 330                return len;
 331
 332        if (maxsize < NFS_FHSIZE)
 333                return -EINVAL;
 334        if (maxsize > NFS3_FHSIZE)
 335                maxsize = NFS3_FHSIZE;
 336
 337        if (qword_get(&mesg, mesg, size)>0)
 338                return -EINVAL;
 339
 340        /* we have all the words, they are in buf.. */
 341        dom = unix_domain_find(dname);
 342        if (!dom)
 343                return -ENOMEM;
 344
 345        len = exp_rootfh(dom, path, &fh,  maxsize);
 346        auth_domain_put(dom);
 347        if (len)
 348                return len;
 349        
 350        mesg = buf;
 351        len = SIMPLE_TRANSACTION_LIMIT;
 352        qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
 353        mesg[-1] = '\n';
 354        return mesg - buf;      
 355}
 356
 357/**
 358 * write_threads - Start NFSD, or report the current number of running threads
 359 *
 360 * Input:
 361 *                      buf:            ignored
 362 *                      size:           zero
 363 * Output:
 364 *      On success:     passed-in buffer filled with '\n'-terminated C
 365 *                      string numeric value representing the number of
 366 *                      running NFSD threads;
 367 *                      return code is the size in bytes of the string
 368 *      On error:       return code is zero
 369 *
 370 * OR
 371 *
 372 * Input:
 373 *                      buf:            C string containing an unsigned
 374 *                                      integer value representing the
 375 *                                      number of NFSD threads to start
 376 *                      size:           non-zero length of C string in @buf
 377 * Output:
 378 *      On success:     NFS service is started;
 379 *                      passed-in buffer filled with '\n'-terminated C
 380 *                      string numeric value representing the number of
 381 *                      running NFSD threads;
 382 *                      return code is the size in bytes of the string
 383 *      On error:       return code is zero or a negative errno value
 384 */
 385static ssize_t write_threads(struct file *file, char *buf, size_t size)
 386{
 387        char *mesg = buf;
 388        int rv;
 389        if (size > 0) {
 390                int newthreads;
 391                rv = get_int(&mesg, &newthreads);
 392                if (rv)
 393                        return rv;
 394                if (newthreads < 0)
 395                        return -EINVAL;
 396                rv = nfsd_svc(NFS_PORT, newthreads);
 397                if (rv < 0)
 398                        return rv;
 399        } else
 400                rv = nfsd_nrthreads();
 401
 402        return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
 403}
 404
 405/**
 406 * write_pool_threads - Set or report the current number of threads per pool
 407 *
 408 * Input:
 409 *                      buf:            ignored
 410 *                      size:           zero
 411 *
 412 * OR
 413 *
 414 * Input:
 415 *                      buf:            C string containing whitespace-
 416 *                                      separated unsigned integer values
 417 *                                      representing the number of NFSD
 418 *                                      threads to start in each pool
 419 *                      size:           non-zero length of C string in @buf
 420 * Output:
 421 *      On success:     passed-in buffer filled with '\n'-terminated C
 422 *                      string containing integer values representing the
 423 *                      number of NFSD threads in each pool;
 424 *                      return code is the size in bytes of the string
 425 *      On error:       return code is zero or a negative errno value
 426 */
 427static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
 428{
 429        /* if size > 0, look for an array of number of threads per node
 430         * and apply them  then write out number of threads per node as reply
 431         */
 432        char *mesg = buf;
 433        int i;
 434        int rv;
 435        int len;
 436        int npools;
 437        int *nthreads;
 438
 439        mutex_lock(&nfsd_mutex);
 440        npools = nfsd_nrpools();
 441        if (npools == 0) {
 442                /*
 443                 * NFS is shut down.  The admin can start it by
 444                 * writing to the threads file but NOT the pool_threads
 445                 * file, sorry.  Report zero threads.
 446                 */
 447                mutex_unlock(&nfsd_mutex);
 448                strcpy(buf, "0\n");
 449                return strlen(buf);
 450        }
 451
 452        nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
 453        rv = -ENOMEM;
 454        if (nthreads == NULL)
 455                goto out_free;
 456
 457        if (size > 0) {
 458                for (i = 0; i < npools; i++) {
 459                        rv = get_int(&mesg, &nthreads[i]);
 460                        if (rv == -ENOENT)
 461                                break;          /* fewer numbers than pools */
 462                        if (rv)
 463                                goto out_free;  /* syntax error */
 464                        rv = -EINVAL;
 465                        if (nthreads[i] < 0)
 466                                goto out_free;
 467                }
 468                rv = nfsd_set_nrthreads(i, nthreads);
 469                if (rv)
 470                        goto out_free;
 471        }
 472
 473        rv = nfsd_get_nrthreads(npools, nthreads);
 474        if (rv)
 475                goto out_free;
 476
 477        mesg = buf;
 478        size = SIMPLE_TRANSACTION_LIMIT;
 479        for (i = 0; i < npools && size > 0; i++) {
 480                snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
 481                len = strlen(mesg);
 482                size -= len;
 483                mesg += len;
 484        }
 485        rv = mesg - buf;
 486out_free:
 487        kfree(nthreads);
 488        mutex_unlock(&nfsd_mutex);
 489        return rv;
 490}
 491
 492static ssize_t __write_versions(struct file *file, char *buf, size_t size)
 493{
 494        char *mesg = buf;
 495        char *vers, *minorp, sign;
 496        int len, num, remaining;
 497        unsigned minor;
 498        ssize_t tlen = 0;
 499        char *sep;
 500
 501        if (size>0) {
 502                if (nfsd_serv)
 503                        /* Cannot change versions without updating
 504                         * nfsd_serv->sv_xdrsize, and reallocing
 505                         * rq_argp and rq_resp
 506                         */
 507                        return -EBUSY;
 508                if (buf[size-1] != '\n')
 509                        return -EINVAL;
 510                buf[size-1] = 0;
 511
 512                vers = mesg;
 513                len = qword_get(&mesg, vers, size);
 514                if (len <= 0) return -EINVAL;
 515                do {
 516                        sign = *vers;
 517                        if (sign == '+' || sign == '-')
 518                                num = simple_strtol((vers+1), &minorp, 0);
 519                        else
 520                                num = simple_strtol(vers, &minorp, 0);
 521                        if (*minorp == '.') {
 522                                if (num < 4)
 523                                        return -EINVAL;
 524                                minor = simple_strtoul(minorp+1, NULL, 0);
 525                                if (minor == 0)
 526                                        return -EINVAL;
 527                                if (nfsd_minorversion(minor, sign == '-' ?
 528                                                     NFSD_CLEAR : NFSD_SET) < 0)
 529                                        return -EINVAL;
 530                                goto next;
 531                        }
 532                        switch(num) {
 533                        case 2:
 534                        case 3:
 535                        case 4:
 536                                nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
 537                                break;
 538                        default:
 539                                return -EINVAL;
 540                        }
 541                next:
 542                        vers += len + 1;
 543                } while ((len = qword_get(&mesg, vers, size)) > 0);
 544                /* If all get turned off, turn them back on, as
 545                 * having no versions is BAD
 546                 */
 547                nfsd_reset_versions();
 548        }
 549
 550        /* Now write current state into reply buffer */
 551        len = 0;
 552        sep = "";
 553        remaining = SIMPLE_TRANSACTION_LIMIT;
 554        for (num=2 ; num <= 4 ; num++)
 555                if (nfsd_vers(num, NFSD_AVAIL)) {
 556                        len = snprintf(buf, remaining, "%s%c%d", sep,
 557                                       nfsd_vers(num, NFSD_TEST)?'+':'-',
 558                                       num);
 559                        sep = " ";
 560
 561                        if (len > remaining)
 562                                break;
 563                        remaining -= len;
 564                        buf += len;
 565                        tlen += len;
 566                }
 567        if (nfsd_vers(4, NFSD_AVAIL))
 568                for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION;
 569                     minor++) {
 570                        len = snprintf(buf, remaining, " %c4.%u",
 571                                        (nfsd_vers(4, NFSD_TEST) &&
 572                                         nfsd_minorversion(minor, NFSD_TEST)) ?
 573                                                '+' : '-',
 574                                        minor);
 575
 576                        if (len > remaining)
 577                                break;
 578                        remaining -= len;
 579                        buf += len;
 580                        tlen += len;
 581                }
 582
 583        len = snprintf(buf, remaining, "\n");
 584        if (len > remaining)
 585                return -EINVAL;
 586        return tlen + len;
 587}
 588
 589/**
 590 * write_versions - Set or report the available NFS protocol versions
 591 *
 592 * Input:
 593 *                      buf:            ignored
 594 *                      size:           zero
 595 * Output:
 596 *      On success:     passed-in buffer filled with '\n'-terminated C
 597 *                      string containing positive or negative integer
 598 *                      values representing the current status of each
 599 *                      protocol version;
 600 *                      return code is the size in bytes of the string
 601 *      On error:       return code is zero or a negative errno value
 602 *
 603 * OR
 604 *
 605 * Input:
 606 *                      buf:            C string containing whitespace-
 607 *                                      separated positive or negative
 608 *                                      integer values representing NFS
 609 *                                      protocol versions to enable ("+n")
 610 *                                      or disable ("-n")
 611 *                      size:           non-zero length of C string in @buf
 612 * Output:
 613 *      On success:     status of zero or more protocol versions has
 614 *                      been updated; passed-in buffer filled with
 615 *                      '\n'-terminated C string containing positive
 616 *                      or negative integer values representing the
 617 *                      current status of each protocol version;
 618 *                      return code is the size in bytes of the string
 619 *      On error:       return code is zero or a negative errno value
 620 */
 621static ssize_t write_versions(struct file *file, char *buf, size_t size)
 622{
 623        ssize_t rv;
 624
 625        mutex_lock(&nfsd_mutex);
 626        rv = __write_versions(file, buf, size);
 627        mutex_unlock(&nfsd_mutex);
 628        return rv;
 629}
 630
 631/*
 632 * Zero-length write.  Return a list of NFSD's current listener
 633 * transports.
 634 */
 635static ssize_t __write_ports_names(char *buf)
 636{
 637        if (nfsd_serv == NULL)
 638                return 0;
 639        return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
 640}
 641
 642/*
 643 * A single 'fd' number was written, in which case it must be for
 644 * a socket of a supported family/protocol, and we use it as an
 645 * nfsd listener.
 646 */
 647static ssize_t __write_ports_addfd(char *buf)
 648{
 649        char *mesg = buf;
 650        int fd, err;
 651
 652        err = get_int(&mesg, &fd);
 653        if (err != 0 || fd < 0)
 654                return -EINVAL;
 655
 656        err = nfsd_create_serv();
 657        if (err != 0)
 658                return err;
 659
 660        err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
 661        if (err < 0) {
 662                svc_destroy(nfsd_serv);
 663                return err;
 664        }
 665
 666        /* Decrease the count, but don't shut down the service */
 667        nfsd_serv->sv_nrthreads--;
 668        return err;
 669}
 670
 671/*
 672 * A '-' followed by the 'name' of a socket means we close the socket.
 673 */
 674static ssize_t __write_ports_delfd(char *buf)
 675{
 676        char *toclose;
 677        int len = 0;
 678
 679        toclose = kstrdup(buf + 1, GFP_KERNEL);
 680        if (toclose == NULL)
 681                return -ENOMEM;
 682
 683        if (nfsd_serv != NULL)
 684                len = svc_sock_names(nfsd_serv, buf,
 685                                        SIMPLE_TRANSACTION_LIMIT, toclose);
 686        kfree(toclose);
 687        return len;
 688}
 689
 690/*
 691 * A transport listener is added by writing it's transport name and
 692 * a port number.
 693 */
 694static ssize_t __write_ports_addxprt(char *buf)
 695{
 696        char transport[16];
 697        struct svc_xprt *xprt;
 698        int port, err;
 699
 700        if (sscanf(buf, "%15s %4u", transport, &port) != 2)
 701                return -EINVAL;
 702
 703        if (port < 1 || port > USHRT_MAX)
 704                return -EINVAL;
 705
 706        err = nfsd_create_serv();
 707        if (err != 0)
 708                return err;
 709
 710        err = svc_create_xprt(nfsd_serv, transport, &init_net,
 711                                PF_INET, port, SVC_SOCK_ANONYMOUS);
 712        if (err < 0)
 713                goto out_err;
 714
 715        err = svc_create_xprt(nfsd_serv, transport, &init_net,
 716                                PF_INET6, port, SVC_SOCK_ANONYMOUS);
 717        if (err < 0 && err != -EAFNOSUPPORT)
 718                goto out_close;
 719
 720        /* Decrease the count, but don't shut down the service */
 721        nfsd_serv->sv_nrthreads--;
 722        return 0;
 723out_close:
 724        xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
 725        if (xprt != NULL) {
 726                svc_close_xprt(xprt);
 727                svc_xprt_put(xprt);
 728        }
 729out_err:
 730        svc_destroy(nfsd_serv);
 731        return err;
 732}
 733
 734/*
 735 * A transport listener is removed by writing a "-", it's transport
 736 * name, and it's port number.
 737 */
 738static ssize_t __write_ports_delxprt(char *buf)
 739{
 740        struct svc_xprt *xprt;
 741        char transport[16];
 742        int port;
 743
 744        if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
 745                return -EINVAL;
 746
 747        if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
 748                return -EINVAL;
 749
 750        xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
 751        if (xprt == NULL)
 752                return -ENOTCONN;
 753
 754        svc_close_xprt(xprt);
 755        svc_xprt_put(xprt);
 756        return 0;
 757}
 758
 759static ssize_t __write_ports(struct file *file, char *buf, size_t size)
 760{
 761        if (size == 0)
 762                return __write_ports_names(buf);
 763
 764        if (isdigit(buf[0]))
 765                return __write_ports_addfd(buf);
 766
 767        if (buf[0] == '-' && isdigit(buf[1]))
 768                return __write_ports_delfd(buf);
 769
 770        if (isalpha(buf[0]))
 771                return __write_ports_addxprt(buf);
 772
 773        if (buf[0] == '-' && isalpha(buf[1]))
 774                return __write_ports_delxprt(buf);
 775
 776        return -EINVAL;
 777}
 778
 779/**
 780 * write_ports - Pass a socket file descriptor or transport name to listen on
 781 *
 782 * Input:
 783 *                      buf:            ignored
 784 *                      size:           zero
 785 * Output:
 786 *      On success:     passed-in buffer filled with a '\n'-terminated C
 787 *                      string containing a whitespace-separated list of
 788 *                      named NFSD listeners;
 789 *                      return code is the size in bytes of the string
 790 *      On error:       return code is zero or a negative errno value
 791 *
 792 * OR
 793 *
 794 * Input:
 795 *                      buf:            C string containing an unsigned
 796 *                                      integer value representing a bound
 797 *                                      but unconnected socket that is to be
 798 *                                      used as an NFSD listener; listen(3)
 799 *                                      must be called for a SOCK_STREAM
 800 *                                      socket, otherwise it is ignored
 801 *                      size:           non-zero length of C string in @buf
 802 * Output:
 803 *      On success:     NFS service is started;
 804 *                      passed-in buffer filled with a '\n'-terminated C
 805 *                      string containing a unique alphanumeric name of
 806 *                      the listener;
 807 *                      return code is the size in bytes of the string
 808 *      On error:       return code is a negative errno value
 809 *
 810 * OR
 811 *
 812 * Input:
 813 *                      buf:            C string containing a "-" followed
 814 *                                      by an integer value representing a
 815 *                                      previously passed in socket file
 816 *                                      descriptor
 817 *                      size:           non-zero length of C string in @buf
 818 * Output:
 819 *      On success:     NFS service no longer listens on that socket;
 820 *                      passed-in buffer filled with a '\n'-terminated C
 821 *                      string containing a unique name of the listener;
 822 *                      return code is the size in bytes of the string
 823 *      On error:       return code is a negative errno value
 824 *
 825 * OR
 826 *
 827 * Input:
 828 *                      buf:            C string containing a transport
 829 *                                      name and an unsigned integer value
 830 *                                      representing the port to listen on,
 831 *                                      separated by whitespace
 832 *                      size:           non-zero length of C string in @buf
 833 * Output:
 834 *      On success:     returns zero; NFS service is started
 835 *      On error:       return code is a negative errno value
 836 *
 837 * OR
 838 *
 839 * Input:
 840 *                      buf:            C string containing a "-" followed
 841 *                                      by a transport name and an unsigned
 842 *                                      integer value representing the port
 843 *                                      to listen on, separated by whitespace
 844 *                      size:           non-zero length of C string in @buf
 845 * Output:
 846 *      On success:     returns zero; NFS service no longer listens
 847 *                      on that transport
 848 *      On error:       return code is a negative errno value
 849 */
 850static ssize_t write_ports(struct file *file, char *buf, size_t size)
 851{
 852        ssize_t rv;
 853
 854        mutex_lock(&nfsd_mutex);
 855        rv = __write_ports(file, buf, size);
 856        mutex_unlock(&nfsd_mutex);
 857        return rv;
 858}
 859
 860
 861int nfsd_max_blksize;
 862
 863/**
 864 * write_maxblksize - Set or report the current NFS blksize
 865 *
 866 * Input:
 867 *                      buf:            ignored
 868 *                      size:           zero
 869 *
 870 * OR
 871 *
 872 * Input:
 873 *                      buf:            C string containing an unsigned
 874 *                                      integer value representing the new
 875 *                                      NFS blksize
 876 *                      size:           non-zero length of C string in @buf
 877 * Output:
 878 *      On success:     passed-in buffer filled with '\n'-terminated C string
 879 *                      containing numeric value of the current NFS blksize
 880 *                      setting;
 881 *                      return code is the size in bytes of the string
 882 *      On error:       return code is zero or a negative errno value
 883 */
 884static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
 885{
 886        char *mesg = buf;
 887        if (size > 0) {
 888                int bsize;
 889                int rv = get_int(&mesg, &bsize);
 890                if (rv)
 891                        return rv;
 892                /* force bsize into allowed range and
 893                 * required alignment.
 894                 */
 895                if (bsize < 1024)
 896                        bsize = 1024;
 897                if (bsize > NFSSVC_MAXBLKSIZE)
 898                        bsize = NFSSVC_MAXBLKSIZE;
 899                bsize &= ~(1024-1);
 900                mutex_lock(&nfsd_mutex);
 901                if (nfsd_serv) {
 902                        mutex_unlock(&nfsd_mutex);
 903                        return -EBUSY;
 904                }
 905                nfsd_max_blksize = bsize;
 906                mutex_unlock(&nfsd_mutex);
 907        }
 908
 909        return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
 910                                                        nfsd_max_blksize);
 911}
 912
 913#ifdef CONFIG_NFSD_V4
 914static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
 915{
 916        char *mesg = buf;
 917        int rv, i;
 918
 919        if (size > 0) {
 920                if (nfsd_serv)
 921                        return -EBUSY;
 922                rv = get_int(&mesg, &i);
 923                if (rv)
 924                        return rv;
 925                /*
 926                 * Some sanity checking.  We don't have a reason for
 927                 * these particular numbers, but problems with the
 928                 * extremes are:
 929                 *      - Too short: the briefest network outage may
 930                 *        cause clients to lose all their locks.  Also,
 931                 *        the frequent polling may be wasteful.
 932                 *      - Too long: do you really want reboot recovery
 933                 *        to take more than an hour?  Or to make other
 934                 *        clients wait an hour before being able to
 935                 *        revoke a dead client's locks?
 936                 */
 937                if (i < 10 || i > 3600)
 938                        return -EINVAL;
 939                *time = i;
 940        }
 941
 942        return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time);
 943}
 944
 945static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
 946{
 947        ssize_t rv;
 948
 949        mutex_lock(&nfsd_mutex);
 950        rv = __nfsd4_write_time(file, buf, size, time);
 951        mutex_unlock(&nfsd_mutex);
 952        return rv;
 953}
 954
 955/**
 956 * write_leasetime - Set or report the current NFSv4 lease time
 957 *
 958 * Input:
 959 *                      buf:            ignored
 960 *                      size:           zero
 961 *
 962 * OR
 963 *
 964 * Input:
 965 *                      buf:            C string containing an unsigned
 966 *                                      integer value representing the new
 967 *                                      NFSv4 lease expiry time
 968 *                      size:           non-zero length of C string in @buf
 969 * Output:
 970 *      On success:     passed-in buffer filled with '\n'-terminated C
 971 *                      string containing unsigned integer value of the
 972 *                      current lease expiry time;
 973 *                      return code is the size in bytes of the string
 974 *      On error:       return code is zero or a negative errno value
 975 */
 976static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
 977{
 978        return nfsd4_write_time(file, buf, size, &nfsd4_lease);
 979}
 980
 981/**
 982 * write_gracetime - Set or report current NFSv4 grace period time
 983 *
 984 * As above, but sets the time of the NFSv4 grace period.
 985 *
 986 * Note this should never be set to less than the *previous*
 987 * lease-period time, but we don't try to enforce this.  (In the common
 988 * case (a new boot), we don't know what the previous lease time was
 989 * anyway.)
 990 */
 991static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
 992{
 993        return nfsd4_write_time(file, buf, size, &nfsd4_grace);
 994}
 995
 996extern char *nfs4_recoverydir(void);
 997
 998static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
 999{
1000        char *mesg = buf;
1001        char *recdir;
1002        int len, status;
1003
1004        if (size > 0) {
1005                if (nfsd_serv)
1006                        return -EBUSY;
1007                if (size > PATH_MAX || buf[size-1] != '\n')
1008                        return -EINVAL;
1009                buf[size-1] = 0;
1010
1011                recdir = mesg;
1012                len = qword_get(&mesg, recdir, size);
1013                if (len <= 0)
1014                        return -EINVAL;
1015
1016                status = nfs4_reset_recoverydir(recdir);
1017                if (status)
1018                        return status;
1019        }
1020
1021        return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
1022                                                        nfs4_recoverydir());
1023}
1024
1025/**
1026 * write_recoverydir - Set or report the pathname of the recovery directory
1027 *
1028 * Input:
1029 *                      buf:            ignored
1030 *                      size:           zero
1031 *
1032 * OR
1033 *
1034 * Input:
1035 *                      buf:            C string containing the pathname
1036 *                                      of the directory on a local file
1037 *                                      system containing permanent NFSv4
1038 *                                      recovery data
1039 *                      size:           non-zero length of C string in @buf
1040 * Output:
1041 *      On success:     passed-in buffer filled with '\n'-terminated C string
1042 *                      containing the current recovery pathname setting;
1043 *                      return code is the size in bytes of the string
1044 *      On error:       return code is zero or a negative errno value
1045 */
1046static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
1047{
1048        ssize_t rv;
1049
1050        mutex_lock(&nfsd_mutex);
1051        rv = __write_recoverydir(file, buf, size);
1052        mutex_unlock(&nfsd_mutex);
1053        return rv;
1054}
1055
1056#endif
1057
1058/*----------------------------------------------------------------------------*/
1059/*
1060 *      populating the filesystem.
1061 */
1062
1063static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
1064{
1065        static struct tree_descr nfsd_files[] = {
1066                [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
1067                [NFSD_Export_features] = {"export_features",
1068                                        &export_features_operations, S_IRUGO},
1069                [NFSD_FO_UnlockIP] = {"unlock_ip",
1070                                        &transaction_ops, S_IWUSR|S_IRUSR},
1071                [NFSD_FO_UnlockFS] = {"unlock_filesystem",
1072                                        &transaction_ops, S_IWUSR|S_IRUSR},
1073                [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
1074                [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
1075                [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
1076                [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
1077                [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
1078                [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
1079                [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
1080#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
1081                [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
1082#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
1083#ifdef CONFIG_NFSD_V4
1084                [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
1085                [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
1086                [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
1087#endif
1088                /* last one */ {""}
1089        };
1090        return simple_fill_super(sb, 0x6e667364, nfsd_files);
1091}
1092
1093static struct dentry *nfsd_mount(struct file_system_type *fs_type,
1094        int flags, const char *dev_name, void *data)
1095{
1096        return mount_single(fs_type, flags, data, nfsd_fill_super);
1097}
1098
1099static struct file_system_type nfsd_fs_type = {
1100        .owner          = THIS_MODULE,
1101        .name           = "nfsd",
1102        .mount          = nfsd_mount,
1103        .kill_sb        = kill_litter_super,
1104};
1105
1106#ifdef CONFIG_PROC_FS
1107static int create_proc_exports_entry(void)
1108{
1109        struct proc_dir_entry *entry;
1110
1111        entry = proc_mkdir("fs/nfs", NULL);
1112        if (!entry)
1113                return -ENOMEM;
1114        entry = proc_create("exports", 0, entry, &exports_operations);
1115        if (!entry)
1116                return -ENOMEM;
1117        return 0;
1118}
1119#else /* CONFIG_PROC_FS */
1120static int create_proc_exports_entry(void)
1121{
1122        return 0;
1123}
1124#endif
1125
1126static int __init init_nfsd(void)
1127{
1128        int retval;
1129        printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
1130
1131        retval = nfs4_state_init(); /* nfs4 locking state */
1132        if (retval)
1133                return retval;
1134        nfsd_stat_init();       /* Statistics */
1135        retval = nfsd_reply_cache_init();
1136        if (retval)
1137                goto out_free_stat;
1138        retval = nfsd_export_init();
1139        if (retval)
1140                goto out_free_cache;
1141        nfsd_lockd_init();      /* lockd->nfsd callbacks */
1142        retval = nfsd_idmap_init();
1143        if (retval)
1144                goto out_free_lockd;
1145        retval = create_proc_exports_entry();
1146        if (retval)
1147                goto out_free_idmap;
1148        retval = register_filesystem(&nfsd_fs_type);
1149        if (retval)
1150                goto out_free_all;
1151        return 0;
1152out_free_all:
1153        remove_proc_entry("fs/nfs/exports", NULL);
1154        remove_proc_entry("fs/nfs", NULL);
1155out_free_idmap:
1156        nfsd_idmap_shutdown();
1157out_free_lockd:
1158        nfsd_lockd_shutdown();
1159        nfsd_export_shutdown();
1160out_free_cache:
1161        nfsd_reply_cache_shutdown();
1162out_free_stat:
1163        nfsd_stat_shutdown();
1164        nfsd4_free_slabs();
1165        return retval;
1166}
1167
1168static void __exit exit_nfsd(void)
1169{
1170        nfsd_export_shutdown();
1171        nfsd_reply_cache_shutdown();
1172        remove_proc_entry("fs/nfs/exports", NULL);
1173        remove_proc_entry("fs/nfs", NULL);
1174        nfsd_stat_shutdown();
1175        nfsd_lockd_shutdown();
1176        nfsd_idmap_shutdown();
1177        nfsd4_free_slabs();
1178        unregister_filesystem(&nfsd_fs_type);
1179}
1180
1181MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
1182MODULE_LICENSE("GPL");
1183module_init(init_nfsd)
1184module_exit(exit_nfsd)
1185