diff options
author | Zheng Liu <wenqing.lz@taobao.com> | 2012-11-08 21:57:37 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-11-08 21:57:37 -0500 |
commit | b3aff3e3f61d13586fd46d1ee6f7353ab3050b6d (patch) | |
tree | 99ad729745ed3d11c07cb1712738bfa7cbfea7d0 /fs | |
parent | 7d1b1fbc95ebf41fee246dde437a77921f3bfec5 (diff) |
ext4: reimplement fiemap using extent status tree
Signed-off-by: Yongqiang Yang <xiaoqiangnk@gmail.com>
Signed-off-by: Allison Henderson <achender@linux.vnet.ibm.com>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/extents.c | 184 |
1 files changed, 21 insertions, 163 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e0bedd1a4ac1..d3dd6182c07a 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -4499,193 +4499,51 @@ static int ext4_ext_fiemap_cb(struct inode *inode, ext4_lblk_t next, | |||
4499 | struct ext4_ext_cache *newex, struct ext4_extent *ex, | 4499 | struct ext4_ext_cache *newex, struct ext4_extent *ex, |
4500 | void *data) | 4500 | void *data) |
4501 | { | 4501 | { |
4502 | struct extent_status es; | ||
4502 | __u64 logical; | 4503 | __u64 logical; |
4503 | __u64 physical; | 4504 | __u64 physical; |
4504 | __u64 length; | 4505 | __u64 length; |
4505 | __u32 flags = 0; | 4506 | __u32 flags = 0; |
4507 | ext4_lblk_t next_del; | ||
4506 | int ret = 0; | 4508 | int ret = 0; |
4507 | struct fiemap_extent_info *fieinfo = data; | 4509 | struct fiemap_extent_info *fieinfo = data; |
4508 | unsigned char blksize_bits; | 4510 | unsigned char blksize_bits; |
4509 | 4511 | ||
4510 | blksize_bits = inode->i_sb->s_blocksize_bits; | 4512 | es.start = newex->ec_block; |
4511 | logical = (__u64)newex->ec_block << blksize_bits; | 4513 | next_del = ext4_es_find_extent(inode, &es); |
4512 | 4514 | ||
4515 | next = min(next_del, next); | ||
4513 | if (newex->ec_start == 0) { | 4516 | if (newex->ec_start == 0) { |
4514 | /* | 4517 | /* |
4515 | * No extent in extent-tree contains block @newex->ec_start, | 4518 | * No extent in extent-tree contains block @newex->ec_start, |
4516 | * then the block may stay in 1)a hole or 2)delayed-extent. | 4519 | * then the block may stay in 1)a hole or 2)delayed-extent. |
4517 | * | ||
4518 | * Holes or delayed-extents are processed as follows. | ||
4519 | * 1. lookup dirty pages with specified range in pagecache. | ||
4520 | * If no page is got, then there is no delayed-extent and | ||
4521 | * return with EXT_CONTINUE. | ||
4522 | * 2. find the 1st mapped buffer, | ||
4523 | * 3. check if the mapped buffer is both in the request range | ||
4524 | * and a delayed buffer. If not, there is no delayed-extent, | ||
4525 | * then return. | ||
4526 | * 4. a delayed-extent is found, the extent will be collected. | ||
4527 | */ | 4520 | */ |
4528 | ext4_lblk_t end = 0; | 4521 | if (es.len == 0) |
4529 | pgoff_t last_offset; | 4522 | /* A hole found. */ |
4530 | pgoff_t offset; | 4523 | return EXT_CONTINUE; |
4531 | pgoff_t index; | 4524 | |
4532 | pgoff_t start_index = 0; | 4525 | if (es.start > newex->ec_block) { |
4533 | struct page **pages = NULL; | 4526 | /* A hole found. */ |
4534 | struct buffer_head *bh = NULL; | 4527 | newex->ec_len = min(es.start - newex->ec_block, |
4535 | struct buffer_head *head = NULL; | 4528 | newex->ec_len); |
4536 | unsigned int nr_pages = PAGE_SIZE / sizeof(struct page *); | 4529 | return EXT_CONTINUE; |
4537 | |||
4538 | pages = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
4539 | if (pages == NULL) | ||
4540 | return -ENOMEM; | ||
4541 | |||
4542 | offset = logical >> PAGE_SHIFT; | ||
4543 | repeat: | ||
4544 | last_offset = offset; | ||
4545 | head = NULL; | ||
4546 | ret = find_get_pages_tag(inode->i_mapping, &offset, | ||
4547 | PAGECACHE_TAG_DIRTY, nr_pages, pages); | ||
4548 | |||
4549 | if (!(flags & FIEMAP_EXTENT_DELALLOC)) { | ||
4550 | /* First time, try to find a mapped buffer. */ | ||
4551 | if (ret == 0) { | ||
4552 | out: | ||
4553 | for (index = 0; index < ret; index++) | ||
4554 | page_cache_release(pages[index]); | ||
4555 | /* just a hole. */ | ||
4556 | kfree(pages); | ||
4557 | return EXT_CONTINUE; | ||
4558 | } | ||
4559 | index = 0; | ||
4560 | |||
4561 | next_page: | ||
4562 | /* Try to find the 1st mapped buffer. */ | ||
4563 | end = ((__u64)pages[index]->index << PAGE_SHIFT) >> | ||
4564 | blksize_bits; | ||
4565 | if (!page_has_buffers(pages[index])) | ||
4566 | goto out; | ||
4567 | head = page_buffers(pages[index]); | ||
4568 | if (!head) | ||
4569 | goto out; | ||
4570 | |||
4571 | index++; | ||
4572 | bh = head; | ||
4573 | do { | ||
4574 | if (end >= newex->ec_block + | ||
4575 | newex->ec_len) | ||
4576 | /* The buffer is out of | ||
4577 | * the request range. | ||
4578 | */ | ||
4579 | goto out; | ||
4580 | |||
4581 | if (buffer_mapped(bh) && | ||
4582 | end >= newex->ec_block) { | ||
4583 | start_index = index - 1; | ||
4584 | /* get the 1st mapped buffer. */ | ||
4585 | goto found_mapped_buffer; | ||
4586 | } | ||
4587 | |||
4588 | bh = bh->b_this_page; | ||
4589 | end++; | ||
4590 | } while (bh != head); | ||
4591 | |||
4592 | /* No mapped buffer in the range found in this page, | ||
4593 | * We need to look up next page. | ||
4594 | */ | ||
4595 | if (index >= ret) { | ||
4596 | /* There is no page left, but we need to limit | ||
4597 | * newex->ec_len. | ||
4598 | */ | ||
4599 | newex->ec_len = end - newex->ec_block; | ||
4600 | goto out; | ||
4601 | } | ||
4602 | goto next_page; | ||
4603 | } else { | ||
4604 | /*Find contiguous delayed buffers. */ | ||
4605 | if (ret > 0 && pages[0]->index == last_offset) | ||
4606 | head = page_buffers(pages[0]); | ||
4607 | bh = head; | ||
4608 | index = 1; | ||
4609 | start_index = 0; | ||
4610 | } | 4530 | } |
4611 | 4531 | ||
4612 | found_mapped_buffer: | 4532 | flags |= FIEMAP_EXTENT_DELALLOC; |
4613 | if (bh != NULL && buffer_delay(bh)) { | 4533 | newex->ec_len = es.start + es.len - newex->ec_block; |
4614 | /* 1st or contiguous delayed buffer found. */ | ||
4615 | if (!(flags & FIEMAP_EXTENT_DELALLOC)) { | ||
4616 | /* | ||
4617 | * 1st delayed buffer found, record | ||
4618 | * the start of extent. | ||
4619 | */ | ||
4620 | flags |= FIEMAP_EXTENT_DELALLOC; | ||
4621 | newex->ec_block = end; | ||
4622 | logical = (__u64)end << blksize_bits; | ||
4623 | } | ||
4624 | /* Find contiguous delayed buffers. */ | ||
4625 | do { | ||
4626 | if (!buffer_delay(bh)) | ||
4627 | goto found_delayed_extent; | ||
4628 | bh = bh->b_this_page; | ||
4629 | end++; | ||
4630 | } while (bh != head); | ||
4631 | |||
4632 | for (; index < ret; index++) { | ||
4633 | if (!page_has_buffers(pages[index])) { | ||
4634 | bh = NULL; | ||
4635 | break; | ||
4636 | } | ||
4637 | head = page_buffers(pages[index]); | ||
4638 | if (!head) { | ||
4639 | bh = NULL; | ||
4640 | break; | ||
4641 | } | ||
4642 | |||
4643 | if (pages[index]->index != | ||
4644 | pages[start_index]->index + index | ||
4645 | - start_index) { | ||
4646 | /* Blocks are not contiguous. */ | ||
4647 | bh = NULL; | ||
4648 | break; | ||
4649 | } | ||
4650 | bh = head; | ||
4651 | do { | ||
4652 | if (!buffer_delay(bh)) | ||
4653 | /* Delayed-extent ends. */ | ||
4654 | goto found_delayed_extent; | ||
4655 | bh = bh->b_this_page; | ||
4656 | end++; | ||
4657 | } while (bh != head); | ||
4658 | } | ||
4659 | } else if (!(flags & FIEMAP_EXTENT_DELALLOC)) | ||
4660 | /* a hole found. */ | ||
4661 | goto out; | ||
4662 | |||
4663 | found_delayed_extent: | ||
4664 | newex->ec_len = min(end - newex->ec_block, | ||
4665 | (ext4_lblk_t)EXT_INIT_MAX_LEN); | ||
4666 | if (ret == nr_pages && bh != NULL && | ||
4667 | newex->ec_len < EXT_INIT_MAX_LEN && | ||
4668 | buffer_delay(bh)) { | ||
4669 | /* Have not collected an extent and continue. */ | ||
4670 | for (index = 0; index < ret; index++) | ||
4671 | page_cache_release(pages[index]); | ||
4672 | goto repeat; | ||
4673 | } | ||
4674 | |||
4675 | for (index = 0; index < ret; index++) | ||
4676 | page_cache_release(pages[index]); | ||
4677 | kfree(pages); | ||
4678 | } | 4534 | } |
4679 | 4535 | ||
4680 | physical = (__u64)newex->ec_start << blksize_bits; | ||
4681 | length = (__u64)newex->ec_len << blksize_bits; | ||
4682 | |||
4683 | if (ex && ext4_ext_is_uninitialized(ex)) | 4536 | if (ex && ext4_ext_is_uninitialized(ex)) |
4684 | flags |= FIEMAP_EXTENT_UNWRITTEN; | 4537 | flags |= FIEMAP_EXTENT_UNWRITTEN; |
4685 | 4538 | ||
4686 | if (next == EXT_MAX_BLOCKS) | 4539 | if (next == EXT_MAX_BLOCKS) |
4687 | flags |= FIEMAP_EXTENT_LAST; | 4540 | flags |= FIEMAP_EXTENT_LAST; |
4688 | 4541 | ||
4542 | blksize_bits = inode->i_sb->s_blocksize_bits; | ||
4543 | logical = (__u64)newex->ec_block << blksize_bits; | ||
4544 | physical = (__u64)newex->ec_start << blksize_bits; | ||
4545 | length = (__u64)newex->ec_len << blksize_bits; | ||
4546 | |||
4689 | ret = fiemap_fill_next_extent(fieinfo, logical, physical, | 4547 | ret = fiemap_fill_next_extent(fieinfo, logical, physical, |
4690 | length, flags); | 4548 | length, flags); |
4691 | if (ret < 0) | 4549 | if (ret < 0) |