aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMark Fasheh <mfasheh@suse.de>2012-08-08 14:33:54 -0400
committerChris Mason <chris.mason@fusionio.com>2012-10-09 09:15:01 -0400
commitd24bec3ae528a47149b838aad76c006d40fe8a39 (patch)
tree5c89eba867198cfd7c04e2e1ed978415aa7a3023 /fs
parentf186373fef005cee948a4a39e6a14c2e5f517298 (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.c173
-rw-r--r--fs/btrfs/backref.h2
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/* 1180static 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 */
1194char *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 */
1263char *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
1532static int iterate_irefs(u64 inum, struct btrfs_root *fs_root, 1548typedef 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
1551static 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
1614static 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
1680static 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 */
1598static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, 1704static 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,
1644int paths_from_inode(u64 inum, struct inode_fs_paths *ipath) 1747int 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
1650struct btrfs_data_container *init_data_container(u32 total_bytes) 1753struct 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
34typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root, 34typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root,
35 void *ctx); 35 void *ctx);
36typedef int (iterate_irefs_t)(u64 parent, struct btrfs_inode_ref *iref,
37 struct extent_buffer *eb, void *ctx);
38 36
39int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, 37int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
40 struct btrfs_path *path); 38 struct btrfs_path *path);