The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfsd/nfsfh.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * linux/fs/nfsd/nfsfh.c
    3  *
    4  * NFS server file handle treatment.
    5  *
    6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
    7  * Portions Copyright (C) 1999 G. Allen Morris III <gam3@acm.org>
    8  * Extensive rewrite by Neil Brown <neilb@cse.unsw.edu.au> Southern-Spring 1999
    9  */
   10 
   11 #include <linux/sched.h>
   12 #include <linux/slab.h>
   13 #include <linux/fs.h>
   14 #include <linux/unistd.h>
   15 #include <linux/string.h>
   16 #include <linux/stat.h>
   17 #include <linux/dcache.h>
   18 #include <asm/pgtable.h>
   19 
   20 #include <linux/sunrpc/svc.h>
   21 #include <linux/nfsd/nfsd.h>
   22 
   23 #define NFSDDBG_FACILITY                NFSDDBG_FH
   24 #define NFSD_PARANOIA 1
   25 /* #define NFSD_DEBUG_VERBOSE 1 */
   26 
   27 
   28 static int nfsd_nr_verified;
   29 static int nfsd_nr_put;
   30 
   31 
   32 struct nfsd_getdents_callback {
   33         char *name;             /* name that was found. It already points to a buffer NAME_MAX+1 is size */
   34         unsigned long ino;      /* the inum we are looking for */
   35         int found;              /* inode matched? */
   36         int sequence;           /* sequence counter */
   37 };
   38 
   39 /*
   40  * A rather strange filldir function to capture
   41  * the name matching the specified inode number.
   42  */
   43 static int filldir_one(void * __buf, const char * name, int len,
   44                         loff_t pos, ino_t ino, unsigned int d_type)
   45 {
   46         struct nfsd_getdents_callback *buf = __buf;
   47         int result = 0;
   48 
   49         buf->sequence++;
   50 #ifdef NFSD_DEBUG_VERBOSE
   51 dprintk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name);
   52 #endif
   53         if (buf->ino == ino) {
   54                 memcpy(buf->name, name, len);
   55                 buf->name[len] = '\0';
   56                 buf->found = 1;
   57                 result = -1;
   58         }
   59         return result;
   60 }
   61 
   62 /**
   63  * nfsd_get_name - default nfsd_operations->get_name function
   64  * @dentry: the directory in which to find a name
   65  * @name:   a pointer to a %NAME_MAX+1 char buffer to store the name
   66  * @child:  the dentry for the child directory.
   67  *
   68  * calls readdir on the parent until it finds an entry with
   69  * the same inode number as the child, and returns that.
   70  */
   71 static int nfsd_get_name(struct dentry *dentry, char *name,
   72                         struct dentry *child)
   73 {
   74         struct inode *dir = dentry->d_inode;
   75         int error;
   76         struct file file;
   77         struct nfsd_getdents_callback buffer;
   78 
   79         error = -ENOTDIR;
   80         if (!dir || !S_ISDIR(dir->i_mode))
   81                 goto out;
   82         error = -EINVAL;
   83         if (!dir->i_fop)
   84                 goto out;
   85         /*
   86          * Open the directory ...
   87          */
   88         error = init_private_file(&file, dentry, FMODE_READ);
   89         if (error)
   90                 goto out;
   91         error = -EINVAL;
   92         if (!file.f_op->readdir)
   93                 goto out_close;
   94 
   95         buffer.name = name;
   96         buffer.ino = child->d_inode->i_ino;
   97         buffer.found = 0;
   98         buffer.sequence = 0;
   99         while (1) {
  100                 int old_seq = buffer.sequence;
  101 
  102                 error = vfs_readdir(&file, filldir_one, &buffer);
  103 
  104                 if (error < 0)
  105                         break;
  106 
  107                 error = 0;
  108                 if (buffer.found)
  109                         break;
  110                 error = -ENOENT;
  111                 if (old_seq == buffer.sequence)
  112                         break;
  113         }
  114 
  115 out_close:
  116         if (file.f_op->release)
  117                 file.f_op->release(dir, &file);
  118 out:
  119         return error;
  120 }
  121 
  122 /* this should be provided by each filesystem in an nfsd_operations interface as
  123  * iget isn't really the right interface
  124  */
  125 static struct dentry *nfsd_iget(struct super_block *sb, unsigned long ino, __u32 generation)
  126 {
  127 
  128         /* iget isn't really right if the inode is currently unallocated!!
  129          * This should really all be done inside each filesystem
  130          *
  131          * ext2fs' read_inode has been strengthed to return a bad_inode if the inode
  132          *   had been deleted.
  133          *
  134          * Currently we don't know the generation for parent directory, so a generation
  135          * of 0 means "accept any"
  136          */
  137         struct inode *inode;
  138         struct list_head *lp;
  139         struct dentry *result;
  140         if (ino == 0)
  141                 return ERR_PTR(-ESTALE);
  142         inode = iget(sb, ino);
  143         if (inode == NULL)
  144                 return ERR_PTR(-ENOMEM);
  145         if (is_bad_inode(inode)
  146             || (generation && inode->i_generation != generation)
  147                 ) {
  148                 /* we didn't find the right inode.. */
  149                 dprintk("fh_verify: Inode %lu, Bad count: %d %d or version  %u %u\n",
  150                         inode->i_ino,
  151                         inode->i_nlink, atomic_read(&inode->i_count),
  152                         inode->i_generation,
  153                         generation);
  154 
  155                 iput(inode);
  156                 return ERR_PTR(-ESTALE);
  157         }
  158         /* now to find a dentry.
  159          * If possible, get a well-connected one
  160          */
  161         spin_lock(&dcache_lock);
  162         for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) {
  163                 result = list_entry(lp,struct dentry, d_alias);
  164                 if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
  165                         dget_locked(result);
  166                         result->d_vfs_flags |= DCACHE_REFERENCED;
  167                         spin_unlock(&dcache_lock);
  168                         iput(inode);
  169                         return result;
  170                 }
  171         }
  172         spin_unlock(&dcache_lock);
  173         result = d_alloc_root(inode);
  174         if (result == NULL) {
  175                 iput(inode);
  176                 return ERR_PTR(-ENOMEM);
  177         }
  178         result->d_flags |= DCACHE_NFSD_DISCONNECTED;
  179         return result;
  180 }
  181 
  182 static struct dentry *nfsd_get_dentry(struct super_block *sb, __u32 *fh,
  183                                              int len, int fhtype, int parent)
  184 {
  185         if (sb->s_op->fh_to_dentry)
  186                 return sb->s_op->fh_to_dentry(sb, fh, len, fhtype, parent);
  187         switch (fhtype) {
  188         case 1:
  189                 if (len < 2)
  190                         break;
  191                 if (parent)
  192                         break;
  193                 return nfsd_iget(sb, fh[0], fh[1]);
  194 
  195         case 2:
  196                 if (len < 3)
  197                         break;
  198                 if (parent)
  199                         return nfsd_iget(sb,fh[2],0);
  200                 return nfsd_iget(sb,fh[0],fh[1]);
  201         default: break;
  202         }
  203         return ERR_PTR(-EINVAL);
  204 }
  205 
  206 
  207 /* this routine links an IS_ROOT dentry into the dcache tree.  It gains "parent"
  208  * as a parent and "name" as a name
  209  * It should possibly go in dcache.c
  210  */
  211 int d_splice(struct dentry *target, struct dentry *parent, struct qstr *name)
  212 {
  213         struct dentry *tdentry;
  214 #ifdef NFSD_PARANOIA
  215         if (!IS_ROOT(target))
  216                 printk("nfsd: d_splice with no-root target: %s/%s\n", parent->d_name.name, name->name);
  217         if (!(target->d_flags & DCACHE_NFSD_DISCONNECTED))
  218                 printk("nfsd: d_splice with non-DISCONNECTED target: %s/%s\n", parent->d_name.name, name->name);
  219 #endif
  220         tdentry = d_alloc(parent, name);
  221         if (tdentry == NULL)
  222                 return -ENOMEM;
  223         d_move(target, tdentry);
  224 
  225         /* tdentry will have been made a "child" of target (the parent of target)
  226          * make it an IS_ROOT instead
  227          */
  228         spin_lock(&dcache_lock);
  229         list_del_init(&tdentry->d_child);
  230         tdentry->d_parent = tdentry;
  231         spin_unlock(&dcache_lock);
  232         d_rehash(target);
  233         dput(tdentry);
  234 
  235         /* if parent is properly connected, then we can assert that
  236          * the children are connected, but it must be a singluar (non-forking)
  237          * branch
  238          */
  239         if (!(parent->d_flags & DCACHE_NFSD_DISCONNECTED)) {
  240                 while (target) {
  241                         target->d_flags &= ~DCACHE_NFSD_DISCONNECTED;
  242                         parent = target;
  243                         spin_lock(&dcache_lock);
  244                         if (list_empty(&parent->d_subdirs))
  245                                 target = NULL;
  246                         else {
  247                                 target = list_entry(parent->d_subdirs.next, struct dentry, d_child);
  248 #ifdef NFSD_PARANOIA
  249                                 /* must be only child */
  250                                 if (target->d_child.next != &parent->d_subdirs
  251                                     || target->d_child.prev != &parent->d_subdirs)
  252                                         printk("nfsd: d_splice found non-singular disconnected branch: %s/%s\n",
  253                                                parent->d_name.name, target->d_name.name);
  254 #endif
  255                         }
  256                         spin_unlock(&dcache_lock);
  257                 }
  258         }
  259         return 0;
  260 }
  261 
  262 /* this routine finds the dentry of the parent of a given directory
  263  * it should be in the filesystem accessed by nfsd_operations
  264  * it assumes lookup("..") works.
  265  */
  266 struct dentry *nfsd_findparent(struct dentry *child)
  267 {
  268         struct dentry *tdentry, *pdentry;
  269         tdentry = d_alloc(child, &(const struct qstr) {"..", 2, 0});
  270         if (!tdentry)
  271                 return ERR_PTR(-ENOMEM);
  272 
  273         /* I'm going to assume that if the returned dentry is different, then
  274          * it is well connected.  But nobody returns different dentrys do they?
  275          */
  276         down(&child->d_inode->i_sem);
  277         pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
  278         up(&child->d_inode->i_sem);
  279         d_drop(tdentry); /* we never want ".." hashed */
  280         if (!pdentry && tdentry->d_inode == NULL) {
  281                 /* File system cannot find ".." ... sad but possible */
  282                 pdentry = ERR_PTR(-EINVAL);
  283         }
  284         if (!pdentry) {
  285                 /* I don't want to return a ".." dentry.
  286                  * I would prefer to return an unconnected "IS_ROOT" dentry,
  287                  * though a properly connected dentry is even better
  288                  */
  289                 /* if first or last of alias list is not tdentry, use that
  290                  * else make a root dentry
  291                  */
  292                 struct list_head *aliases = &tdentry->d_inode->i_dentry;
  293                 spin_lock(&dcache_lock);
  294                 if (aliases->next != aliases) {
  295                         pdentry = list_entry(aliases->next, struct dentry, d_alias);
  296                         if (pdentry == tdentry)
  297                                 pdentry = list_entry(aliases->prev, struct dentry, d_alias);
  298                         if (pdentry == tdentry)
  299                                 pdentry = NULL;
  300                         if (pdentry) dget_locked(pdentry);
  301                 }
  302                 spin_unlock(&dcache_lock);
  303                 if (pdentry == NULL) {
  304                         pdentry = d_alloc_root(tdentry->d_inode);
  305                         if (pdentry) {
  306                                 igrab(tdentry->d_inode);
  307                                 pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
  308                         }
  309                 }
  310                 if (pdentry == NULL)
  311                         pdentry = ERR_PTR(-ENOMEM);
  312         }
  313         dput(tdentry); /* it is not hashed, it will be discarded */
  314         return pdentry;
  315 }
  316 
  317 static struct dentry *splice(struct dentry *child, struct dentry *parent)
  318 {
  319         int err = 0, nerr;
  320         struct qstr qs;
  321         char namebuf[256];
  322         struct list_head *lp;
  323         /* child is an IS_ROOT (anonymous) dentry, but it is hypothesised that
  324          * it should be a child of parent.
  325          * We see if we can find a name and, if we can - splice it in.
  326          * We lookup the name before locking (i_sem) the directory as namelookup
  327          * also claims i_sem.  If the name gets changed then we will loop around
  328          * and try again in find_fh_dentry.
  329          */
  330 
  331         nerr = nfsd_get_name(parent, namebuf, child);
  332 
  333         /*
  334          * We now claim the parent i_sem so that no-one else tries to create
  335          * a dentry in the parent while we are.
  336          */
  337         
  338         down(&parent->d_inode->i_sem);
  339 
  340         /* Now, things might have changed while we waited.
  341          * Possibly a friendly filesystem found child and spliced it in in response
  342          * to a lookup (though nobody does this yet).  In this case, just succeed.
  343          */
  344         if (child->d_parent == parent) goto out;
  345         
  346         /* Possibly a new dentry has been made for this child->d_inode in
  347          * parent by a lookup.  In this case return that dentry. Caller must
  348          * notice and act accordingly
  349          */
  350         spin_lock(&dcache_lock);
  351         list_for_each(lp, &child->d_inode->i_dentry) {
  352                 struct dentry *tmp = list_entry(lp,struct dentry, d_alias);
  353                 if (!list_empty(&tmp->d_hash) &&
  354                     tmp->d_parent == parent) {
  355                         child = dget_locked(tmp);
  356                         spin_unlock(&dcache_lock);
  357                         goto out;
  358                 }
  359         }
  360         spin_unlock(&dcache_lock);
  361 
  362         /* now we need that name.  If there was an error getting it, now is th
  363          * time to bail out.
  364          */
  365         if ((err = nerr))
  366                 goto out;
  367         qs.name = namebuf;
  368         qs.len = strlen(namebuf);
  369         if (find_inode_number(parent, &qs) != 0) {
  370                 /* Now that IS odd.  I wonder what it means... */
  371                 err = -EEXIST;
  372                 printk("nfsd-fh: found a name that I didn't expect: %s/%s\n", parent->d_name.name, qs.name);
  373                 goto out;
  374         }
  375         err = d_splice(child, parent, &qs);
  376         dprintk("nfsd_fh: found name %s for ino %ld\n", child->d_name.name, child->d_inode->i_ino);
  377  out:
  378         up(&parent->d_inode->i_sem);
  379         if (err)
  380                 return ERR_PTR(err);
  381         else
  382                 return child;
  383 }
  384 
  385 /*
  386  * This is the basic lookup mechanism for turning an NFS file handle
  387  * into a dentry.
  388  * We use nfsd_iget and if that doesn't return a suitably connected dentry,
  389  * we try to find the parent, and the parent of that and so-on until a
  390  * connection if made.
  391  */
  392 static struct dentry *
  393 find_fh_dentry(struct super_block *sb, __u32 *datap, int len, int fhtype, int needpath)
  394 {
  395         struct dentry *dentry, *result = NULL;
  396         struct dentry *tmp;
  397         int err = -ESTALE;
  398         /* the sb->s_nfsd_free_path_sem semaphore is needed to make sure that only one unconnected (free)
  399          * dcache path ever exists, as otherwise two partial paths might get
  400          * joined together, which would be very confusing.
  401          * If there is ever an unconnected non-root directory, then this lock
  402          * must be held.
  403          */
  404 
  405 
  406         nfsdstats.fh_lookup++;
  407         /*
  408          * Attempt to find the inode.
  409          */
  410  retry:
  411         down(&sb->s_nfsd_free_path_sem);
  412         result = nfsd_get_dentry(sb, datap, len, fhtype, 0);
  413         if (IS_ERR(result)
  414             || !(result->d_flags & DCACHE_NFSD_DISCONNECTED)
  415             || (!S_ISDIR(result->d_inode->i_mode) && ! needpath)) {
  416                 up(&sb->s_nfsd_free_path_sem);
  417             
  418                 err = PTR_ERR(result);
  419                 if (IS_ERR(result))
  420                         goto err_out;
  421                 if ((result->d_flags & DCACHE_NFSD_DISCONNECTED))
  422                         nfsdstats.fh_anon++;
  423                 return result;
  424         }
  425 
  426         /* It's a directory, or we are required to confirm the file's
  427          * location in the tree.
  428          */
  429         dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,datap[0]);
  430 
  431         if (!S_ISDIR(result->d_inode->i_mode)) {
  432                 nfsdstats.fh_nocache_nondir++;
  433                         /* need to iget dirino and make sure this inode is in that directory */
  434                         dentry = nfsd_get_dentry(sb, datap, len, fhtype, 1);
  435                         err = PTR_ERR(dentry);
  436                         if (IS_ERR(dentry))
  437                                 goto err_result;
  438                         err = -ESTALE;
  439                         if (!dentry->d_inode
  440                             || !S_ISDIR(dentry->d_inode->i_mode)) {
  441                                 goto err_dentry;
  442                         }
  443                         tmp = splice(result, dentry);
  444                         err = PTR_ERR(tmp);
  445                         if (IS_ERR(tmp))
  446                                 goto err_dentry;
  447                         if (tmp != result) {
  448                                 /* it is safe to just use tmp instead, but we must discard result first */
  449                                 d_drop(result);
  450                                 dput(result);
  451                                 result = tmp;
  452                         }
  453         } else {
  454                 nfsdstats.fh_nocache_dir++;
  455                 dentry = dget(result);
  456         }
  457 
  458         while(dentry->d_flags & DCACHE_NFSD_DISCONNECTED) {
  459                 /* LOOP INVARIANT */
  460                 /* haven't found a place in the tree yet, but we do have a free path
  461                  * from dentry down to result, and dentry is a directory.
  462                  * Have a hold on dentry and result */
  463                 struct dentry *pdentry;
  464                 struct inode *parent;
  465 
  466                 pdentry = nfsd_findparent(dentry);
  467                 err = PTR_ERR(pdentry);
  468                 if (IS_ERR(pdentry))
  469                         goto err_dentry;
  470                 parent = pdentry->d_inode;
  471                 err = -EACCES;
  472                 if (!parent) {
  473                         dput(pdentry);
  474                         goto err_dentry;
  475                 }
  476 
  477                 tmp = splice(dentry, pdentry);
  478                 if (tmp != dentry) {
  479                         /* Something wrong.  We need to drop the whole dentry->result path
  480                          * whatever it was
  481                          */
  482                         struct dentry *d;
  483                         for (d=result ; d ; d=(d->d_parent == d)?NULL:d->d_parent)
  484                                 d_drop(d);
  485                 }
  486                 if (IS_ERR(tmp)) {
  487                         err = PTR_ERR(tmp);
  488                         dput(pdentry);
  489                         goto err_dentry;
  490                 }
  491                 if (tmp != dentry) {
  492                         /* we lost a race,  try again
  493                          */
  494                         dput(pdentry);
  495                         dput(tmp);
  496                         dput(dentry);
  497                         dput(result);   /* this will discard the whole free path, so we can up the semaphore */
  498                         up(&sb->s_nfsd_free_path_sem);
  499                         goto retry;
  500                 }
  501                 dput(dentry);
  502                 dentry = pdentry;
  503         }
  504         dput(dentry);
  505         up(&sb->s_nfsd_free_path_sem);
  506         return result;
  507 
  508 err_dentry:
  509         dput(dentry);
  510 err_result:
  511         dput(result);
  512         up(&sb->s_nfsd_free_path_sem);
  513 err_out:
  514         if (err == -ESTALE)
  515                 nfsdstats.fh_stale++;
  516         return ERR_PTR(err);
  517 }
  518 
  519 /*
  520  * Perform sanity checks on the dentry in a client's file handle.
  521  *
  522  * Note that the file handle dentry may need to be freed even after
  523  * an error return.
  524  *
  525  * This is only called at the start of an nfsproc call, so fhp points to
  526  * a svc_fh which is all 0 except for the over-the-wire file handle.
  527  */
  528 u32
  529 fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
  530 {
  531         struct knfsd_fh *fh = &fhp->fh_handle;
  532         struct svc_export *exp;
  533         struct dentry   *dentry;
  534         struct inode    *inode;
  535         u32             error = 0;
  536 
  537         dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
  538 
  539         /* keep this filehandle for possible reference  when encoding attributes */
  540         rqstp->rq_reffh = fh;
  541 
  542         if (!fhp->fh_dentry) {
  543                 kdev_t xdev = NODEV;
  544                 ino_t xino = 0;
  545                 __u32 *datap=NULL;
  546                 int data_left = fh->fh_size/4;
  547                 int nfsdev;
  548                 int fsid = 0;
  549 
  550                 error = nfserr_stale;
  551                 if (rqstp->rq_vers == 3)
  552                         error = nfserr_badhandle;
  553                 if (fh->fh_version == 1) {
  554                         
  555                         datap = fh->fh_auth;
  556                         if (--data_left<0) goto out;
  557                         switch (fh->fh_auth_type) {
  558                         case 0: break;
  559                         default: goto out;
  560                         }
  561 
  562                         switch (fh->fh_fsid_type) {
  563                         case 0:
  564                                 if ((data_left-=2)<0) goto out;
  565                                 nfsdev = ntohl(*datap++);
  566                                 xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF);
  567                                 xino = *datap++;
  568                                 break;
  569                         case 1:
  570                                 if ((data_left-=1)<0) goto out;
  571                                 fsid = *datap++;
  572                                 break;
  573                         default:
  574                                 goto out;
  575                         }
  576                 } else {
  577                         if (fh->fh_size != NFS_FHSIZE)
  578                                 goto out;
  579                         /* assume old filehandle format */
  580                         xdev = u32_to_kdev_t(fh->ofh_xdev);
  581                         xino = u32_to_ino_t(fh->ofh_xino);
  582                 }
  583 
  584                 /*
  585                  * Look up the export entry.
  586                  */
  587                 error = nfserr_stale; 
  588                 if (fh->fh_version == 1 && fh->fh_fsid_type == 1)
  589                         exp = exp_get_fsid(rqstp->rq_client, fsid);
  590                 else
  591                         exp = exp_get(rqstp->rq_client, xdev, xino);
  592 
  593                 if (!exp)
  594                         /* export entry revoked */
  595                         goto out;
  596 
  597                 /* Check if the request originated from a secure port. */
  598                 error = nfserr_perm;
  599                 if (!rqstp->rq_secure && EX_SECURE(exp)) {
  600                         printk(KERN_WARNING
  601                                "nfsd: request from insecure port (%08x:%d)!\n",
  602                                ntohl(rqstp->rq_addr.sin_addr.s_addr),
  603                                ntohs(rqstp->rq_addr.sin_port));
  604                         goto out;
  605                 }
  606 
  607                 /* Set user creds if we haven't done so already. */
  608                 nfsd_setuser(rqstp, exp);
  609 
  610                 /*
  611                  * Look up the dentry using the NFS file handle.
  612                  */
  613                 error = nfserr_stale;
  614                 if (rqstp->rq_vers == 3)
  615                         error = nfserr_badhandle;
  616 
  617                 if (fh->fh_version == 1) {
  618                         /* if fileid_type != 0, and super_operations provide fh_to_dentry lookup,
  619                          *  then should use that */
  620                         switch (fh->fh_fileid_type) {
  621                         case 0:
  622                                 dentry = dget(exp->ex_dentry);
  623                                 /* need to revalidate the inode */
  624                                 inode = dentry->d_inode;
  625                                 if (inode->i_op && inode->i_op->revalidate)
  626                                         if (inode->i_op->revalidate(dentry)) {
  627                                                 dput(dentry);
  628                                                 dentry = ERR_PTR(-ESTALE);
  629                                         }
  630                                 break;
  631                         default:
  632                                 dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
  633                                                         datap, data_left, fh->fh_fileid_type,
  634                                                         !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
  635                         }
  636                 } else {
  637                         __u32 tfh[3];
  638                         tfh[0] = fh->ofh_ino;
  639                         tfh[1] = fh->ofh_generation;
  640                         tfh[2] = fh->ofh_dirino;
  641                         dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
  642                                                 tfh, 3, fh->ofh_dirino?2:1,
  643                                                 !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
  644                 }
  645                 if (IS_ERR(dentry)) {
  646                         if (PTR_ERR(dentry) != -EINVAL)
  647                                 error = nfserrno(PTR_ERR(dentry));
  648                         goto out;
  649                 }
  650 #ifdef NFSD_PARANOIA
  651                 if (S_ISDIR(dentry->d_inode->i_mode) &&
  652                     (dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) {
  653                         printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
  654                                dentry->d_parent->d_name.name, dentry->d_name.name);
  655                 }
  656 #endif
  657 
  658                 fhp->fh_dentry = dentry;
  659                 fhp->fh_export = exp;
  660                 nfsd_nr_verified++;
  661         } else {
  662                 /* just rechecking permissions
  663                  * (e.g. nfsproc_create calls fh_verify, then nfsd_create does as well)
  664                  */
  665                 dprintk("nfsd: fh_verify - just checking\n");
  666                 dentry = fhp->fh_dentry;
  667                 exp = fhp->fh_export;
  668         }
  669 
  670         inode = dentry->d_inode;
  671 
  672         /* Type check. The correct error return for type mismatches
  673          * does not seem to be generally agreed upon. SunOS seems to
  674          * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
  675          * spec says this is incorrect (implementation notes for the
  676          * write call).
  677          */
  678 
  679         /* Type can be negative to e.g. exclude directories from linking */
  680         if (type > 0 && (inode->i_mode & S_IFMT) != type) {
  681                 if (type == S_IFDIR)
  682                         error = nfserr_notdir;
  683                 else if ((inode->i_mode & S_IFMT) == S_IFDIR)
  684                         error = nfserr_isdir;
  685                 else
  686                         error = nfserr_inval;
  687                 goto out;
  688         }
  689         if (type < 0 && (inode->i_mode & S_IFMT) == -type) {
  690                 error = (type == -S_IFDIR)? nfserr_isdir : nfserr_notdir;
  691                 goto out;
  692         }
  693 
  694         /*
  695          * Security: Check that the export is valid for dentry <gam3@acm.org>
  696          */
  697         error = 0;
  698 
  699         if (!(exp->ex_flags & NFSEXP_NOSUBTREECHECK)) {
  700                 struct dentry *tdentry = dentry;
  701 
  702                 while (tdentry != exp->ex_dentry && !IS_ROOT(tdentry)) {
  703                         struct dentry *parent = tdentry->d_parent;
  704 
  705                         /* make sure parents give x permission to user */
  706                         error = permission(parent->d_inode, MAY_EXEC);
  707                         if (error)
  708                                 break;
  709                         tdentry = parent;
  710                 }
  711                 if (exp->ex_dentry != tdentry) {
  712                         error = nfserr_stale;
  713                         printk("fh_verify: no root_squashed access at %s/%s.\n",
  714                                dentry->d_parent->d_name.name,
  715                                dentry->d_name.name);
  716                         goto out;
  717                 }
  718         }
  719 
  720         /* Finally, check access permissions. */
  721         if (!error) {
  722                 error = nfsd_permission(exp, dentry, access);
  723         }
  724 #ifdef NFSD_PARANOIA_EXTREME
  725         if (error) {
  726                 printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
  727                        dentry->d_parent->d_name.name, dentry->d_name.name, access, (error >> 24));
  728         }
  729 #endif
  730 out:
  731         if (error == nfserr_stale)
  732                 nfsdstats.fh_stale++;
  733         return error;
  734 }
  735 
  736 /*
  737  * Compose a file handle for an NFS reply.
  738  *
  739  * Note that when first composed, the dentry may not yet have
  740  * an inode.  In this case a call to fh_update should be made
  741  * before the fh goes out on the wire ...
  742  */
  743 inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
  744                       __u32 *datap, int *maxsize)
  745 {
  746         struct super_block *sb = dentry->d_inode->i_sb;
  747         
  748         if (dentry == exp->ex_dentry) {
  749                 *maxsize = 0;
  750                 return 0;
  751         }
  752 
  753         if (sb->s_op->dentry_to_fh) {
  754                 int need_parent = !S_ISDIR(dentry->d_inode->i_mode) &&
  755                         !(exp->ex_flags & NFSEXP_NOSUBTREECHECK);
  756                 
  757                 int type = sb->s_op->dentry_to_fh(dentry, datap, maxsize, need_parent);
  758                 return type;
  759         }
  760 
  761         if (*maxsize < 2)
  762                 return 255;
  763         *datap++ = ino_t_to_u32(dentry->d_inode->i_ino);
  764         *datap++ = dentry->d_inode->i_generation;
  765         if (*maxsize ==2 ||
  766             S_ISDIR(dentry->d_inode->i_mode) ||
  767             (exp->ex_flags & NFSEXP_NOSUBTREECHECK)) {
  768                 *maxsize = 2;
  769                 return 1;
  770         }
  771         *datap++ = ino_t_to_u32(dentry->d_parent->d_inode->i_ino);
  772         *maxsize = 3;
  773         return 2;
  774 }
  775 
  776 /*
  777  * for composing old style file handles
  778  */
  779 inline void _fh_update_old(struct dentry *dentry, struct svc_export *exp,
  780                            struct knfsd_fh *fh)
  781 {
  782         fh->ofh_ino = ino_t_to_u32(dentry->d_inode->i_ino);
  783         fh->ofh_generation = dentry->d_inode->i_generation;
  784         if (S_ISDIR(dentry->d_inode->i_mode) ||
  785             (exp->ex_flags & NFSEXP_NOSUBTREECHECK))
  786                 fh->ofh_dirino = 0;
  787 }
  788 
  789 int
  790 fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct svc_fh *ref_fh)
  791 {
  792         /* ref_fh is a reference file handle.
  793          * if it is non-null, then we should compose a filehandle which is
  794          * of the same version, where possible.
  795          * Currently, that means that if ref_fh->fh_handle.fh_version == 0xca
  796          * Then create a 32byte filehandle using nfs_fhbase_old
  797          * But only do this if dentry_to_fh is not available
  798          *
  799          */
  800         
  801         struct inode * inode = dentry->d_inode;
  802         struct dentry *parent = dentry->d_parent;
  803         __u32 *datap;
  804 
  805         dprintk("nfsd: fh_compose(exp %x/%ld %s/%s, ino=%ld)\n",
  806                 exp->ex_dev, (long) exp->ex_ino,
  807                 parent->d_name.name, dentry->d_name.name,
  808                 (inode ? inode->i_ino : 0));
  809 
  810         if (fhp->fh_locked || fhp->fh_dentry) {
  811                 printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n",
  812                         parent->d_name.name, dentry->d_name.name);
  813         }
  814         if (fhp->fh_maxsize < NFS_FHSIZE)
  815                 printk(KERN_ERR "fh_compose: called with maxsize %d! %s/%s\n",
  816                        fhp->fh_maxsize, parent->d_name.name, dentry->d_name.name);
  817 
  818         fhp->fh_dentry = dentry; /* our internal copy */
  819         fhp->fh_export = exp;
  820 
  821         if (ref_fh &&
  822             ref_fh->fh_handle.fh_version == 0xca &&
  823             parent->d_inode->i_sb->s_op->dentry_to_fh == NULL) {
  824                 /* old style filehandle please */
  825                 memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
  826                 fhp->fh_handle.fh_size = NFS_FHSIZE;
  827                 fhp->fh_handle.ofh_dcookie = 0xfeebbaca;
  828                 fhp->fh_handle.ofh_dev =  htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
  829                 fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
  830                 fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_ino);
  831                 fhp->fh_handle.ofh_dirino = ino_t_to_u32(dentry->d_parent->d_inode->i_ino);
  832                 if (inode)
  833                         _fh_update_old(dentry, exp, &fhp->fh_handle);
  834         } else {
  835                 fhp->fh_handle.fh_version = 1;
  836                 fhp->fh_handle.fh_auth_type = 0;
  837                 datap = fhp->fh_handle.fh_auth+0;
  838                 if ((exp->ex_flags & NFSEXP_FSID) &&
  839                     (!ref_fh || ref_fh->fh_handle.fh_fsid_type == 1)) {
  840                         fhp->fh_handle.fh_fsid_type = 1;
  841                         /* fsid_type 1 == 4 bytes filesystem id */
  842                         *datap++ = exp->ex_fsid;
  843                         fhp->fh_handle.fh_size = 2*4;
  844                 } else {
  845                         fhp->fh_handle.fh_fsid_type = 0;
  846                         /* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
  847                         *datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
  848                         *datap++ = ino_t_to_u32(exp->ex_ino);
  849                         fhp->fh_handle.fh_size = 3*4;
  850                 }
  851                 if (inode) {
  852                         int size = fhp->fh_maxsize/4 - 3;
  853                         fhp->fh_handle.fh_fileid_type =
  854                                 _fh_update(dentry, exp, datap, &size);
  855                         fhp->fh_handle.fh_size += size*4;
  856                 }
  857         }
  858 
  859         nfsd_nr_verified++;
  860         if (fhp->fh_handle.fh_fileid_type == 255)
  861                 return nfserr_opnotsupp;
  862         return 0;
  863 }
  864 
  865 /*
  866  * Update file handle information after changing a dentry.
  867  * This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create
  868  */
  869 int
  870 fh_update(struct svc_fh *fhp)
  871 {
  872         struct dentry *dentry;
  873         __u32 *datap;
  874         
  875         if (!fhp->fh_dentry)
  876                 goto out_bad;
  877 
  878         dentry = fhp->fh_dentry;
  879         if (!dentry->d_inode)
  880                 goto out_negative;
  881         if (fhp->fh_handle.fh_version != 1) {
  882                 _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle);
  883         } else {
  884                 int size;
  885                 if (fhp->fh_handle.fh_fileid_type != 0)
  886                         goto out_uptodate;
  887                 datap = fhp->fh_handle.fh_auth+
  888                         fhp->fh_handle.fh_size/4 -1;
  889                 size = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
  890                 fhp->fh_handle.fh_fileid_type =
  891                         _fh_update(dentry, fhp->fh_export, datap, &size);
  892                 fhp->fh_handle.fh_size += size*4;
  893         }
  894 out:
  895         return 0;
  896 
  897 out_bad:
  898         printk(KERN_ERR "fh_update: fh not verified!\n");
  899         goto out;
  900 out_negative:
  901         printk(KERN_ERR "fh_update: %s/%s still negative!\n",
  902                 dentry->d_parent->d_name.name, dentry->d_name.name);
  903         goto out;
  904 out_uptodate:
  905         printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
  906                 dentry->d_parent->d_name.name, dentry->d_name.name);
  907         goto out;
  908 }
  909 
  910 /*
  911  * Release a file handle.
  912  */
  913 void
  914 fh_put(struct svc_fh *fhp)
  915 {
  916         struct dentry * dentry = fhp->fh_dentry;
  917         if (dentry) {
  918                 fh_unlock(fhp);
  919                 fhp->fh_dentry = NULL;
  920                 dput(dentry);
  921                 nfsd_nr_put++;
  922         }
  923         return;
  924 }

Cache object: b9dbd8f248d305fb2446e73aa735e74d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.