diff options
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 92 |
1 files changed, 92 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 | { |