aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
authorDavid Shaw <dshaw@jabberwocky.com>2009-03-05 20:16:14 -0500
committerJ. Bruce Fields <bfields@citi.umich.edu>2009-03-18 17:38:40 -0400
commit31dec2538e45e9fff2007ea1f4c6bae9f78db724 (patch)
treec2b42679c73c1c6f31312f38a1b1d049e918d635 /fs/nfsd/vfs.c
parent1e685ec270cb97680be4eb8cf6b615f5f7f1403a (diff)
Short write in nfsd becomes a full write to the client
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. Here is a patch to properly return the short write count to the client. Signed-off-by: David Shaw <dshaw@jabberwocky.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r--fs/nfsd/vfs.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 0c076293155d..54404d730809 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -960,7 +960,7 @@ static void kill_suid(struct dentry *dentry)
960static __be32 960static __be32
961nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, 961nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
962 loff_t offset, struct kvec *vec, int vlen, 962 loff_t offset, struct kvec *vec, int vlen,
963 unsigned long cnt, int *stablep) 963 unsigned long *cnt, int *stablep)
964{ 964{
965 struct svc_export *exp; 965 struct svc_export *exp;
966 struct dentry *dentry; 966 struct dentry *dentry;
@@ -974,7 +974,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
974 err = nfserr_perm; 974 err = nfserr_perm;
975 975
976 if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && 976 if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
977 (!lock_may_write(file->f_path.dentry->d_inode, offset, cnt))) 977 (!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt)))
978 goto out; 978 goto out;
979#endif 979#endif
980 980
@@ -1006,7 +1006,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1006 host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); 1006 host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
1007 set_fs(oldfs); 1007 set_fs(oldfs);
1008 if (host_err >= 0) { 1008 if (host_err >= 0) {
1009 nfsdstats.io_write += cnt; 1009 nfsdstats.io_write += host_err;
1010 fsnotify_modify(file->f_path.dentry); 1010 fsnotify_modify(file->f_path.dentry);
1011 } 1011 }
1012 1012
@@ -1051,9 +1051,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1051 } 1051 }
1052 1052
1053 dprintk("nfsd: write complete host_err=%d\n", host_err); 1053 dprintk("nfsd: write complete host_err=%d\n", host_err);
1054 if (host_err >= 0) 1054 if (host_err >= 0) {
1055 err = 0; 1055 err = 0;
1056 else 1056 *cnt = host_err;
1057 } else
1057 err = nfserrno(host_err); 1058 err = nfserrno(host_err);
1058out: 1059out:
1059 return err; 1060 return err;
@@ -1095,7 +1096,7 @@ out:
1095 */ 1096 */
1096__be32 1097__be32
1097nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, 1098nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1098 loff_t offset, struct kvec *vec, int vlen, unsigned long cnt, 1099 loff_t offset, struct kvec *vec, int vlen, unsigned long *cnt,
1099 int *stablep) 1100 int *stablep)
1100{ 1101{
1101 __be32 err = 0; 1102 __be32 err = 0;