Skip to content

Commit 555dbf1

Browse files
Trond Myklebustchucklever
authored andcommitted
nfsd: Replace use of rwsem with errseq_t
The nfsd_file nf_rwsem is currently being used to separate file write and commit instances to ensure that we catch errors and apply them to the correct write/commit. We can improve scalability at the expense of a little accuracy (some extra false positives) by replacing the nf_rwsem with more careful use of the errseq_t mechanism to track errors across the different operations. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> [ cel: rebased on zero-verifier fix ]
1 parent f11ad7a commit 555dbf1

4 files changed

Lines changed: 24 additions & 34 deletions

File tree

fs/nfsd/filecache.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval,
189189
__set_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags);
190190
}
191191
nf->nf_mark = NULL;
192-
init_rwsem(&nf->nf_rwsem);
193192
trace_nfsd_file_alloc(nf);
194193
}
195194
return nf;

fs/nfsd/filecache.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ struct nfsd_file {
4646
refcount_t nf_ref;
4747
unsigned char nf_may;
4848
struct nfsd_file_mark *nf_mark;
49-
struct rw_semaphore nf_rwsem;
5049
};
5150

5251
int nfsd_file_cache_init(void);

fs/nfsd/nfs4proc.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,6 +1510,9 @@ static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync)
15101510

