Skip to content

Commit 38a125b

Browse files
MaxKellermannTrond Myklebust
authored andcommitted
fs/nfs/io: make nfs_start_io_*() killable
This allows killing processes that wait for a lock when one process is stuck waiting for the NFS server. This aims to complete the coverage of NFS operations being killable, like nfs_direct_wait() does, for example. Signed-off-by: Max Kellermann <max.kellermann@ionos.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
1 parent 614733f commit 38a125b

File tree

4 files changed

+66
-20
lines changed

4 files changed

+66
-20
lines changed

fs/nfs/direct.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,16 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter,
454454
if (user_backed_iter(iter))
455455
dreq->flags = NFS_ODIRECT_SHOULD_DIRTY;
456456

457-
if (!swap)
458-
nfs_start_io_direct(inode);
457+
if (!swap) {
458+
result = nfs_start_io_direct(inode);
459+
if (result) {
460+
/* release the reference that would usually be
461+
* consumed by nfs_direct_read_schedule_iovec()
462+
*/
463+
nfs_direct_req_release(dreq);
464+
goto out_release;
465+
}
466+
}
459467

460468
NFS_I(inode)->read_io += count;
461469
requested = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos);
@@ -1007,7 +1015,14 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter,
10071015
requested = nfs_direct_write_schedule_iovec(dreq, iter, pos,
10081016
FLUSH_STABLE);
10091017
} else {
1010-
nfs_start_io_direct(inode);
1018+
result = nfs_start_io_direct(inode);
1019+
if (result) {
1020+
/* release the reference that would usually be
1021+
* consumed by nfs_direct_write_schedule_iovec()
1022+
*/
1023+
nfs_direct_req_release(dreq);
1024+
goto out_release;
1025+
}
10111026

10121027
requested = nfs_direct_write_schedule_iovec(dreq, iter, pos,
10131028
FLUSH_COND_STABLE);

fs/nfs/file.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,10 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
166166
iocb->ki_filp,
167167
iov_iter_count(to), (unsigned long) iocb->ki_pos);
168168

169-
nfs_start_io_read(inode);
169+
result = nfs_start_io_read(inode);
170+
if (result)
171+
return result;
172+
170173
result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
171174
if (!result) {
172175
result = generic_file_read_iter(iocb, to);
@@ -187,7 +190,10 @@ nfs_file_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe
187190

188191
dprintk("NFS: splice_read(%pD2, %zu@%llu)\n", in, len, *ppos);
189192

190-
nfs_start_io_read(inode);
193+
result = nfs_start_io_read(inode);
194+
if (result)
195+
return result;
196+
191197
result = nfs_revalidate_mapping(inode, in->f_mapping);
192198
if (!result) {
193199
result = filemap_splice_read(in, ppos, pipe, len, flags);
@@ -668,7 +674,9 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
668674
nfs_clear_invalid_mapping(file->f_mapping);
669675

670676
since = filemap_sample_wb_err(file->f_mapping);
671-
nfs_start_io_write(inode);
677+
error = nfs_start_io_write(inode);
678+
if (error)
679+
return error;
672680
result = generic_write_checks(iocb, from);
673681
if (result > 0)
674682
result = generic_perform_write(iocb, from);

fs/nfs/internal.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "nfs4_fs.h"
77
#include <linux/fs_context.h>
88
#include <linux/security.h>
9+
#include <linux/compiler_attributes.h>
910
#include <linux/crc32.h>
1011
#include <linux/sunrpc/addr.h>
1112
#include <linux/nfs_page.h>
@@ -516,11 +517,11 @@ extern const struct netfs_request_ops nfs_netfs_ops;
516517
#endif
517518

518519
/* io.c */
519-
extern void nfs_start_io_read(struct inode *inode);
520+
extern __must_check int nfs_start_io_read(struct inode *inode);
520521
extern void nfs_end_io_read(struct inode *inode);
521-
extern void nfs_start_io_write(struct inode *inode);
522+
extern __must_check int nfs_start_io_write(struct inode *inode);
522523
extern void nfs_end_io_write(struct inode *inode);
523-
extern void nfs_start_io_direct(struct inode *inode);
524+
extern __must_check int nfs_start_io_direct(struct inode *inode);
524525
extern void nfs_end_io_direct(struct inode *inode);
525526

526527
static inline bool nfs_file_io_is_buffered(struct nfs_inode *nfsi)

fs/nfs/io.c

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,28 @@ static void nfs_block_o_direct(struct nfs_inode *nfsi, struct inode *inode)
3939
* Note that buffered writes and truncates both take a write lock on
4040
* inode->i_rwsem, meaning that those are serialised w.r.t. the reads.
4141
*/
42-
void
42+
int
4343
nfs_start_io_read(struct inode *inode)
4444
{
4545
struct nfs_inode *nfsi = NFS_I(inode);
46+
int err;
47+
4648
/* Be an optimist! */
47-
down_read(&inode->i_rwsem);
49+
err = down_read_killable(&inode->i_rwsem);
50+
if (err)
51+
return err;
4852
if (test_bit(NFS_INO_ODIRECT, &nfsi->flags) == 0)
49-
return;
53+
return 0;
5054
up_read(&inode->i_rwsem);
55+
5156
/* Slow path.... */
52-
down_write(&inode->i_rwsem);
57+
err = down_write_killable(&inode->i_rwsem);
58+
if (err)
59+
return err;
5360
nfs_block_o_direct(nfsi, inode);
5461
downgrade_write(&inode->i_rwsem);
62+
63+
return 0;
5564
}
5665

5766
/**
@@ -74,11 +83,15 @@ nfs_end_io_read(struct inode *inode)
7483
* Declare that a buffered read operation is about to start, and ensure
7584
* that we block all direct I/O.
7685
*/
77-
void
86+
int
7887
nfs_start_io_write(struct inode *inode)
7988
{
80-
down_write(&inode->i_rwsem);
81-
nfs_block_o_direct(NFS_I(inode), inode);
89+
int err;
90+
91+
err = down_write_killable(&inode->i_rwsem);
92+
if (!err)
93+
nfs_block_o_direct(NFS_I(inode), inode);
94+
return err;
8295
}
8396

8497
/**
@@ -119,19 +132,28 @@ static void nfs_block_buffered(struct nfs_inode *nfsi, struct inode *inode)
119132
* Note that buffered writes and truncates both take a write lock on
120133
* inode->i_rwsem, meaning that those are serialised w.r.t. O_DIRECT.
121134
*/
122-
void
135+
int
123136
nfs_start_io_direct(struct inode *inode)
124137
{
125138
struct nfs_inode *nfsi = NFS_I(inode);
139+
int err;
140+
126141
/* Be an optimist! */
127-
down_read(&inode->i_rwsem);
142+
err = down_read_killable(&inode->i_rwsem);
143+
if (err)
144+
return err;
128145
if (test_bit(NFS_INO_ODIRECT, &nfsi->flags) != 0)
129-
return;
146+
return 0;
130147
up_read(&inode->i_rwsem);
148+
131149
/* Slow path.... */
132-
down_write(&inode->i_rwsem);
150+
err = down_write_killable(&inode->i_rwsem);
151+
if (err)
152+
return err;
133153
nfs_block_buffered(nfsi, inode);
134154
downgrade_write(&inode->i_rwsem);
155+
156+
return 0;
135157
}
136158

137159
/**

0 commit comments

Comments
 (0)