nfsd: Revert "nfsd: special case truncates some more"
This patch incorrectly attempted nested mnt_want_write, and incorrectly disabled nfsd's owner override for truncate. We'll fix those problems and make another attempt soon, for the moment I think the safest is to revert. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
		
							parent
							
								
									d5adbfcd5f
								
							
						
					
					
						commit
						0839ffb83e
					
				| @ -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