arm64: dts: rk3399-sapphire: enable isp0 isp1
[firefly-linux-kernel-4.4.55.git] / fs / nfsd / vfs.c
index 994d66fbb4467ac8892a4d2ae0e5e9fda2a05722..91e0c5429b4d62f58be1100bb51b93a4ba2832e3 100644 (file)
@@ -369,7 +369,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        __be32          err;
        int             host_err;
        bool            get_write_count;
-       int             size_change = 0;
+       bool            size_change = (iap->ia_valid & ATTR_SIZE);
 
        if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
                accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
@@ -382,11 +382,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        /* Get inode */
        err = fh_verify(rqstp, fhp, ftype, accmode);
        if (err)
-               goto out;
+               return err;
        if (get_write_count) {
                host_err = fh_want_write(fhp);
                if (host_err)
-                       return nfserrno(host_err);
+                       goto out;
        }
 
        dentry = fhp->fh_dentry;
@@ -397,20 +397,28 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
                iap->ia_valid &= ~ATTR_MODE;
 
        if (!iap->ia_valid)
-               goto out;
+               return 0;
 
        nfsd_sanitize_attrs(inode, iap);
 
+       if (check_guard && guardtime != inode->i_ctime.tv_sec)
+               return nfserr_notsync;
+
        /*
         * The size case is special, it changes the file in addition to the
-        * attributes.
+        * attributes, and file systems don't expect it to be mixed with
+        * "random" attribute changes.  We thus split out the size change
+        * into a separate call to ->setattr, and do the rest as a separate
+        * setattr call.
         */
-       if (iap->ia_valid & ATTR_SIZE) {
+       if (size_change) {
                err = nfsd_get_write_access(rqstp, fhp, iap);
                if (err)
-                       goto out;
-               size_change = 1;
+                       return err;
+       }
 
+       fh_lock(fhp);
+       if (size_change) {
                /*
                 * RFC5661, Section 18.30.4:
                 *   Changing the size of a file with SETATTR indirectly
@@ -418,29 +426,36 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
                 *
                 * (and similar for the older RFCs)
                 */
-               if (iap->ia_size != i_size_read(inode))
-                       iap->ia_valid |= ATTR_MTIME;
-       }
+               struct iattr size_attr = {
+                       .ia_valid       = ATTR_SIZE | ATTR_CTIME | ATTR_MTIME,
+                       .ia_size        = iap->ia_size,
+               };
 
-       iap->ia_valid |= ATTR_CTIME;
+               host_err = notify_change(dentry, &size_attr, NULL);
+               if (host_err)
+                       goto out_unlock;
+               iap->ia_valid &= ~ATTR_SIZE;
 
-       if (check_guard && guardtime != inode->i_ctime.tv_sec) {
-               err = nfserr_notsync;
-               goto out_put_write_access;
+               /*
+                * Avoid the additional setattr call below if the only other
+                * attribute that the client sends is the mtime, as we update
+                * it as part of the size change above.
+                */
+               if ((iap->ia_valid & ~ATTR_MTIME) == 0)
+                       goto out_unlock;
        }
 
-       fh_lock(fhp);
+       iap->ia_valid |= ATTR_CTIME;
        host_err = notify_change(dentry, iap, NULL);
-       fh_unlock(fhp);
-       err = nfserrno(host_err);
 
-out_put_write_access:
+out_unlock:
+       fh_unlock(fhp);
        if (size_change)
                put_write_access(inode);
-       if (!err)
-               err = nfserrno(commit_metadata(fhp));
 out:
-       return err;
+       if (!host_err)
+               host_err = commit_metadata(fhp);
+       return nfserrno(host_err);
 }
 
 #if defined(CONFIG_NFSD_V4)