aboutsummaryrefslogtreecommitdiffstats
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
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>
-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,