nfsd: remove unnecessary positive-dentry check
[cascardo/linux.git] / fs / nfsd / vfs.c
index 6fbd81e..c957094 100644 (file)
@@ -1135,16 +1135,9 @@ nfsd_check_ignore_resizing(struct iattr *iap)
                iap->ia_valid &= ~ATTR_SIZE;
 }
 
-/*
- * Create a file (regular, directory, device, fifo); UNIX sockets 
- * not yet implemented.
- * If the response fh has been verified, the parent directory should
- * already be locked. Note that the parent directory is left locked.
- *
- * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
- */
+/* The parent directory should already be locked: */
 __be32
-nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
+nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
                char *fname, int flen, struct iattr *iap,
                int type, dev_t rdev, struct svc_fh *resfhp)
 {
@@ -1154,63 +1147,21 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        __be32          err2;
        int             host_err;
 
-       err = nfserr_perm;
-       if (!flen)
-               goto out;
-       err = nfserr_exist;
-       if (isdotent(fname, flen))
-               goto out;
-
-       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
-       if (err)
-               goto out;
-
        dentry = fhp->fh_dentry;
        dirp = d_inode(dentry);
 
-       err = nfserr_notdir;
-       if (!dirp->i_op->lookup)
-               goto out;
-       /*
-        * Check whether the response file handle has been verified yet.
-        * If it has, the parent directory should already be locked.
-        */
-       if (!resfhp->fh_dentry) {
-               host_err = fh_want_write(fhp);
-               if (host_err)
-                       goto out_nfserr;
-
-               /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
-               fh_lock_nested(fhp, I_MUTEX_PARENT);
-               dchild = lookup_one_len(fname, dentry, flen);
-               host_err = PTR_ERR(dchild);
-               if (IS_ERR(dchild))
-                       goto out_nfserr;
-               err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
-               if (err)
-                       goto out;
-       } else {
-               /* called from nfsd_proc_create */
-               dchild = dget(resfhp->fh_dentry);
-               if (!fhp->fh_locked) {
-                       /* not actually possible */
-                       printk(KERN_ERR
-                               "nfsd_create: parent %pd2 not locked!\n",
+       dchild = dget(resfhp->fh_dentry);
+       if (!fhp->fh_locked) {
+               WARN_ONCE(1, "nfsd_create: parent %pd2 not locked!\n",
                                dentry);
-                       err = nfserr_io;
-                       goto out;
-               }
-       }
-       /*
-        * Make sure the child dentry is still negative ...
-        */
-       err = nfserr_exist;
-       if (d_really_is_positive(dchild)) {
-               dprintk("nfsd_create: dentry %pd/%pd not negative!\n",
-                       dentry, dchild);
-               goto out; 
+               err = nfserr_io;
+               goto out;
        }
 
+       err = nfsd_permission(rqstp, fhp->fh_export, dentry, NFSD_MAY_CREATE);
+       if (err)
+               goto out;
+
        if (!(iap->ia_valid & ATTR_MODE))
                iap->ia_mode = 0;
        iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type;
@@ -1222,9 +1173,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                goto out;
        }
 
-       /*
-        * Get the dir op function pointer.
-        */
        err = 0;
        host_err = 0;
        switch (type) {
@@ -1251,7 +1199,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        /*
         * nfsd_create_setattr already committed the child.  Transactional
         * filesystems had a chance to commit changes for both parent and
-        * child simultaneously making the following commit_metadata a
+        * child simultaneously making the following commit_metadata a
         * noop.
         */
        err2 = nfserrno(commit_metadata(fhp));
@@ -1272,6 +1220,54 @@ out_nfserr:
        goto out;
 }
 
+/*
+ * Create a filesystem object (regular, directory, special).
+ * Note that the parent directory is left locked.
+ *
+ * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
+ */
+__be32
+nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               char *fname, int flen, struct iattr *iap,
+               int type, dev_t rdev, struct svc_fh *resfhp)
+{
+       struct dentry   *dentry, *dchild = NULL;
+       struct inode    *dirp;
+       __be32          err;
+       int             host_err;
+
+       if (isdotent(fname, flen))
+               return nfserr_exist;
+
+       /*
+        * Even though it is a create, first let's see if we are even allowed
+        * to peek inside the parent
+        */
+       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
+       if (err)
+               return err;
+
+       dentry = fhp->fh_dentry;
+       dirp = d_inode(dentry);
+
+       host_err = fh_want_write(fhp);
+       if (host_err)
+               return nfserrno(host_err);
+
+       fh_lock_nested(fhp, I_MUTEX_PARENT);
+       dchild = lookup_one_len(fname, dentry, flen);
+       host_err = PTR_ERR(dchild);
+       if (IS_ERR(dchild))
+               return nfserrno(host_err);
+       err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+       if (err) {
+               dput(dchild);
+               return err;
+       }
+       return nfsd_create_locked(rqstp, fhp, fname, flen, iap, type,
+                                       rdev, resfhp);
+}
+
 #ifdef CONFIG_NFSD_V3
 
 /*
@@ -1304,12 +1300,6 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        dentry = fhp->fh_dentry;
        dirp = d_inode(dentry);
 
-       /* Get all the sanity checks out of the way before
-        * we lock the parent. */
-       err = nfserr_notdir;
-       if (!dirp->i_op->lookup)
-               goto out;
-
        host_err = fh_want_write(fhp);
        if (host_err)
                goto out_nfserr;