aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChen Baozi <baozich@gmail.com>2012-08-15 17:34:35 +0800
committerPaulo Alcantara <pcacjr@zytor.com>2012-09-02 19:28:43 -0300
commit65e257cafb44a8ec60ff171cfe4560a9106a15ec (patch)
treefb5a3f51bf9bab9d74511bb3429425240aa3b948
parent51b3add13273dede5b5cc51dd5296604f0a38601 (diff)
downloadsyslinux-65e257cafb44a8ec60ff171cfe4560a9106a15ec.tar.gz
syslinux-65e257cafb44a8ec60ff171cfe4560a9106a15ec.tar.xz
syslinux-65e257cafb44a8ec60ff171cfe4560a9106a15ec.zip
xfs: Add XFS_DINODE_FMT_BTREE support in xfs_next_extent()
XFS's extent B+Tree is organized in the key of offset. So we cannot traverse the tree to look up the given extent number. Luckily, the tree has been already threaded. So what we have to do is just to find the first extent’s leaf, then traverse in a "linked list". Signed-off-by: Chen Baozi <baozich@gmail.com> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r--core/fs/xfs/xfs.c63
-rw-r--r--core/fs/xfs/xfs.h13
-rw-r--r--core/fs/xfs/xfs_dir2.c13
3 files changed, 69 insertions, 20 deletions
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
index fe7e46aa..33a229af 100644
--- a/core/fs/xfs/xfs.c
+++ b/core/fs/xfs/xfs.c
@@ -95,7 +95,14 @@ static int xfs_next_extent(struct inode *inode, uint32_t lstart)
struct fs_info *fs = inode->fs;
xfs_dinode_t *core = NULL;
xfs_bmbt_irec_t rec;
- block_t blk;
+ block_t bno;
+ xfs_bmdr_block_t *rblock;
+ int fsize;
+ xfs_bmbt_ptr_t *pp;
+ xfs_btree_block_t *blk;
+ uint16_t nextents;
+ block_t nextbno;
+ uint32_t index;
(void)lstart;
@@ -107,21 +114,63 @@ static int xfs_next_extent(struct inode *inode, uint32_t lstart)
goto out;
}
- if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
- /* The data fork contains the file's data extents */
- if (XFS_PVT(inode)->i_cur_extent == be32_to_cpu(core->di_nextents))
- goto out;
+ /* The data fork contains the file's data extents */
+ if (XFS_PVT(inode)->i_cur_extent == be32_to_cpu(core->di_nextents))
+ goto out;
+ if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
XFS_PVT(inode)->i_cur_extent++);
- blk = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
+ bno = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
XFS_PVT(inode)->i_offset = rec.br_startoff;
- inode->next_extent.pstart = blk << BLOCK_SHIFT(fs) >> SECTOR_SHIFT(fs);
+ inode->next_extent.pstart = bno << BLOCK_SHIFT(fs) >> SECTOR_SHIFT(fs);
inode->next_extent.len = ((rec.br_blockcount << BLOCK_SHIFT(fs)) +
SECTOR_SIZE(fs) - 1) >> SECTOR_SHIFT(fs);
+ } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
+ xfs_debug("XFS_DINODE_FMT_BTREE");
+ index = XFS_PVT(inode)->i_cur_extent++;
+ rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
+ fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
+ pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
+ bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >> BLOCK_SHIFT(fs);
+
+ /* Find the leaf */
+ for (;;) {
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ if (be16_to_cpu(blk->bb_level) == 0)
+ break;
+ pp = XFS_BMBT_PTR_ADDR(fs, blk, 1,
+ xfs_bmdr_maxrecs(XFS_INFO(fs)->blocksize, 0));
+ bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >> BLOCK_SHIFT(fs);
+ }
+
+ /* Find the right extent among threaded leaves */
+ for (;;) {
+ nextbno = be64_to_cpu(blk->bb_u.l.bb_rightsib);
+ nextents = be16_to_cpu(blk->bb_numrecs);
+ if (nextents - index > 0) {
+ bmbt_irec_get(&rec, XFS_BMDR_REC_ADDR(blk, index + 1));
+
+ bno = fsblock_to_bytes(fs, rec.br_startblock)
+ >> BLOCK_SHIFT(fs);
+
+ XFS_PVT(inode)->i_offset = rec.br_startoff;
+
+ inode->next_extent.pstart = bno << BLOCK_SHIFT(fs)
+ >> SECTOR_SHIFT(fs);
+ inode->next_extent.len = ((rec.br_blockcount
+ << BLOCK_SHIFT(fs))
+ + SECTOR_SIZE(fs) - 1)
+ >> SECTOR_SHIFT(fs);
+ break;
+ }
+ index -= nextents;
+ bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs);
+ blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ }
}
return 0;
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
index 64d01fdd..96bfbdb8 100644
--- a/core/fs/xfs/xfs.h
+++ b/core/fs/xfs/xfs.h
@@ -734,4 +734,17 @@ typedef uint64_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
(maxrecs) * sizeof(xfs_bmdr_key_t) + \
((index) - 1) * sizeof(xfs_bmdr_ptr_t)))
+/*
+ * Calculate number of records in a bmap btree inode root.
+ */
+static inline int
+xfs_bmdr_maxrecs(int blocklen, int leaf)
+{
+ blocklen -= sizeof(xfs_bmdr_block_t);
+
+ if (leaf)
+ return blocklen / sizeof(xfs_bmdr_rec_t);
+ return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
+}
+
#endif /* XFS_H_ */
diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c
index 90cafeb0..3b0d8c2d 100644
--- a/core/fs/xfs/xfs_dir2.c
+++ b/core/fs/xfs/xfs_dir2.c
@@ -432,19 +432,6 @@ failed:
return ip;
}
-/*
- * Calculate number of records in a bmap btree inode root.
- */
-static inline int
-xfs_bmdr_maxrecs(int blocklen, int leaf)
-{
- blocklen -= sizeof(xfs_bmdr_block_t);
-
- if (leaf)
- return blocklen / sizeof(xfs_bmdr_rec_t);
- return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
-}
-
static xfs_fsblock_t
select_child(xfs_dfiloff_t off,
xfs_bmbt_key_t *kp,