aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c126
1 files changed, 124 insertions, 2 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 8d392ed73d57..44b926646e33 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1913,7 +1913,7 @@ static int btrfs_clean_io_failures(struct inode *inode, u64 start)
1913 1913
1914 private = 0; 1914 private = 0;
1915 if (count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private, 1915 if (count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private,
1916 (u64)-1, 1, EXTENT_DIRTY)) { 1916 (u64)-1, 1, EXTENT_DIRTY, 0)) {
1917 ret = get_state_private(&BTRFS_I(inode)->io_failure_tree, 1917 ret = get_state_private(&BTRFS_I(inode)->io_failure_tree,
1918 start, &private_failure); 1918 start, &private_failure);
1919 if (ret == 0) { 1919 if (ret == 0) {
@@ -5282,6 +5282,128 @@ out:
5282 return em; 5282 return em;
5283} 5283}
5284 5284
5285struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
5286 size_t pg_offset, u64 start, u64 len,
5287 int create)
5288{
5289 struct extent_map *em;
5290 struct extent_map *hole_em = NULL;
5291 u64 range_start = start;
5292 u64 end;
5293 u64 found;
5294 u64 found_end;
5295 int err = 0;
5296
5297 em = btrfs_get_extent(inode, page, pg_offset, start, len, create);
5298 if (IS_ERR(em))
5299 return em;
5300 if (em) {
5301 /*
5302 * if our em maps to a hole, there might
5303 * actually be delalloc bytes behind it
5304 */
5305 if (em->block_start != EXTENT_MAP_HOLE)
5306 return em;
5307 else
5308 hole_em = em;
5309 }
5310
5311 /* check to see if we've wrapped (len == -1 or similar) */
5312 end = start + len;
5313 if (end < start)
5314 end = (u64)-1;
5315 else
5316 end -= 1;
5317
5318 em = NULL;
5319
5320 /* ok, we didn't find anything, lets look for delalloc */
5321 found = count_range_bits(&BTRFS_I(inode)->io_tree, &range_start,
5322 end, len, EXTENT_DELALLOC, 1);
5323 found_end = range_start + found;
5324 if (found_end < range_start)
5325 found_end = (u64)-1;
5326
5327 /*
5328 * we didn't find anything useful, return
5329 * the original results from get_extent()
5330 */
5331 if (range_start > end || found_end <= start) {
5332 em = hole_em;
5333 hole_em = NULL;
5334 goto out;
5335 }
5336
5337 /* adjust the range_start to make sure it doesn't
5338 * go backwards from the start they passed in
5339 */
5340 range_start = max(start,range_start);
5341 found = found_end - range_start;
5342
5343 if (found > 0) {
5344 u64 hole_start = start;
5345 u64 hole_len = len;
5346
5347 em = alloc_extent_map(GFP_NOFS);
5348 if (!em) {
5349 err = -ENOMEM;
5350 goto out;
5351 }
5352 /*
5353 * when btrfs_get_extent can't find anything it
5354 * returns one huge hole
5355 *
5356 * make sure what it found really fits our range, and
5357 * adjust to make sure it is based on the start from
5358 * the caller
5359 */
5360 if (hole_em) {
5361 u64 calc_end = extent_map_end(hole_em);
5362
5363 if (calc_end <= start || (hole_em->start > end)) {
5364 free_extent_map(hole_em);
5365 hole_em = NULL;
5366 } else {
5367 hole_start = max(hole_em->start, start);
5368 hole_len = calc_end - hole_start;
5369 }
5370 }
5371 em->bdev = NULL;
5372 if (hole_em && range_start > hole_start) {
5373 /* our hole starts before our delalloc, so we
5374 * have to return just the parts of the hole
5375 * that go until the delalloc starts
5376 */
5377 em->len = min(hole_len,
5378 range_start - hole_start);
5379 em->start = hole_start;
5380 em->orig_start = hole_start;
5381 /*
5382 * don't adjust block start at all,
5383 * it is fixed at EXTENT_MAP_HOLE
5384 */
5385 em->block_start = hole_em->block_start;
5386 em->block_len = hole_len;
5387 } else {
5388 em->start = range_start;
5389 em->len = found;
5390 em->orig_start = range_start;
5391 em->block_start = EXTENT_MAP_DELALLOC;
5392 em->block_len = found;
5393 }
5394 } else if (hole_em) {
5395 return hole_em;
5396 }
5397out:
5398
5399 free_extent_map(hole_em);
5400 if (err) {
5401 free_extent_map(em);
5402 return ERR_PTR(err);
5403 }
5404 return em;
5405}
5406
5285static struct extent_map *btrfs_new_extent_direct(struct inode *inode, 5407static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
5286 u64 start, u64 len) 5408 u64 start, u64 len)
5287{ 5409{
@@ -6104,7 +6226,7 @@ out:
6104static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 6226static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
6105 __u64 start, __u64 len) 6227 __u64 start, __u64 len)
6106{ 6228{
6107 return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent); 6229 return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent_fiemap);
6108} 6230}
6109 6231
6110int btrfs_readpage(struct file *file, struct page *page) 6232int btrfs_readpage(struct file *file, struct page *page)