Commit d24bec3a authored by Mark Fasheh's avatar Mark Fasheh Committed by Chris Mason

btrfs: extended inode ref iteration

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: default avatarMark Fasheh <mfasheh@suse.de>
parent f186373f
......@@ -1177,26 +1177,12 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
return ret;
}
/*
* this iterates to turn a btrfs_inode_ref into a full filesystem path. elements
* of the path are separated by '/' and the path is guaranteed to be
* 0-terminated. the path is only given within the current file system.
* Therefore, it never starts with a '/'. the caller is responsible to provide
* "size" bytes in "dest". the dest buffer will be filled backwards. finally,
* the start point of the resulting string is returned. this pointer is within
* dest, normally.
* in case the path buffer would overflow, the pointer is decremented further
* as if output was written to the buffer, though no more output is actually
* generated. that way, the caller can determine how much space would be
* required for the path to fit into the buffer. in that case, the returned
* value will be smaller than dest. callers must check this!
*/
char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
struct btrfs_inode_ref *iref,
static char *ref_to_path(struct btrfs_root *fs_root,
struct btrfs_path *path,
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;
......@@ -1204,17 +1190,17 @@ char *btrfs_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);
......@@ -1224,6 +1210,7 @@ char *btrfs_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 */
......@@ -1239,8 +1226,11 @@ char *btrfs_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)
......@@ -1256,6 +1246,32 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
return dest + bytes_left;
}
/*
* this iterates to turn a btrfs_inode_ref into a full filesystem path. elements
* of the path are separated by '/' and the path is guaranteed to be
* 0-terminated. the path is only given within the current file system.
* Therefore, it never starts with a '/'. the caller is responsible to provide
* "size" bytes in "dest". the dest buffer will be filled backwards. finally,
* the start point of the resulting string is returned. this pointer is within
* dest, normally.
* in case the path buffer would overflow, the pointer is decremented further
* as if output was written to the buffer, though no more output is actually
* generated. that way, the caller can determine how much space would be
* required for the path to fit into the buffer. in that case, the returned
* value will be smaller than dest. callers must check this!
*/
char *btrfs_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)
{
return ref_to_path(fs_root, path,
btrfs_inode_ref_name_len(eb_in, iref),
(unsigned long)(iref + 1),
eb_in, parent, dest, size);
}
/*
* this makes the path point to (logical EXTENT_ITEM *)
* returns BTRFS_EXTENT_FLAG_DATA for data, BTRFS_EXTENT_FLAG_TREE_BLOCK for
......@@ -1529,9 +1545,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;
......@@ -1548,7 +1567,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) {
......@@ -1576,7 +1595,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;
......@@ -1591,12 +1611,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;
......@@ -1609,20 +1715,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 = btrfs_iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb,
inum, fspath_min, bytes_left);
fspath = ref_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;
......@@ -1644,7 +1747,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)
......
......@@ -33,8 +33,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);
......
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