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