aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@zytor.com>2012-07-09 14:35:14 -0300
committerPaulo Alcantara <pcacjr@zytor.com>2012-07-21 01:21:45 -0300
commit13546ed6db73f7d179292fb9db1613d5d03c2848 (patch)
treeb8f4bbf930dfecbef5fa1f602b9ea09dc6d1c85a
parent3f7455cd963b4136e495bf62296b82bc2dbfc2e7 (diff)
downloadsyslinux-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.c151
-rw-r--r--core/fs/xfs/xfs.h121
-rw-r--r--core/fs/xfs/xfs_ag.h27
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