[RFC PATCH] blkdev: __blkdev_direct_IO: collect async writes in error case

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Christoph, Jens, Jan, all,

while pondering over blkdev_direct_IO(), I found the following semantic change
introduced by 542ff7b in the "normal" (i.e. not "simple") path, and came up
with this patch. Please tell me what you think.

Thanks
Martin

For the blkdev_direc_IO() path, the call to do_blockdev_direct_IO() has been
replaced by __blkdev_direct_IO() in 542ff7bf18c6.

do_blockdev_direct_IO() takes care not to leave async bios in flight for
partial writes if an error occurs. Implement the same semantics for
__blkdev_direct_IO().

Signed-off-by: Martin Wilck <mwilck@xxxxxxxx>
Fixes: 542ff7bf18c6 ("block: new direct I/O implementation")
---
 fs/block_dev.c | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/fs/block_dev.c b/fs/block_dev.c
index aba2541..9d17260 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -363,7 +363,8 @@ __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int nr_pages)
 		ret = bio_iov_iter_get_pages(bio, iter);
 		if (unlikely(ret)) {
 			bio->bi_status = BLK_STS_IOERR;
-			bio_endio(bio);
+			if (!dio->multi_bio || is_sync || is_read)
+				bio_endio(bio);
 			break;
 		}
 
@@ -397,8 +398,29 @@ __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int nr_pages)
 	}
 	blk_finish_plug(&plug);
 
-	if (!is_sync)
-		return -EIOCBQUEUED;
+	if (!is_sync) {
+		if (!ret || is_read)
+			return -EIOCBQUEUED;
+
+		else if (dio->multi_bio) {
+			/*
+			 * Special case: async, WRITE, page-pinning error,
+			 * and at least one bio submitted already.
+			 * In this case we return an error. We need to wait
+			 * for already-submitted bios to finish.
+			 */
+			for (;;) {
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				if (atomic_read(&dio->ref) == 1)
+					break;
+				/* Nothing to poll for here */
+				io_schedule();
+			}
+			__set_current_state(TASK_RUNNING);
+			bio_endio(bio);
+		}
+		return ret;
+	}
 
 	for (;;) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
-- 
2.17.1




[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux