[PATCH 1/5] direct-io: fix page_errors handling

From: Tejun Heo
Date: Wed Nov 08 2006 - 20:16:46 EST


When a page error occurs during write request, dio_refill_page() sets
dio->page_errors, maps zero page instead and proceeds as usual if
mapped blocks exist to clear mapped blocks. After clearing all
blocks, get_more_blocks() is called to map more blocks. The function
fails if dio->page_errors is set thus propagating the delayed error
condition.

However, the delayed propagation doesn't work if page error occurs for
the last chunk. get_more_blocks() is not called after clearing
currently mapped buffers; thus, the error condition is not reflected
in the return value. dio->page_errors is later taken into account in
synchronous completion path but not in async completion path.

This bug can be exposed by direct aio writing a buffer which has the
tailing pages munmapped. The file blocks corresponding to the
unmapped area are cleared to zero but the write successfully completes
with result set to full length of the request.

This patch fixes the bug by making do_direct_IO() always propagate
page_errors to its return value. As this makes page_errors
propagation the responsibility of do_direct_IO() proper,
dio->page_errors handling in synchronous completion path is removed.

This patch also fixes error precedence bug in synchronous completion
path. If both page_errors and io_error occur, page_errors should be
reported to user but the original code gave precedence to IO error
reported from dio_await_completion().

Signed-off-by: Tejun Heo <htejun@xxxxxxxxx>
---
fs/direct-io.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/direct-io.c b/fs/direct-io.c
index 5981e17..25721b2 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -940,6 +940,8 @@ next_block:
block_in_page = 0;
}
out:
+ if (ret == 0)
+ ret = dio->page_errors;
return ret;
}

@@ -1125,8 +1127,6 @@ direct_io_worker(int rw, struct kiocb *i
ret2 = dio_await_completion(dio);
if (ret == 0)
ret = ret2;
- if (ret == 0)
- ret = dio->page_errors;
if (dio->result) {
loff_t i_size = i_size_read(inode);

--
1.4.3.3


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/