aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent_io.c
diff options
context:
space:
mode:
authorYehuda Sadeh <yehuda@hq.newdream.net>2009-01-21 14:39:14 -0500
committerChris Mason <chris.mason@oracle.com>2009-01-21 14:39:14 -0500
commit1506fcc8189cdd4b95e06df7845a09f18b4526a6 (patch)
treebf737082390c26c517d7449135045e3f6d4ba055 /fs/btrfs/extent_io.c
parent35054394c4b3cecd52577c2662c84da1f3e73525 (diff)
Btrfs: fiemap support
Now that bmap support is gone, this is the only way to get extent mappings for userland. These are still not valid for IO, but they can tell us if a file has holes or how much fragmentation there is. Signed-off-by: Yehuda Sadeh <yehuda@hq.newdream.net>
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r--fs/btrfs/extent_io.c92
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
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{