[PATCH] btrfs: allow read-/writing an extent to handle arbitrarily sized bios

From: Ming Lin
Date: Fri Dec 12 2014 - 01:32:31 EST


Fix bugs in end_bio_extent_{read,write}page(), upon reading or writing
biovec that has length of multiple pages. The condition "bvec.bv_len
!= PAGE_CACHE_SIZE" would not be always valid any more, because now
biovec is able to handle arbitrary size of bio. Without this patch,
read/write IO stalls with the following log:

BTRFS error (device sdb1): partial page write in btrfs with offset 0 and length 8192
BTRFS critical (device sdb1): bad ordered accounting left 0 size 4096

Signed-off-by: Ming Lin <mlin@xxxxxxxxxx>
Signed-off-by: Dongsu Park <dongsu.park@xxxxxxxxxxxxxxxx>
---
fs/btrfs/extent_io.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 2ac08e2..790a83b 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2468,7 +2468,7 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
* advance bv_offset and adjust bv_len to compensate.
* Print a warning for nonzero offsets, and an error
* if they don't add up to a full page. */
- if (bvec.bv_offset || bvec.bv_len != PAGE_CACHE_SIZE) {
+ if (bvec.bv_offset) {
if (bvec.bv_offset + bvec.bv_len != PAGE_CACHE_SIZE)
btrfs_err(BTRFS_I(page->mapping->host)->root->fs_info,
"partial page write in btrfs with offset %u and length %u",
@@ -2481,7 +2481,8 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
}

start = page_offset(page);
- end = start + bvec.bv_offset + bvec.bv_len - 1;
+ end = start + bvec.bv_offset
+ + min_t(unsigned int, bvec.bv_len, PAGE_CACHE_SIZE) - 1;

if (end_extent_writepage(page, err, start, end))
continue;
@@ -2548,7 +2549,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
* advance bv_offset and adjust bv_len to compensate.
* Print a warning for nonzero offsets, and an error
* if they don't add up to a full page. */
- if (bvec.bv_offset || bvec.bv_len != PAGE_CACHE_SIZE) {
+ if (bvec.bv_offset) {
if (bvec.bv_offset + bvec.bv_len != PAGE_CACHE_SIZE)
btrfs_err(BTRFS_I(page->mapping->host)->root->fs_info,
"partial page read in btrfs with offset %u and length %u",
@@ -2561,7 +2562,8 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
}

start = page_offset(page);
- end = start + bvec.bv_offset + bvec.bv_len - 1;
+ end = start + bvec.bv_offset
+ + min_t(unsigned int, bvec.bv_len, PAGE_CACHE_SIZE) - 1;
len = bvec.bv_len;

mirror = io_bio->mirror_num;
--
2.1.0

--
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/