diff options
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 77 |
1 files changed, 62 insertions, 15 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index eac10e3260a9..3e86b9f36507 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -1828,9 +1828,9 @@ static void end_bio_extent_preparewrite(struct bio *bio, int err) | |||
1828 | bio_put(bio); | 1828 | bio_put(bio); |
1829 | } | 1829 | } |
1830 | 1830 | ||
1831 | static struct bio * | 1831 | struct bio * |
1832 | extent_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, | 1832 | btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, |
1833 | gfp_t gfp_flags) | 1833 | gfp_t gfp_flags) |
1834 | { | 1834 | { |
1835 | struct bio *bio; | 1835 | struct bio *bio; |
1836 | 1836 | ||
@@ -1919,7 +1919,7 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, | |||
1919 | else | 1919 | else |
1920 | nr = bio_get_nr_vecs(bdev); | 1920 | nr = bio_get_nr_vecs(bdev); |
1921 | 1921 | ||
1922 | bio = extent_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH); | 1922 | bio = btrfs_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH); |
1923 | 1923 | ||
1924 | bio_add_page(bio, page, page_size, offset); | 1924 | bio_add_page(bio, page, page_size, offset); |
1925 | bio->bi_end_io = end_io_func; | 1925 | bio->bi_end_io = end_io_func; |
@@ -2901,21 +2901,53 @@ out: | |||
2901 | int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 2901 | int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
2902 | __u64 start, __u64 len, get_extent_t *get_extent) | 2902 | __u64 start, __u64 len, get_extent_t *get_extent) |
2903 | { | 2903 | { |
2904 | int ret; | 2904 | int ret = 0; |
2905 | u64 off = start; | 2905 | u64 off = start; |
2906 | u64 max = start + len; | 2906 | u64 max = start + len; |
2907 | u32 flags = 0; | 2907 | u32 flags = 0; |
2908 | u32 found_type; | ||
2909 | u64 last; | ||
2908 | u64 disko = 0; | 2910 | u64 disko = 0; |
2911 | struct btrfs_key found_key; | ||
2909 | struct extent_map *em = NULL; | 2912 | struct extent_map *em = NULL; |
2910 | struct extent_state *cached_state = NULL; | 2913 | struct extent_state *cached_state = NULL; |
2914 | struct btrfs_path *path; | ||
2915 | struct btrfs_file_extent_item *item; | ||
2911 | int end = 0; | 2916 | int end = 0; |
2912 | u64 em_start = 0, em_len = 0; | 2917 | u64 em_start = 0, em_len = 0; |
2913 | unsigned long emflags; | 2918 | unsigned long emflags; |
2914 | ret = 0; | 2919 | int hole = 0; |
2915 | 2920 | ||
2916 | if (len == 0) | 2921 | if (len == 0) |
2917 | return -EINVAL; | 2922 | return -EINVAL; |
2918 | 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 | |||
2919 | lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0, | 2951 | lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0, |
2920 | &cached_state, GFP_NOFS); | 2952 | &cached_state, GFP_NOFS); |
2921 | em = get_extent(inode, NULL, 0, off, max - off, 0); | 2953 | em = get_extent(inode, NULL, 0, off, max - off, 0); |
@@ -2925,11 +2957,18 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
2925 | ret = PTR_ERR(em); | 2957 | ret = PTR_ERR(em); |
2926 | goto out; | 2958 | goto out; |
2927 | } | 2959 | } |
2960 | |||
2928 | while (!end) { | 2961 | while (!end) { |
2962 | hole = 0; | ||
2929 | off = em->start + em->len; | 2963 | off = em->start + em->len; |
2930 | if (off >= max) | 2964 | if (off >= max) |
2931 | end = 1; | 2965 | end = 1; |
2932 | 2966 | ||
2967 | if (em->block_start == EXTENT_MAP_HOLE) { | ||
2968 | hole = 1; | ||
2969 | goto next; | ||
2970 | } | ||
2971 | |||
2933 | em_start = em->start; | 2972 | em_start = em->start; |
2934 | em_len = em->len; | 2973 | em_len = em->len; |
2935 | 2974 | ||
@@ -2939,8 +2978,6 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
2939 | if (em->block_start == EXTENT_MAP_LAST_BYTE) { | 2978 | if (em->block_start == EXTENT_MAP_LAST_BYTE) { |
2940 | end = 1; | 2979 | end = 1; |
2941 | flags |= FIEMAP_EXTENT_LAST; | 2980 | flags |= FIEMAP_EXTENT_LAST; |
2942 | } else if (em->block_start == EXTENT_MAP_HOLE) { | ||
2943 | flags |= FIEMAP_EXTENT_UNWRITTEN; | ||
2944 | } else if (em->block_start == EXTENT_MAP_INLINE) { | 2981 | } else if (em->block_start == EXTENT_MAP_INLINE) { |
2945 | flags |= (FIEMAP_EXTENT_DATA_INLINE | | 2982 | flags |= (FIEMAP_EXTENT_DATA_INLINE | |
2946 | FIEMAP_EXTENT_NOT_ALIGNED); | 2983 | FIEMAP_EXTENT_NOT_ALIGNED); |
@@ -2953,10 +2990,10 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
2953 | if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) | 2990 | if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) |
2954 | flags |= FIEMAP_EXTENT_ENCODED; | 2991 | flags |= FIEMAP_EXTENT_ENCODED; |
2955 | 2992 | ||
2993 | next: | ||
2956 | emflags = em->flags; | 2994 | emflags = em->flags; |
2957 | free_extent_map(em); | 2995 | free_extent_map(em); |
2958 | em = NULL; | 2996 | em = NULL; |
2959 | |||
2960 | if (!end) { | 2997 | if (!end) { |
2961 | em = get_extent(inode, NULL, 0, off, max - off, 0); | 2998 | em = get_extent(inode, NULL, 0, off, max - off, 0); |
2962 | if (!em) | 2999 | if (!em) |
@@ -2967,15 +3004,23 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
2967 | } | 3004 | } |
2968 | emflags = em->flags; | 3005 | emflags = em->flags; |
2969 | } | 3006 | } |
3007 | |||
2970 | if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) { | 3008 | if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) { |
2971 | flags |= FIEMAP_EXTENT_LAST; | 3009 | flags |= FIEMAP_EXTENT_LAST; |
2972 | end = 1; | 3010 | end = 1; |
2973 | } | 3011 | } |
2974 | 3012 | ||
2975 | ret = fiemap_fill_next_extent(fieinfo, em_start, disko, | 3013 | if (em_start == last) { |
2976 | em_len, flags); | 3014 | flags |= FIEMAP_EXTENT_LAST; |
2977 | if (ret) | 3015 | end = 1; |
2978 | goto out_free; | 3016 | } |
3017 | |||
3018 | if (!hole) { | ||
3019 | ret = fiemap_fill_next_extent(fieinfo, em_start, disko, | ||
3020 | em_len, flags); | ||
3021 | if (ret) | ||
3022 | goto out_free; | ||
3023 | } | ||
2979 | } | 3024 | } |
2980 | out_free: | 3025 | out_free: |
2981 | free_extent_map(em); | 3026 | free_extent_map(em); |
@@ -3836,8 +3881,10 @@ int try_release_extent_buffer(struct extent_io_tree *tree, struct page *page) | |||
3836 | 3881 | ||
3837 | spin_lock(&tree->buffer_lock); | 3882 | spin_lock(&tree->buffer_lock); |
3838 | eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT); | 3883 | eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT); |
3839 | if (!eb) | 3884 | if (!eb) { |
3840 | goto out; | 3885 | spin_unlock(&tree->buffer_lock); |
3886 | return ret; | ||
3887 | } | ||
3841 | 3888 | ||
3842 | if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { | 3889 | if (test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { |
3843 | ret = 0; | 3890 | ret = 0; |