[syslinux:elflink] xfs: Implement dir2_block_find_entry() function.

syslinux-bot for Chen Baozi baozich at gmail.com
Tue Nov 27 12:57:12 PST 2012


Commit-ID:  fa2b511f8b46c32c8dd1708d429331afa52d2003
Gitweb:     http://www.syslinux.org/commit/fa2b511f8b46c32c8dd1708d429331afa52d2003
Author:     Chen Baozi <baozich at gmail.com>
AuthorDate: Thu, 19 Jul 2012 14:47:19 +0800
Committer:  Paulo Alcantara <pcacjr at zytor.com>
CommitDate: Sat, 21 Jul 2012 01:21:47 -0300

xfs: Implement dir2_block_find_entry() function.

dir2_block_find_entry() is used to handle the Block Directory, which
is the sub-case of a XFS_DINODE_FMT_EXTENTS. Besides, we have
established the frame work to handle all cases of XFS_DINODE_FMT_EXENTS.
What to be worked next step is dir2_leaf_find_entry() and
dir2_node_find_entry.

To test this patch, I just touched 24 extra empty file named from 0 to 23
in the /boot directory, which number is more than what short format holds
and less than the Leaf Directory holds.

Signed-off-by: Chen Baozi <baozich at gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>

---
 core/fs/xfs/xfs.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 core/fs/xfs/xfs.h | 157 ++++++++++++++++++++++++++++++++++++++----
 2 files changed, 336 insertions(+), 22 deletions(-)

diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
index b5dacb4..354e465 100644
--- a/core/fs/xfs/xfs.c
+++ b/core/fs/xfs/xfs.c
@@ -30,9 +30,10 @@
 #include "codepage.h"
 #include "xfs_types.h"
 #include "xfs_sb.h"
+#include "misc.h"
 #include "xfs.h"
 #include "xfs_ag.h"
