Commit 5011af4c authored by Trond Myklebust's avatar Trond Myklebust Committed by J. Bruce Fields
Browse files

nfsd: Fix stable writes



Strictly speaking, a stable write error needs to reflect the
write + the commit of that write (and only that write). To
ensure that we don't pick up the write errors from other
writebacks, add a rw_semaphore to provide exclusion.

Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 16f8f894
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -195,6 +195,7 @@ nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval,
				__set_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags);
		}
		nf->nf_mark = NULL;
		init_rwsem(&nf->nf_rwsem);
		trace_nfsd_file_alloc(nf);
	}
	return nf;
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ struct nfsd_file {
	atomic_t		nf_ref;
	unsigned char		nf_may;
	struct nfsd_file_mark	*nf_mark;
	struct rw_semaphore	nf_rwsem;
};

int nfsd_file_cache_init(void);
+16 −2
Original line number Diff line number Diff line
@@ -982,7 +982,18 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
		flags |= RWF_SYNC;

	iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt);
	if (flags & RWF_SYNC) {
		down_write(&nf->nf_rwsem);
		host_err = vfs_iter_write(file, &iter, &pos, flags);
		if (host_err < 0)
			nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp),
						 nfsd_net_id));
		up_write(&nf->nf_rwsem);
	} else {
		down_read(&nf->nf_rwsem);
		host_err = vfs_iter_write(file, &iter, &pos, flags);
		up_read(&nf->nf_rwsem);
	}
	if (host_err < 0)
		goto out_nfserr;
	*cnt = host_err;
@@ -1097,8 +1108,10 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
	if (err)
		goto out;
	if (EX_ISSYNC(fhp->fh_export)) {
		int err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
		int err2;

		down_write(&nf->nf_rwsem);
		err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
		switch (err2) {
		case 0:
			break;
@@ -1110,6 +1123,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
			nfsd_reset_boot_verifier(net_generic(nf->nf_net,
						 nfsd_net_id));
		}
		up_write(&nf->nf_rwsem);
	}

	nfsd_file_put(nf);