diff options
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 1f87c4d0e7a0..be1bf627a14b 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -2285,16 +2285,22 @@ static void end_bio_extent_readpage(struct bio *bio, int err) | |||
2285 | clean_io_failure(start, page); | 2285 | clean_io_failure(start, page); |
2286 | } | 2286 | } |
2287 | if (!uptodate) { | 2287 | if (!uptodate) { |
2288 | u64 failed_mirror; | 2288 | int failed_mirror; |
2289 | failed_mirror = (u64)bio->bi_bdev; | 2289 | failed_mirror = (int)(unsigned long)bio->bi_bdev; |
2290 | if (tree->ops && tree->ops->readpage_io_failed_hook) | 2290 | /* |
2291 | ret = tree->ops->readpage_io_failed_hook( | 2291 | * The generic bio_readpage_error handles errors the |
2292 | bio, page, start, end, | 2292 | * following way: If possible, new read requests are |
2293 | failed_mirror, state); | 2293 | * created and submitted and will end up in |
2294 | else | 2294 | * end_bio_extent_readpage as well (if we're lucky, not |
2295 | ret = bio_readpage_error(bio, page, start, end, | 2295 | * in the !uptodate case). In that case it returns 0 and |
2296 | failed_mirror, NULL); | 2296 | * we just go on with the next page in our bio. If it |
2297 | * can't handle the error it will return -EIO and we | ||
2298 | * remain responsible for that page. | ||
2299 | */ | ||
2300 | ret = bio_readpage_error(bio, page, start, end, | ||
2301 | failed_mirror, NULL); | ||
2297 | if (ret == 0) { | 2302 | if (ret == 0) { |
2303 | error_handled: | ||
2298 | uptodate = | 2304 | uptodate = |
2299 | test_bit(BIO_UPTODATE, &bio->bi_flags); | 2305 | test_bit(BIO_UPTODATE, &bio->bi_flags); |
2300 | if (err) | 2306 | if (err) |
@@ -2302,6 +2308,13 @@ static void end_bio_extent_readpage(struct bio *bio, int err) | |||
2302 | uncache_state(&cached); | 2308 | uncache_state(&cached); |
2303 | continue; | 2309 | continue; |
2304 | } | 2310 | } |
2311 | if (tree->ops && tree->ops->readpage_io_failed_hook) { | ||
2312 | ret = tree->ops->readpage_io_failed_hook( | ||
2313 | bio, page, start, end, | ||
2314 | failed_mirror, state); | ||
2315 | if (ret == 0) | ||
2316 | goto error_handled; | ||
2317 | } | ||
2305 | } | 2318 | } |
2306 | 2319 | ||
2307 | if (uptodate) { | 2320 | if (uptodate) { |
@@ -3366,6 +3379,9 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
3366 | return -ENOMEM; | 3379 | return -ENOMEM; |
3367 | path->leave_spinning = 1; | 3380 | path->leave_spinning = 1; |
3368 | 3381 | ||
3382 | start = ALIGN(start, BTRFS_I(inode)->root->sectorsize); | ||
3383 | len = ALIGN(len, BTRFS_I(inode)->root->sectorsize); | ||
3384 | |||
3369 | /* | 3385 | /* |
3370 | * lookup the last file extent. We're not using i_size here | 3386 | * lookup the last file extent. We're not using i_size here |
3371 | * because there might be preallocation past i_size | 3387 | * because there might be preallocation past i_size |
@@ -3413,7 +3429,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
3413 | lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0, | 3429 | lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0, |
3414 | &cached_state, GFP_NOFS); | 3430 | &cached_state, GFP_NOFS); |
3415 | 3431 | ||
3416 | em = get_extent_skip_holes(inode, off, last_for_get_extent, | 3432 | em = get_extent_skip_holes(inode, start, last_for_get_extent, |
3417 | get_extent); | 3433 | get_extent); |
3418 | if (!em) | 3434 | if (!em) |
3419 | goto out; | 3435 | goto out; |