diff options
-rw-r--r-- | fs/ext4/extents.c | 187 |
1 files changed, 148 insertions, 39 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index d16f6b5a140b..9ea1bc64ca6d 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -3775,6 +3775,7 @@ int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset, | |||
3775 | } | 3775 | } |
3776 | return ret > 0 ? ret2 : ret; | 3776 | return ret > 0 ? ret2 : ret; |
3777 | } | 3777 | } |
3778 | |||
3778 | /* | 3779 | /* |
3779 | * Callback function called for each extent to gather FIEMAP information. | 3780 | * Callback function called for each extent to gather FIEMAP information. |
3780 | */ | 3781 | */ |
@@ -3782,38 +3783,162 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path, | |||
3782 | struct ext4_ext_cache *newex, struct ext4_extent *ex, | 3783 | struct ext4_ext_cache *newex, struct ext4_extent *ex, |
3783 | void *data) | 3784 | void *data) |
3784 | { | 3785 | { |
3785 | struct fiemap_extent_info *fieinfo = data; | ||
3786 | unsigned char blksize_bits = inode->i_sb->s_blocksize_bits; | ||
3787 | __u64 logical; | 3786 | __u64 logical; |
3788 | __u64 physical; | 3787 | __u64 physical; |
3789 | __u64 length; | 3788 | __u64 length; |
3789 | loff_t size; | ||
3790 | __u32 flags = 0; | 3790 | __u32 flags = 0; |
3791 | int error; | 3791 | int ret = 0; |
3792 | struct fiemap_extent_info *fieinfo = data; | ||
3793 | unsigned char blksize_bits; | ||
3792 | 3794 | ||
3793 | logical = (__u64)newex->ec_block << blksize_bits; | 3795 | blksize_bits = inode->i_sb->s_blocksize_bits; |
3796 | logical = (__u64)newex->ec_block << blksize_bits; | ||
3794 | 3797 | ||
3795 | if (newex->ec_start == 0) { | 3798 | if (newex->ec_start == 0) { |
3796 | pgoff_t offset; | 3799 | /* |
3797 | struct page *page; | 3800 | * No extent in extent-tree contains block @newex->ec_start, |
3801 | * then the block may stay in 1)a hole or 2)delayed-extent. | ||
3802 | * | ||
3803 | * Holes or delayed-extents are processed as follows. | ||
3804 | * 1. lookup dirty pages with specified range in pagecache. | ||
3805 | * If no page is got, then there is no delayed-extent and | ||
3806 | * return with EXT_CONTINUE. | ||
3807 | * 2. find the 1st mapped buffer, | ||
3808 | * 3. check if the mapped buffer is both in the request range | ||
3809 | * and a delayed buffer. If not, there is no delayed-extent, | ||
3810 | * then return. | ||
3811 | * 4. a delayed-extent is found, the extent will be collected. | ||
3812 | */ | ||
3813 | ext4_lblk_t end = 0; | ||
3814 | pgoff_t last_offset; | ||
3815 | pgoff_t offset; | ||
3816 | pgoff_t index; | ||
3817 | struct page **pages = NULL; | ||
3798 | struct buffer_head *bh = NULL; | 3818 | struct buffer_head *bh = NULL; |
3819 | struct buffer_head *head = NULL; | ||
3820 | unsigned int nr_pages = PAGE_SIZE / sizeof(struct page *); | ||
3821 | |||
3822 | pages = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
3823 | if (pages == NULL) | ||
3824 | return -ENOMEM; | ||
3799 | 3825 | ||
3800 | offset = logical >> PAGE_SHIFT; | 3826 | offset = logical >> PAGE_SHIFT; |
3801 | page = find_get_page(inode->i_mapping, offset); | 3827 | repeat: |
3802 | if (!page || !page_has_buffers(page)) | 3828 | last_offset = offset; |
3803 | return EXT_CONTINUE; | 3829 | head = NULL; |
3830 | ret = find_get_pages_tag(inode->i_mapping, &offset, | ||
3831 | PAGECACHE_TAG_DIRTY, nr_pages, pages); | ||
3832 | |||
3833 | if (!(flags & FIEMAP_EXTENT_DELALLOC)) { | ||
3834 | /* First time, try to find a mapped buffer. */ | ||
3835 | if (ret == 0) { | ||
3836 | out: | ||
3837 | for (index = 0; index < ret; index++) | ||
3838 | page_cache_release(pages[index]); | ||
3839 | /* just a hole. */ | ||
3840 | kfree(pages); | ||
3841 | return EXT_CONTINUE; | ||
3842 | } | ||
3804 | 3843 | ||
3805 | bh = page_buffers(page); | 3844 | /* Try to find the 1st mapped buffer. */ |
3845 | end = ((__u64)pages[0]->index << PAGE_SHIFT) >> | ||
3846 | blksize_bits; | ||
3847 | if (!page_has_buffers(pages[0])) | ||
3848 | goto out; | ||
3849 | head = page_buffers(pages[0]); | ||
3850 | if (!head) | ||
3851 | goto out; | ||
3806 | 3852 | ||
3807 | if (!bh) | 3853 | bh = head; |
3808 | return EXT_CONTINUE; | 3854 | do { |
3855 | if (buffer_mapped(bh)) { | ||
3856 | /* get the 1st mapped buffer. */ | ||
3857 | if (end > newex->ec_block + | ||
3858 | newex->ec_len) | ||
3859 | /* The buffer is out of | ||
3860 | * the request range. | ||
3861 | */ | ||
3862 | goto out; | ||
3863 | goto found_mapped_buffer; | ||
3864 | } | ||
3865 | bh = bh->b_this_page; | ||
3866 | end++; | ||
3867 | } while (bh != head); | ||
3809 | 3868 | ||
3810 | if (buffer_delay(bh)) { | 3869 | /* No mapped buffer found. */ |
3811 | flags |= FIEMAP_EXTENT_DELALLOC; | 3870 | goto out; |
3812 | page_cache_release(page); | ||
3813 | } else { | 3871 | } else { |
3814 | page_cache_release(page); | 3872 | /*Find contiguous delayed buffers. */ |
3815 | return EXT_CONTINUE; | 3873 | if (ret > 0 && pages[0]->index == last_offset) |
3874 | head = page_buffers(pages[0]); | ||
3875 | bh = head; | ||
3876 | } | ||
3877 | |||
3878 | found_mapped_buffer: | ||
3879 | if (bh != NULL && buffer_delay(bh)) { | ||
3880 | /* 1st or contiguous delayed buffer found. */ | ||
3881 | if (!(flags & FIEMAP_EXTENT_DELALLOC)) { | ||
3882 | /* | ||
3883 | * 1st delayed buffer found, record | ||
3884 | * the start of extent. | ||
3885 | */ | ||
3886 | flags |= FIEMAP_EXTENT_DELALLOC; | ||
3887 | newex->ec_block = end; | ||
3888 | logical = (__u64)end << blksize_bits; | ||
3889 | } | ||
3890 | /* Find contiguous delayed buffers. */ | ||
3891 | do { | ||
3892 | if (!buffer_delay(bh)) | ||
3893 | goto found_delayed_extent; | ||
3894 | bh = bh->b_this_page; | ||
3895 | end++; | ||
3896 | } while (bh != head); | ||
3897 | |||
3898 | for (index = 1; index < ret; index++) { | ||
3899 | if (!page_has_buffers(pages[index])) { | ||
3900 | bh = NULL; | ||
3901 | break; | ||
3902 | } | ||
3903 | head = page_buffers(pages[index]); | ||
3904 | if (!head) { | ||
3905 | bh = NULL; | ||
3906 | break; | ||
3907 | } | ||
3908 | if (pages[index]->index != | ||
3909 | pages[0]->index + index) { | ||
3910 | /* Blocks are not contiguous. */ | ||
3911 | bh = NULL; | ||
3912 | break; | ||
3913 | } | ||
3914 | bh = head; | ||
3915 | do { | ||
3916 | if (!buffer_delay(bh)) | ||
3917 | /* Delayed-extent ends. */ | ||
3918 | goto found_delayed_extent; | ||
3919 | bh = bh->b_this_page; | ||
3920 | end++; | ||
3921 | } while (bh != head); | ||
3922 | } | ||
3923 | } else if (!(flags & FIEMAP_EXTENT_DELALLOC)) | ||
3924 | /* a hole found. */ | ||
3925 | goto out; | ||
3926 | |||
3927 | found_delayed_extent: | ||
3928 | newex->ec_len = min(end - newex->ec_block, | ||
3929 | (ext4_lblk_t)EXT_INIT_MAX_LEN); | ||
3930 | if (ret == nr_pages && bh != NULL && | ||
3931 | newex->ec_len < EXT_INIT_MAX_LEN && | ||
3932 | buffer_delay(bh)) { | ||
3933 | /* Have not collected an extent and continue. */ | ||
3934 | for (index = 0; index < ret; index++) | ||
3935 | page_cache_release(pages[index]); | ||
3936 | goto repeat; | ||
3816 | } | 3937 | } |
3938 | |||
3939 | for (index = 0; index < ret; index++) | ||
3940 | page_cache_release(pages[index]); | ||
3941 | kfree(pages); | ||
3817 | } | 3942 | } |
3818 | 3943 | ||
3819 | physical = (__u64)newex->ec_start << blksize_bits; | 3944 | physical = (__u64)newex->ec_start << blksize_bits; |
@@ -3822,32 +3947,16 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path, | |||
3822 | if (ex && ext4_ext_is_uninitialized(ex)) | 3947 | if (ex && ext4_ext_is_uninitialized(ex)) |
3823 | flags |= FIEMAP_EXTENT_UNWRITTEN; | 3948 | flags |= FIEMAP_EXTENT_UNWRITTEN; |
3824 | 3949 | ||
3825 | /* | 3950 | size = i_size_read(inode); |
3826 | * If this extent reaches EXT_MAX_BLOCK, it must be last. | 3951 | if (logical + length >= size) |
3827 | * | ||
3828 | * Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK, | ||
3829 | * this also indicates no more allocated blocks. | ||
3830 | * | ||
3831 | * XXX this might miss a single-block extent at EXT_MAX_BLOCK | ||
3832 | */ | ||
3833 | if (ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK || | ||
3834 | newex->ec_block + newex->ec_len - 1 == EXT_MAX_BLOCK) { | ||
3835 | loff_t size = i_size_read(inode); | ||
3836 | loff_t bs = EXT4_BLOCK_SIZE(inode->i_sb); | ||
3837 | |||
3838 | flags |= FIEMAP_EXTENT_LAST; | 3952 | flags |= FIEMAP_EXTENT_LAST; |
3839 | if ((flags & FIEMAP_EXTENT_DELALLOC) && | ||
3840 | logical+length > size) | ||
3841 | length = (size - logical + bs - 1) & ~(bs-1); | ||
3842 | } | ||
3843 | 3953 | ||
3844 | error = fiemap_fill_next_extent(fieinfo, logical, physical, | 3954 | ret = fiemap_fill_next_extent(fieinfo, logical, physical, |
3845 | length, flags); | 3955 | length, flags); |
3846 | if (error < 0) | 3956 | if (ret < 0) |
3847 | return error; | 3957 | return ret; |
3848 | if (error == 1) | 3958 | if (ret == 1) |
3849 | return EXT_BREAK; | 3959 | return EXT_BREAK; |
3850 | |||
3851 | return EXT_CONTINUE; | 3960 | return EXT_CONTINUE; |
3852 | } | 3961 | } |
3853 | 3962 | ||