diff options
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 93 |
1 files changed, 92 insertions, 1 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index e086d407f1fa..a3b0676403f7 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/spinlock.h> | 9 | #include <linux/spinlock.h> |
10 | #include <linux/blkdev.h> | 10 | #include <linux/blkdev.h> |
11 | #include <linux/swap.h> | 11 | #include <linux/swap.h> |
12 | #include <linux/version.h> | ||
13 | #include <linux/writeback.h> | 12 | #include <linux/writeback.h> |
14 | #include <linux/pagevec.h> | 13 | #include <linux/pagevec.h> |
15 | #include "extent_io.h" | 14 | #include "extent_io.h" |
@@ -2855,6 +2854,98 @@ out: | |||
2855 | return sector; | 2854 | return sector; |
2856 | } | 2855 | } |
2857 | 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 | |||
2858 | static inline struct page *extent_buffer_page(struct extent_buffer *eb, | 2949 | static inline struct page *extent_buffer_page(struct extent_buffer *eb, |
2859 | unsigned long i) | 2950 | unsigned long i) |
2860 | { | 2951 | { |