diff options
author | Paulo Alcantara <pcacjr@zytor.com> | 2012-07-14 06:41:18 -0300 |
---|---|---|
committer | Paulo Alcantara <pcacjr@zytor.com> | 2012-07-21 01:21:46 -0300 |
commit | ca104cd54f6c6546cc3e542d98dbfa6d0be0f675 (patch) | |
tree | 0625807e8b3e95c5cb55bc838b68631e9f611222 | |
parent | f65e6cbd5514d64e50a3d5cee7baab1172a7a239 (diff) | |
download | syslinux-ca104cd54f6c6546cc3e542d98dbfa6d0be0f675.tar.gz syslinux-ca104cd54f6c6546cc3e542d98dbfa6d0be0f675.tar.xz syslinux-ca104cd54f6c6546cc3e542d98dbfa6d0be0f675.zip |
xfs: Some bugfixes
XFS inodes never share filesystem blocks with anything else. The driver
used to calculate wrong the offset within a chunk of inode found in inode
B+trees. The correct calculation is to get the lower bits of the inode
number (which is the inode number within a chunk) and multiply by inode
size to get the right offset.
The "bb_rumrecs" and "bb_level" fields (found in leaf entries of inode
B+trees) were being read incorrectly, since they're all stored in
big-endian on disk and we did not convert them to litte-endian respectively.
Besides, fix some memory leaks.
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r-- | core/fs/xfs/xfs.c | 89 |
1 files changed, 57 insertions, 32 deletions
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c index 3b55b1d3..064a6fb0 100644 --- a/core/fs/xfs/xfs.c +++ b/core/fs/xfs/xfs.c @@ -139,12 +139,21 @@ static const void *xfs_get_ino_chunk(struct fs_info *fs, xfs_ino_t ino) return buf; } +static inline void xfs_ino_core_free(struct inode *inode, xfs_dinode_t *core) +{ + if (core && (inode && XFS_PVT(inode)->i_chunk_offset)) + free((void *)((uint8_t *)core - XFS_PVT(inode)->i_chunk_offset)); +} + /* 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, uint64_t *chunk_offset) { uint8_t *p; + uint32_t mask = (uint32_t)((1ULL << XFS_INFO(fs)->inopb_shift) - 1); + + xfs_debug("start_ino %llu ino %llu", start_ino, ino); if (start_ino == ino) { *chunk_offset = 0; @@ -152,9 +161,14 @@ static xfs_dinode_t *xfs_find_chunk_ino(struct fs_info *fs, } p = (uint8_t *)xfs_get_ino_chunk(fs, start_ino); - *chunk_offset = (ino - start_ino) << XFS_INFO(fs)->inode_shift; + /* Get the inode number within the chunk from lower bits and calculate + * the offset (lower bits * inode size). + */ + *chunk_offset = (uint64_t)((int)ino & mask) << XFS_INFO(fs)->inode_shift; - return (xfs_dinode_t *)p + *chunk_offset; + xfs_debug("chunk_offset %llu", *chunk_offset); + + return (xfs_dinode_t *)((uint8_t *)p + *chunk_offset); } static char *get_entry_name(uint8_t *start, uint8_t *end) @@ -188,7 +202,7 @@ struct inode *xfs_fmt_local_find_entry(const char *dname, struct inode *parent, block_t blk; xfs_agi_t *agi; xfs_btree_sblock_t *ibt_hdr; - uint32_t i; + uint16_t i; xfs_inobt_rec_t *rec; xfs_dinode_t *ncore = NULL; @@ -205,8 +219,10 @@ struct inode *xfs_fmt_local_find_entry(const char *dname, struct inode *parent, xfs_debug("entry name: %s", name); - if (!strncmp(name, dname, strlen(dname))) + if (!strncmp(name, dname, strlen(dname))) { + free(name); goto found; + } free(name); @@ -269,26 +285,32 @@ found: goto out; } - xfs_debug("bb_level %lu", ibt_hdr->bb_level); - xfs_debug("bb_numrecs %lu", ibt_hdr->bb_numrecs); + xfs_debug("bb_level %lu", be16_to_cpu(ibt_hdr->bb_level)); + xfs_debug("bb_numrecs %lu", be16_to_cpu(ibt_hdr->bb_numrecs)); rec = (xfs_inobt_rec_t *)((uint8_t *)ibt_hdr + sizeof *ibt_hdr); - for (i = ibt_hdr->bb_numrecs; i--; rec++) { + for (i = be16_to_cpu(ibt_hdr->bb_numrecs); i; i--, rec++) { xfs_debug("freecount %lu free 0x%llx", be32_to_cpu(rec->ir_freecount), be64_to_cpu(rec->ir_free)); ncore = xfs_find_chunk_ino(fs, be32_to_cpu(rec->ir_startino), ino, &XFS_PVT(inode)->i_chunk_offset); - if (ncore) - goto core_found; + if (ncore) { + if (be16_to_cpu(ncore->di_magic) == + be16_to_cpu(*(uint16_t *)XFS_DINODE_MAGIC)) { + goto core_found; + } else { + xfs_error("Inode core's magic number does not match!"); + xfs_debug("magic number 0x%04x", be16_to_cpu(ncore->di_magic)); + goto out; + } + } } out: + xfs_ino_core_free(inode, ncore); free(inode); - if (ncore && XFS_PVT(inode)->i_chunk_offset) - free(ncore); - return NULL; no_agi_needed: @@ -306,8 +328,7 @@ core_found: xfs_debug("Found a %s inode", inode->mode == DT_DIR ? "directory" : "file"); - if (ncore && XFS_PVT(inode)->i_chunk_offset) - free(ncore); + xfs_ino_core_free(inode, ncore); return inode; } @@ -315,7 +336,7 @@ core_found: static struct inode *xfs_iget(const char *dname, struct inode *parent) { struct fs_info *fs = parent->fs; - xfs_dinode_t *core; + xfs_dinode_t *core = NULL; struct inode *inode = NULL; xfs_debug("dname %s parent %p parent ino %lu", dname, parent, parent->ino); @@ -347,17 +368,14 @@ static struct inode *xfs_iget(const char *dname, struct inode *parent) xfs_debug("TODO: format \"local\" is the only supported ATM"); goto out; } - } else if (parent->mode == DT_REG) { - xfs_debug("Parent inode is a file (not working yet)"); - for (;;) - ; } + xfs_ino_core_free(inode, core); + return inode; out: - if (XFS_PVT(parent)->i_chunk_offset) - free(core); + xfs_ino_core_free(inode, core); return NULL; } @@ -367,7 +385,7 @@ static struct inode *xfs_iget_root(struct fs_info *fs) xfs_agi_t *agi; block_t blk; xfs_btree_sblock_t *ibt_hdr; - uint32_t i; + uint16_t i; xfs_inobt_rec_t *rec; xfs_dinode_t *core = NULL; struct inode *inode = xfs_new_inode(fs); @@ -403,19 +421,29 @@ static struct inode *xfs_iget_root(struct fs_info *fs) goto out; } - xfs_debug("bb_level %lu", ibt_hdr->bb_level); - xfs_debug("bb_numrecs %lu", ibt_hdr->bb_numrecs); + xfs_debug("bb_level %lu", be16_to_cpu(ibt_hdr->bb_level)); + xfs_debug("bb_numrecs %lu", be16_to_cpu(ibt_hdr->bb_numrecs)); + + XFS_PVT(inode)->i_chunk_offset = 0; rec = (xfs_inobt_rec_t *)((uint8_t *)ibt_hdr + sizeof *ibt_hdr); - for (i = ibt_hdr->bb_numrecs; i--; rec++) { + for (i = be16_to_cpu(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, &XFS_PVT(inode)->i_chunk_offset); - if (core) - goto found; + if (core) { + if (be16_to_cpu(core->di_magic) == + be16_to_cpu(*(uint16_t *)XFS_DINODE_MAGIC)) { + goto found; + } else { + xfs_error("Inode core's magic number does not match!"); + xfs_debug("magic number 0x%04x", be16_to_cpu(core->di_magic)); + goto out; + } + } } xfs_error("Root inode not found!"); @@ -435,19 +463,16 @@ found: inode->mode = DT_DIR; inode->size = be64_to_cpu(core->di_size); - if (core && XFS_PVT(inode)->i_chunk_offset) - free(core); + xfs_ino_core_free(inode, core); return inode; not_found: out: + xfs_ino_core_free(inode, core); free(inode); - if (core && XFS_PVT(inode)->i_chunk_offset) - free(core); - return NULL; } |