diff options
author | Mark Fasheh <mfasheh@suse.de> | 2012-08-08 14:33:54 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2012-10-09 09:15:01 -0400 |
commit | d24bec3ae528a47149b838aad76c006d40fe8a39 (patch) | |
tree | 5c89eba867198cfd7c04e2e1ed978415aa7a3023 /fs | |
parent | f186373fef005cee948a4a39e6a14c2e5f517298 (diff) |
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: Mark Fasheh <mfasheh@suse.de>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/backref.c | 173 | ||||
-rw-r--r-- | fs/btrfs/backref.h | 2 |
2 files changed, 138 insertions, 37 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index dc963121d1db..f3187938e081 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
@@ -1177,26 +1177,12 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid, | |||
1177 | return ret; | 1177 | return ret; |
1178 | } | 1178 | } |
1179 | 1179 | ||
1180 | /* | 1180 | static char *ref_to_path(struct btrfs_root *fs_root, |
1181 | * this iterates to turn a btrfs_inode_ref into a full filesystem path. elements | 1181 | struct btrfs_path *path, |
1182 | * of the path are separated by '/' and the path is guaranteed to be | 1182 | u32 name_len, unsigned long name_off, |
1183 | * 0-terminated. the path is only given within the current file system. | ||
1184 | * Therefore, it never starts with a '/'. the caller is responsible to provide | ||
1185 | * "size" bytes in "dest". the dest buffer will be filled backwards. finally, | ||
1186 | * the start point of the resulting string is returned. this pointer is within | ||
1187 | * dest, normally. | ||
1188 | * in case the path buffer would overflow, the pointer is decremented further | ||
1189 | * as if output was written to the buffer, though no more output is actually | ||
1190 | * generated. that way, the caller can determine how much space would be | ||
1191 | * required for the path to fit into the buffer. in that case, the returned | ||
1192 | * value will be smaller than dest. callers must check this! | ||
1193 | */ | ||
1194 | char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, | ||
1195 | struct btrfs_inode_ref *iref, | ||
1196 | struct extent_buffer *eb_in, u64 parent, | 1183 | struct extent_buffer *eb_in, u64 parent, |
1197 | char *dest, u32 size) | 1184 | char *dest, u32 size) |
1198 | { | 1185 | { |
1199 | u32 len; | ||
1200 | int slot; | 1186 | int slot; |
1201 | u64 next_inum; | 1187 | u64 next_inum; |
1202 | int ret; | 1188 | int ret; |
@@ -1204,17 +1190,17 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, | |||
1204 | struct extent_buffer *eb = eb_in; | 1190 | struct extent_buffer *eb = eb_in; |
1205 | struct btrfs_key found_key; | 1191 | struct btrfs_key found_key; |
1206 | int leave_spinning = path->leave_spinning; | 1192 | int leave_spinning = path->leave_spinning; |
1193 | struct btrfs_inode_ref *iref; | ||
1207 | 1194 | ||
1208 | if (bytes_left >= 0) | 1195 | if (bytes_left >= 0) |
1209 | dest[bytes_left] = '\0'; | 1196 | dest[bytes_left] = '\0'; |
1210 | 1197 | ||
1211 | path->leave_spinning = 1; | 1198 | path->leave_spinning = 1; |
1212 | while (1) { | 1199 | while (1) { |
1213 | len = btrfs_inode_ref_name_len(eb, iref); | 1200 | bytes_left -= name_len; |
1214 | bytes_left -= len; | ||
1215 | if (bytes_left >= 0) | 1201 | if (bytes_left >= 0) |
1216 | read_extent_buffer(eb, dest + bytes_left, | 1202 | read_extent_buffer(eb, dest + bytes_left, |
1217 | (unsigned long)(iref + 1), len); | 1203 | name_off, name_len); |
1218 | if (eb != eb_in) { | 1204 | if (eb != eb_in) { |
1219 | btrfs_tree_read_unlock_blocking(eb); | 1205 | btrfs_tree_read_unlock_blocking(eb); |
1220 | free_extent_buffer(eb); | 1206 | free_extent_buffer(eb); |
@@ -1224,6 +1210,7 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, | |||
1224 | ret = -ENOENT; | 1210 | ret = -ENOENT; |
1225 | if (ret) | 1211 | if (ret) |
1226 | break; | 1212 | break; |
1213 | |||
1227 | next_inum = found_key.offset; | 1214 | next_inum = found_key.offset; |
1228 | 1215 | ||
1229 | /* regular exit ahead */ | 1216 | /* regular exit ahead */ |
@@ -1239,8 +1226,11 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, | |||
1239 | btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); | 1226 | btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); |
1240 | } | 1227 | } |
1241 | btrfs_release_path(path); | 1228 | btrfs_release_path(path); |
1242 | |||
1243 | iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); | 1229 | iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); |
1230 | |||
1231 | name_len = btrfs_inode_ref_name_len(eb, iref); | ||
1232 | name_off = (unsigned long)(iref + 1); | ||
1233 | |||
1244 | parent = next_inum; | 1234 | parent = next_inum; |
1245 | --bytes_left; | 1235 | --bytes_left; |
1246 | if (bytes_left >= 0) | 1236 | if (bytes_left >= 0) |
@@ -1257,6 +1247,32 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, | |||
1257 | } | 1247 | } |
1258 | 1248 | ||
1259 | /* | 1249 | /* |
1250 | * this iterates to turn a btrfs_inode_ref into a full filesystem path. elements | ||
1251 | * of the path are separated by '/' and the path is guaranteed to be | ||
1252 | * 0-terminated. the path is only given within the current file system. | ||
1253 | * Therefore, it never starts with a '/'. the caller is responsible to provide | ||
1254 | * "size" bytes in "dest". the dest buffer will be filled backwards. finally, | ||
1255 | * the start point of the resulting string is returned. this pointer is within | ||
1256 | * dest, normally. | ||
1257 | * in case the path buffer would overflow, the pointer is decremented further | ||
1258 | * as if output was written to the buffer, though no more output is actually | ||
1259 | * generated. that way, the caller can determine how much space would be | ||
1260 | * required for the path to fit into the buffer. in that case, the returned | ||
1261 | * value will be smaller than dest. callers must check this! | ||
1262 | */ | ||
1263 | char *btrfs_iref_to_path(struct btrfs_root *fs_root, | ||
1264 | struct btrfs_path *path, | ||
1265 | struct btrfs_inode_ref *iref, | ||
1266 | struct extent_buffer *eb_in, u64 parent, | ||
1267 | char *dest, u32 size) | ||
1268 | { | ||
1269 | return ref_to_path(fs_root, path, | ||
1270 | btrfs_inode_ref_name_len(eb_in, iref), | ||
1271 | (unsigned long)(iref + 1), | ||
1272 | eb_in, parent, dest, size); | ||
1273 | } | ||
1274 | |||
1275 | /* | ||
1260 | * this makes the path point to (logical EXTENT_ITEM *) | 1276 | * this makes the path point to (logical EXTENT_ITEM *) |
1261 | * returns BTRFS_EXTENT_FLAG_DATA for data, BTRFS_EXTENT_FLAG_TREE_BLOCK for | 1277 | * returns BTRFS_EXTENT_FLAG_DATA for data, BTRFS_EXTENT_FLAG_TREE_BLOCK for |
1262 | * tree blocks and <0 on error. | 1278 | * tree blocks and <0 on error. |
@@ -1529,9 +1545,12 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, | |||
1529 | return ret; | 1545 | return ret; |
1530 | } | 1546 | } |
1531 | 1547 | ||
1532 | static int iterate_irefs(u64 inum, struct btrfs_root *fs_root, | 1548 | typedef int (iterate_irefs_t)(u64 parent, u32 name_len, unsigned long name_off, |
1533 | struct btrfs_path *path, | 1549 | struct extent_buffer *eb, void *ctx); |
1534 | iterate_irefs_t *iterate, void *ctx) | 1550 | |
1551 | static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root, | ||
1552 | struct btrfs_path *path, | ||
1553 | iterate_irefs_t *iterate, void *ctx) | ||
1535 | { | 1554 | { |
1536 | int ret = 0; | 1555 | int ret = 0; |
1537 | int slot; | 1556 | int slot; |
@@ -1548,7 +1567,7 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root, | |||
1548 | while (!ret) { | 1567 | while (!ret) { |
1549 | path->leave_spinning = 1; | 1568 | path->leave_spinning = 1; |
1550 | ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path, | 1569 | ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path, |
1551 | &found_key); | 1570 | &found_key); |
1552 | if (ret < 0) | 1571 | if (ret < 0) |
1553 | break; | 1572 | break; |
1554 | if (ret) { | 1573 | if (ret) { |
@@ -1576,7 +1595,8 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root, | |||
1576 | "tree %llu\n", cur, | 1595 | "tree %llu\n", cur, |
1577 | (unsigned long long)found_key.objectid, | 1596 | (unsigned long long)found_key.objectid, |
1578 | (unsigned long long)fs_root->objectid); | 1597 | (unsigned long long)fs_root->objectid); |
1579 | ret = iterate(parent, iref, eb, ctx); | 1598 | ret = iterate(parent, name_len, |
1599 | (unsigned long)(iref + 1), eb, ctx); | ||
1580 | if (ret) | 1600 | if (ret) |
1581 | break; | 1601 | break; |
1582 | len = sizeof(*iref) + name_len; | 1602 | len = sizeof(*iref) + name_len; |
@@ -1591,12 +1611,98 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root, | |||
1591 | return ret; | 1611 | return ret; |
1592 | } | 1612 | } |
1593 | 1613 | ||
1614 | static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root, | ||
1615 | struct btrfs_path *path, | ||
1616 | iterate_irefs_t *iterate, void *ctx) | ||
1617 | { | ||
1618 | int ret; | ||
1619 | int slot; | ||
1620 | u64 offset = 0; | ||
1621 | u64 parent; | ||
1622 | int found = 0; | ||
1623 | struct extent_buffer *eb; | ||
1624 | struct btrfs_inode_extref *extref; | ||
1625 | struct extent_buffer *leaf; | ||
1626 | u32 item_size; | ||
1627 | u32 cur_offset; | ||
1628 | unsigned long ptr; | ||
1629 | |||
1630 | while (1) { | ||
1631 | ret = btrfs_find_one_extref(fs_root, inum, offset, path, &extref, | ||
1632 | &offset); | ||
1633 | if (ret < 0) | ||
1634 | break; | ||
1635 | if (ret) { | ||
1636 | ret = found ? 0 : -ENOENT; | ||
1637 | break; | ||
1638 | } | ||
1639 | ++found; | ||
1640 | |||
1641 | slot = path->slots[0]; | ||
1642 | eb = path->nodes[0]; | ||
1643 | /* make sure we can use eb after releasing the path */ | ||
1644 | atomic_inc(&eb->refs); | ||
1645 | |||
1646 | btrfs_tree_read_lock(eb); | ||
1647 | btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); | ||
1648 | btrfs_release_path(path); | ||
1649 | |||
1650 | leaf = path->nodes[0]; | ||
1651 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); | ||
1652 | ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); | ||
1653 | cur_offset = 0; | ||
1654 | |||
1655 | while (cur_offset < item_size) { | ||
1656 | u32 name_len; | ||
1657 | |||
1658 | extref = (struct btrfs_inode_extref *)(ptr + cur_offset); | ||
1659 | parent = btrfs_inode_extref_parent(eb, extref); | ||
1660 | name_len = btrfs_inode_extref_name_len(eb, extref); | ||
1661 | ret = iterate(parent, name_len, | ||
1662 | (unsigned long)&extref->name, eb, ctx); | ||
1663 | if (ret) | ||
1664 | break; | ||
1665 | |||
1666 | cur_offset += btrfs_inode_extref_name_len(leaf, extref); | ||
1667 | cur_offset += sizeof(*extref); | ||
1668 | } | ||
1669 | btrfs_tree_read_unlock_blocking(eb); | ||
1670 | free_extent_buffer(eb); | ||
1671 | |||
1672 | offset++; | ||
1673 | } | ||
1674 | |||
1675 | btrfs_release_path(path); | ||
1676 | |||
1677 | return ret; | ||
1678 | } | ||
1679 | |||
1680 | static int iterate_irefs(u64 inum, struct btrfs_root *fs_root, | ||
1681 | struct btrfs_path *path, iterate_irefs_t *iterate, | ||
1682 | void *ctx) | ||
1683 | { | ||
1684 | int ret; | ||
1685 | int found_refs = 0; | ||
1686 | |||
1687 | ret = iterate_inode_refs(inum, fs_root, path, iterate, ctx); | ||
1688 | if (!ret) | ||
1689 | ++found_refs; | ||
1690 | else if (ret != -ENOENT) | ||
1691 | return ret; | ||
1692 | |||
1693 | ret = iterate_inode_extrefs(inum, fs_root, path, iterate, ctx); | ||
1694 | if (ret == -ENOENT && found_refs) | ||
1695 | return 0; | ||
1696 | |||
1697 | return ret; | ||
1698 | } | ||
1699 | |||
1594 | /* | 1700 | /* |
1595 | * returns 0 if the path could be dumped (probably truncated) | 1701 | * returns 0 if the path could be dumped (probably truncated) |
1596 | * returns <0 in case of an error | 1702 | * returns <0 in case of an error |
1597 | */ | 1703 | */ |
1598 | static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, | 1704 | static int inode_to_path(u64 inum, u32 name_len, unsigned long name_off, |
1599 | struct extent_buffer *eb, void *ctx) | 1705 | struct extent_buffer *eb, void *ctx) |
1600 | { | 1706 | { |
1601 | struct inode_fs_paths *ipath = ctx; | 1707 | struct inode_fs_paths *ipath = ctx; |
1602 | char *fspath; | 1708 | char *fspath; |
@@ -1609,20 +1715,17 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, | |||
1609 | ipath->fspath->bytes_left - s_ptr : 0; | 1715 | ipath->fspath->bytes_left - s_ptr : 0; |
1610 | 1716 | ||
1611 | fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr; | 1717 | fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr; |
1612 | fspath = btrfs_iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb, | 1718 | fspath = ref_to_path(ipath->fs_root, ipath->btrfs_path, name_len, |
1613 | inum, fspath_min, bytes_left); | 1719 | name_off, eb, inum, fspath_min, |
1720 | bytes_left); | ||
1614 | if (IS_ERR(fspath)) | 1721 | if (IS_ERR(fspath)) |
1615 | return PTR_ERR(fspath); | 1722 | return PTR_ERR(fspath); |
1616 | 1723 | ||
1617 | if (fspath > fspath_min) { | 1724 | if (fspath > fspath_min) { |
1618 | pr_debug("path resolved: %s\n", fspath); | ||
1619 | ipath->fspath->val[i] = (u64)(unsigned long)fspath; | 1725 | ipath->fspath->val[i] = (u64)(unsigned long)fspath; |
1620 | ++ipath->fspath->elem_cnt; | 1726 | ++ipath->fspath->elem_cnt; |
1621 | ipath->fspath->bytes_left = fspath - fspath_min; | 1727 | ipath->fspath->bytes_left = fspath - fspath_min; |
1622 | } else { | 1728 | } else { |
1623 | pr_debug("missed path, not enough space. missing bytes: %lu, " | ||
1624 | "constructed so far: %s\n", | ||
1625 | (unsigned long)(fspath_min - fspath), fspath_min); | ||
1626 | ++ipath->fspath->elem_missed; | 1729 | ++ipath->fspath->elem_missed; |
1627 | ipath->fspath->bytes_missing += fspath_min - fspath; | 1730 | ipath->fspath->bytes_missing += fspath_min - fspath; |
1628 | ipath->fspath->bytes_left = 0; | 1731 | ipath->fspath->bytes_left = 0; |
@@ -1644,7 +1747,7 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, | |||
1644 | int paths_from_inode(u64 inum, struct inode_fs_paths *ipath) | 1747 | int paths_from_inode(u64 inum, struct inode_fs_paths *ipath) |
1645 | { | 1748 | { |
1646 | return iterate_irefs(inum, ipath->fs_root, ipath->btrfs_path, | 1749 | return iterate_irefs(inum, ipath->fs_root, ipath->btrfs_path, |
1647 | inode_to_path, ipath); | 1750 | inode_to_path, ipath); |
1648 | } | 1751 | } |
1649 | 1752 | ||
1650 | struct btrfs_data_container *init_data_container(u32 total_bytes) | 1753 | struct btrfs_data_container *init_data_container(u32 total_bytes) |
diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h index 0b920c113952..e75533043a5f 100644 --- a/fs/btrfs/backref.h +++ b/fs/btrfs/backref.h | |||
@@ -33,8 +33,6 @@ struct inode_fs_paths { | |||
33 | 33 | ||
34 | typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root, | 34 | typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root, |
35 | void *ctx); | 35 | void *ctx); |
36 | typedef int (iterate_irefs_t)(u64 parent, struct btrfs_inode_ref *iref, | ||
37 | struct extent_buffer *eb, void *ctx); | ||
38 | 36 | ||
39 | int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, | 37 | int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, |
40 | struct btrfs_path *path); | 38 | struct btrfs_path *path); |