diff options
| -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, |
