aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/extent_io.c92
-rw-r--r--fs/btrfs/extent_io.h2
-rw-r--r--fs/btrfs/inode.c7
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
2857int 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 }
2941out_free:
2942 free_extent_map(em);
2943out:
2944 unlock_extent(&BTRFS_I(inode)->io_tree, start, start + len,
2945 GFP_NOFS);
2946 return ret;
2947}
2948
2857static inline struct page *extent_buffer_page(struct extent_buffer *eb, 2949static 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);
194sector_t extent_bmap(struct address_space *mapping, sector_t iblock, 194sector_t extent_bmap(struct address_space *mapping, sector_t iblock,
195 get_extent_t *get_extent); 195 get_extent_t *get_extent);
196int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
197 __u64 start, __u64 len, get_extent_t *get_extent);
196int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end); 198int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end);
197int set_state_private(struct extent_io_tree *tree, u64 start, u64 private); 199int set_state_private(struct extent_io_tree *tree, u64 start, u64 private);
198int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private); 200int 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
4159static 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
4159int btrfs_readpage(struct file *file, struct page *page) 4165int 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};
5025static struct inode_operations btrfs_special_inode_operations = { 5032static struct inode_operations btrfs_special_inode_operations = {
5026 .getattr = btrfs_getattr, 5033 .getattr = btrfs_getattr,