-#include "misc.h"
+
 
 static inline struct inode *xfs_new_inode(struct fs_info *fs)
 {
@@ -51,9 +52,8 @@ static inline void fill_xfs_inode_pvt(struct fs_info *fs, struct inode *inode,
     XFS_PVT(inode)->i_agblock =
 	agnumber_to_bytes(fs, XFS_INO_TO_AGNO(fs, ino)) >> BLOCK_SHIFT(fs);
     XFS_PVT(inode)->i_ino_blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
-    XFS_PVT(inode)->i_block_offset =
-	XFS_INO_TO_OFFSET((struct xfs_fs_info *)(fs->fs_info), ino) <<
-			((struct xfs_fs_info *)(fs->fs_info))->inode_shift;
+    XFS_PVT(inode)->i_block_offset = XFS_INO_TO_OFFSET(XFS_INFO(fs), ino) <<
+                                     XFS_INFO(fs)->inode_shift;
 }
 
 static xfs_dinode_t *xfs_get_ino_core(struct fs_info *fs, xfs_ino_t ino)
@@ -65,8 +65,7 @@ static xfs_dinode_t *xfs_get_ino_core(struct fs_info *fs, xfs_ino_t ino)
     xfs_debug("ino %lu", ino);
 
     blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
-    offset = XFS_INO_TO_OFFSET((struct xfs_fs_info *)(fs->fs_info), ino) <<
-	    ((struct xfs_fs_info *)(fs->fs_info))->inode_shift;
+    offset = XFS_INO_TO_OFFSET(XFS_INFO(fs), ino) << XFS_INFO(fs)->inode_shift;
     if (offset > BLOCK_SIZE(fs)) {
         xfs_error("Invalid inode offset in block!");
         xfs_debug("offset: 0x%llx", offset);
@@ -108,6 +107,38 @@ static char *get_entry_name(uint8_t *start, uint8_t *end)
     return s;
 }
 
+/* See if the directory is a single-leaf form directory. */
+static bool xfs_dir2_isleaf(xfs_dinode_t *dip)
+{
+    (void) dip;
+    xfs_debug("in");
+
+    return true;
+}
+
+static void *get_dirblk(struct fs_info *fs, block_t startblock)
+{
+    int count = 1 << XFS_INFO(fs)->dirblklog;
+    uint8_t *p;
+    uint8_t *buf;
+    off_t offset = 0;
+
+    buf = malloc(XFS_INFO(fs)->dirblksize);
+    if (!buf)
+        malloc_error("buffer memory");
+
+    memset(buf, 0, XFS_INFO(fs)->dirblksize);
+
+    while (count--) {
+        p = (uint8_t *)get_cache(fs->fs_dev, startblock++);
+        memcpy(buf + offset, p,  BLOCK_SIZE(fs));
+        offset += BLOCK_SIZE(fs);
+    }
+
+    return buf;
+}
+		       
+
 struct inode *xfs_fmt_local_find_entry(const char *dname, struct inode *parent,
 				       xfs_dinode_t *core)
 {
@@ -253,6 +284,151 @@ out:
     return -1;
 }
 
+static struct inode *dir2_block_find_entry(const char *dname,
+					   struct inode *parent,
+					   xfs_dinode_t *core)
+{
+    xfs_bmbt_irec_t r;
+    block_t dir_blk;
+    struct fs_info *fs = parent->fs;
+    uint8_t *dirblk_buf;
+    uint8_t *p, *endp;
+    xfs_dir2_data_hdr_t *hdr;
+    struct inode *inode = NULL;
+    xfs_dir2_block_tail_t *btp;
+    xfs_dir2_data_unused_t *dup;
+    xfs_dir2_data_entry_t *dep;
+    xfs_intino_t ino;
+    xfs_dinode_t *ncore;
+
+    bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+    dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
+
+    dirblk_buf = get_dirblk(fs, dir_blk);
+    hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
+    if (be32_to_cpu(hdr->magic) != 
+        XFS_DIR2_BLOCK_MAGIC) {
+        xfs_error("Block directory header's magic number does not match!");
+        xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
+        goto out;
+    }
+
+    p = (uint8_t *)(hdr + 1);
+
+    btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
+    endp = (uint8_t *)((xfs_dir2_leaf_entry_t *)btp - be32_to_cpu(btp->count));
+
+    while (p < endp) {
+        uint8_t *start_name;
+        uint8_t *end_name;
+        char *name;
+
+        dup = (xfs_dir2_data_unused_t *)p;
+        if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+            p += be16_to_cpu(dup->length);
+            continue;
+        }
+
+        dep = (xfs_dir2_data_entry_t *)p;
+        
+        start_name = &dep->name[0];
+        end_name = start_name + dep->namelen;
+        name = get_entry_name(start_name, end_name);
+
+        if (!strncmp(name, dname, strlen(dname))) {
+            free(name);
+            goto found;
+        }
+
+        free(name);
+	p += xfs_dir2_data_entsize(dep->namelen);
+    }
+
+out:
+    free(dirblk_buf);
+
+    return NULL;
+
+found:
+    inode = xfs_new_inode(fs);
+
+    ino = be64_to_cpu(dep->inumber);
+
+    xfs_debug("entry inode's number %lu", ino);
+
+    ncore = xfs_get_ino_core(fs, ino);
+    fill_xfs_inode_pvt(inode, fs, ino);
+    if (!ncore) {
+        xfs_error("Failed to get dinode!");
+        goto failed;
+    }
+
+    inode->ino = ino;
+    XFS_PVT(inode)->i_ino_blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
+    inode->size = be64_to_cpu(ncore->di_size);
+
+    if (be16_to_cpu(ncore->di_mode) & S_IFDIR) {
+        inode->mode = DT_DIR;
+        xfs_debug("Found a directory inode!");
+    } else if (be16_to_cpu(ncore->di_mode) & S_IFREG) {
+        inode->mode = DT_REG;
+        xfs_debug("Found a file inode!");
+        xfs_debug("inode size %llu", inode->size);
+    }
+
+    xfs_debug("entry inode's number %lu", ino);
+
+    free(dirblk_buf);
+    return inode;
+
+failed:
+
+    free(inode);
+    free(dirblk_buf);
+
+    return NULL;
+}
+
+static struct inode *dir2_leaf_find_entry(const char *dname,
+					  struct inode *parent,
+					  xfs_dinode_t *core)
+{
+    (void) dname;
+    (void) parent;
+    (void) core;
+    return NULL;
+}
+
+static struct inode *dir2_node_find_entry(const char *dname,
+					  struct inode *parent,
+					  xfs_dinode_t *core)
+{
+    (void) dname;
+    (void) parent;
+    (void) core;
+    return NULL;
+}
+
+static struct inode *xfs_fmt_extents_find_entry(const char *dname,
+						struct inode *parent,
+						xfs_dinode_t *core)
+{
+    struct inode *inode;
+
+    if (be32_to_cpu(core->di_nextents) <= 1) {
+        /* Single-block Directories */
+        inode = dir2_block_find_entry(dname, parent, core);
+    } else if (xfs_dir2_isleaf(core)) {
+        /* Leaf Directory */
+	inode = dir2_leaf_find_entry(dname, parent, core);
+    } else {
+        /* Node Directory */
+        inode = dir2_node_find_entry(dname, parent, core);
+    }
+
+    return inode;
+}
+
 static struct inode *xfs_iget(const char *dname, struct inode *parent)
 {
     struct fs_info *fs = parent->fs;
@@ -270,16 +446,19 @@ static struct inode *xfs_iget(const char *dname, struct inode *parent)
     /* TODO: Handle both shortform and block directories */
     if (core->di_format == XFS_DINODE_FMT_LOCAL) {
 	inode = xfs_fmt_local_find_entry(dname, parent, core);
-	if (!inode) {
-	    xfs_error("Entry not found!");
-	    goto out;
-	}
+    } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
+        inode = xfs_fmt_extents_find_entry(dname, parent, core);
     } else {
 	xfs_debug("format %hhu", core->di_format);
 	xfs_debug("TODO: format \"local\" is the only supported ATM");
 	goto out;
     }
 
