Commit 001945a7 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: 6a218b9c ("nfs/localio: do not issue misaligned DIO out-of-order")
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Reviewed-by: default avatarMike Snitzer <snitzer@kernel.org>
parent df56ddd0
Loading
Loading
Loading
Loading
+14 −16
Original line number Diff line number Diff line
@@ -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,16 +636,16 @@ 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)) {
		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;
		}
	}
}
}

static int
nfs_local_do_read(struct nfs_local_kiocb *iocb,
@@ -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,15 +841,15 @@ 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)) {
		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);

	current->flags = old_flags;