Btrfs: fix fiemap

There are two big problems currently with FIEMAP

1) We return extents for holes. This isn't supposed to happen, we just don't
return extents for holes and then userspace interprets the lack of an extent as
a hole.

2) We sometimes don't set FIEMAP_EXTENT_LAST properly. This is because we wait
to see a EXTENT_FLAG_VACANCY flag on the em, but this won't happen if say we ask
fiemap to map up to the last extent in a file, and there is nothing but holes up
to the i_size. To fix this we need to lookup the last extent in this file and
save the logical offset, so if we happen to try and map that extent we can be
sure to set FIEMAP_EXTENT_LAST.

With this patch we now pass xfstest 225, which we never have before.

Signed-off-by: Josef Bacik <josef@redhat.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>

authored by Josef Bacik and committed by Chris Mason 975f84fe 619c8c76

+54 -9
+54 -9
fs/btrfs/extent_io.c
··· 2901 int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 2902 __u64 start, __u64 len, get_extent_t *get_extent) 2903 { 2904 - int ret; 2905 u64 off = start; 2906 u64 max = start + len; 2907 u32 flags = 0; 2908 u64 disko = 0; 2909 struct extent_map *em = NULL; 2910 struct extent_state *cached_state = NULL; 2911 int end = 0; 2912 u64 em_start = 0, em_len = 0; 2913 unsigned long emflags; 2914 - ret = 0; 2915 2916 if (len == 0) 2917 return -EINVAL; 2918 2919 lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0, 2920 &cached_state, GFP_NOFS); ··· 2957 ret = PTR_ERR(em); 2958 goto out; 2959 } 2960 while (!end) { 2961 off = em->start + em->len; 2962 if (off >= max) 2963 end = 1; 2964 2965 em_start = em->start; 2966 em_len = em->len; ··· 2978 if (em->block_start == EXTENT_MAP_LAST_BYTE) { 2979 end = 1; 2980 flags |= FIEMAP_EXTENT_LAST; 2981 - } else if (em->block_start == EXTENT_MAP_HOLE) { 2982 - flags |= FIEMAP_EXTENT_UNWRITTEN; 2983 } else if (em->block_start == EXTENT_MAP_INLINE) { 2984 flags |= (FIEMAP_EXTENT_DATA_INLINE | 2985 FIEMAP_EXTENT_NOT_ALIGNED); ··· 2990 if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) 2991 flags |= FIEMAP_EXTENT_ENCODED; 2992 2993 emflags = em->flags; 2994 free_extent_map(em); 2995 em = NULL; 2996 - 2997 if (!end) { 2998 em = get_extent(inode, NULL, 0, off, max - off, 0); 2999 if (!em) ··· 3004 } 3005 emflags = em->flags; 3006 } 3007 if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) { 3008 flags |= FIEMAP_EXTENT_LAST; 3009 end = 1; 3010 } 3011 3012 - ret = fiemap_fill_next_extent(fieinfo, em_start, disko, 3013 - em_len, flags); 3014 - if (ret) 3015 - goto out_free; 3016 } 3017 out_free: 3018 free_extent_map(em);
··· 2901 int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 2902 __u64 start, __u64 len, get_extent_t *get_extent) 2903 { 2904 + int ret = 0; 2905 u64 off = start; 2906 u64 max = start + len; 2907 u32 flags = 0; 2908 + u32 found_type; 2909 + u64 last; 2910 u64 disko = 0; 2911 + struct btrfs_key found_key; 2912 struct extent_map *em = NULL; 2913 struct extent_state *cached_state = NULL; 2914 + struct btrfs_path *path; 2915 + struct btrfs_file_extent_item *item; 2916 int end = 0; 2917 u64 em_start = 0, em_len = 0; 2918 unsigned long emflags; 2919 + int hole = 0; 2920 2921 if (len == 0) 2922 return -EINVAL; 2923 + 2924 + path = btrfs_alloc_path(); 2925 + if (!path) 2926 + return -ENOMEM; 2927 + path->leave_spinning = 1; 2928 + 2929 + ret = btrfs_lookup_file_extent(NULL, BTRFS_I(inode)->root, 2930 + path, inode->i_ino, -1, 0); 2931 + if (ret < 0) { 2932 + btrfs_free_path(path); 2933 + return ret; 2934 + } 2935 + WARN_ON(!ret); 2936 + path->slots[0]--; 2937 + item = btrfs_item_ptr(path->nodes[0], path->slots[0], 2938 + struct btrfs_file_extent_item); 2939 + btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); 2940 + found_type = btrfs_key_type(&found_key); 2941 + 2942 + /* No extents, just return */ 2943 + if (found_key.objectid != inode->i_ino || 2944 + found_type != BTRFS_EXTENT_DATA_KEY) { 2945 + btrfs_free_path(path); 2946 + return 0; 2947 + } 2948 + last = found_key.offset; 2949 + btrfs_free_path(path); 2950 2951 lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0, 2952 &cached_state, GFP_NOFS); ··· 2925 ret = PTR_ERR(em); 2926 goto out; 2927 } 2928 + 2929 while (!end) { 2930 + hole = 0; 2931 off = em->start + em->len; 2932 if (off >= max) 2933 end = 1; 2934 + 2935 + if (em->block_start == EXTENT_MAP_HOLE) { 2936 + hole = 1; 2937 + goto next; 2938 + } 2939 2940 em_start = em->start; 2941 em_len = em->len; ··· 2939 if (em->block_start == EXTENT_MAP_LAST_BYTE) { 2940 end = 1; 2941 flags |= FIEMAP_EXTENT_LAST; 2942 } else if (em->block_start == EXTENT_MAP_INLINE) { 2943 flags |= (FIEMAP_EXTENT_DATA_INLINE | 2944 FIEMAP_EXTENT_NOT_ALIGNED); ··· 2953 if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) 2954 flags |= FIEMAP_EXTENT_ENCODED; 2955 2956 + next: 2957 emflags = em->flags; 2958 free_extent_map(em); 2959 em = NULL; 2960 if (!end) { 2961 em = get_extent(inode, NULL, 0, off, max - off, 0); 2962 if (!em) ··· 2967 } 2968 emflags = em->flags; 2969 } 2970 + 2971 if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) { 2972 flags |= FIEMAP_EXTENT_LAST; 2973 end = 1; 2974 } 2975 2976 + if (em_start == last) { 2977 + flags |= FIEMAP_EXTENT_LAST; 2978 + end = 1; 2979 + } 2980 + 2981 + if (!hole) { 2982 + ret = fiemap_fill_next_extent(fieinfo, em_start, disko, 2983 + em_len, flags); 2984 + if (ret) 2985 + goto out_free; 2986 + } 2987 } 2988 out_free: 2989 free_extent_map(em);