diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2010-01-19 19:24:45 +0200 |
---|---|---|
committer | Boaz Harrosh <bharrosh@panasas.com> | 2010-02-28 03:35:26 -0800 |
commit | 22ddc556380cf5645c52292b6d980766646eb864 (patch) | |
tree | 07d498ba10f4393fb4cde6a79b22a50b6a0f7efb /fs | |
parent | 518f167a37b3c53f3cf44d27800455ca24e920f6 (diff) | |
download | op-kernel-dev-22ddc556380cf5645c52292b6d980766646eb864.zip op-kernel-dev-22ddc556380cf5645c52292b6d980766646eb864.tar.gz |
exofs: Recover in the case of read-passed-end-of-file
In check_io, implement the case of reading passed end of
file, by clearing the pages and recover with no error. In
a raid arrangement this can become a legitimate situation
in case of holes in the file.
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/exofs/ios.c | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/fs/exofs/ios.c b/fs/exofs/ios.c index 3cc0dd3..439c5d0 100644 --- a/fs/exofs/ios.c +++ b/fs/exofs/ios.c @@ -173,6 +173,21 @@ static int exofs_io_execute(struct exofs_io_state *ios) return ret; } +static void _clear_bio(struct bio *bio) +{ + struct bio_vec *bv; + unsigned i; + + __bio_for_each_segment(bv, bio, i, 0) { + unsigned this_count = bv->bv_len; + + if (likely(PAGE_SIZE == this_count)) + clear_highpage(bv->bv_page); + else + zero_user(bv->bv_page, bv->bv_offset, this_count); + } +} + int exofs_check_io(struct exofs_io_state *ios, u64 *resid) { enum osd_err_priority acumulated_osd_err = 0; @@ -181,16 +196,25 @@ int exofs_check_io(struct exofs_io_state *ios, u64 *resid) for (i = 0; i < ios->numdevs; i++) { struct osd_sense_info osi; - int ret = osd_req_decode_sense(ios->per_dev[i].or, &osi); + struct osd_request *or = ios->per_dev[i].or; + int ret; + + if (unlikely(!or)) + continue; + ret = osd_req_decode_sense(or, &osi); if (likely(!ret)) continue; - if (unlikely(ret == -EFAULT)) { - EXOFS_DBGMSG("%s: EFAULT Need page clear\n", __func__); - /*FIXME: All the pages in this device range should: - * clear_highpage(page); - */ + if (OSD_ERR_PRI_CLEAR_PAGES == osi.osd_err_pri) { + /* start read offset passed endof file */ + _clear_bio(ios->per_dev[i].bio); + EXOFS_DBGMSG("start read offset passed end of file " + "offset=0x%llx, length=0x%llx\n", + _LLU(ios->offset), + _LLU(ios->length)); + + continue; /* we recovered */ } if (osi.osd_err_pri >= acumulated_osd_err) { |