This patch turned out to have a couple problems. The problems are
fixable, but at least one of the fixes is a little ugly. The original bug has always been there, so we can wait another week or two to get this right. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJYncSKAAoJECebzXlCjuG+txsP/iqR4qsw9BOpLDb0Jf3sRpcj FzNaHC3a8yIsQsgEBqaoslg1ZUIWzbcudxR4G1X0ieeE00uFLNs4/nYDBlQlYAKi bXtUcHyIqpU9eCDfe+BdrNDyfoMizQW+OoYVoLzXWR8jEzEe3HWGOtSv8Y1McIwo N75lTYfzYtM3xrUjCaQMY5BgwmOhXZMUh0bkyTGKNv0V/HY2zRrDWbNShsZnh3M+ ywhoDGHKCo1fMM8Gs4fQU4V5z6RXVqi7kNjoAdAjyxsPsBc0U7ggjNfq0mlal0FT tgGoa+KHuCyMAfbZ5gQVuqetuZXiBnc5CDyxg7idClY/aDzmwPO5dIHXoWUwCrHR Y/zJRQ0h0jfZK8Mis/T2c9ueYPkSERLHY9Pol8g35FOlkJhR2kc30wQM33Ya0hsk Hp3qPHWrVoL3AbxuPHkY3aF/YrCIOsHiqdTvxctzrPI9V+rI0Zqx0uro/yOZ/17C T38O9usblHa5KGT0rFVQDBIuZaF6lNWTV+gCQNFFu+Xxl01i82CQohmckYvV/iC7 zWnMBh7lTXwCmzw6/lWI7d277QdkfJkMYlmsOFPrkV1qxZ92KFJyqas1NFAt0Gg2 V8RmBABd6JSqmA0RWQxNh9iy9Ot53HkugTDMZKgBsBIIiI88DcY2hkhanpRhUXVn /3uBqGHbWw4wwQaeZiRe =1kRc -----END PGP SIGNATURE----- Merge tag 'nfsd-4.10-3' of git://linux-nfs.org/~bfields/linux Pull nfsd revert from Bruce Fields: "This patch turned out to have a couple problems. The problems are fixable, but at least one of the fixes is a little ugly. The original bug has always been there, so we can wait another week or two to get this right" * tag 'nfsd-4.10-3' of git://linux-nfs.org/~bfields/linux: nfsd: Revert "nfsd: special case truncates some more"
This commit is contained in:
commit
7fe654dca2
@ -332,6 +332,37 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
|
||||
}
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
struct iattr *iap)
|
||||
{
|
||||
struct inode *inode = d_inode(fhp->fh_dentry);
|
||||
int host_err;
|
||||
|
||||
if (iap->ia_size < inode->i_size) {
|
||||
__be32 err;
|
||||
|
||||
err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
|
||||
NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
host_err = get_write_access(inode);
|
||||
if (host_err)
|
||||
goto out_nfserrno;
|
||||
|
||||
host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
|
||||
if (host_err)
|
||||
goto out_put_write_access;
|
||||
return 0;
|
||||
|
||||
out_put_write_access:
|
||||
put_write_access(inode);
|
||||
out_nfserrno:
|
||||
return nfserrno(host_err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set various file attributes. After this call fhp needs an fh_put.
|
||||
*/
|
||||
@ -346,6 +377,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;
|
||||
|
||||
if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
|
||||
accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
|
||||
@ -358,11 +390,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)
|
||||
return err;
|
||||
goto out;
|
||||
if (get_write_count) {
|
||||
host_err = fh_want_write(fhp);
|
||||
if (host_err)
|
||||
goto out_host_err;
|
||||
return nfserrno(host_err);
|
||||
}
|
||||
|
||||
dentry = fhp->fh_dentry;
|
||||
@ -373,59 +405,50 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||||
iap->ia_valid &= ~ATTR_MODE;
|
||||
|
||||
if (!iap->ia_valid)
|
||||
return 0;
|
||||
goto out;
|
||||
|
||||
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, 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 for vfs_truncate, and do the rest as a
|
||||
* a separate setattr call.
|
||||
* attributes.
|
||||
*/
|
||||
if (iap->ia_valid & ATTR_SIZE) {
|
||||
struct path path = {
|
||||
.mnt = fhp->fh_export->ex_path.mnt,
|
||||
.dentry = dentry,
|
||||
};
|
||||
bool implicit_mtime = false;
|
||||
err = nfsd_get_write_access(rqstp, fhp, iap);
|
||||
if (err)
|
||||
goto out;
|
||||
size_change = 1;
|
||||
|
||||
/*
|
||||
* vfs_truncate implicity updates the mtime IFF the file size
|
||||
* actually changes. Avoid the additional seattr call below if
|
||||
* the only other attribute that the client sends is the mtime.
|
||||
* RFC5661, Section 18.30.4:
|
||||
* Changing the size of a file with SETATTR indirectly
|
||||
* changes the time_modify and change attributes.
|
||||
*
|
||||
* (and similar for the older RFCs)
|
||||
*/
|
||||
if (iap->ia_size != i_size_read(inode) &&
|
||||
((iap->ia_valid & ~(ATTR_SIZE | ATTR_MTIME)) == 0))
|
||||
implicit_mtime = true;
|
||||
|
||||
host_err = vfs_truncate(&path, iap->ia_size);
|
||||
if (host_err)
|
||||
goto out_host_err;
|
||||
|
||||
iap->ia_valid &= ~ATTR_SIZE;
|
||||
if (implicit_mtime)
|
||||
iap->ia_valid &= ~ATTR_MTIME;
|
||||
if (!iap->ia_valid)
|
||||
goto done;
|
||||
if (iap->ia_size != i_size_read(inode))
|
||||
iap->ia_valid |= ATTR_MTIME;
|
||||
}
|
||||
|
||||
iap->ia_valid |= ATTR_CTIME;
|
||||
|
||||
if (check_guard && guardtime != inode->i_ctime.tv_sec) {
|
||||
err = nfserr_notsync;
|
||||
goto out_put_write_access;
|
||||
}
|
||||
|
||||
fh_lock(fhp);
|
||||
host_err = notify_change(dentry, iap, NULL);
|
||||
fh_unlock(fhp);
|
||||
if (host_err)
|
||||
goto out_host_err;
|
||||
err = nfserrno(host_err);
|
||||
|
||||
done:
|
||||
host_err = commit_metadata(fhp);
|
||||
out_host_err:
|
||||
return nfserrno(host_err);
|
||||
out_put_write_access:
|
||||
if (size_change)
|
||||
put_write_access(inode);
|
||||
if (!err)
|
||||
err = nfserrno(commit_metadata(fhp));
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFSD_V4)
|
||||
|
Loading…
Reference in New Issue
Block a user