[snip] I think this patch can do work: Those case which i tested A: filesize=0, buffer=1M B: data[2M] | hole| data[2M], bs= 6M/7M C: data[4m] | hole | hole |data[2M] bs=16M/18M
Are there some case ignore? Thanks! Jianpeng Ma diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 2ddf061..96ce893 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -319,7 +319,7 @@ static int striped_read(struct inode *inode, int read; struct page **page_pos; int ret; - bool hit_stripe, was_short; + bool hit_stripe, was_short, hit_hole = false; /* * we may need to do multiple reads. not atomic, unfortunately. @@ -342,21 +342,30 @@ more: ci->i_truncate_seq, ci->i_truncate_size, page_pos, pages_left, page_align); - if (ret == -ENOENT) + + if ((ret == 0 || ret == -ENOENT) && pos < inode->i_size) + hit_hole = true; + else if (ret == -ENOENT) ret = 0; + hit_stripe = this_len < left; - was_short = ret >= 0 && ret < this_len; - dout("striped_read %llu~%u (read %u) got %d%s%s\n", pos, left, read, - ret, hit_stripe ? " HITSTRIPE" : "", was_short ? " SHORT" : ""); - - if (ret > 0) { - int didpages = (page_align + ret) >> PAGE_CACHE_SHIFT; - - if (read < pos - off) { - dout(" zero gap %llu to %llu\n", off + read, pos); - ceph_zero_page_vector_range(page_align + read, - pos - off - read, pages); + was_short = ret > 0 && ret < this_len; + dout("striped_read %llu~%u (read %u) got %d%s%s%s\n", pos, left, read, + ret, hit_stripe ? " HITSTRIPE" : "", was_short ? " SHORT" : "", + hit_hole ? " HITHOLE" : ""); + + if (ret > 0 || hit_hole) { + int didpages; + + if (hit_hole) { + ret = this_len; + dout(" zero hole %llu to %llu\n", pos , pos + ret); + ceph_zero_page_vector_range(page_align + read, + ret, pages); + hit_hole = false; } + didpages = (page_align + ret) >> PAGE_CACHE_SHIFT; + pos += ret; read = pos - off; left -= ret;