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.c129
1 files changed, 127 insertions, 2 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index bcc461a9695f..0efdb65953c5 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -644,6 +644,7 @@ retry:
644 async_extent->ram_size - 1, 0); 644 async_extent->ram_size - 1, 0);
645 645
646 em = alloc_extent_map(GFP_NOFS); 646 em = alloc_extent_map(GFP_NOFS);
647 BUG_ON(!em);
647 em->start = async_extent->start; 648 em->start = async_extent->start;
648 em->len = async_extent->ram_size; 649 em->len = async_extent->ram_size;
649 em->orig_start = em->start; 650 em->orig_start = em->start;
@@ -820,6 +821,7 @@ static noinline int cow_file_range(struct inode *inode,
820 BUG_ON(ret); 821 BUG_ON(ret);
821 822
822 em = alloc_extent_map(GFP_NOFS); 823 em = alloc_extent_map(GFP_NOFS);
824 BUG_ON(!em);
823 em->start = start; 825 em->start = start;
824 em->orig_start = em->start; 826 em->orig_start = em->start;
825 ram_size = ins.offset; 827 ram_size = ins.offset;
@@ -1169,6 +1171,7 @@ out_check:
1169 struct extent_map_tree *em_tree; 1171 struct extent_map_tree *em_tree;
1170 em_tree = &BTRFS_I(inode)->extent_tree; 1172 em_tree = &BTRFS_I(inode)->extent_tree;
1171 em = alloc_extent_map(GFP_NOFS); 1173 em = alloc_extent_map(GFP_NOFS);
1174 BUG_ON(!em);
1172 em->start = cur_offset; 1175 em->start = cur_offset;
1173 em->orig_start = em->start; 1176 em->orig_start = em->start;
1174 em->len = num_bytes; 1177 em->len = num_bytes;
@@ -1910,7 +1913,7 @@ static int btrfs_clean_io_failures(struct inode *inode, u64 start)
1910 1913
1911 private = 0; 1914 private = 0;
1912 if (count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private, 1915 if (count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private,
1913 (u64)-1, 1, EXTENT_DIRTY)) { 1916 (u64)-1, 1, EXTENT_DIRTY, 0)) {
1914 ret = get_state_private(&BTRFS_I(inode)->io_failure_tree, 1917 ret = get_state_private(&BTRFS_I(inode)->io_failure_tree,
1915 start, &private_failure); 1918 start, &private_failure);
1916 if (ret == 0) { 1919 if (ret == 0) {
@@ -5277,6 +5280,128 @@ out:
5277 return em; 5280 return em;
5278} 5281}
5279 5282
5283struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
5284 size_t pg_offset, u64 start, u64 len,
5285 int create)
5286{
5287 struct extent_map *em;
5288 struct extent_map *hole_em = NULL;
5289 u64 range_start = start;
5290 u64 end;
5291 u64 found;
5292 u64 found_end;
5293 int err = 0;
5294
5295 em = btrfs_get_extent(inode, page, pg_offset, start, len, create);
5296 if (IS_ERR(em))
5297 return em;
5298 if (em) {
5299 /*
5300 * if our em maps to a hole, there might
5301 * actually be delalloc bytes behind it
5302 */
5303 if (em->block_start != EXTENT_MAP_HOLE)
5304 return em;
5305 else
5306 hole_em = em;
5307 }
5308
5309 /* check to see if we've wrapped (len == -1 or similar) */
5310 end = start + len;
5311 if (end < start)
5312 end = (u64)-1;
5313 else
5314 end -= 1;
5315
5316 em = NULL;
5317
5318 /* ok, we didn't find anything, lets look for delalloc */
5319 found = count_range_bits(&BTRFS_I(inode)->io_tree, &range_start,
5320 end, len, EXTENT_DELALLOC, 1);
5321 found_end = range_start + found;
5322 if (found_end < range_start)
5323 found_end = (u64)-1;
5324
5325 /*
5326 * we didn't find anything useful, return
5327 * the original results from get_extent()
5328 */
5329 if (range_start > end || found_end <= start) {
5330 em = hole_em;
5331 hole_em = NULL;
5332 goto out;
5333 }
5334
5335 /* adjust the range_start to make sure it doesn't
5336 * go backwards from the start they passed in
5337 */
5338 range_start = max(start,range_start);
5339 found = found_end - range_start;
5340
5341 if (found > 0) {
5342 u64 hole_start = start;
5343 u64 hole_len = len;
5344
5345 em = alloc_extent_map(GFP_NOFS);
5346 if (!em) {
5347 err = -ENOMEM;
5348 goto out;
5349 }
5350 /*
5351 * when btrfs_get_extent can't find anything it
5352 * returns one huge hole
5353 *
5354 * make sure what it found really fits our range, and
5355 * adjust to make sure it is based on the start from
5356 * the caller
5357 */
5358 if (hole_em) {
5359 u64 calc_end = extent_map_end(hole_em);
5360
5361 if (calc_end <= start || (hole_em->start > end)) {
5362 free_extent_map(hole_em);
5363 hole_em = NULL;
5364 } else {
5365 hole_start = max(hole_em->start, start);
5366 hole_len = calc_end - hole_start;
5367 }
5368 }
5369 em->bdev = NULL;
5370 if (hole_em && range_start > hole_start) {
5371 /* our hole starts before our delalloc, so we
5372 * have to return just the parts of the hole
5373 * that go until the delalloc starts
5374 */
5375 em->len = min(hole_len,
5376 range_start - hole_start);
5377 em->start = hole_start;
5378 em->orig_start = hole_start;
5379 /*
5380 * don't adjust block start at all,
5381 * it is fixed at EXTENT_MAP_HOLE
5382 */
5383 em->block_start = hole_em->block_start;
5384 em->block_len = hole_len;
5385 } else {
5386 em->start = range_start;
5387 em->len = found;
5388 em->orig_start = range_start;
5389 em->block_start = EXTENT_MAP_DELALLOC;
5390 em->block_len = found;
5391 }
5392 } else if (hole_em) {
5393 return hole_em;
5394 }
5395out:
5396
5397 free_extent_map(hole_em);
5398 if (err) {
5399 free_extent_map(em);
5400 return ERR_PTR(err);
5401 }
5402 return em;
5403}
5404
5280static struct extent_map *btrfs_new_extent_direct(struct inode *inode, 5405static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
5281 u64 start, u64 len) 5406 u64 start, u64 len)
5282{ 5407{
@@ -6099,7 +6224,7 @@ out:
6099static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 6224static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
6100 __u64 start, __u64 len) 6225 __u64 start, __u64 len)
6101{ 6226{
6102 return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent); 6227 return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent_fiemap);
6103} 6228}
6104 6229
6105int btrfs_readpage(struct file *file, struct page *page) 6230int btrfs_readpage(struct file *file, struct page *page)