summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@hammerspace.com>2026-01-03 00:01:06 +0300
committerTrond Myklebust <trond.myklebust@hammerspace.com>2026-01-07 20:28:26 +0300
commit001945a777ec4de8610f646397a054c62d272c2d (patch)
treef8b229fcd6fe40c05472d0bc42d8071e37a6a3c1
parentdf56ddd057424d21483bd0bee4da3632706d6606 (diff)
downloadlinux-001945a777ec4de8610f646397a054c62d272c2d.tar.xz
NFS/localio: Stop further I/O upon hitting an error
If the call into the filesystem results in an I/O error, then the next chunk of data won't be contiguous with the end of the last successful chunk. So break out of the I/O loop and report the results. Currently the localio code will do this for a short read/write, but not for an error. Fixes: 6a218b9c3183 ("nfs/localio: do not issue misaligned DIO out-of-order") Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Reviewed-by: Mike Snitzer <snitzer@kernel.org>
-rw-r--r--fs/nfs/localio.c30
1 files changed, 14 insertions, 16 deletions
diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c
index a113bfdacfd6..c884245e8fb8 100644
--- a/fs/nfs/localio.c
+++ b/fs/nfs/localio.c
@@ -618,7 +618,6 @@ static void nfs_local_call_read(struct work_struct *work)
struct nfs_local_kiocb *iocb =
container_of(work, struct nfs_local_kiocb, work);
struct file *filp = iocb->kiocb.ki_filp;
- bool force_done = false;
ssize_t status;
int n_iters;
@@ -637,13 +636,13 @@ static void nfs_local_call_read(struct work_struct *work)
scoped_with_creds(filp->f_cred)
status = filp->f_op->read_iter(&iocb->kiocb, &iocb->iters[i]);
- if (status != -EIOCBQUEUED) {
- if (unlikely(status >= 0 && status < iocb->iters[i].count))
- force_done = true; /* Partial read */
- if (nfs_local_pgio_done(iocb, status, force_done)) {
- nfs_local_read_iocb_done(iocb);
- break;
- }
+ if (status == -EIOCBQUEUED)
+ continue;
+ /* Break on completion, errors, or short reads */
+ if (nfs_local_pgio_done(iocb, status, false) || status < 0 ||
+ (size_t)status < iov_iter_count(&iocb->iters[i])) {
+ nfs_local_read_iocb_done(iocb);
+ break;
}
}
}
@@ -821,7 +820,6 @@ static void nfs_local_call_write(struct work_struct *work)
container_of(work, struct nfs_local_kiocb, work);
struct file *filp = iocb->kiocb.ki_filp;
unsigned long old_flags = current->flags;
- bool force_done = false;
ssize_t status;
int n_iters;
@@ -843,13 +841,13 @@ static void nfs_local_call_write(struct work_struct *work)
scoped_with_creds(filp->f_cred)
status = filp->f_op->write_iter(&iocb->kiocb, &iocb->iters[i]);
- if (status != -EIOCBQUEUED) {
- if (unlikely(status >= 0 && status < iocb->iters[i].count))
- force_done = true; /* Partial write */
- if (nfs_local_pgio_done(iocb, status, force_done)) {
- nfs_local_write_iocb_done(iocb);
- break;
- }
+ if (status == -EIOCBQUEUED)
+ continue;
+ /* Break on completion, errors, or short writes */
+ if (nfs_local_pgio_done(iocb, status, false) || status < 0 ||
+ (size_t)status < iov_iter_count(&iocb->iters[i])) {
+ nfs_local_write_iocb_done(iocb);
+ break;
}
}
file_end_write(filp);