]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'nfsd/nfsd-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 00:07:28 +0000 (11:07 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 00:07:28 +0000 (11:07 +1100)
1  2 
fs/namei.c

diff --combined fs/namei.c
index 33e9495a31293e2c080b5b0bd2e50523a460ceee,d68c21fe4598b10c597f7b34dc030afc73bcbc72..5d4645e6537691677ba91a488bfb149c24fa0b08
@@@ -1558,6 -1558,8 +1558,6 @@@ static int lookup_fast(struct nameidat
                negative = d_is_negative(dentry);
                if (read_seqcount_retry(&dentry->d_seq, seq))
                        return -ECHILD;
 -              if (negative)
 -                      return -ENOENT;
  
                /*
                 * This sequence count validates that the parent had no
                                goto unlazy;
                        }
                }
 +              /*
 +               * Note: do negative dentry check after revalidation in
 +               * case that drops it.
 +               */
 +              if (negative)
 +                      return -ENOENT;
                path->mnt = mnt;
                path->dentry = dentry;
                if (likely(__follow_mount_rcu(nd, path, inode, seqp)))
@@@ -2282,6 -2278,8 +2282,8 @@@ EXPORT_SYMBOL(vfs_path_lookup)
   *
   * Note that this routine is purely a helper for filesystem usage and should
   * not be called by generic code.
+  *
+  * The caller must hold base->i_mutex.
   */
  struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
  {
  }
  EXPORT_SYMBOL(lookup_one_len);
  
+ /**
+  * lookup_one_len_unlocked - filesystem helper to lookup single pathname component
+  * @name:     pathname component to lookup
+  * @base:     base directory to lookup from
+  * @len:      maximum length @len should be interpreted to
+  *
+  * Note that this routine is purely a helper for filesystem usage and should
+  * not be called by generic code.
+  *
+  * Unlike lookup_one_len, it should be called without the parent
+  * i_mutex held, and will take the i_mutex itself if necessary.
+  */
+ struct dentry *lookup_one_len_unlocked(const char *name,
+                                      struct dentry *base, int len)
+ {
+       struct qstr this;
+       unsigned int c;
+       int err;
+       struct dentry *ret;
+       this.name = name;
+       this.len = len;
+       this.hash = full_name_hash(name, len);
+       if (!len)
+               return ERR_PTR(-EACCES);
+       if (unlikely(name[0] == '.')) {
+               if (len < 2 || (len == 2 && name[1] == '.'))
+                       return ERR_PTR(-EACCES);
+       }
+       while (len--) {
+               c = *(const unsigned char *)name++;
+               if (c == '/' || c == '\0')
+                       return ERR_PTR(-EACCES);
+       }
+       /*
+        * See if the low-level filesystem might want
+        * to use its own hash..
+        */
+       if (base->d_flags & DCACHE_OP_HASH) {
+               int err = base->d_op->d_hash(base, &this);
+               if (err < 0)
+                       return ERR_PTR(err);
+       }
+       err = inode_permission(base->d_inode, MAY_EXEC);
+       if (err)
+               return ERR_PTR(err);
+       ret = __d_lookup(base, &this);
+       if (ret)
+               return ret;
+       /*
+        * __d_lookup() is used to try to get a quick answer and avoid the
+        * mutex.  A false-negative does no harm.
+        */
+       ret = __d_lookup(base, &this);
+       if (ret && ret->d_flags & DCACHE_OP_REVALIDATE) {
+               dput(ret);
+               ret = NULL;
+       }
+       if (ret)
+               return ret;
+       mutex_lock(&base->d_inode->i_mutex);
+       ret =  __lookup_hash(&this, base, 0);
+       mutex_unlock(&base->d_inode->i_mutex);
+       return ret;
+ }
+ EXPORT_SYMBOL(lookup_one_len_unlocked);
  int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
                 struct path *path, int *empty)
  {