NFSD: Refactor nfsd_create_setattr()
[sfrench/cifs-2.6.git] / fs / nfsd / vfs.c
index bbed7a986784a9fc0b2353976c58be655ca78b2c..83c989a5d6f3cffda000a3b7921f15235b70a999 100644 (file)
@@ -1181,14 +1181,26 @@ out:
        return err;
 }
 
-static __be32
-nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
-                       struct iattr *iap)
+/**
+ * nfsd_create_setattr - Set a created file's attributes
+ * @rqstp: RPC transaction being executed
+ * @fhp: NFS filehandle of parent directory
+ * @resfhp: NFS filehandle of new object
+ * @iap: requested attributes of new object
+ *
+ * Returns nfs_ok on success, or an nfsstat in network byte order.
+ */
+__be32
+nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
+                   struct svc_fh *resfhp, struct iattr *iap)
 {
+       __be32 status;
+
        /*
-        * Mode has already been set earlier in create:
+        * Mode has already been set by file creation.
         */
        iap->ia_valid &= ~ATTR_MODE;
+
        /*
         * Setting uid/gid works only for root.  Irix appears to
         * send along the gid on create when it tries to implement
@@ -1196,10 +1208,31 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
         */
        if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID))
                iap->ia_valid &= ~(ATTR_UID|ATTR_GID);
+
+       /*
+        * Callers expect new file metadata to be committed even
+        * if the attributes have not changed.
+        */
        if (iap->ia_valid)
-               return nfsd_setattr(rqstp, resfhp, iap, 0, (time64_t)0);
-       /* Callers expect file metadata to be committed here */
-       return nfserrno(commit_metadata(resfhp));
+               status = nfsd_setattr(rqstp, resfhp, iap, 0, (time64_t)0);
+       else
+               status = nfserrno(commit_metadata(resfhp));
+
+       /*
+        * Transactional filesystems had a chance to commit changes
+        * for both parent and child simultaneously making the
+        * following commit_metadata a noop in many cases.
+        */
+       if (!status)
+               status = nfserrno(commit_metadata(fhp));
+
+       /*
+        * Update the new filehandle to pick up the new attributes.
+        */
+       if (!status)
+               status = fh_update(resfhp);
+
+       return status;
 }
 
 /* HPUX client sometimes creates a file in mode 000, and sets size to 0.
@@ -1226,7 +1259,6 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
        struct dentry   *dentry, *dchild;
        struct inode    *dirp;
        __be32          err;
-       __be32          err2;
        int             host_err;
 
        dentry = fhp->fh_dentry;
@@ -1299,22 +1331,8 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (host_err < 0)
                goto out_nfserr;
 
-       err = nfsd_create_setattr(rqstp, resfhp, iap);
+       err = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
 
-       /*
-        * 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
-        * noop.
-        */
-       err2 = nfserrno(commit_metadata(fhp));
-       if (err2)
-               err = err2;
-       /*
-        * Update the file handle to get the new inode info.
-        */
-       if (!err)
-               err = fh_update(resfhp);
 out:
        dput(dchild);
        return err;
@@ -1505,20 +1523,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        }
 
  set_attr:
-       err = nfsd_create_setattr(rqstp, resfhp, iap);
-
-       /*
-        * nfsd_create_setattr already committed the child
-        * (and possibly also the parent).
-        */
-       if (!err)
-               err = nfserrno(commit_metadata(fhp));
-
-       /*
-        * Update the filehandle to get the new inode info.
-        */
-       if (!err)
-               err = fh_update(resfhp);
+       err = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
 
  out:
        fh_unlock(fhp);