diff options
author | Paulo Alcantara <pcacjr@zytor.com> | 2012-07-09 14:35:14 -0300 |
---|---|---|
committer | Paulo Alcantara <pcacjr@zytor.com> | 2012-07-21 01:21:45 -0300 |
commit | 13546ed6db73f7d179292fb9db1613d5d03c2848 (patch) | |
tree | b8f4bbf930dfecbef5fa1f602b9ea09dc6d1c85a | |
parent | 3f7455cd963b4136e495bf62296b82bc2dbfc2e7 (diff) | |
download | syslinux-13546ed6db73f7d179292fb9db1613d5d03c2848.tar.gz syslinux-13546ed6db73f7d179292fb9db1613d5d03c2848.tar.xz syslinux-13546ed6db73f7d179292fb9db1613d5d03c2848.zip |
xfs: Add xfs_iget_root() to XFS filesystem ops
This patch adds initial implementation of the xfs_iget_root() filesystem
operation.
Note also that this is not going to work with inode B+trees with any
level associated with it other than only leafs in the tree. I intend to
finish these remaining features in xfs_iget_root() once I get xfs_iget()
function working properly.
I'm looking forward to implement xfs_iget() function since we have now
xfs_iget_root() function at some point.
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r-- | core/fs/xfs/xfs.c | 151 | ||||
-rw-r--r-- | core/fs/xfs/xfs.h | 121 | ||||
-rw-r--r-- | core/fs/xfs/xfs_ag.h | 27 |
3 files changed, 260 insertions, 39 deletions
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c index b36feecb..b3cc351a 100644 --- a/core/fs/xfs/xfs.c +++ b/core/fs/xfs/xfs.c @@ -34,15 +34,154 @@ #include "xfs_ag.h" #include "misc.h" -static struct inode *xfs_iget_root(struct fs_info *unused) +static inline struct inode *xfs_new_inode(struct fs_info *fs) { - (void)unused; + struct inode *inode; + + inode = alloc_inode(fs, 0, sizeof(struct xfs_inode)); + if (!inode) + malloc_error("xfs_inode structure"); + + return inode; +} + +static xfs_dinode_t *xfs_get_dinode(struct fs_info *fs, xfs_ino_t ino) +{ + block_t blk; + block_t blk_offset; + xfs_dinode_t *dino; + + 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) { + xfs_error("Error in reading filesystem block 0x%llX (%llu)", blk, blk); + goto out; + } + + if (be16_to_cpu(dino->di_magic) != + be16_to_cpu(*(uint16_t *)XFS_DINODE_MAGIC)) { + xfs_error("Inode core's magic number does not match!"); + goto out; + } + + return dino; + +out: + return NULL; +} + +static struct inode *xfs_iget(const char *unused_0, struct inode *unused_1) +{ + (void)unused_0; + (void)unused_1; xfs_debug("in"); return NULL; } +static struct inode *xfs_iget_root(struct fs_info *fs) +{ + xfs_agnumber_t agno; + block_t blk; + xfs_agi_t *agi; + xfs_btree_sblock_t *ibt_hdr; + uint32_t i; + xfs_inobt_rec_t *rec; + xfs_dinode_t *dino; + struct inode *inode = xfs_new_inode(fs); + + xfs_debug("Looking for the root inode..."); + + agno = XFS_INO_TO_AGNO(fs, XFS_INFO(fs)->rootino); + if (agno >= XFS_INFO(fs)->agcount) { + xfs_error("Invalid AG number"); + goto out; + } + + blk = XFS_AGNO_TO_FSB(fs, agno); + agi = XFS_AGI_OFFS(fs, get_cache(fs->fs_dev, blk)); + if (!agi) { + xfs_error("Error in reading filesystem block 0x%llX (%llu)", blk, blk); + goto out; + } + + XFS_PVT(inode)->i_agblock = blk; + + if (be32_to_cpu(agi->agi_magicnum) != + be32_to_cpu(*(uint32_t *)XFS_AGI_MAGIC)) { + xfs_error("AGI's magic number does not match!"); + goto out; + } + + xfs_debug("agi_count %lu", be32_to_cpu(agi->agi_count)); + xfs_debug("agi_level %lu", be32_to_cpu(agi->agi_level)); + + /* Get block number relative to the AG containing the root of the inode + * B+tree. + */ + blk = agno + be32_to_cpu(agi->agi_root); + + xfs_debug("inode B+tree's block %llu", blk); + + ibt_hdr = (xfs_btree_sblock_t *)get_cache(fs->fs_dev, blk); + if (!ibt_hdr) { + xfs_error("Error in reading filesystem block 0x%llX (%llu)", blk, blk); + goto out; + } + + if (be32_to_cpu(ibt_hdr->bb_magic) != + be32_to_cpu(*(uint32_t *)XFS_IBT_MAGIC)) { + xfs_error("AGI inode B+tree header's magic number does not match!"); + goto out; + } + + xfs_debug("bb_level %lu", ibt_hdr->bb_level); + 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) + goto found; + } + + xfs_error("Root inode not found!"); + 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)) { + xfs_error("root inode is not a directory ?! No makes sense..."); + goto out; + } + + inode->mode = DT_DIR; + inode->size = dino->di_size; + + return inode; + +not_found: + +out: + free(inode); + + return NULL; +} + static inline int xfs_read_superblock(struct fs_info *fs, xfs_sb_t *sb) { struct disk *disk = fs->fs_dev->disk; @@ -136,10 +275,10 @@ const struct fs_ops xfs_fs_ops = { .iget_root = xfs_iget_root, .searchdir = NULL, .getfssec = NULL, - .load_config = NULL, - .close_file = NULL, - .mangle_name = NULL, + .load_config = generic_load_config, + .close_file = generic_close_file, + .mangle_name = generic_mangle_name, .readdir = NULL, - .iget = NULL, + .iget = xfs_iget, .next_extent = NULL, }; diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h index 466ce00a..93000273 100644 --- a/core/fs/xfs/xfs.h +++ b/core/fs/xfs/xfs.h @@ -39,18 +39,38 @@ struct xfs_fs_info; #define XFS_INFO(fs) ((struct xfs_fs_info *)((fs)->fs_info)) -#define XFS_PVT(ino) ((xfs_agi_t *)((ino)->pvt)) +#define XFS_PVT(ino) ((struct xfs_inode *)((ino)->pvt)) -#define XFS_AG_BLOCK(fs, bytes) \ - ((block_t)(((bytes) + XFS_INFO((fs))->agblocks - 1) / \ - XFS_INFO((fs))->agblocks) - 1) +#define XFS_INO_TO_AGNO(fs, ino) \ + (xfs_agnumber_t)((ino) >> XFS_INFO((fs))->ag_relative_ino_shift) -#define XFS_AGI_OFFSET(fs, mp) \ - ((xfs_agi_t *)((uint8_t *)(mp) + 2 * SECTOR_SIZE((fs)))) +#define XFS_AGNO_TO_FSB(fs, agno) \ + (block_t)((agno) << XFS_INFO((fs))->agblocks_shift) + +#define XFS_AGI_OFFS(fs, mp) \ + (xfs_agi_t *)((uint8_t *)(mp) + 2 * SECTOR_SIZE((fs))) /* Superblock's LBA */ #define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */ +/* Magic numbers */ +#define XFS_AGI_MAGIC "XAGI" +#define XFS_IBT_MAGIC "IABT" +#define XFS_DINODE_MAGIC "IN" + +/* File types and modes */ +#define S_IFMT 00170000 +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + /* * NOTE: The fields in the superblock are stored in big-endian format on disk. */ @@ -143,6 +163,95 @@ struct xfs_fs_info { uint8_t inode_shift; /* Inode size in bits */ } __attribute__((__packed__)); +typedef struct xfs_agi { + /* + * Common allocation group header information + */ + uint32_t agi_magicnum; /* magic number == XFS_AGI_MAGIC */ + uint32_t agi_versionnum; /* header version == XFS_AGI_VERSION */ + uint32_t agi_seqno; /* sequence # starting from 0 */ + uint32_t agi_length; /* size in blocks of a.g. */ + /* + * Inode information + * Inodes are mapped by interpreting the inode number, so no + * mapping data is needed here. + */ + uint32_t agi_count; /* count of allocated inodes */ + uint32_t agi_root; /* root of inode btree */ + uint32_t agi_level; /* levels in inode btree */ + uint32_t agi_freecount; /* number of free inodes */ + uint32_t agi_newino; /* new inode just allocated */ + uint32_t agi_dirino; /* last directory inode chunk */ + /* + * Hash table of inodes which have been unlinked but are + * still being referenced. + */ + uint32_t agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; +} __attribute__((__packed__)) xfs_agi_t; + +typedef struct xfs_btree_sblock { + uint32_t bb_magic; + uint16_t bb_level; + uint16_t bb_numrecs; + uint32_t bb_leftsib; + uint32_t bb_rightsib; +} __attribute__((__packed__)) xfs_btree_sblock_t; + +typedef struct xfs_inobt_rec { + uint32_t ir_startino; + uint32_t ir_freecount; + uint64_t ir_free; +} __attribute__((__packed__)) xfs_inobt_rec_t; + +typedef struct xfs_timestamp { + int32_t t_sec; + int32_t t_nsec; +} __attribute__((__packed__)) xfs_timestamp_t; + +typedef enum xfs_dinode_fmt { + XFS_DINODE_FMT_DEV, + XFS_DINODE_FMT_LOCAL, + XFS_DINODE_FMT_EXTENTS, + XFS_DINODE_FMT_BTREE, + XFS_DINODE_FMT_UUID, +} xfs_dinode_fmt_t; + +typedef struct xfs_dinode { + uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */ + uint16_t di_mode; /* mode and type of file */ + uint8_t di_version; /* inode version */ + uint8_t di_format; /* format of di_c data */ + uint16_t di_onlink; /* old number of links to file */ + uint32_t di_uid; /* owner's user id */ + uint32_t di_gid; /* owner's group id */ + uint32_t di_nlink; /* number of links to file */ + uint16_t di_projid_lo; /* lower part of owner's project id */ + uint16_t di_projid_hi; /* higher part owner's project id */ + uint8_t di_pad[6]; /* unused, zeroed space */ + uint16_t di_flushiter; /* incremented on flush */ + xfs_timestamp_t di_atime; /* time last accessed */ + xfs_timestamp_t di_mtime; /* time last modified */ + xfs_timestamp_t di_ctime; /* time created/inode modified */ + uint64_t di_size; /* number of bytes in file */ + uint64_t di_nblocks; /* # of direct & btree blocks used */ + uint32_t di_extsize; /* basic/minimum extent size for file */ + uint32_t di_nextents; /* number of extents in data fork */ + uint16_t di_anextents; /* number of extents in attribute fork*/ + uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ + int8_t di_aformat; /* format of attr fork's data */ + uint32_t di_dmevmask; /* DMIG event mask */ + uint16_t di_dmstate; /* DMIG state info */ + uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ + uint32_t di_gen; /* generation number */ + + /* di_next_unlinked is the only non-core field in the old dinode */ + uint32_t di_next_unlinked;/* agi unlinked list ptr */ +} __attribute__((packed)) xfs_dinode_t; + +struct xfs_inode { + xfs_agblock_t i_agblock; +}; + static inline bool xfs_is_valid_magicnum(const xfs_sb_t *sb) { return sb->sb_magicnum == *(uint32_t *)XFS_SB_MAGIC; diff --git a/core/fs/xfs/xfs_ag.h b/core/fs/xfs/xfs_ag.h index 9167a0aa..808e1c92 100644 --- a/core/fs/xfs/xfs_ag.h +++ b/core/fs/xfs/xfs_ag.h @@ -38,7 +38,6 @@ struct xfs_mount; struct xfs_trans; #define XFS_AGF_MAGIC "XAGF" -#define XFS_AGI_MAGIC "XAGI" #define XFS_AGF_VERSION 1 #define XFS_AGI_VERSION 1 @@ -122,32 +121,6 @@ extern int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp, */ #define XFS_AGI_UNLINKED_BUCKETS 64 -typedef struct xfs_agi { - /* - * Common allocation group header information - */ - uint32_t agi_magicnum; /* magic number == XFS_AGI_MAGIC */ - uint32_t agi_versionnum; /* header version == XFS_AGI_VERSION */ - uint32_t agi_seqno; /* sequence # starting from 0 */ - uint32_t agi_length; /* size in blocks of a.g. */ - /* - * Inode information - * Inodes are mapped by interpreting the inode number, so no - * mapping data is needed here. - */ - uint32_t agi_count; /* count of allocated inodes */ - uint32_t agi_root; /* root of inode btree */ - uint32_t agi_level; /* levels in inode btree */ - uint32_t agi_freecount; /* number of free inodes */ - uint32_t agi_newino; /* new inode just allocated */ - uint32_t agi_dirino; /* last directory inode chunk */ - /* - * Hash table of inodes which have been unlinked but are - * still being referenced. - */ - uint32_t agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; -} xfs_agi_t; - #define XFS_AGI_MAGICNUM 0x00000001 #define XFS_AGI_VERSIONNUM 0x00000002 #define XFS_AGI_SEQNO 0x00000004 |