15111511
static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
15121512
{
1513+
struct file *dst = copy->nf_dst->nf_file;
1514+
struct file *src = copy->nf_src->nf_file;
1515+
errseq_t since;
15131516
ssize_t bytes_copied = 0;
15141517
u64 bytes_total = copy->cp_count;
15151518
u64 src_pos = copy->cp_src_pos;
@@ -1522,9 +1525,8 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
15221525
do {
15231526
if (kthread_should_stop())
15241527
break;
1525-
bytes_copied = nfsd_copy_file_range(copy->nf_src->nf_file,
1526-
src_pos, copy->nf_dst->nf_file, dst_pos,
1527-
bytes_total);
1528+
bytes_copied = nfsd_copy_file_range(src, src_pos, dst, dst_pos,
1529+
bytes_total);
15281530
if (bytes_copied <= 0)
15291531
break;
15301532
bytes_total -= bytes_copied;
@@ -1534,11 +1536,11 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
15341536
} while (bytes_total > 0 && !copy->cp_synchronous);
15351537
/* for a non-zero asynchronous copy do a commit of data */
15361538
if (!copy->cp_synchronous && copy->cp_res.wr_bytes_written > 0) {
1537-
down_write(&copy->nf_dst->nf_rwsem);
1538-
status = vfs_fsync_range(copy->nf_dst->nf_file,
1539-
copy->cp_dst_pos,
1539+
since = READ_ONCE(dst->f_wb_err);
1540+
status = vfs_fsync_range(dst, copy->cp_dst_pos,
15401541
copy->cp_res.wr_bytes_written, 0);
1541-
up_write(&copy->nf_dst->nf_rwsem);
1542+
if (!status)
1543+
status = filemap_check_wb_err(dst->f_mapping, since);
15421544
if (!status)
15431545
copy->committed = true;
15441546
}

fs/nfsd/vfs.c

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -522,10 +522,11 @@ __be32 nfsd4_clone_file_range(struct nfsd_file *nf_src, u64 src_pos,
522522
{
523523
struct file *src = nf_src->nf_file;
524524
struct file *dst = nf_dst->nf_file;
525+
errseq_t since;
525526
loff_t cloned;
526527
__be32 ret = 0;
527528

528-
down_write(&nf_dst->nf_rwsem);
529+
since = READ_ONCE(dst->f_wb_err);
529530
cloned = vfs_clone_file_range(src, src_pos, dst, dst_pos, count, 0);
530531
if (cloned < 0) {
531532
ret = nfserrno(cloned);
@@ -539,6 +540,8 @@ __be32 nfsd4_clone_file_range(struct nfsd_file *nf_src, u64 src_pos,
539540
loff_t dst_end = count ? dst_pos + count - 1 : LLONG_MAX;
540541
int status = vfs_fsync_range(dst, dst_pos, dst_end, 0);
541542

543+
if (!status)
544+
status = filemap_check_wb_err(dst->f_mapping, since);
542545
if (!status)
543546
status = commit_inode_metadata(file_inode(src));
544547
if (status < 0) {
@@ -548,7 +551,6 @@ __be32 nfsd4_clone_file_range(struct nfsd_file *nf_src, u64 src_pos,
548551
}
549552
}
550553
out_err:
551-
up_write(&nf_dst->nf_rwsem);
552554
return ret;
553555
}
554556

@@ -956,6 +958,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
956958
struct super_block *sb = file_inode(file)->i_sb;
957959
struct svc_export *exp;
958960
struct iov_iter iter;
961+
errseq_t since;
959962
__be32 nfserr;
960963
int host_err;
961964
int use_wgather;
@@ -993,8 +996,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
993996
flags |= RWF_SYNC;
994997

995998
iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt);
999+
since = READ_ONCE(file->f_wb_err);
9961000
if (flags & RWF_SYNC) {
997-
down_write(&nf->nf_rwsem);
9981001
if (verf)
9991002
nfsd_copy_boot_verifier(verf,
10001003
net_generic(SVC_NET(rqstp),
@@ -1003,15 +1006,12 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
10031006
if (host_err < 0)
10041007
nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp),
10051008
nfsd_net_id));
1006-
up_write(&nf->nf_rwsem);
10071009
} else {
1008-
down_read(&nf->nf_rwsem);
10091010
if (verf)
10101011
nfsd_copy_boot_verifier(verf,
10111012
net_generic(SVC_NET(rqstp),
10121013
nfsd_net_id));
10131014
host_err = vfs_iter_write(file, &iter, &pos, flags);
1014-
up_read(&nf->nf_rwsem);
10151015
}
10161016
if (host_err < 0) {
10171017
nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp),
@@ -1021,6 +1021,9 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
10211021
*cnt = host_err;
10221022
nfsd_stats_io_write_add(exp, *cnt);
10231023
fsnotify_modify(file);
1024+
host_err = filemap_check_wb_err(file->f_mapping, since);
1025+
if (host_err < 0)
1026+
goto out_nfserr;
10241027

10251028
if (stable && use_wgather) {
10261029
host_err = wait_for_concurrent_writes(file);
@@ -1101,19 +1104,6 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
11011104
}
11021105

11031106
#ifdef CONFIG_NFSD_V3
1104-
static int
1105-
nfsd_filemap_write_and_wait_range(struct nfsd_file *nf, loff_t offset,
1106-
loff_t end)
1107-
{
1108-
struct address_space *mapping = nf->nf_file->f_mapping;
1109-
int ret = filemap_fdatawrite_range(mapping, offset, end);
1110-
1111-
if (ret)
1112-
return ret;
1113-
filemap_fdatawait_range_keep_errors(mapping, offset, end);
1114-
return 0;
1115-
}
1116-
11171107
/*
11181108
* Commit all pending writes to stable storage.
11191109
*
@@ -1144,25 +1134,25 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
11441134
if (err)
11451135
goto out;
11461136
if (EX_ISSYNC(fhp->fh_export)) {
1147-
int err2 = nfsd_filemap_write_and_wait_range(nf, offset, end);
1137+
errseq_t since = READ_ONCE(nf->nf_file->f_wb_err);
1138+
int err2;
11481139

1149-
down_write(&nf->nf_rwsem);
1150-
if (!err2)
1151-
err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
1140+
err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
11521141
switch (err2) {
11531142
case 0:
11541143
nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net,
11551144
nfsd_net_id));
1145+
err2 = filemap_check_wb_err(nf->nf_file->f_mapping,
1146+
since);
11561147
break;
11571148
case -EINVAL:
11581149
err = nfserr_notsupp;
11591150
break;
11601151
default:
1161-
err = nfserrno(err2);
11621152
nfsd_reset_boot_verifier(net_generic(nf->nf_net,
11631153
nfsd_net_id));
11641154
}
1165-
up_write(&nf->nf_rwsem);
1155+
err = nfserrno(err2);
11661156
} else
11671157
nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net,
11681158
nfsd_net_id));

0 commit comments

Comments
 (0)