On Wed, August 08, 2012 at 20:55 (+0200), Mark Fasheh wrote:
> The iterate_irefs in backref.c is used to build path components from inode
> refs. This patch adds code to iterate extended refs as well.
>
> I had modify the callback function signature to abstract out some of the
> differences between ref structures. iref_to_path() also needed similar
> changes.
>
> Signed-off-by: Mark Fasheh <mfasheh@xxxxxxx>
> ---
> fs/btrfs/backref.c | 134 +++++++++++++++++++++++++++++++++++++++++++---------
> fs/btrfs/backref.h | 2 -
> 2 files changed, 112 insertions(+), 24 deletions(-)
>
> diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
> index 658e09c..4a01f7c 100644
> --- a/fs/btrfs/backref.c
> +++ b/fs/btrfs/backref.c
> @@ -1194,11 +1194,10 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
> * value will be smaller than dest. callers must check this!
> */
> static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
> - struct btrfs_inode_ref *iref,
> - struct extent_buffer *eb_in, u64 parent,
> - char *dest, u32 size)
> + u32 name_len, unsigned long name_off,
> + struct extent_buffer *eb_in, u64 parent,
> + char *dest, u32 size)
> {
> - u32 len;
> int slot;
> u64 next_inum;
> int ret;
> @@ -1206,17 +1205,17 @@ static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
> struct extent_buffer *eb = eb_in;
> struct btrfs_key found_key;
> int leave_spinning = path->leave_spinning;
> + struct btrfs_inode_ref *iref;
>
> if (bytes_left >= 0)
> dest[bytes_left] = '\0';
>
> path->leave_spinning = 1;
> while (1) {
> - len = btrfs_inode_ref_name_len(eb, iref);
> - bytes_left -= len;
> + bytes_left -= name_len;
> if (bytes_left >= 0)
> read_extent_buffer(eb, dest + bytes_left,
> - (unsigned long)(iref + 1), len);
> + name_off, name_len);
> if (eb != eb_in) {
> btrfs_tree_read_unlock_blocking(eb);
> free_extent_buffer(eb);
> @@ -1226,6 +1225,7 @@ static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
> ret = -ENOENT;
> if (ret)
> break;
> +
> next_inum = found_key.offset;
>
> /* regular exit ahead */
> @@ -1241,8 +1241,11 @@ static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
> btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
> }
> btrfs_release_path(path);
> -
> iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);
> +
> + name_len = btrfs_inode_ref_name_len(eb, iref);
> + name_off = (unsigned long)(iref + 1);
> +
> parent = next_inum;
> --bytes_left;
> if (bytes_left >= 0)
> @@ -1531,9 +1534,12 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
> return ret;
> }
>
> -static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
> - struct btrfs_path *path,
> - iterate_irefs_t *iterate, void *ctx)
> +typedef int (iterate_irefs_t)(u64 parent, u32 name_len, unsigned long name_off,
> + struct extent_buffer *eb, void *ctx);
> +
> +static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
> + struct btrfs_path *path,
> + iterate_irefs_t *iterate, void *ctx)
> {
> int ret = 0;
> int slot;
> @@ -1550,7 +1556,7 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
> while (!ret) {
> path->leave_spinning = 1;
> ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path,
> - &found_key);
> + &found_key);
> if (ret < 0)
> break;
> if (ret) {
> @@ -1578,7 +1584,8 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
> "tree %llu\n", cur,
> (unsigned long long)found_key.objectid,
> (unsigned long long)fs_root->objectid);
> - ret = iterate(parent, iref, eb, ctx);
> + ret = iterate(parent, name_len,
> + (unsigned long)(iref + 1), eb, ctx);
> if (ret)
> break;
> len = sizeof(*iref) + name_len;
> @@ -1593,12 +1600,98 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
> return ret;
> }
>
> +static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root,
> + struct btrfs_path *path,
> + iterate_irefs_t *iterate, void *ctx)
> +{
> + int ret;
> + int slot;
> + u64 offset = 0;
> + u64 parent;
> + int found = 0;
> + struct extent_buffer *eb;
> + struct btrfs_inode_extref *extref;
> + struct extent_buffer *leaf;
> + u32 item_size;
> + u32 cur_offset;
> + unsigned long ptr;
> +
> + while (1) {
> + ret = btrfs_find_one_extref(fs_root, inum, offset, path, &extref,
> + &offset);
> + if (ret < 0)
> + break;
> + if (ret) {
> + ret = found ? 0 : -ENOENT;
> + break;
> + }
> + ++found;
> +
> + slot = path->slots[0];
> + eb = path->nodes[0];
> + /* make sure we can use eb after releasing the path */
> + atomic_inc(&eb->refs);
> +
> + btrfs_tree_read_lock(eb);
> + btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
> + btrfs_release_path(path);
> +
> + leaf = path->nodes[0];
> + item_size = btrfs_item_size_nr(leaf, path->slots[0]);
> + ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
> + cur_offset = 0;
> +
> + while (cur_offset < item_size) {
> + u32 name_len;
> +
> + extref = (struct btrfs_inode_extref *)(ptr + cur_offset);
> + parent = btrfs_inode_extref_parent(eb, extref);
> + name_len = btrfs_inode_extref_name_len(eb, extref);
> + ret = iterate(parent, name_len,
> + (unsigned long)&extref->name, eb, ctx);
> + if (ret)
> + break;
> +
> + cur_offset += btrfs_inode_extref_name_len(leaf, extref);
> + cur_offset += sizeof(*extref);
> + }
> + btrfs_tree_read_unlock_blocking(eb);
> + free_extent_buffer(eb);
> +
> + offset++;
> + }
> +
> + btrfs_release_path(path);
> +
> + return ret;
> +}
> +
> +static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
> + struct btrfs_path *path, iterate_irefs_t *iterate,
> + void *ctx)
> +{
> + int ret;
> + int found_refs = 0;
> +
> + ret = iterate_inode_refs(inum, fs_root, path, iterate, ctx);
> + if (!ret)
> + ++found_refs;
> + else if (ret != -ENOENT)
> + return ret;
> +
> + ret = iterate_inode_extrefs(inum, fs_root, path, iterate, ctx);
> + if (ret == -ENOENT && found_refs)
> + return 0;
> +
> + return ret;
> +}
> +
> /*
> * returns 0 if the path could be dumped (probably truncated)
> * returns <0 in case of an error
> */
> -static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref,
> - struct extent_buffer *eb, void *ctx)
> +static int inode_to_path(u64 inum, u32 name_len, unsigned long name_off,
> + struct extent_buffer *eb, void *ctx)
> {
> struct inode_fs_paths *ipath = ctx;
> char *fspath;
> @@ -1611,20 +1704,17 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref,
> ipath->fspath->bytes_left - s_ptr : 0;
>
> fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr;
> - fspath = iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb,
> - inum, fspath_min, bytes_left);
> + fspath = iref_to_path(ipath->fs_root, ipath->btrfs_path, name_len,
> + name_off, eb, inum, fspath_min,
> + bytes_left);
> if (IS_ERR(fspath))
> return PTR_ERR(fspath);
>
> if (fspath > fspath_min) {
> - pr_debug("path resolved: %s\n", fspath);
> ipath->fspath->val[i] = (u64)(unsigned long)fspath;
> ++ipath->fspath->elem_cnt;
> ipath->fspath->bytes_left = fspath - fspath_min;
> } else {
> - pr_debug("missed path, not enough space. missing bytes: %lu, "
> - "constructed so far: %s\n",
> - (unsigned long)(fspath_min - fspath), fspath_min);
> ++ipath->fspath->elem_missed;
> ipath->fspath->bytes_missing += fspath_min - fspath;
> ipath->fspath->bytes_left = 0;
> @@ -1646,7 +1736,7 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref,
> int paths_from_inode(u64 inum, struct inode_fs_paths *ipath)
> {
> return iterate_irefs(inum, ipath->fs_root, ipath->btrfs_path,
> - inode_to_path, ipath);
> + inode_to_path, ipath);
> }
>
> struct btrfs_data_container *init_data_container(u32 total_bytes)
> diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h
> index 9f3e251..c80889a 100644
> --- a/fs/btrfs/backref.h
> +++ b/fs/btrfs/backref.h
> @@ -32,8 +32,6 @@ struct inode_fs_paths {
>
> typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root,
> void *ctx);
> -typedef int (iterate_irefs_t)(u64 parent, struct btrfs_inode_ref *iref,
> - struct extent_buffer *eb, void *ctx);
>
> int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
> struct btrfs_path *path);
Reviewed-by: Jan Schmidt <list.btrfs@xxxxxxxxxxxxx>
-Jan
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html