+    if (!inode) {
+        xfs_error("Entry not found!");
+        goto out;
+    }
+
     if (inode->mode == DT_REG) {
 	XFS_PVT(inode)->i_offset = 0;
 	XFS_PVT(inode)->i_cur_extent = 0;
@@ -347,6 +526,8 @@ static struct xfs_fs_info *xfs_new_sb_info(xfs_sb_t *sb)
 
     info->blocksize		= be32_to_cpu(sb->sb_blocksize);
     info->block_shift		= sb->sb_blocklog;
+    info->dirblksize		= 1 << (sb->sb_blocklog + sb->sb_dirblklog);
+    info->dirblklog		= sb->sb_dirblklog;
     info->inopb_shift 		= sb->sb_inopblog;
     info->agblk_shift 		= sb->sb_agblklog;
     info->rootino 		= be64_to_cpu(sb->sb_rootino);
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
index bfab2ae..e068468 100644
--- a/core/fs/xfs/xfs.h
+++ b/core/fs/xfs/xfs.h
@@ -103,6 +103,10 @@ struct xfs_fs_info;
 #define XFS_IBT_MAGIC 		"IABT"
 #define XFS_DINODE_MAGIC	"IN"
 
+#define XFS_DIR2_BLOCK_MAGIC    0x58443242U      /* XD2B: single block dirs */
+#define XFS_DIR2_DATA_MAGIC     0x58443244U      /* XD2D: multiblock dirs */
+#define XFS_DIR2_FREE_MAGIC     0x58443246U      /* XD2F: free index blocks */
+
 /* File types and modes */
 #define S_IFMT  	00170000
 #define S_IFSOCK 	0140000
@@ -192,6 +196,8 @@ typedef struct xfs_sb {
 struct xfs_fs_info {
     uint32_t 		blocksize; /* Filesystem block size */
     uint8_t		block_shift; /* Filesystem block size in bits */
+    uint32_t		dirblksize;
+    uint8_t		dirblklog;
     uint8_t		inopb_shift;
     uint8_t		agblk_shift;
 
@@ -246,6 +252,48 @@ typedef struct xfs_inobt_rec {
     uint64_t ir_free;
 } __attribute__((__packed__)) xfs_inobt_rec_t;
 
+/*
+ * Bmap btree record and extent descriptor.
+ *  l0:63 is an extent flag (value 1 indicates non-normal).
+ *  l0:9-62 are startoff.
+ *  l0:0-8 and l1:21-63 are startblock.
+ *  l1:0-20 are blockcount.
+ */
+typedef struct xfs_bmbt_rec {
+    uint64_t l0, l1;
+} xfs_bmbt_rec_t;
+
+/*
+ * Possible extent states.
+ */
+typedef enum {
+    XFS_EXT_NORM, XFS_EXT_UNWRITTEN,
+    XFS_EXT_DMAPI_OFFLINE, XFS_EXT_INVALID
+} xfs_exntst_t;
+
+typedef struct xfs_bmbt_irec
+{
+    xfs_fileoff_t br_startoff;    /* starting file offset */
+    xfs_fsblock_t br_startblock;  /* starting block number */
+    xfs_filblks_t br_blockcount;  /* number of blocks */
+    xfs_exntst_t  br_state;       /* extent state */
+} xfs_bmbt_irec_t;
+
+static inline void bmbt_irec_get(xfs_bmbt_irec_t *dest,
+				 const xfs_bmbt_rec_t *src)
+{
+    uint64_t l0, l1;
+
+    l0 = be64_to_cpu(src->l0);
+    l1 = be64_to_cpu(src->l1);
+
+    dest->br_startoff = ((xfs_fileoff_t)l0 & 0x7ffffffffffffe00ULL) >> 9;
+    dest->br_startblock = (((xfs_fsblock_t)l0 & 0x00000000000001ffULL) << 43) |
+                          (((xfs_fsblock_t)l1) >> 21);
+    dest->br_blockcount = (xfs_filblks_t)(l1 & 0x00000000001fffffULL);
+    dest->br_state = (l0 & 0x8000000000000000ULL) ? XFS_EXT_UNWRITTEN : XFS_EXT_NORM;
+}
+
 typedef struct xfs_timestamp {
     int32_t t_sec;
     int32_t t_nsec;
@@ -328,18 +376,6 @@ typedef struct xfs_dir2_sf {
     xfs_dir2_sf_entry_t     list[1];        /* shortform entries */
 } __attribute__((__packed__)) xfs_dir2_sf_t;
 
-typedef enum {
-    XFS_EXT_NORM,
-    XFS_EXT_UNWRITTEN,
-    XFS_EXT_DMAPI_OFFLINE,
-    XFS_EXT_INVALID,
-} xfs_exntst_t;
-
-typedef struct xfs_bmbt_rec {
-    uint64_t l0;
-    uint64_t l1;
-} __attribute__((__packed__)) xfs_bmbt_rec_t;
-
 typedef xfs_ino_t	xfs_intino_t;
 
 static inline xfs_intino_t xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp,
@@ -350,6 +386,103 @@ static inline xfs_intino_t xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp,
 	    (xfs_intino_t)XFS_GET_DIR_INO8((from)->i8));
 }
 
+/*
+ * DIR2 Data block structures.
+ *
+ * A pure data block looks like the following drawing on disk:
+ *
+ *    +-------------------------------------------------+
+ *    | xfs_dir2_data_hdr_t                             |
+ *    +-------------------------------------------------+
+ *    | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ *    | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ *    | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t |
+ *    | ...                                             |
+ *    +-------------------------------------------------+
+ *    | unused space                                    |
+ *    +-------------------------------------------------+
+ *
+ * As all the entries are variable size structure the accessors below should
+ * be used to iterate over them.
+ *
+ * In addition to the pure data blocks for the data and node formats.
+ * most structures are also used for the combined data/freespace "block"
+ * format below.
+ */
+
+#define XFS_DIR2_DATA_ALIGN_LOG 3
+#define XFS_DIR2_DATA_ALIGN     (1 << XFS_DIR2_DATA_ALIGN_LOG)
+#define XFS_DIR2_DATA_FREE_TAG  0xffff
+#define XFS_DIR2_DATA_FD_COUNT  3
+
+typedef struct xfs_dir2_data_free {
+    uint16_t offset;
+    uint16_t length;
+} xfs_dir2_data_free_t;
+
+typedef struct xfs_dir2_data_hdr {
+    uint32_t magic;
+    xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT];
+} xfs_dir2_data_hdr_t;
+
+typedef struct xfs_dir2_data_entry {
+    uint64_t inumber; /* inode number */
+    uint8_t  namelen; /* name length */
+    uint8_t  name[];  /* name types, no null */
+ /* uint16_t tag; */  /* starting offset of us */
+} xfs_dir2_data_entry_t;
+
+typedef struct xfs_dir2_data_unused {
+    uint16_t freetag; /* XFS_DIR2_DATA_FREE_TAG */
+    uint16_t length;  /* total free length */
+                      /* variable offset */
+ /* uint16_t tag; */  /* starting offset of us */
+} xfs_dir2_data_unused_t;
+
+#define roundup(x, y) (					\
+{							\
+	const typeof(y) __y = y;			\
+	(((x) + (__y - 1)) / __y) * __y;		\
+}							\
+)
+
+static inline int xfs_dir2_data_entsize(int n)
+{
+    return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n + 
+			(unsigned int)sizeof(uint16_t), XFS_DIR2_DATA_ALIGN);
+}
+
+static inline uint16_t *
+xfs_dir2_data_entry_tag_p(struct xfs_dir2_data_entry *dep)
+{
+    return (uint16_t *)((char *)dep +
+	    xfs_dir2_data_entsize(dep->namelen) - sizeof(uint16_t));
+}
+
+static inline uint16_t *
+xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup)
+{
+    return (uint16_t *)((char *)dup +
+	    be16_to_cpu(dup->length) - sizeof(uint16_t));
+}
+
+typedef struct xfs_dir2_block_tail {
+    uint32_t 		count;			/* count of leaf entries */
+    uint32_t 		stale;			/* count of stale lf entries */
+} xfs_dir2_block_tail_t;
+
+static inline struct xfs_dir2_block_tail *
+xfs_dir2_block_tail_p(struct xfs_fs_info *fs_info, struct xfs_dir2_data_hdr *hdr)
+{
+    return ((struct xfs_dir2_block_tail *)
+	    ((char *)hdr + fs_info->dirblksize)) - 1;
+}
+
+typedef struct xfs_dir2_leaf_entry {
+    uint32_t		hashval;		/* hash value of name */
+    uint32_t		address;		/* address of data entry */
+} xfs_dir2_leaf_entry_t;
+
 static inline bool xfs_is_valid_magicnum(const xfs_sb_t *sb)
 {
     return sb->sb_magicnum == *(uint32_t *)XFS_SB_MAGIC;


More information about the Syslinux-commits mailing list