aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorZheng Liu <wenqing.lz@taobao.com>2012-11-08 21:57:37 -0500
committerTheodore Ts'o <tytso@mit.edu>2012-11-08 21:57:37 -0500
commitb3aff3e3f61d13586fd46d1ee6f7353ab3050b6d (patch)
tree99ad729745ed3d11c07cb1712738bfa7cbfea7d0 /fs
parent7d1b1fbc95ebf41fee246dde437a77921f3bfec5 (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.c184
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;
4543repeat:
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) {
4552out:
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
4561next_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
4612found_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
4663found_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)