diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/extent_io.c | 92 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 2 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 7 |
3 files changed, 101 insertions, 0 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index c9446d4840ed..a3b0676403f7 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -2854,6 +2854,98 @@ out: | |||
2854 | return sector; | 2854 | return sector; |
2855 | } | 2855 | } |
2856 | 2856 | ||
2857 | int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
2858 | __u64 start, __u64 len, get_extent_t *get_extent) | ||
2859 | { | ||
2860 | int ret; | ||
2861 | u64 off = start; | ||
2862 | u64 max = start + len; | ||
2863 | u32 flags = 0; | ||
2864 | u64 disko = 0; | ||
2865 | struct extent_map *em = NULL; | ||
2866 | int end = 0; | ||
2867 | u64 em_start = 0, em_len = 0; | ||
2868 | unsigned long emflags; | ||
2869 | ret = 0; | ||
2870 | |||
2871 | if (len == 0) | ||
2872 | return -EINVAL; | ||
2873 | |||
2874 | lock_extent(&BTRFS_I(inode)->io_tree, start, start + len, | ||
2875 | GFP_NOFS); | ||
2876 | em = get_extent(inode, NULL, 0, off, max - off, 0); | ||
2877 | if (!em) | ||
2878 | goto out; | ||
2879 | if (IS_ERR(em)) { | ||
2880 | ret = PTR_ERR(em); | ||
2881 | goto out; | ||
2882 | } | ||
2883 | while (!end) { | ||
2884 | off = em->start + em->len; | ||
2885 | if (off >= max) | ||
2886 | end = 1; | ||
2887 | |||
2888 | em_start = em->start; | ||
2889 | em_len = em->len; | ||
2890 | |||
2891 | disko = 0; | ||
2892 | flags = 0; | ||
2893 | |||
2894 | switch (em->block_start) { | ||
2895 | case EXTENT_MAP_LAST_BYTE: | ||
2896 | end = 1; | ||
2897 | flags |= FIEMAP_EXTENT_LAST; | ||
2898 | break; | ||
2899 | case EXTENT_MAP_HOLE: | ||
2900 | flags |= FIEMAP_EXTENT_UNWRITTEN; | ||
2901 | break; | ||
2902 | case EXTENT_MAP_INLINE: | ||
2903 | flags |= (FIEMAP_EXTENT_DATA_INLINE | | ||
2904 | FIEMAP_EXTENT_NOT_ALIGNED); | ||
2905 | break; | ||
2906 | case EXTENT_MAP_DELALLOC: | ||
2907 | flags |= (FIEMAP_EXTENT_DELALLOC | | ||
2908 | FIEMAP_EXTENT_UNKNOWN); | ||
2909 | break; | ||
2910 | default: | ||
2911 | disko = em->block_start; | ||
2912 | break; | ||
2913 | } | ||
2914 | if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) | ||
2915 | flags |= FIEMAP_EXTENT_ENCODED; | ||
2916 | |||
2917 | emflags = em->flags; | ||
2918 | free_extent_map(em); | ||
2919 | em = NULL; | ||
2920 | |||
2921 | if (!end) { | ||
2922 | em = get_extent(inode, NULL, 0, off, max - off, 0); | ||
2923 | if (!em) | ||
2924 | goto out; | ||
2925 | if (IS_ERR(em)) { | ||
2926 | ret = PTR_ERR(em); | ||
2927 | goto out; | ||
2928 | } | ||
2929 | emflags = em->flags; | ||
2930 | } | ||
2931 | if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) { | ||
2932 | flags |= FIEMAP_EXTENT_LAST; | ||
2933 | end = 1; | ||
2934 | } | ||
2935 | |||
2936 | ret = fiemap_fill_next_extent(fieinfo, em_start, disko, | ||
2937 | em_len, flags); | ||
2938 | if (ret) | ||
2939 | goto out_free; | ||
2940 | } | ||
2941 | out_free: | ||
2942 | free_extent_map(em); | ||
2943 | out: | ||
2944 | unlock_extent(&BTRFS_I(inode)->io_tree, start, start + len, | ||
2945 | GFP_NOFS); | ||
2946 | return ret; | ||
2947 | } | ||
2948 | |||
2857 | static inline struct page *extent_buffer_page(struct extent_buffer *eb, | 2949 | static inline struct page *extent_buffer_page(struct extent_buffer *eb, |
2858 | unsigned long i) | 2950 | unsigned long i) |
2859 | { | 2951 | { |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index c5b483a79137..e80c6d96b318 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
@@ -193,6 +193,8 @@ int extent_commit_write(struct extent_io_tree *tree, | |||
193 | unsigned from, unsigned to); | 193 | unsigned from, unsigned to); |
194 | sector_t extent_bmap(struct address_space *mapping, sector_t iblock, | 194 | sector_t extent_bmap(struct address_space *mapping, sector_t iblock, |
195 | get_extent_t *get_extent); | 195 | get_extent_t *get_extent); |
196 | int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
197 | __u64 start, __u64 len, get_extent_t *get_extent); | ||
196 | int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end); | 198 | int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end); |
197 | int set_state_private(struct extent_io_tree *tree, u64 start, u64 private); | 199 | int set_state_private(struct extent_io_tree *tree, u64 start, u64 private); |
198 | int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private); | 200 | int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2e25d698bab0..288c2cdc7543 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -4156,6 +4156,12 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, | |||
4156 | return -EINVAL; | 4156 | return -EINVAL; |
4157 | } | 4157 | } |
4158 | 4158 | ||
4159 | static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
4160 | __u64 start, __u64 len) | ||
4161 | { | ||
4162 | return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent); | ||
4163 | } | ||
4164 | |||
4159 | int btrfs_readpage(struct file *file, struct page *page) | 4165 | int btrfs_readpage(struct file *file, struct page *page) |
4160 | { | 4166 | { |
4161 | struct extent_io_tree *tree; | 4167 | struct extent_io_tree *tree; |
@@ -5021,6 +5027,7 @@ static struct inode_operations btrfs_file_inode_operations = { | |||
5021 | .removexattr = btrfs_removexattr, | 5027 | .removexattr = btrfs_removexattr, |
5022 | .permission = btrfs_permission, | 5028 | .permission = btrfs_permission, |
5023 | .fallocate = btrfs_fallocate, | 5029 | .fallocate = btrfs_fallocate, |
5030 | .fiemap = btrfs_fiemap, | ||
5024 | }; | 5031 | }; |
5025 | static struct inode_operations btrfs_special_inode_operations = { | 5032 | static struct inode_operations btrfs_special_inode_operations = { |
5026 | .getattr = btrfs_getattr, | 5033 | .getattr = btrfs_getattr, |