Re: [PATCH] Short write in nfsd becomes a full write to the client

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Mar 05, 2009 at 08:16:14PM -0500, David Shaw wrote:
> If a filesystem being written to via NFS returns a short write count
> (as opposed to an error) to nfsd, nfsd treats that as a success for
> the entire write, rather than the short count that actually succeeded.
> 
> For example, given a 8192 byte write, if the underlying filesystem
> only writes 4096 bytes, nfsd will ack back to the nfs client that all
> 8192 bytes were written.  The nfs client does have retry logic for
> short writes, but this is never called as the client is told the
> complete write succeeded.
> 
> There are probably other ways it could happen, but in my case it
> happened with a fuse (filesystem in userspace) filesystem which can
> rather easily have a partial write.

Got it.

> 
> Here is a patch to properly return the short write count to the
> client.

Applied for-2.6.30 with one minor style fix, noted below.

Looks good, thanks for your persistance.--b.

> 
> Signed-off-by: David Shaw <dshaw@xxxxxxxxxxxxxxx>
> ---
> 
>  fs/nfsd/nfs3proc.c        |    5 +++--
>  fs/nfsd/nfs4proc.c        |    7 +++++--
>  fs/nfsd/nfsproc.c         |    3 ++-
>  fs/nfsd/vfs.c             |   12 +++++++-----
>  include/linux/nfsd/nfsd.h |    2 +-
>  5 files changed, 18 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
> index 9dbd2eb..9f262b3 100644
> --- a/fs/nfsd/nfs3proc.c
> +++ b/fs/nfsd/nfs3proc.c
> @@ -202,6 +202,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
>  					 struct nfsd3_writeres  *resp)
>  {
>  	__be32	nfserr;
> +	unsigned long cnt = argp->len;
>  
>  	dprintk("nfsd: WRITE(3)    %s %d bytes at %ld%s\n",
>  				SVCFH_fmt(&argp->fh),
> @@ -214,9 +215,9 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
>  	nfserr = nfsd_write(rqstp, &resp->fh, NULL,
>  				   argp->offset,
>  				   rqstp->rq_vec, argp->vlen,
> -				   argp->len,
> +				   &cnt,
>  				   &resp->committed);
> -	resp->count = argp->count;
> +	resp->count = cnt;
>  	RETURN_STATUS(nfserr);
>  }
>  
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 9fa60a3..8ed1b93 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -685,6 +685,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>  	struct file *filp = NULL;
>  	u32 *p;
>  	__be32 status = nfs_ok;
> +	unsigned long cnt;
>  
>  	/* no need to check permission - this will be done in nfsd_write() */
>  
> @@ -703,7 +704,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>  		return status;
>  	}
>  
> -	write->wr_bytes_written = write->wr_buflen;
> +	cnt = write->wr_buflen;
>  	write->wr_how_written = write->wr_stable_how;
>  	p = (u32 *)write->wr_verifier.data;
>  	*p++ = nfssvc_boot.tv_sec;
> @@ -711,10 +712,12 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>  
>  	status =  nfsd_write(rqstp, &cstate->current_fh, filp,
>  			     write->wr_offset, rqstp->rq_vec, write->wr_vlen,
> -			     write->wr_buflen, &write->wr_how_written);
> +			     &cnt, &write->wr_how_written);
>  	if (filp)
>  		fput(filp);
>  
> +	write->wr_bytes_written = cnt;
> +
>  	if (status == nfserr_symlink)
>  		status = nfserr_inval;
>  	return status;
> diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
> index 6f7f263..e298e26 100644
> --- a/fs/nfsd/nfsproc.c
> +++ b/fs/nfsd/nfsproc.c
> @@ -180,6 +180,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
>  {
>  	__be32	nfserr;
>  	int	stable = 1;
> +	unsigned long cnt = argp->len;
>  
>  	dprintk("nfsd: WRITE    %s %d bytes at %d\n",
>  		SVCFH_fmt(&argp->fh),
> @@ -188,7 +189,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
>  	nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
>  				   argp->offset,
>  				   rqstp->rq_vec, argp->vlen,
> -				   argp->len,
> +			           &cnt,
>  				   &stable);
>  	return nfsd_return_attrs(nfserr, resp);
>  }
> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> index 6e50aaa..d3c8429 100644
> --- a/fs/nfsd/vfs.c
> +++ b/fs/nfsd/vfs.c
> @@ -960,7 +960,7 @@ static void kill_suid(struct dentry *dentry)
>  static __be32
>  nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
>  				loff_t offset, struct kvec *vec, int vlen,
> -	   			unsigned long cnt, int *stablep)
> +	   			unsigned long *cnt, int *stablep)
>  {
>  	struct svc_export	*exp;
>  	struct dentry		*dentry;
> @@ -974,7 +974,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
>  	err = nfserr_perm;
>  
>  	if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
> -		(!lock_may_write(file->f_path.dentry->d_inode, offset, cnt)))
> +		(!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt)))
>  		goto out;
>  #endif
>  
> @@ -1006,7 +1006,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
>  	host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
>  	set_fs(oldfs);
>  	if (host_err >= 0) {
> -		nfsdstats.io_write += cnt;
> +		nfsdstats.io_write += host_err;
>  		fsnotify_modify(file->f_path.dentry);
>  	}
>  
> @@ -1051,8 +1051,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
>  	}
>  
>  	dprintk("nfsd: write complete host_err=%d\n", host_err);
> -	if (host_err >= 0)
> +	if (host_err >= 0) {
>  		err = 0;
> +		*cnt = host_err;
> +	}
>  	else 

That should be } else

--b.

>  		err = nfserrno(host_err);
>  out:
> @@ -1095,7 +1097,7 @@ out:
>   */
>  __be32
>  nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
> -		loff_t offset, struct kvec *vec, int vlen, unsigned long cnt,
> +		loff_t offset, struct kvec *vec, int vlen, unsigned long *cnt,
>  		int *stablep)
>  {
>  	__be32			err = 0;
> diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
> index e19f459..eefa241 100644
> --- a/include/linux/nfsd/nfsd.h
> +++ b/include/linux/nfsd/nfsd.h
> @@ -105,7 +105,7 @@ void		nfsd_close(struct file *);
>  __be32 		nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
>  				loff_t, struct kvec *, int, unsigned long *);
>  __be32 		nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
> -				loff_t, struct kvec *,int, unsigned long, int *);
> +				loff_t, struct kvec *,int, unsigned long *, int *);
>  __be32		nfsd_readlink(struct svc_rqst *, struct svc_fh *,
>  				char *, int *);
>  __be32		nfsd_symlink(struct svc_rqst *, struct svc_fh *,
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux