linux/fs/nfsd/nfsfh.c
<<
>>
Prefs
   1/*
   2 * NFS server file handle treatment.
   3 *
   4 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   5 * Portions Copyright (C) 1999 G. Allen Morris III <gam3@acm.org>
   6 * Extensive rewrite by Neil Brown <neilb@cse.unsw.edu.au> Southern-Spring 1999
   7 * ... and again Southern-Winter 2001 to support export_operations
   8 */
   9
  10#include <linux/exportfs.h>
  11
  12#include <linux/sunrpc/svcauth_gss.h>
  13#include "nfsd.h"
  14#include "vfs.h"
  15#include "auth.h"
  16
  17#define NFSDDBG_FACILITY                NFSDDBG_FH
  18
  19
  20/*
  21 * our acceptability function.
  22 * if NOSUBTREECHECK, accept anything
  23 * if not, require that we can walk up to exp->ex_dentry
  24 * doing some checks on the 'x' bits
  25 */
  26static int nfsd_acceptable(void *expv, struct dentry *dentry)
  27{
  28        struct svc_export *exp = expv;
  29        int rv;
  30        struct dentry *tdentry;
  31        struct dentry *parent;
  32
  33        if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
  34                return 1;
  35
  36        tdentry = dget(dentry);
  37        while (tdentry != exp->ex_path.dentry && !IS_ROOT(tdentry)) {
  38                /* make sure parents give x permission to user */
  39                int err;
  40                parent = dget_parent(tdentry);
  41                err = inode_permission(d_inode(parent), MAY_EXEC);
  42                if (err < 0) {
  43                        dput(parent);
  44                        break;
  45                }
  46                dput(tdentry);
  47                tdentry = parent;
  48        }
  49        if (tdentry != exp->ex_path.dentry)
  50                dprintk("nfsd_acceptable failed at %p %pd\n", tdentry, tdentry);
  51        rv = (tdentry == exp->ex_path.dentry);
  52        dput(tdentry);
  53        return rv;
  54}
  55
  56/* Type check. The correct error return for type mismatches does not seem to be
  57 * generally agreed upon. SunOS seems to use EISDIR if file isn't S_IFREG; a
  58 * comment in the NFSv3 spec says this is incorrect (implementation notes for
  59 * the write call).
  60 */
  61static inline __be32
  62nfsd_mode_check(struct svc_rqst *rqstp, struct dentry *dentry,
  63                umode_t requested)
  64{
  65        umode_t mode = d_inode(dentry)->i_mode & S_IFMT;
  66
  67        if (requested == 0) /* the caller doesn't care */
  68                return nfs_ok;
  69        if (mode == requested) {
  70                if (mode == S_IFDIR && !d_can_lookup(dentry)) {
  71                        WARN_ON_ONCE(1);
  72                        return nfserr_notdir;
  73                }
  74                return nfs_ok;
  75        }
  76        /*
  77         * v4 has an error more specific than err_notdir which we should
  78         * return in preference to err_notdir:
  79         */
  80        if (rqstp->rq_vers == 4 && mode == S_IFLNK)
  81                return nfserr_symlink;
  82        if (requested == S_IFDIR)
  83                return nfserr_notdir;
  84        if (mode == S_IFDIR)
  85                return nfserr_isdir;
  86        return nfserr_inval;
  87}
  88
  89static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
  90                                          struct svc_export *exp)
  91{
  92        int flags = nfsexp_flags(rqstp, exp);
  93
  94        /* Check if the request originated from a secure port. */
  95        if (!test_bit(RQ_SECURE, &rqstp->rq_flags) && !(flags & NFSEXP_INSECURE_PORT)) {
  96                RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
  97                dprintk("nfsd: request from insecure port %s!\n",
  98                        svc_print_addr(rqstp, buf, sizeof(buf)));
  99                return nfserr_perm;
 100        }
 101
 102        /* Set user creds for this exportpoint */
 103        return nfserrno(nfsd_setuser(rqstp, exp));
 104}
 105
 106static inline __be32 check_pseudo_root(struct svc_rqst *rqstp,
 107        struct dentry *dentry, struct svc_export *exp)
 108{
 109        if (!(exp->ex_flags & NFSEXP_V4ROOT))
 110                return nfs_ok;
 111        /*
 112         * v2/v3 clients have no need for the V4ROOT export--they use
 113         * the mount protocl instead; also, further V4ROOT checks may be
 114         * in v4-specific code, in which case v2/v3 clients could bypass
 115         * them.
 116         */
 117        if (!nfsd_v4client(rqstp))
 118                return nfserr_stale;
 119        /*
 120         * We're exposing only the directories and symlinks that have to be
 121         * traversed on the way to real exports:
 122         */
 123        if (unlikely(!d_is_dir(dentry) &&
 124                     !d_is_symlink(dentry)))
 125                return nfserr_stale;
 126        /*
 127         * A pseudoroot export gives permission to access only one
 128         * single directory; the kernel has to make another upcall
 129         * before granting access to anything else under it:
 130         */
 131        if (unlikely(dentry != exp->ex_path.dentry))
 132                return nfserr_stale;
 133        return nfs_ok;
 134}
 135
 136/*
 137 * Use the given filehandle to look up the corresponding export and
 138 * dentry.  On success, the results are used to set fh_export and
 139 * fh_dentry.
 140 */
 141static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
 142{
 143        struct knfsd_fh *fh = &fhp->fh_handle;
 144        struct fid *fid = NULL, sfid;
 145        struct svc_export *exp;
 146        struct dentry *dentry;
 147        int fileid_type;
 148        int data_left = fh->fh_size/4;
 149        __be32 error;
 150
 151        error = nfserr_stale;
 152        if (rqstp->rq_vers > 2)
 153                error = nfserr_badhandle;
 154        if (rqstp->rq_vers == 4 && fh->fh_size == 0)
 155                return nfserr_nofilehandle;
 156
 157        if (fh->fh_version == 1) {
 158                int len;
 159
 160                if (--data_left < 0)
 161                        return error;
 162                if (fh->fh_auth_type != 0)
 163                        return error;
 164                len = key_len(fh->fh_fsid_type) / 4;
 165                if (len == 0)
 166                        return error;
 167                if  (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
 168                        /* deprecated, convert to type 3 */
 169                        len = key_len(FSID_ENCODE_DEV)/4;
 170                        fh->fh_fsid_type = FSID_ENCODE_DEV;
 171                        /*
 172                         * struct knfsd_fh uses host-endian fields, which are
 173                         * sometimes used to hold net-endian values. This
 174                         * confuses sparse, so we must use __force here to
 175                         * keep it from complaining.
 176                         */
 177                        fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl((__force __be32)fh->fh_fsid[0]),
 178                                                        ntohl((__force __be32)fh->fh_fsid[1])));
 179                        fh->fh_fsid[1] = fh->fh_fsid[2];
 180                }
 181                data_left -= len;
 182                if (data_left < 0)
 183                        return error;
 184                exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_fsid);
 185                fid = (struct fid *)(fh->fh_fsid + len);
 186        } else {
 187                __u32 tfh[2];
 188                dev_t xdev;
 189                ino_t xino;
 190
 191                if (fh->fh_size != NFS_FHSIZE)
 192                        return error;
 193                /* assume old filehandle format */
 194                xdev = old_decode_dev(fh->ofh_xdev);
 195                xino = u32_to_ino_t(fh->ofh_xino);
 196                mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
 197                exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
 198        }
 199
 200        error = nfserr_stale;
 201        if (PTR_ERR(exp) == -ENOENT)
 202                return error;
 203
 204        if (IS_ERR(exp))
 205                return nfserrno(PTR_ERR(exp));
 206
 207        if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) {
 208                /* Elevate privileges so that the lack of 'r' or 'x'
 209                 * permission on some parent directory will
 210                 * not stop exportfs_decode_fh from being able
 211                 * to reconnect a directory into the dentry cache.
 212                 * The same problem can affect "SUBTREECHECK" exports,
 213                 * but as nfsd_acceptable depends on correct
 214                 * access control settings being in effect, we cannot
 215                 * fix that case easily.
 216                 */
 217                struct cred *new = prepare_creds();
 218                if (!new) {
 219                        error =  nfserrno(-ENOMEM);
 220                        goto out;
 221                }
 222                new->cap_effective =
 223                        cap_raise_nfsd_set(new->cap_effective,
 224                                           new->cap_permitted);
 225                put_cred(override_creds(new));
 226                put_cred(new);
 227        } else {
 228                error = nfsd_setuser_and_check_port(rqstp, exp);
 229                if (error)
 230                        goto out;
 231        }
 232
 233        /*
 234         * Look up the dentry using the NFS file handle.
 235         */
 236        error = nfserr_stale;
 237        if (rqstp->rq_vers > 2)
 238                error = nfserr_badhandle;
 239
 240        if (fh->fh_version != 1) {
 241                sfid.i32.ino = fh->ofh_ino;
 242                sfid.i32.gen = fh->ofh_generation;
 243                sfid.i32.parent_ino = fh->ofh_dirino;
 244                fid = &sfid;
 245                data_left = 3;
 246                if (fh->ofh_dirino == 0)
 247                        fileid_type = FILEID_INO32_GEN;
 248                else
 249                        fileid_type = FILEID_INO32_GEN_PARENT;
 250        } else
 251                fileid_type = fh->fh_fileid_type;
 252
 253        if (fileid_type == FILEID_ROOT)
 254                dentry = dget(exp->ex_path.dentry);
 255        else {
 256                dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
 257                                data_left, fileid_type,
 258                                nfsd_acceptable, exp);
 259        }
 260        if (dentry == NULL)
 261                goto out;
 262        if (IS_ERR(dentry)) {
 263                if (PTR_ERR(dentry) != -EINVAL)
 264                        error = nfserrno(PTR_ERR(dentry));
 265                goto out;
 266        }
 267
 268        if (d_is_dir(dentry) &&
 269                        (dentry->d_flags & DCACHE_DISCONNECTED)) {
 270                printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %pd2\n",
 271                                dentry);
 272        }
 273
 274        fhp->fh_dentry = dentry;
 275        fhp->fh_export = exp;
 276        return 0;
 277out:
 278        exp_put(exp);
 279        return error;
 280}
 281
 282/**
 283 * fh_verify - filehandle lookup and access checking
 284 * @rqstp: pointer to current rpc request
 285 * @fhp: filehandle to be verified
 286 * @type: expected type of object pointed to by filehandle
 287 * @access: type of access needed to object
 288 *
 289 * Look up a dentry from the on-the-wire filehandle, check the client's
 290 * access to the export, and set the current task's credentials.
 291 *
 292 * Regardless of success or failure of fh_verify(), fh_put() should be
 293 * called on @fhp when the caller is finished with the filehandle.
 294 *
 295 * fh_verify() may be called multiple times on a given filehandle, for
 296 * example, when processing an NFSv4 compound.  The first call will look
 297 * up a dentry using the on-the-wire filehandle.  Subsequent calls will
 298 * skip the lookup and just perform the other checks and possibly change
 299 * the current task's credentials.
 300 *
 301 * @type specifies the type of object expected using one of the S_IF*
 302 * constants defined in include/linux/stat.h.  The caller may use zero
 303 * to indicate that it doesn't care, or a negative integer to indicate
 304 * that it expects something not of the given type.
 305 *
 306 * @access is formed from the NFSD_MAY_* constants defined in
 307 * fs/nfsd/vfs.h.
 308 */
 309__be32
 310fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
 311{
 312        struct svc_export *exp;
 313        struct dentry   *dentry;
 314        __be32          error;
 315
 316        dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
 317
 318        if (!fhp->fh_dentry) {
 319                error = nfsd_set_fh_dentry(rqstp, fhp);
 320                if (error)
 321                        goto out;
 322        }
 323        dentry = fhp->fh_dentry;
 324        exp = fhp->fh_export;
 325        /*
 326         * We still have to do all these permission checks, even when
 327         * fh_dentry is already set:
 328         *      - fh_verify may be called multiple times with different
 329         *        "access" arguments (e.g. nfsd_proc_create calls
 330         *        fh_verify(...,NFSD_MAY_EXEC) first, then later (in
 331         *        nfsd_create) calls fh_verify(...,NFSD_MAY_CREATE).
 332         *      - in the NFSv4 case, the filehandle may have been filled
 333         *        in by fh_compose, and given a dentry, but further
 334         *        compound operations performed with that filehandle
 335         *        still need permissions checks.  In the worst case, a
 336         *        mountpoint crossing may have changed the export
 337         *        options, and we may now need to use a different uid
 338         *        (for example, if different id-squashing options are in
 339         *        effect on the new filesystem).
 340         */
 341        error = check_pseudo_root(rqstp, dentry, exp);
 342        if (error)
 343                goto out;
 344
 345        error = nfsd_setuser_and_check_port(rqstp, exp);
 346        if (error)
 347                goto out;
 348
 349        error = nfsd_mode_check(rqstp, dentry, type);
 350        if (error)
 351                goto out;
 352
 353        /*
 354         * pseudoflavor restrictions are not enforced on NLM,
 355         * which clients virtually always use auth_sys for,
 356         * even while using RPCSEC_GSS for NFS.
 357         */
 358        if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
 359                goto skip_pseudoflavor_check;
 360        /*
 361         * Clients may expect to be able to use auth_sys during mount,
 362         * even if they use gss for everything else; see section 2.3.2
 363         * of rfc 2623.
 364         */
 365        if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
 366                        && exp->ex_path.dentry == dentry)
 367                goto skip_pseudoflavor_check;
 368
 369        error = check_nfsd_access(exp, rqstp);
 370        if (error)
 371                goto out;
 372
 373skip_pseudoflavor_check:
 374        /* Finally, check access permissions. */
 375        error = nfsd_permission(rqstp, exp, dentry, access);
 376
 377        if (error) {
 378                dprintk("fh_verify: %pd2 permission failure, "
 379                        "acc=%x, error=%d\n",
 380                        dentry,
 381                        access, ntohl(error));
 382        }
 383out:
 384        if (error == nfserr_stale)
 385                nfsdstats.fh_stale++;
 386        return error;
 387}
 388
 389
 390/*
 391 * Compose a file handle for an NFS reply.
 392 *
 393 * Note that when first composed, the dentry may not yet have
 394 * an inode.  In this case a call to fh_update should be made
 395 * before the fh goes out on the wire ...
 396 */
 397static void _fh_update(struct svc_fh *fhp, struct svc_export *exp,
 398                struct dentry *dentry)
 399{
 400        if (dentry != exp->ex_path.dentry) {
 401                struct fid *fid = (struct fid *)
 402                        (fhp->fh_handle.fh_fsid + fhp->fh_handle.fh_size/4 - 1);
 403                int maxsize = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
 404                int subtreecheck = !(exp->ex_flags & NFSEXP_NOSUBTREECHECK);
 405
 406                fhp->fh_handle.fh_fileid_type =
 407                        exportfs_encode_fh(dentry, fid, &maxsize, subtreecheck);
 408                fhp->fh_handle.fh_size += maxsize * 4;
 409        } else {
 410                fhp->fh_handle.fh_fileid_type = FILEID_ROOT;
 411        }
 412}
 413
 414/*
 415 * for composing old style file handles
 416 */
 417static inline void _fh_update_old(struct dentry *dentry,
 418                                  struct svc_export *exp,
 419                                  struct knfsd_fh *fh)
 420{
 421        fh->ofh_ino = ino_t_to_u32(d_inode(dentry)->i_ino);
 422        fh->ofh_generation = d_inode(dentry)->i_generation;
 423        if (d_is_dir(dentry) ||
 424            (exp->ex_flags & NFSEXP_NOSUBTREECHECK))
 425                fh->ofh_dirino = 0;
 426}
 427
 428static bool is_root_export(struct svc_export *exp)
 429{
 430        return exp->ex_path.dentry == exp->ex_path.dentry->d_sb->s_root;
 431}
 432
 433static struct super_block *exp_sb(struct svc_export *exp)
 434{
 435        return exp->ex_path.dentry->d_sb;
 436}
 437
 438static bool fsid_type_ok_for_exp(u8 fsid_type, struct svc_export *exp)
 439{
 440        switch (fsid_type) {
 441        case FSID_DEV:
 442                if (!old_valid_dev(exp_sb(exp)->s_dev))
 443                        return 0;
 444                /* FALL THROUGH */
 445        case FSID_MAJOR_MINOR:
 446        case FSID_ENCODE_DEV:
 447                return exp_sb(exp)->s_type->fs_flags & FS_REQUIRES_DEV;
 448        case FSID_NUM:
 449                return exp->ex_flags & NFSEXP_FSID;
 450        case FSID_UUID8:
 451        case FSID_UUID16:
 452                if (!is_root_export(exp))
 453                        return 0;
 454                /* fall through */
 455        case FSID_UUID4_INUM:
 456        case FSID_UUID16_INUM:
 457                return exp->ex_uuid != NULL;
 458        }
 459        return 1;
 460}
 461
 462
 463static void set_version_and_fsid_type(struct svc_fh *fhp, struct svc_export *exp, struct svc_fh *ref_fh)
 464{
 465        u8 version;
 466        u8 fsid_type;
 467retry:
 468        version = 1;
 469        if (ref_fh && ref_fh->fh_export == exp) {
 470                version = ref_fh->fh_handle.fh_version;
 471                fsid_type = ref_fh->fh_handle.fh_fsid_type;
 472
 473                ref_fh = NULL;
 474
 475                switch (version) {
 476                case 0xca:
 477                        fsid_type = FSID_DEV;
 478                        break;
 479                case 1:
 480                        break;
 481                default:
 482                        goto retry;
 483                }
 484
 485                /*
 486                 * As the fsid -> filesystem mapping was guided by
 487                 * user-space, there is no guarantee that the filesystem
 488                 * actually supports that fsid type. If it doesn't we
 489                 * loop around again without ref_fh set.
 490                 */
 491                if (!fsid_type_ok_for_exp(fsid_type, exp))
 492                        goto retry;
 493        } else if (exp->ex_flags & NFSEXP_FSID) {
 494                fsid_type = FSID_NUM;
 495        } else if (exp->ex_uuid) {
 496                if (fhp->fh_maxsize >= 64) {
 497                        if (is_root_export(exp))
 498                                fsid_type = FSID_UUID16;
 499                        else
 500                                fsid_type = FSID_UUID16_INUM;
 501                } else {
 502                        if (is_root_export(exp))
 503                                fsid_type = FSID_UUID8;
 504                        else
 505                                fsid_type = FSID_UUID4_INUM;
 506                }
 507        } else if (!old_valid_dev(exp_sb(exp)->s_dev))
 508                /* for newer device numbers, we must use a newer fsid format */
 509                fsid_type = FSID_ENCODE_DEV;
 510        else
 511                fsid_type = FSID_DEV;
 512        fhp->fh_handle.fh_version = version;
 513        if (version)
 514                fhp->fh_handle.fh_fsid_type = fsid_type;
 515}
 516
 517__be32
 518fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
 519           struct svc_fh *ref_fh)
 520{
 521        /* ref_fh is a reference file handle.
 522         * if it is non-null and for the same filesystem, then we should compose
 523         * a filehandle which is of the same version, where possible.
 524         * Currently, that means that if ref_fh->fh_handle.fh_version == 0xca
 525         * Then create a 32byte filehandle using nfs_fhbase_old
 526         *
 527         */
 528
 529        struct inode * inode = d_inode(dentry);
 530        dev_t ex_dev = exp_sb(exp)->s_dev;
 531
 532        dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %pd2, ino=%ld)\n",
 533                MAJOR(ex_dev), MINOR(ex_dev),
 534                (long) d_inode(exp->ex_path.dentry)->i_ino,
 535                dentry,
 536                (inode ? inode->i_ino : 0));
 537
 538        /* Choose filehandle version and fsid type based on
 539         * the reference filehandle (if it is in the same export)
 540         * or the export options.
 541         */
 542        set_version_and_fsid_type(fhp, exp, ref_fh);
 543
 544        if (ref_fh == fhp)
 545                fh_put(ref_fh);
 546
 547        if (fhp->fh_locked || fhp->fh_dentry) {
 548                printk(KERN_ERR "fh_compose: fh %pd2 not initialized!\n",
 549                       dentry);
 550        }
 551        if (fhp->fh_maxsize < NFS_FHSIZE)
 552                printk(KERN_ERR "fh_compose: called with maxsize %d! %pd2\n",
 553                       fhp->fh_maxsize,
 554                       dentry);
 555
 556        fhp->fh_dentry = dget(dentry); /* our internal copy */
 557        fhp->fh_export = exp_get(exp);
 558
 559        if (fhp->fh_handle.fh_version == 0xca) {
 560                /* old style filehandle please */
 561                memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
 562                fhp->fh_handle.fh_size = NFS_FHSIZE;
 563                fhp->fh_handle.ofh_dcookie = 0xfeebbaca;
 564                fhp->fh_handle.ofh_dev =  old_encode_dev(ex_dev);
 565                fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
 566                fhp->fh_handle.ofh_xino =
 567                        ino_t_to_u32(d_inode(exp->ex_path.dentry)->i_ino);
 568                fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry));
 569                if (inode)
 570                        _fh_update_old(dentry, exp, &fhp->fh_handle);
 571        } else {
 572                fhp->fh_handle.fh_size =
 573                        key_len(fhp->fh_handle.fh_fsid_type) + 4;
 574                fhp->fh_handle.fh_auth_type = 0;
 575
 576                mk_fsid(fhp->fh_handle.fh_fsid_type,
 577                        fhp->fh_handle.fh_fsid,
 578                        ex_dev,
 579                        d_inode(exp->ex_path.dentry)->i_ino,
 580                        exp->ex_fsid, exp->ex_uuid);
 581
 582                if (inode)
 583                        _fh_update(fhp, exp, dentry);
 584                if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) {
 585                        fh_put(fhp);
 586                        return nfserr_opnotsupp;
 587                }
 588        }
 589
 590        return 0;
 591}
 592
 593/*
 594 * Update file handle information after changing a dentry.
 595 * This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create
 596 */
 597__be32
 598fh_update(struct svc_fh *fhp)
 599{
 600        struct dentry *dentry;
 601
 602        if (!fhp->fh_dentry)
 603                goto out_bad;
 604
 605        dentry = fhp->fh_dentry;
 606        if (d_really_is_negative(dentry))
 607                goto out_negative;
 608        if (fhp->fh_handle.fh_version != 1) {
 609                _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle);
 610        } else {
 611                if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT)
 612                        return 0;
 613
 614                _fh_update(fhp, fhp->fh_export, dentry);
 615                if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID)
 616                        return nfserr_opnotsupp;
 617        }
 618        return 0;
 619out_bad:
 620        printk(KERN_ERR "fh_update: fh not verified!\n");
 621        return nfserr_serverfault;
 622out_negative:
 623        printk(KERN_ERR "fh_update: %pd2 still negative!\n",
 624                dentry);
 625        return nfserr_serverfault;
 626}
 627
 628/*
 629 * Release a file handle.
 630 */
 631void
 632fh_put(struct svc_fh *fhp)
 633{
 634        struct dentry * dentry = fhp->fh_dentry;
 635        struct svc_export * exp = fhp->fh_export;
 636        if (dentry) {
 637                fh_unlock(fhp);
 638                fhp->fh_dentry = NULL;
 639                dput(dentry);
 640                fh_clear_wcc(fhp);
 641        }
 642        fh_drop_write(fhp);
 643        if (exp) {
 644                exp_put(exp);
 645                fhp->fh_export = NULL;
 646        }
 647        return;
 648}
 649
 650/*
 651 * Shorthand for dprintk()'s
 652 */
 653char * SVCFH_fmt(struct svc_fh *fhp)
 654{
 655        struct knfsd_fh *fh = &fhp->fh_handle;
 656
 657        static char buf[80];
 658        sprintf(buf, "%d: %08x %08x %08x %08x %08x %08x",
 659                fh->fh_size,
 660                fh->fh_base.fh_pad[0],
 661                fh->fh_base.fh_pad[1],
 662                fh->fh_base.fh_pad[2],
 663                fh->fh_base.fh_pad[3],
 664                fh->fh_base.fh_pad[4],
 665                fh->fh_base.fh_pad[5]);
 666        return buf;
 667}
 668
 669enum fsid_source fsid_source(struct svc_fh *fhp)
 670{
 671        if (fhp->fh_handle.fh_version != 1)
 672                return FSIDSOURCE_DEV;
 673        switch(fhp->fh_handle.fh_fsid_type) {
 674        case FSID_DEV:
 675        case FSID_ENCODE_DEV:
 676        case FSID_MAJOR_MINOR:
 677                if (exp_sb(fhp->fh_export)->s_type->fs_flags & FS_REQUIRES_DEV)
 678                        return FSIDSOURCE_DEV;
 679                break;
 680        case FSID_NUM:
 681                if (fhp->fh_export->ex_flags & NFSEXP_FSID)
 682                        return FSIDSOURCE_FSID;
 683                break;
 684        default:
 685                break;
 686        }
 687        /* either a UUID type filehandle, or the filehandle doesn't
 688         * match the export.
 689         */
 690        if (fhp->fh_export->ex_flags & NFSEXP_FSID)
 691                return FSIDSOURCE_FSID;
 692        if (fhp->fh_export->ex_uuid)
 693                return FSIDSOURCE_UUID;
 694        return FSIDSOURCE_DEV;
 695}
 696