aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@zytor.com>2012-07-12 01:17:50 -0300
committerPaulo Alcantara <pcacjr@zytor.com>2012-07-21 01:21:45 -0300
commitdc661742c31fef4fc19d35450081c8b585e18499 (patch)
treeb09a72e6e6874fbfba796de5c5edbe528fbc7244
parent549dc8a73f31c087b7cc68ec27c20890ca1cc46f (diff)
downloadsyslinux-dc661742c31fef4fc19d35450081c8b585e18499.tar.gz
syslinux-dc661742c31fef4fc19d35450081c8b585e18499.tar.xz
syslinux-dc661742c31fef4fc19d35450081c8b585e18499.zip
xfs: Fix inode lookup in chunks of 64 inodes
Leaf entries found in inode btrees in XFS contain the starting inode number of some chunk, count of free entries, and some bitmask to handle the free entries. There are several inode numbers where its respective filesystem block can be the same, so we need to read retrieve them through those chunks of inodes. Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r--core/fs/xfs/xfs.c96
-rw-r--r--core/fs/xfs/xfs.h4
2 files changed, 72 insertions, 28 deletions
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
index 201680fd..2d0f9cc5 100644
--- a/core/fs/xfs/xfs.c
+++ b/core/fs/xfs/xfs.c
@@ -45,34 +45,75 @@ static inline struct inode *xfs_new_inode(struct fs_info *fs)
return inode;
}
-static xfs_dinode_t *xfs_get_dinode(struct fs_info *fs, xfs_ino_t ino)
+static xfs_dinode_t *xfs_get_ino_core(struct fs_info *fs, xfs_ino_t ino)
{
block_t blk;
- block_t blk_offset;
- xfs_dinode_t *dino;
+ xfs_dinode_t *core;
blk = ino << XFS_INFO(fs)->inode_shift >> BLOCK_SHIFT(fs);
- blk_offset = (blk << BLOCK_SHIFT(fs)) % BLOCK_SIZE(fs);
-
- dino = (xfs_dinode_t *)((uint8_t *)get_cache(fs->fs_dev, blk) +
- blk_offset);
- if (!dino) {
+ core = (xfs_dinode_t *)get_cache(fs->fs_dev, blk);
+ if (!core) {
xfs_error("Error in reading filesystem block 0x%llX (%llu)", blk, blk);
goto out;
}
- if (be16_to_cpu(dino->di_magic) !=
+ if (be16_to_cpu(core->di_magic) !=
be16_to_cpu(*(uint16_t *)XFS_DINODE_MAGIC)) {
xfs_error("Inode core's magic number does not match!");
goto out;
}
- return dino;
+ return core;
out:
return NULL;
}
+/* Allocate a region for the chunk of 64 inodes found in the leaf entries of
+ * inode B+Trees, and return that allocated region.
+ */
+static const void *xfs_get_ino_chunk(struct fs_info *fs, xfs_ino_t ino)
+{
+ const int len = 64 * XFS_INFO(fs)->inodesize;
+ void *buf;
+ block_t nblks;
+ uint8_t *p;
+ block_t start_blk = ino << XFS_INFO(fs)->inode_shift >> BLOCK_SHIFT(fs);
+ off_t offset = 0;
+
+ buf = malloc(len);
+ if (!buf)
+ malloc_error("buffer memory");
+
+ memset(buf, 0, len);
+
+ nblks = len >> BLOCK_SHIFT(fs);
+ while (nblks--) {
+ p = (uint8_t *)get_cache(fs->fs_dev, start_blk++);
+
+ memcpy(buf, p, BLOCK_SIZE(fs));
+ offset += BLOCK_SIZE(fs);
+ }
+
+ return buf;
+}
+
+/* Find an inode from a chunk of 64 inodes by giving its inode # */
+static xfs_dinode_t *xfs_find_chunk_ino(struct fs_info *fs,
+ block_t start_ino, xfs_ino_t ino)
+{
+ uint8_t *p;
+ uint64_t offset;
+
+ if (start_ino == ino)
+ return xfs_get_ino_core(fs, ino);
+
+ p = (uint8_t *)xfs_get_ino_chunk(fs, start_ino);
+ offset = (ino - start_ino) << XFS_INFO(fs)->inode_shift;
+
+ return (xfs_dinode_t *)p + offset;
+}
+
static struct inode *xfs_iget(const char *unused_0, struct inode *unused_1)
{
(void)unused_0;
@@ -91,7 +132,7 @@ static struct inode *xfs_iget_root(struct fs_info *fs)
xfs_btree_sblock_t *ibt_hdr;
uint32_t i;
xfs_inobt_rec_t *rec;
- xfs_dinode_t *dino;
+ xfs_dinode_t *core;
struct inode *inode = xfs_new_inode(fs);
xfs_debug("Looking for the root inode...");
@@ -143,34 +184,37 @@ static struct inode *xfs_iget_root(struct fs_info *fs)
xfs_debug("bb_numrecs %lu", ibt_hdr->bb_numrecs);
rec = (xfs_inobt_rec_t *)((uint8_t *)ibt_hdr + sizeof *ibt_hdr);
- i = ibt_hdr->bb_numrecs;
- for ( ; i--; rec++) {
- if (be32_to_cpu(rec->ir_startino) == XFS_INFO(fs)->rootino)
+ for (i = ibt_hdr->bb_numrecs; i--; rec++) {
+ xfs_debug("freecount %lu free 0x%llx", be32_to_cpu(rec->ir_freecount),
+ be64_to_cpu(rec->ir_free));
+
+ core = xfs_find_chunk_ino(fs, be32_to_cpu(rec->ir_startino),
+ XFS_INFO(fs)->rootino);
+ if (core)
goto found;
}
xfs_error("Root inode not found!");
+
+ free(core);
+
goto not_found;
found:
xfs_debug("Root inode has been found!");
- inode->ino = XFS_INFO(fs)->rootino;
-
- dino = xfs_get_dinode(fs, XFS_INFO(fs)->rootino);
- if (!dino) {
- xfs_error("Failed to get inode core from inode %lu",
- XFS_INFO(fs)->rootino);
- goto out;
- }
-
- if (!(be16_to_cpu(dino->di_mode) & S_IFDIR)) {
+ if (!(be16_to_cpu(core->di_mode) & S_IFDIR)) {
xfs_error("root inode is not a directory ?! No makes sense...");
goto out;
}
- inode->mode = DT_DIR;
- inode->size = dino->di_size;
+ XFS_PVT(inode)->i_ino_blk = XFS_INFO(fs)->rootino <<
+ XFS_INFO(fs)->inode_shift >> BLOCK_SHIFT(fs);
+ inode->ino = XFS_INFO(fs)->rootino;
+ inode->mode = DT_DIR;
+ inode->size = core->di_size;
+
+ free(core);
return inode;
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
index 93000273..2aae8c18 100644
--- a/core/fs/xfs/xfs.h
+++ b/core/fs/xfs/xfs.h
@@ -6,7 +6,6 @@
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
* All Rights Reserved.
*
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
@@ -249,7 +248,8 @@ typedef struct xfs_dinode {
} __attribute__((packed)) xfs_dinode_t;
struct xfs_inode {
- xfs_agblock_t i_agblock;
+ xfs_agblock_t i_agblock;
+ block_t i_ino_blk;
};
static inline bool xfs_is_valid_magicnum(const xfs_sb_t *sb)