Commit fe09e16c authored by Liu Bo's avatar Liu Bo Committed by Chris Mason

Btrfs: export btrfs space shared info to userspace

Similar to ocfs2, btrfs also supports that extents can be shared by
different inodes, and there are some userspace tools requesting
for this kind of 'space shared infomation'.[1]

ocfs2 uses flag FIEMAP_EXTENT_SHARED, so does btrfs.

[1]: http://thr3ads.net/ocfs2-devel/2010/09/489052-PATCH-3-3-shared-du-using-fiemap-to-figure-up-the-shared-extents-per-file-and-the-footprint-inReviewed-by: default avatarDavid Sterba <dsterba@suse.cz>
Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parent 74514323
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "check-integrity.h" #include "check-integrity.h"
#include "locking.h" #include "locking.h"
#include "rcu-string.h" #include "rcu-string.h"
#include "backref.h"
static struct kmem_cache *extent_state_cache; static struct kmem_cache *extent_state_cache;
static struct kmem_cache *extent_buffer_cache; static struct kmem_cache *extent_buffer_cache;
...@@ -4062,6 +4063,19 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode, ...@@ -4062,6 +4063,19 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode,
return NULL; return NULL;
} }
static noinline int count_ext_ref(u64 inum, u64 offset, u64 root_id, void *ctx)
{
unsigned long cnt = *((unsigned long *)ctx);
cnt++;
*((unsigned long *)ctx) = cnt;
/* Now we're sure that the extent is shared. */
if (cnt > 1)
return 1;
return 0;
}
int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len, get_extent_t *get_extent) __u64 start, __u64 len, get_extent_t *get_extent)
{ {
...@@ -4128,7 +4142,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -4128,7 +4142,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
last = found_key.offset; last = found_key.offset;
last_for_get_extent = last + 1; last_for_get_extent = last + 1;
} }
btrfs_free_path(path); btrfs_release_path(path);
/* /*
* we might have some extents allocated but more delalloc past those * we might have some extents allocated but more delalloc past those
...@@ -4198,7 +4212,24 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -4198,7 +4212,24 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
flags |= (FIEMAP_EXTENT_DELALLOC | flags |= (FIEMAP_EXTENT_DELALLOC |
FIEMAP_EXTENT_UNKNOWN); FIEMAP_EXTENT_UNKNOWN);
} else { } else {
unsigned long ref_cnt = 0;
disko = em->block_start + offset_in_extent; disko = em->block_start + offset_in_extent;
/*
* As btrfs supports shared space, this information
* can be exported to userspace tools via
* flag FIEMAP_EXTENT_SHARED.
*/
ret = iterate_inodes_from_logical(
em->block_start,
BTRFS_I(inode)->root->fs_info,
path, count_ext_ref, &ref_cnt);
if (ret < 0 && ret != -ENOENT)
goto out_free;
if (ref_cnt > 1)
flags |= FIEMAP_EXTENT_SHARED;
} }
if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
flags |= FIEMAP_EXTENT_ENCODED; flags |= FIEMAP_EXTENT_ENCODED;
...@@ -4230,6 +4261,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -4230,6 +4261,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
out_free: out_free:
free_extent_map(em); free_extent_map(em);
out: out:
btrfs_free_path(path);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len - 1, unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len - 1,
&cached_state, GFP_NOFS); &cached_state, GFP_NOFS);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment