Paulo Alcantara
2015-Dec-15 00:54 UTC
[syslinux] [PATCH] xfs: Add support for v3 directories
Besides supporting newer version of xfs file system, this patch also does some code refactoring and fix completely broken listing and searching on v2-3 node directories. Cc: Gene Cumm <gene.cumm at gmail.com> Cc: H. Peter Anvin <hpa at zytor.com> Cc: Raphael S. Carvalho <raphael.scarv at gmail.com> Cc: Ady <ady-sf at hotmail.com> Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> --- core/fs/xfs/xfs.c | 19 +-- core/fs/xfs/xfs.h | 155 +++++++++++++++++++----- core/fs/xfs/xfs_dinode.c | 2 +- core/fs/xfs/xfs_dir2.c | 296 +++++++++++++++++++++++++--------------------- core/fs/xfs/xfs_dir2.h | 6 +- core/fs/xfs/xfs_readdir.c | 151 ++++++++++++++--------- 6 files changed, 399 insertions(+), 230 deletions(-) diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c index 8dbc803..6f45973 100644 --- a/core/fs/xfs/xfs.c +++ b/core/fs/xfs/xfs.c @@ -74,10 +74,13 @@ static int xfs_readdir(struct file *file, struct dirent *dirent) return -1; } - if (core->di_format == XFS_DINODE_FMT_LOCAL) + switch (core->di_format) { + case XFS_DINODE_FMT_LOCAL: return xfs_fmt_local_readdir(file, dirent, core); - else if (core->di_format == XFS_DINODE_FMT_EXTENTS) + case XFS_DINODE_FMT_EXTENTS: + case XFS_DINODE_FMT_BTREE: return xfs_fmt_extents_readdir(file, dirent, core); + } return -1; } @@ -117,8 +120,10 @@ static int xfs_next_extent(struct inode *inode, uint32_t lstart) goto out; if (core->di_format == XFS_DINODE_FMT_EXTENTS) { - bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] + - XFS_PVT(inode)->i_cur_extent++); + bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)XFS_DFORK_PTR(core, + XFS_DATA_FORK) + + XFS_PVT(inode)->i_cur_extent); + XFS_PVT(inode)->i_cur_extent++; bno = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs); @@ -130,7 +135,7 @@ static int xfs_next_extent(struct inode *inode, uint32_t lstart) } else if (core->di_format == XFS_DINODE_FMT_BTREE) { xfs_debug("XFS_DINODE_FMT_BTREE"); index = XFS_PVT(inode)->i_cur_extent++; - rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0]; + rblock = XFS_DFORK_PTR(core, XFS_DATA_FORK); fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK); pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0)); bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >> BLOCK_SHIFT(fs); @@ -278,9 +283,9 @@ static int xfs_readlink(struct inode *inode, char *buf) } if (core->di_format == XFS_DINODE_FMT_LOCAL) { - memcpy(buf, (char *)&core->di_literal_area[0], pathlen); + memcpy(buf, XFS_DFORK_PTR(core, XFS_DATA_FORK), pathlen); } else if (core->di_format == XFS_DINODE_FMT_EXTENTS) { - bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0]); + bmbt_irec_get(&rec, XFS_DFORK_PTR(core, XFS_DATA_FORK)); db = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs); dir_buf = xfs_dir2_dirblks_get_cached(fs, db, rec.br_blockcount); diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h index a8bfa93..65acd17 100644 --- a/core/fs/xfs/xfs.h +++ b/core/fs/xfs/xfs.h @@ -116,6 +116,9 @@ struct xfs_fs_info; #define XFS_DIR2_NULL_DATAPTR ((uint32_t)0) +#define XFS_DIR3_BLOCK_MAGIC 0x58444233 /* XDB3: single block dirs */ +#define XFS_DIR3_DATA_MAGIC 0x58444433 /* XDD3: multiblock dirs */ + /* File types and modes */ #define S_IFMT 00170000 #define S_IFSOCK 0140000 @@ -346,8 +349,19 @@ typedef struct xfs_dinode { /* di_next_unlinked is the only non-core field in the old dinode */ uint32_t di_next_unlinked;/* agi unlinked list ptr */ - uint8_t di_literal_area[1]; -} __attribute__((packed)) xfs_dinode_t; + + /* start of the extended dinode, writable fields */ + uint32_t di_crc; /* CRC of the inode */ + uint64_t di_changecount; /* number of attribute changes */ + uint64_t di_lsn; /* flush sequence */ + uint64_t di_flags2; /* more random flags */ + uint8_t di_pad2[16]; + + /* fields only written to during inode creation */ + xfs_timestamp_t di_crtime; /* time created */ + uint64_t di_ino; /* inode number */ + uuid_t di_uuid; /* UUID of the filesystem */ +} __attribute__((__packed__)) xfs_dinode_t; /* * Inode size for given fs. @@ -359,23 +373,41 @@ typedef struct xfs_dinode { (XFS_BTREE_LBLOCK_LEN - sizeof(xfs_bmdr_block_t)) /* + * Size of the core inode on disk. Version 1 and 2 inodes have + * the same size, but version 3 has grown a few additional fields. + */ +static inline unsigned int xfs_dinode_size(int version) +{ + if (version == 3) + return sizeof(struct xfs_dinode); + return offsetof(struct xfs_dinode, di_crc); +} + +/* * Inode data & attribute fork sizes, per inode. */ #define XFS_DFORK_Q(dip) ((dip)->di_forkoff != 0) #define XFS_DFORK_BOFF(dip) ((int)((dip)->di_forkoff << 3)) -#define XFS_DFORK_DSIZE(dip, fs) \ - (XFS_DFORK_Q(dip) ? \ - XFS_DFORK_BOFF(dip) : \ - XFS_LITINO(fs)) -#define XFS_DFORK_ASIZE(dip, fs) \ - (XFS_DFORK_Q(dip) ? \ - XFS_LITINO(fs) - XFS_DFORK_BOFF(dip) : \ - 0) -#define XFS_DFORK_SIZE(dip, fs, w) \ - ((w) == XFS_DATA_FORK ? \ - XFS_DFORK_DSIZE(dip, fs) : \ - XFS_DFORK_ASIZE(dip, fs)) +#define XFS_DFORK_DSIZE(dip, fs) \ + (XFS_DFORK_Q(dip) ? \ + XFS_DFORK_BOFF(dip) : \ + XFS_LITINO(fs)) +#define XFS_DFORK_ASIZE(dip, fs) \ + (XFS_DFORK_Q(dip) ? \ + XFS_LITINO(fs) - XFS_DFORK_BOFF(dip) : \ + 0) +#define XFS_DFORK_SIZE(dip, fs, w) \ + ((w) == XFS_DATA_FORK ? \ + XFS_DFORK_DSIZE(dip, fs) : \ + XFS_DFORK_ASIZE(dip, fs)) + +#define XFS_DFORK_DPTR(dip) \ + ((void *)((uint8_t *)dip + xfs_dinode_size(dip->di_version))) +#define XFS_DFORK_APTR(dip) \ + ((void *)((uint8_t *)XFS_DFORK_DPTR(dip) + XFS_DFORK_BOFF(dip))) +#define XFS_DFORK_PTR(dip,w) \ + ((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR(dip) : XFS_DFORK_APTR(dip)) struct xfs_inode { xfs_agblock_t i_agblock; @@ -406,13 +438,12 @@ typedef struct xfs_dir2_sf_hdr { typedef struct xfs_dir2_sf_entry { uint8_t namelen; /* actual name length */ xfs_dir2_sf_off_t offset; /* saved offset */ - uint8_t name[1]; /* name, variable size */ - xfs_dir2_inou_t inumber; /* inode number, var. offset */ + uint8_t name[]; /* name, variable size */ } __attribute__((__packed__)) xfs_dir2_sf_entry_t; typedef struct xfs_dir2_sf { - xfs_dir2_sf_hdr_t hdr; /* shortform header */ - xfs_dir2_sf_entry_t list[1]; /* shortform entries */ + xfs_dir2_sf_hdr_t hdr; /* shortform header */ + xfs_dir2_sf_entry_t list[]; /* shortform entries */ } __attribute__((__packed__)) xfs_dir2_sf_t; typedef xfs_ino_t xfs_intino_t; @@ -483,6 +514,21 @@ typedef struct xfs_dir2_data_unused { /* uint16_t tag; */ /* starting offset of us */ } __attribute__((__packed__)) xfs_dir2_data_unused_t; +struct xfs_dir3_blk_hdr { + uint32_t magic; /* magic number */ + uint32_t crc; /* CRC of block */ + uint64_t blkno; /* first block of the buffer */ + uint64_t lsn; /* sequence number of last write */ + uuid_t uuid; /* filesystem we belong to */ + uint64_t owner; /* inode that owns the block */ +} __attribute__((__packed__)); + +struct xfs_dir3_data_hdr { + struct xfs_dir3_blk_hdr hdr; + xfs_dir2_data_free_t best_free[XFS_DIR2_DATA_FD_COUNT]; + uint32_t pad; /* 64 bit alignment */ +} __attribute__((__packed__)); + /** * rol32 - rotate a 32-bit value left * @word: value to rotate @@ -502,10 +548,17 @@ static inline uint32_t rol32(uint32_t word, signed int shift) static inline int xfs_dir2_data_entsize(int n) { - return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n + + return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n + (unsigned int)sizeof(uint16_t), XFS_DIR2_DATA_ALIGN); } +static inline int xfs_dir3_data_entsize(int n) +{ + return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n + + (unsigned int)sizeof(uint16_t) + sizeof(uint8_t), + XFS_DIR2_DATA_ALIGN); +} + static inline uint16_t * xfs_dir2_data_entry_tag_p(struct xfs_dir2_data_entry *dep) { @@ -598,25 +651,67 @@ typedef struct xfs_dir2_leaf { xfs_dir2_leaf_entry_t ents[]; /* entries */ } __attribute__((__packed__)) xfs_dir2_leaf_t; +typedef struct xfs_da3_blkinfo { + /* + * the node link manipulation code relies on the fact that the first + * element of this structure is the struct xfs_da_blkinfo so it can + * ignore the differences in the rest of the structures. + */ + xfs_da_blkinfo_t hdr; + uint32_t crc; /* CRC of block */ + uint64_t blkno; /* first block of the buffer */ + uint64_t lsn; /* sequence number of last write */ + uuid_t uuid; /* filesystem we belong to */ + uint64_t owner; /* inode that owns the block */ +} __attribute__((__packed__)) xfs_da3_blkinfo_t; + +typedef struct xfs_dir3_leaf_hdr { + xfs_da3_blkinfo_t info; /* header for da routines */ + uint16_t count; /* count of entries */ + uint16_t stale; /* count of stale entries */ + uint32_t pad; /* 64 bit alignment */ +} __attribute__((__packed__)) xfs_dir3_leaf_hdr_t; + +typedef struct xfs_dir3_leaf { + xfs_dir3_leaf_hdr_t hdr; /* leaf header */ + xfs_dir2_leaf_entry_t ents[]; /* entries */ +} __attribute__((__packed__)) xfs_dir3_leaf_t; + #define XFS_DA_NODE_MAGIC 0xfebeU /* magic number: non-leaf blocks */ #define XFS_ATTR_LEAF_MAGIC 0xfbeeU /* magic number: attribute leaf blks */ #define XFS_DIR2_LEAF1_MAGIC 0xd2f1U /* magic number: v2 dirlf single blks */ #define XFS_DIR2_LEAFN_MAGIC 0xd2ffU /* magic number: V2 dirlf multi blks */ +#define XFS_DA3_NODE_MAGIC 0x3ebe /* magic number: non-leaf blocks */ +#define XFS_ATTR3_LEAF_MAGIC 0x3bee /* magic number: attribute leaf blks */ +#define XFS_DIR3_LEAF1_MAGIC 0x3df1 /* magic number: v2 dirlf single blks */ +#define XFS_DIR3_LEAFN_MAGIC 0x3dff /* magic number: v2 dirlf multi blks */ + +#define XFS_DIR3_LEAF1_MAGIC 0x3df1 /* magic number: v2 dirlf single blks */ +#define XFS_DIR3_LEAFN_MAGIC 0x3dff /* magic number: v2 dirlf multi blks */ + +typedef struct xfs_da_node_hdr { + xfs_da_blkinfo_t info; /* block type, links, etc. */ + uint16_t count; /* count of active entries */ + uint16_t level; /* level above leaves (leaf == 0) */ +} __attribute__((__packed__)) xfs_da_node_hdr_t; + +typedef struct xfs_da_node_entry { + uint32_t hashval; /* hash value for this descendant */ + uint32_t before; /* Btree block before this key */ +} __attribute__((__packed__)) xfs_da_node_entry_t; + typedef struct xfs_da_intnode { - struct xfs_da_node_hdr { /* constant-structure header block */ - xfs_da_blkinfo_t info; /* block type, links, etc. */ - uint16_t count; /* count of active entries */ - uint16_t level; /* level above leaves (leaf == 0) */ - } hdr; - struct xfs_da_node_entry { - uint32_t hashval; /* hash value for this descendant */ - uint32_t before; /* Btree block before this key */ - } btree[1]; + xfs_da_node_hdr_t hdr; + xfs_da_node_entry_t btree[]; } __attribute__((__packed__)) xfs_da_intnode_t; -typedef struct xfs_da_node_hdr xfs_da_node_hdr_t; -typedef struct xfs_da_node_entry xfs_da_node_entry_t; +typedef struct xfs_da3_node_hdr { + xfs_da3_blkinfo_t info; /* block type, links, etc. */ + uint16_t count; /* count of active entries */ + uint16_t level; /* level above leaves (leaf == 0) */ + uint32_t pad32; +} __attribute__((__packed__)) xfs_da3_node_hdr_t; static inline bool xfs_is_valid_sb(const xfs_sb_t *sb) { diff --git a/core/fs/xfs/xfs_dinode.c b/core/fs/xfs/xfs_dinode.c index 55be6e2..dff7382 100644 --- a/core/fs/xfs/xfs_dinode.c +++ b/core/fs/xfs/xfs_dinode.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr at zytor.com> + * Copyright (c) 2012-2015 Paulo Alcantara <pcacjr at zytor.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c index de37ef7..f738a58 100644 --- a/core/fs/xfs/xfs_dir2.c +++ b/core/fs/xfs/xfs_dir2.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr at zytor.com> + * Copyright (c) 2012-2015 Paulo Alcantara <pcacjr at zytor.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -67,30 +67,29 @@ uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen) } static void *get_dirblks(struct fs_info *fs, block_t startblock, - xfs_filblks_t c) + xfs_filblks_t c) { - int count = c << XFS_INFO(fs)->dirblklog; - uint8_t *p; - uint8_t *buf; - off_t offset = 0; + const size_t len = c * XFS_INFO(fs)->dirblksize; + uint64_t offs = startblock << BLOCK_SHIFT(fs); + void *buf; + size_t ret; - buf = malloc(c * XFS_INFO(fs)->dirblksize); + buf = malloc(len); if (!buf) malloc_error("buffer memory"); + memset(buf, 0, len); - 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); + ret = cache_read(fs, buf, offs, len); + if (ret != len) { + xfs_error("failed to read contiguous directory blocks\n"); + free(buf); + return NULL; } - return buf; } -const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock, - xfs_filblks_t c) +void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock, + xfs_filblks_t c) { unsigned char i; void *buf; @@ -100,6 +99,8 @@ const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock, if (!dirblks_cached_count) { buf = get_dirblks(fs, startblock, c); + if (!buf) + return NULL; dirblks_cache[dirblks_cached_count].dc_startblock = startblock; dirblks_cache[dirblks_cached_count].dc_blkscount = c; @@ -116,6 +117,8 @@ const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock, } buf = get_dirblks(fs, startblock, c); + if (!buf) + return NULL; dirblks_cache[XFS_DIR2_DIRBLKS_CACHE_SIZE / 2].dc_startblock startblock; @@ -144,6 +147,8 @@ const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock, } buf = get_dirblks(fs, startblock, c); + if (!buf) + return NULL; dirblks_cache[dirblks_cached_count].dc_startblock = startblock; dirblks_cache[dirblks_cached_count].dc_blkscount = c; @@ -152,7 +157,6 @@ const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock, return dirblks_cache[dirblks_cached_count++].dc_area; } } - return NULL; } @@ -171,23 +175,27 @@ void xfs_dir2_dirblks_flush_cache(void) struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent, xfs_dinode_t *core) { - xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0]; + xfs_dir2_sf_t *sf = XFS_DFORK_PTR(core, XFS_DATA_FORK); xfs_dir2_sf_entry_t *sf_entry; + uint8_t ftypelen = core->di_version == 3 ? 1 : 0; uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count; struct fs_info *fs = parent->fs; struct inode *inode; + xfs_dir2_inou_t *inou; xfs_intino_t ino; xfs_dinode_t *ncore = NULL; xfs_debug("dname %s parent %p core %p", dname, parent, core); xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count); - sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] - + sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf->list - (!sf->hdr.i8count ? 4 : 0)); while (count--) { - uint8_t *start_name = &sf_entry->name[0]; + uint8_t *start_name = sf_entry->name; uint8_t *end_name = start_name + sf_entry->namelen; + xfs_debug("namelen %u", sf_entry->namelen); + if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) { xfs_debug("Found entry %s", dname); goto found; @@ -195,8 +203,9 @@ struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent, sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf_entry + offsetof(struct xfs_dir2_sf_entry, - name[0]) + + name) + sf_entry->namelen + + ftypelen + (sf->hdr.i8count ? 8 : 4)); } @@ -205,11 +214,12 @@ struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent, found: inode = xfs_new_inode(fs); - ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)( - (uint8_t *)sf_entry + - offsetof(struct xfs_dir2_sf_entry, - name[0]) + - sf_entry->namelen)); + inou = (xfs_dir2_inou_t *)((uint8_t *)sf_entry + + offsetof(struct xfs_dir2_sf_entry, + name) + + sf_entry->namelen + + ftypelen); + ino = xfs_dir2_sf_get_inumber(sf, inou); xfs_debug("entry inode's number %lu", ino); @@ -251,6 +261,7 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent, block_t dir_blk; struct fs_info *fs = parent->fs; const uint8_t *dirblk_buf; + bool isdir3; uint8_t *p, *endp; xfs_dir2_data_hdr_t *hdr; struct inode *inode = NULL; @@ -262,18 +273,26 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent, xfs_debug("dname %s parent %p core %p", dname, parent, core); - bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]); + bmbt_irec_get(&r, XFS_DFORK_PTR(core, XFS_DATA_FORK)); dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs); dirblk_buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, r.br_blockcount); + if (!dirblk_buf) + return NULL; + hdr = (xfs_dir2_data_hdr_t *)dirblk_buf; - if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) { + if (be32_to_cpu(hdr->magic) == XFS_DIR2_BLOCK_MAGIC) { + isdir3 = false; + } else if (be32_to_cpu(hdr->magic) == XFS_DIR3_BLOCK_MAGIC) { + isdir3 = true; + } else { 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); + p = (uint8_t *)dirblk_buf + (isdir3 ? sizeof(struct xfs_dir3_data_hdr) : + sizeof(struct xfs_dir2_data_hdr)); btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr); endp = (uint8_t *)((xfs_dir2_leaf_entry_t *)btp - be32_to_cpu(btp->count)); @@ -290,7 +309,7 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent, dep = (xfs_dir2_data_entry_t *)p; - start_name = &dep->name[0]; + start_name = dep->name; end_name = start_name + dep->namelen; if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) { @@ -298,7 +317,8 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent, goto found; } - p += xfs_dir2_data_entsize(dep->namelen); + p += (isdir3 ? xfs_dir3_data_entsize(dep->namelen) : + xfs_dir2_data_entsize(dep->namelen)); } out: @@ -348,7 +368,9 @@ failed: struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent, xfs_dinode_t *core) { - xfs_dir2_leaf_t *leaf; + xfs_dir2_leaf_hdr_t *hdr; + xfs_dir2_leaf_entry_t *ents; + uint16_t count; xfs_bmbt_irec_t irec; block_t leaf_blk, dir_blk; xfs_dir2_leaf_entry_t *lep; @@ -358,37 +380,47 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent, uint32_t hash = 0; uint32_t hashwant; uint32_t newdb, curdb = -1; - xfs_dir2_data_entry_t *dep; + xfs_dir2_data_entry_t *dep = NULL; struct inode *ip; xfs_dir2_data_hdr_t *data_hdr; uint8_t *start_name; uint8_t *end_name; xfs_intino_t ino; xfs_dinode_t *ncore; - const uint8_t *buf = NULL; + uint8_t *buf = NULL; xfs_debug("dname %s parent %p core %p", dname, parent, core); - bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + + bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)XFS_DFORK_PTR(core, XFS_DATA_FORK) + be32_to_cpu(core->di_nextents) - 1); leaf_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >> BLOCK_SHIFT(parent->fs); - leaf = (xfs_dir2_leaf_t *)xfs_dir2_dirblks_get_cached(parent->fs, leaf_blk, - irec.br_blockcount); - if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) { + hdr = xfs_dir2_dirblks_get_cached(parent->fs, leaf_blk, + irec.br_blockcount); + if (!hdr) + return NULL; + + if (be16_to_cpu(hdr->info.magic) == XFS_DIR2_LEAF1_MAGIC) { + count = be16_to_cpu(hdr->count); + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)hdr + + sizeof(struct xfs_dir2_leaf_hdr)); + } else if (be16_to_cpu(hdr->info.magic) == XFS_DIR3_LEAF1_MAGIC) { + count = be16_to_cpu(((xfs_dir3_leaf_hdr_t *)hdr)->count); + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)hdr + + sizeof(struct xfs_dir3_leaf_hdr)); + } else { xfs_error("Single leaf block header's magic number does not match!"); goto out; } - if (!leaf->hdr.count) + if (!count) goto out; hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname)); /* Binary search */ - for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1; - low <= high; ) { + for (lep = ents, low = 0, high = count - 1; low <= high; ) { mid = (low + high) >> 1; if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant) break; @@ -407,10 +439,8 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent, while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant) mid--; - for (lep = &leaf->ents[mid]; - mid < be16_to_cpu(leaf->hdr.count) && - be32_to_cpu(lep->hashval) == hashwant; - lep++, mid++) { + for (lep = &ents[mid]; + mid < count && be32_to_cpu(lep->hashval) == hashwant; lep++, mid++) { /* Skip over stale leaf entries. */ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) continue; @@ -418,13 +448,17 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent, newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address)); if (newdb != curdb) { bmbt_irec_get(&irec, - ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + newdb); + (xfs_bmbt_rec_t *)XFS_DFORK_PTR(core, + XFS_DATA_FORK) + + newdb); dir_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >> BLOCK_SHIFT(parent->fs); - buf = xfs_dir2_dirblks_get_cached(parent->fs, dir_blk, irec.br_blockcount); + buf = xfs_dir2_dirblks_get_cached(parent->fs, dir_blk, + irec.br_blockcount); data_hdr = (xfs_dir2_data_hdr_t *)buf; - if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) { + if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC && + be32_to_cpu(data_hdr->magic) != XFS_DIR3_DATA_MAGIC) { xfs_error("Leaf directory's data magic No. does not match!"); goto out; } @@ -432,10 +466,10 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent, curdb = newdb; } - dep = (xfs_dir2_data_entry_t *)((char *)buf + - xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address))); - - start_name = &dep->name[0]; + dep = (xfs_dir2_data_entry_t *)( + buf + xfs_dir2_dataptr_to_off(parent->fs, + be32_to_cpu(lep->address))); + start_name = dep->name; end_name = start_name + dep->namelen; if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) { @@ -523,7 +557,7 @@ block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core, int nextents; xfs_bmbt_ptr_t *pp; xfs_bmbt_key_t *kp; - xfs_btree_block_t *blk; + const xfs_btree_block_t *blk; xfs_bmbt_rec_t *xp; *error = 0; @@ -531,7 +565,8 @@ block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core, xfs_debug("XFS_DINODE_FMT_EXTENTS"); for (idx = 0; idx < be32_to_cpu(core->di_nextents); idx++) { bmbt_irec_get(&irec, - ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + idx); + (xfs_bmbt_rec_t *) + XFS_DFORK_PTR(core, XFS_DATA_FORK) + idx); if (fsblkno >= irec.br_startoff && fsblkno < irec.br_startoff + irec.br_blockcount) break; @@ -539,7 +574,7 @@ block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core, } else if (core->di_format == XFS_DINODE_FMT_BTREE) { xfs_debug("XFS_DINODE_FMT_BTREE"); bno = NULLFSBLOCK; - rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0]; + rblock = XFS_DFORK_PTR(core, XFS_DATA_FORK); fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK); pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0)); kp = XFS_BMDR_KEY_ADDR(rblock, 1); @@ -549,7 +584,7 @@ block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core, /* Find the leaf */ for (;;) { - blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno); + blk = get_cache(fs->fs_dev, bno); if (be16_to_cpu(blk->bb_level) == 0) break; pp = XFS_BMBT_PTR_ADDR(fs, blk, 1, @@ -576,7 +611,7 @@ block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core, if (nextbno == NULLFSBLOCK) break; bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs); - blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno); + blk = get_cache(fs->fs_dev, bno); } } @@ -593,110 +628,99 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent, xfs_dinode_t *core) { block_t fsblkno; - xfs_da_intnode_t *node = NULL; + xfs_da_node_hdr_t *nhdr; uint32_t hashwant; - uint32_t hash = 0; + uint32_t hash; + uint16_t i; + uint16_t count; xfs_da_node_entry_t *btree; - uint16_t max; - uint16_t span; - uint16_t probe; int error; + xfs_dir2_leaf_hdr_t *lhdr; xfs_dir2_data_hdr_t *data_hdr; - xfs_dir2_leaf_t *leaf; xfs_dir2_leaf_entry_t *lep; xfs_dir2_data_entry_t *dep; + xfs_dir2_leaf_entry_t *ents; struct inode *ip; uint8_t *start_name; uint8_t *end_name; int low; int high; - int mid = 0; - uint32_t newdb, curdb = -1; + int mid; + uint32_t newdb; + uint32_t curdb; xfs_intino_t ino; xfs_dinode_t *ncore; - const uint8_t *buf = NULL; + uint8_t *buf = NULL; xfs_debug("dname %s parent %p core %p", dname, parent, core); - hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname)); - - fsblkno = xfs_dir2_get_right_blk(parent->fs, core, - xfs_dir2_byte_to_db(parent->fs, XFS_DIR2_LEAF_OFFSET), - &error); + curdb = xfs_dir2_byte_to_db(parent->fs, XFS_DIR2_LEAF_OFFSET); + fsblkno = xfs_dir2_get_right_blk(parent->fs, core, curdb, &error); if (error) { xfs_error("Cannot find right rec!"); return NULL; } - node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(parent->fs, fsblkno, - 1); - if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) { - xfs_error("Node's magic number does not match!"); + nhdr = xfs_dir2_dirblks_get_cached(parent->fs, fsblkno, 1); + if (be16_to_cpu(nhdr->info.magic) == XFS_DA_NODE_MAGIC) { + count = be16_to_cpu(nhdr->count); + btree = (xfs_da_node_entry_t *)((uint8_t *)nhdr + + sizeof(struct xfs_da_node_hdr)); + } else if (be16_to_cpu(nhdr->info.magic) == XFS_DA3_NODE_MAGIC) { + count = be16_to_cpu(((xfs_da3_node_hdr_t *)nhdr)->count); + btree = (xfs_da_node_entry_t *)((uint8_t *)nhdr + + sizeof(struct xfs_da3_node_hdr)); + } else { + xfs_error("Node's magic number (0x%04x) does not match!"); goto out; } - do { - if (!node->hdr.count) - goto out; - - /* Given a hash to lookup, you read the node's btree array and first - * "hashval" in the array that exceeds the given hash and it can then - * be found in the block pointed by the "before" value. - */ - max = be16_to_cpu(node->hdr.count); - - probe = span = max/2; - for (btree = &node->btree[probe]; - span > 4; btree = &node->btree[probe]) { - span /= 2; - hash = be32_to_cpu(btree->hashval); - - if (hash < hashwant) - probe += span; - else if (hash > hashwant) - probe -= span; - else - break; - } - - while ((probe > 0) && (be32_to_cpu(btree->hashval) >= hashwant)) { - btree--; - probe--; - } - - while ((probe < max) && (be32_to_cpu(btree->hashval) < hashwant)) { - btree++; - probe++; - } + hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname)); - if (probe == max) - fsblkno = be32_to_cpu(node->btree[max-1].before); - else - fsblkno = be32_to_cpu(node->btree[probe].before); + /* Given a hash to lookup, you read the node's btree array and first + * "hashval" in the array that exceeds the given hash and it can then + * be found in the block pointed by the "before" value. + */ + fsblkno = 0; + for (i = 0; i < count; i++) { + if (hashwant < be32_to_cpu(btree[i].hashval)) { + fsblkno = be32_to_cpu(btree[i].before); + break; + } + } - fsblkno = xfs_dir2_get_right_blk(parent->fs, core, fsblkno, &error); - if (error) { - xfs_error("Cannot find right rec!"); - goto out; - } + if (!fsblkno) + goto out; - node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(parent->fs, - fsblkno, 1); - } while(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC); + fsblkno = xfs_dir2_get_right_blk(parent->fs, core, fsblkno, &error); + if (error) { + xfs_error("Cannot find leaf record"); + goto out; + } - leaf = (xfs_dir2_leaf_t*)node; - if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) { - xfs_error("Leaf's magic number does not match!"); + lhdr = xfs_dir2_dirblks_get_cached(parent->fs, fsblkno, 1); + if (be16_to_cpu(lhdr->info.magic) == XFS_DIR2_LEAFN_MAGIC) { + count = be16_to_cpu(lhdr->count); + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr + + sizeof(struct xfs_dir2_leaf_hdr)); + } else if (be16_to_cpu(lhdr->info.magic) == XFS_DIR3_LEAFN_MAGIC) { + count = be16_to_cpu(((xfs_dir3_leaf_hdr_t *)lhdr)->count); + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr + + sizeof(struct xfs_dir3_leaf_hdr)); + } else { + xfs_error("Leaf's magic number does not match (0x%04x)!", + be16_to_cpu(lhdr->info.magic)); goto out; } - if (!leaf->hdr.count) - goto out; + if (!count) + goto out; - for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1; - low <= high; ) { + lep = ents; + low = 0; + high = count - 1; + while (low <= high) { mid = (low + high) >> 1; - if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant) break; if (hash < hashwant) @@ -714,9 +738,8 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent, while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant) mid--; - for (lep = &leaf->ents[mid]; - mid < be16_to_cpu(leaf->hdr.count) && - be32_to_cpu(lep->hashval) == hashwant; + curdb = -1; + for (lep = &ents[mid]; mid < count && be32_to_cpu(lep->hashval) == hashwant; lep++, mid++) { /* Skip over stale leaf entries. */ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) @@ -732,7 +755,8 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent, buf = xfs_dir2_dirblks_get_cached(parent->fs, fsblkno, 1); data_hdr = (xfs_dir2_data_hdr_t *)buf; - if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) { + if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC && + be32_to_cpu(data_hdr->magic) != XFS_DIR3_DATA_MAGIC) { xfs_error("Leaf directory's data magic No. does not match!"); goto out; } @@ -740,10 +764,10 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent, curdb = newdb; } - dep = (xfs_dir2_data_entry_t *)((char *)buf + - xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address))); - - start_name = &dep->name[0]; + dep = (xfs_dir2_data_entry_t *)( + buf + xfs_dir2_dataptr_to_off(parent->fs, + be32_to_cpu(lep->address))); + start_name = dep->name; end_name = start_name + dep->namelen; if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) { diff --git a/core/fs/xfs/xfs_dir2.h b/core/fs/xfs/xfs_dir2.h index 158cf44..1e1fb57 100644 --- a/core/fs/xfs/xfs_dir2.h +++ b/core/fs/xfs/xfs_dir2.h @@ -23,8 +23,8 @@ #include "xfs.h" -const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock, - xfs_filblks_t c); +void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock, + xfs_filblks_t c); void xfs_dir2_dirblks_flush_cache(void); uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen); @@ -46,7 +46,7 @@ static inline bool xfs_dir2_isleaf(struct fs_info *fs, xfs_dinode_t *dip) uint64_t last = 0; xfs_bmbt_irec_t irec; - bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&dip->di_literal_area[0]) + + bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, XFS_DATA_FORK) + be32_to_cpu(dip->di_nextents) - 1); last = irec.br_startoff + irec.br_blockcount; diff --git a/core/fs/xfs/xfs_readdir.c b/core/fs/xfs/xfs_readdir.c index 86c8a77..51518ef 100644 --- a/core/fs/xfs/xfs_readdir.c +++ b/core/fs/xfs/xfs_readdir.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr at zytor.com> + * Copyright (c) 2012-2015 Paulo Alcantara <pcacjr at zytor.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -64,10 +64,12 @@ static int fill_dirent(struct fs_info *fs, struct dirent *dirent, int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent, xfs_dinode_t *core) { - xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0]; + xfs_dir2_sf_t *sf = XFS_DFORK_PTR(core, XFS_DATA_FORK); xfs_dir2_sf_entry_t *sf_entry; + uint8_t ftypelen = core->di_version == 3 ? 1 : 0; uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count; uint32_t offset = file->offset; + xfs_dir2_inou_t *inou; uint8_t *start_name; uint8_t *end_name; xfs_ino_t ino; @@ -82,7 +84,7 @@ int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent, file->offset++; - sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] - + sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf->list - (!sf->hdr.i8count ? 4 : 0)); if (file->offset - 1) { @@ -91,20 +93,22 @@ int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent, sf_entry = (xfs_dir2_sf_entry_t *)( (uint8_t *)sf_entry + offsetof(struct xfs_dir2_sf_entry, - name[0]) + + name) + sf_entry->namelen + + ftypelen + (sf->hdr.i8count ? 8 : 4)); } } - start_name = &sf_entry->name[0]; + start_name = sf_entry->name; end_name = start_name + sf_entry->namelen; - ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)( - (uint8_t *)sf_entry + - offsetof(struct xfs_dir2_sf_entry, - name[0]) + - sf_entry->namelen)); + inou = (xfs_dir2_inou_t *)((uint8_t *)sf_entry + + offsetof(struct xfs_dir2_sf_entry, + name) + + sf_entry->namelen + + ftypelen); + ino = xfs_dir2_sf_get_inumber(sf, inou); retval = fill_dirent(fs, dirent, file->offset, ino, (char *)start_name, end_name - start_name); @@ -126,6 +130,7 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent, block_t dir_blk; struct fs_info *fs = file->fs; const uint8_t *dirblk_buf; + bool isdir3; uint8_t *p; uint32_t offset; xfs_dir2_data_hdr_t *hdr; @@ -139,12 +144,16 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent, xfs_debug("file %p dirent %p core %p", file, dirent, core); - bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]); + bmbt_irec_get(&r, XFS_DFORK_PTR(core, XFS_DATA_FORK)); dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs); dirblk_buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, r.br_blockcount); hdr = (xfs_dir2_data_hdr_t *)dirblk_buf; - if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) { + if (be32_to_cpu(hdr->magic) == XFS_DIR2_BLOCK_MAGIC) { + isdir3 = false; + } else if (be32_to_cpu(hdr->magic) == XFS_DIR3_BLOCK_MAGIC) { + isdir3 = true; + } else { xfs_error("Block directory header's magic number does not match!"); xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic)); goto out; @@ -157,7 +166,8 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent, file->offset++; - p = (uint8_t *)(hdr + 1); + p = (uint8_t *)dirblk_buf + (isdir3 ? sizeof(struct xfs_dir3_data_hdr) : + sizeof(struct xfs_dir2_data_hdr)); if (file->offset - 1) { offset = file->offset; @@ -170,7 +180,8 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent, continue; } - p += xfs_dir2_data_entsize(dep->namelen); + p += (isdir3 ? xfs_dir3_data_entsize(dep->namelen) : + xfs_dir2_data_entsize(dep->namelen)); } } @@ -197,9 +208,11 @@ out: int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent, xfs_dinode_t *core) { + xfs_dir2_leaf_hdr_t *hdr; + xfs_dir2_leaf_entry_t *ents; + uint16_t count; xfs_bmbt_irec_t irec; struct fs_info *fs = file->fs; - xfs_dir2_leaf_t *leaf; block_t leaf_blk, dir_blk; xfs_dir2_leaf_entry_t *lep; uint32_t db; @@ -214,39 +227,49 @@ int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent, xfs_debug("file %p dirent %p core %p", file, dirent, core); - bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + + bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)XFS_DFORK_PTR(core, XFS_DATA_FORK) + be32_to_cpu(core->di_nextents) - 1); leaf_blk = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(file->fs); - leaf = (xfs_dir2_leaf_t *)xfs_dir2_dirblks_get_cached(fs, leaf_blk, - irec.br_blockcount); - if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) { + hdr = xfs_dir2_dirblks_get_cached(fs, leaf_blk, irec.br_blockcount); + if (!hdr) + return -1; + + if (be16_to_cpu(hdr->info.magic) == XFS_DIR2_LEAF1_MAGIC) { + count = be16_to_cpu(hdr->count); + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)hdr + + sizeof(struct xfs_dir2_leaf_hdr)); + } else if (be16_to_cpu(hdr->info.magic) == XFS_DIR3_LEAF1_MAGIC) { + count = be16_to_cpu(((xfs_dir3_leaf_hdr_t *)hdr)->count); + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)hdr + + sizeof(struct xfs_dir3_leaf_hdr)); + } else { xfs_error("Single leaf block header's magic number does not match!"); goto out; } - if (!leaf->hdr.count) - goto out; - - if (file->offset + 1 > be16_to_cpu(leaf->hdr.count)) + if (!count || file->offset + 1 > count) goto out; - lep = &leaf->ents[file->offset++]; + lep = &ents[file->offset++]; /* Skip over stale leaf entries */ for ( ; be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR; - lep++, file->offset++); + lep++, file->offset++) + ; db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address)); - bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] + db); + bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)XFS_DFORK_PTR(core, + XFS_DATA_FORK) + db); dir_blk = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs); buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, irec.br_blockcount); data_hdr = (xfs_dir2_data_hdr_t *)buf; - if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) { + if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC && + be32_to_cpu(data_hdr->magic) != XFS_DIR3_DATA_MAGIC) { xfs_error("Leaf directory's data magic number does not match!"); goto out; } @@ -277,14 +300,16 @@ int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent, xfs_dinode_t *core) { struct fs_info *fs = file->fs; - xfs_bmbt_irec_t irec; - uint32_t node_off = 0; block_t fsblkno; - xfs_da_intnode_t *node = NULL; + xfs_da_node_hdr_t *nhdr; + xfs_da_node_entry_t *btree; + uint16_t btcount; + uint16_t lfcount; + xfs_dir2_leaf_hdr_t *lhdr; + xfs_dir2_leaf_entry_t *ents; struct inode *inode = file->inode; int error; xfs_dir2_data_hdr_t *data_hdr; - xfs_dir2_leaf_t *leaf; xfs_dir2_leaf_entry_t *lep; unsigned int offset; xfs_dir2_data_entry_t *dep; @@ -296,52 +321,71 @@ int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent, xfs_debug("file %p dirent %p core %p", file, dirent, core); - do { - bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] + - ++node_off); - } while (irec.br_startoff < xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET)); - - fsblkno = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs); + db = xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET); + fsblkno = xfs_dir2_get_right_blk(fs, core, db, &error); + if (error) { + xfs_error("Cannot find fs block"); + return -1; + } - node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(fs, fsblkno, 1); - if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) { - xfs_error("Node's magic number does not match!"); + nhdr = xfs_dir2_dirblks_get_cached(fs, fsblkno, 1); + if (be16_to_cpu(nhdr->info.magic) == XFS_DA_NODE_MAGIC) { + btcount = be16_to_cpu(nhdr->count); + btree = (xfs_da_node_entry_t *)((uint8_t *)nhdr + + sizeof(struct xfs_da_node_hdr)); + } else if (be16_to_cpu(nhdr->info.magic) == XFS_DA3_NODE_MAGIC) { + btcount = be16_to_cpu(((xfs_da3_node_hdr_t *)nhdr)->count); + btree = (xfs_da_node_entry_t *)((uint8_t *)nhdr + + sizeof(struct xfs_da3_node_hdr)); + } else { + xfs_error("Node's magic number (0x%04x) does not match!", + be16_to_cpu(nhdr->info.magic)); goto out; } try_next_btree: - if (!node->hdr.count || - XFS_PVT(inode)->i_btree_offset >= be16_to_cpu(node->hdr.count)) + if (!btcount || + XFS_PVT(inode)->i_btree_offset >= btcount) goto out; - fsblkno = be32_to_cpu(node->btree[XFS_PVT(inode)->i_btree_offset].before); + fsblkno = be32_to_cpu(btree[XFS_PVT(inode)->i_btree_offset].before); fsblkno = xfs_dir2_get_right_blk(fs, core, fsblkno, &error); if (error) { xfs_error("Cannot find leaf rec!"); goto out; } - leaf = (xfs_dir2_leaf_t*)xfs_dir2_dirblks_get_cached(fs, fsblkno, 1); - if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) { - xfs_error("Leaf's magic number does not match!"); + lhdr = xfs_dir2_dirblks_get_cached(fs, fsblkno, 1); + if (be16_to_cpu(lhdr->info.magic) == XFS_DIR2_LEAFN_MAGIC) { + lfcount = be16_to_cpu(lhdr->count); + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr + + sizeof(struct xfs_dir2_leaf_hdr)); + } else if (be16_to_cpu(lhdr->info.magic) == XFS_DIR3_LEAFN_MAGIC) { + lfcount = be16_to_cpu(((xfs_dir3_leaf_hdr_t *)lhdr)->count); + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr + + sizeof(struct xfs_dir3_leaf_hdr)); + } else { + xfs_error("Leaf's magic number does not match (0x%04x)!", + be16_to_cpu(lhdr->info.magic)); goto out; } - if (!leaf->hdr.count || - XFS_PVT(inode)->i_leaf_ent_offset >= be16_to_cpu(leaf->hdr.count)) { + if (!lfcount || + XFS_PVT(inode)->i_leaf_ent_offset >= lfcount) { XFS_PVT(inode)->i_btree_offset++; XFS_PVT(inode)->i_leaf_ent_offset = 0; goto try_next_btree; } - lep = &leaf->ents[XFS_PVT(inode)->i_leaf_ent_offset]; + lep = &ents[XFS_PVT(inode)->i_leaf_ent_offset]; /* Skip over stale leaf entries */ - for ( ; XFS_PVT(inode)->i_leaf_ent_offset < be16_to_cpu(leaf->hdr.count) && + for ( ; XFS_PVT(inode)->i_leaf_ent_offset < lfcount && be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR; - lep++, XFS_PVT(inode)->i_leaf_ent_offset++); + lep++, XFS_PVT(inode)->i_leaf_ent_offset++) + ; - if (XFS_PVT(inode)->i_leaf_ent_offset == be16_to_cpu(leaf->hdr.count)) { + if (XFS_PVT(inode)->i_leaf_ent_offset == lfcount) { XFS_PVT(inode)->i_btree_offset++; XFS_PVT(inode)->i_leaf_ent_offset = 0; goto try_next_btree; @@ -359,7 +403,8 @@ try_next_btree: buf = xfs_dir2_dirblks_get_cached(fs, fsblkno, 1); data_hdr = (xfs_dir2_data_hdr_t *)buf; - if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) { + if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC && + be32_to_cpu(data_hdr->magic) != XFS_DIR3_DATA_MAGIC) { xfs_error("Leaf directory's data magic No. does not match!"); goto out; } -- 2.4.3
> Besides supporting newer version of xfs file system, this patch also > does some code refactoring and fix completely broken listing and > searching on v2-3 node directories. >Thank you. About the XFS "version" you are mentioning, a small clearer reference might be worth. The initial problem that triggered the need for this patch is seen when formatting the partition with xfsprogs v4.x, not necessarily with prior versions of xfsprogs. Searching information about what changed in xfsprogs v4.x, there are some references to "XFS v.5". At the same time, this patch mentions versions 1/2/3 of XFS node directories. These several not-so-clear "version" references could possibly be a source of confusion, if not now, then for some users asking questions in the future, or for future bug reports. Could someone please clarify? TIA, Ady.
Paulo Alcantara
2015-Dec-15 13:16 UTC
[syslinux] [PATCH] xfs: Add support for v3 directories
On Tue, December 15, 2015 5:50 am, Ady via Syslinux wrote:> >> Besides supporting newer version of xfs file system, this patch also >> does some code refactoring and fix completely broken listing and >> searching on v2-3 node directories. >> > > Thank you. > > About the XFS "version" you are mentioning, a small clearer reference > might be worth. > > The initial problem that triggered the need for this patch is seen when > formatting the partition with xfsprogs v4.x, not necessarily with prior > versions of xfsprogs. > > Searching information about what changed in xfsprogs v4.x, there are > some references to "XFS v.5". At the same time, this patch mentions > versions 1/2/3 of XFS node directories. These several not-so-clear > "version" references could possibly be a source of confusion, if not > now, then for some users asking questions in the future, or for future > bug reports. > > Could someone please clarify?I'm not an xfs guru, but what I was trying to refer to is about version of the file system metadata. That has nothing to do with xfsprogs versions. I've just followed spec and looked at the new fs metadata structures -- which are mentioned as v3 ones -- to fix the known issues. Paulo -- Paulo Alcantara, HP Inc. Speaking for myself only.
> Besides supporting newer version of xfs file system, this patch also > does some code refactoring and fix completely broken listing and > searching on v2-3 node directories. >> Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> > --- > core/fs/xfs/xfs.c | 19 +-- > core/fs/xfs/xfs.h | 155 +++++++++++++++++++----- > core/fs/xfs/xfs_dinode.c | 2 +- > core/fs/xfs/xfs_dir2.c | 296 +++++++++++++++++++++++++--------------------- > core/fs/xfs/xfs_dir2.h | 6 +- > core/fs/xfs/xfs_readdir.c | 151 ++++++++++++++--------- > 6 files changed, 399 insertions(+), 230 deletions(-) >Are there any reasons not to commit this patch (sent during 2015Dec)? Additionally: 1_ There was a patch sent by Paulo during 2015Jul: xfs: use cache_read() to read contiguous fs blocks Is it still adequate / relevant / valid / current/ needed / desired? Another patch, "xfs: rename xfs_is_valid_magicnum to xfs_is_valid_sb", also sent during 2015Jul, was already committed. 2_ In "mbr/mbr.S" as of v.6.03, there is specific code for XFS' VBRs. Besides the resulting "mbr.bin", are others "bios/mbr/*.bin" binaries capable of a similar / equivalent resulting feature (i.e. using XFS as boot partition for EXTLINUX)? If this feature is currently (v.6.03) available only to "mbr.bin", is there a way to make this feature more "*mbr*.bin"-generic, making it available to additional "bios/mbr/*.bin" binaries? Would this feature be useful / needed for any other "bios/mbr/*.bin" binary? Is there a need to add a similar / equivalent feature to "gptmbr.S"? Or, in other words, can XFS be used to boot EXTLINUX in a GPT scheme (in BIOS)? Normally, I would had tested this matter before asking here; unfortunately I am unable to perform tests at this time (and will be unable to test for the foreseeable future). TIA, Ady.
H. Peter Anvin
2016-Jan-15 19:48 UTC
[syslinux] [PATCH] xfs: Add support for v3 directories
On 01/08/2016 05:06 AM, Ady via Syslinux wrote:> > 2_ In "mbr/mbr.S" as of v.6.03, there is specific code for XFS' VBRs. > > Besides the resulting "mbr.bin", are others "bios/mbr/*.bin" binaries > capable of a similar / equivalent resulting feature (i.e. using XFS as > boot partition for EXTLINUX)? > > If this feature is currently (v.6.03) available only to "mbr.bin", is > there a way to make this feature more "*mbr*.bin"-generic, making it > available to additional "bios/mbr/*.bin" binaries? Would this feature > be useful / needed for any other "bios/mbr/*.bin" binary? >It would, indeed.> Is there a need to add a similar / equivalent feature to "gptmbr.S"? > Or, in other words, can XFS be used to boot EXTLINUX in a GPT scheme > (in BIOS)? Normally, I would had tested this matter before asking here; > unfortunately I am unable to perform tests at this time (and will be > unable to test for the foreseeable future).Yes, it is needed. -hpa
On Jan 15, 2016 5:46 PM, "Gene Cumm" <gene.cumm at gmail.com> wrote:> > On Jan 8, 2016 8:09 AM, "Ady via Syslinux" <syslinux at zytor.com> wrote: > > > > > > > Besides supporting newer version of xfs file system, this patch also > > > does some code refactoring and fix completely broken listing and > > > searching on v2-3 node directories. > > > > > > > > Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> > > > --- > > > core/fs/xfs/xfs.c | 19 +-- > > > core/fs/xfs/xfs.h | 155 +++++++++++++++++++----- > > > core/fs/xfs/xfs_dinode.c | 2 +- > > > core/fs/xfs/xfs_dir2.c | 296+++++++++++++++++++++++++---------------------> > > core/fs/xfs/xfs_dir2.h | 6 +- > > > core/fs/xfs/xfs_readdir.c | 151 ++++++++++++++--------- > > > 6 files changed, 399 insertions(+), 230 deletions(-) > > > > > > > Are there any reasons not to commit this patch (sent during 2015Dec)? > > It was next on my last actually. > > > Additionally: > > > > 1_ There was a patch sent by Paulo during 2015Jul: > > > > xfs: use cache_read() to read contiguous fs blocks > > > > Is it still adequate / relevant / valid / current/ needed / desired? > > I'll take a peak and ask Paulo if needed. > > --GeneSomehow forgot reply all
On Mon, Dec 14, 2015 at 7:54 PM, Paulo Alcantara <pcacjr at gmail.com> wrote:> Besides supporting newer version of xfs file system, this patch also > does some code refactoring and fix completely broken listing and > searching on v2-3 node directories. > > Cc: Gene Cumm <gene.cumm at gmail.com> > Cc: H. Peter Anvin <hpa at zytor.com> > Cc: Raphael S. Carvalho <raphael.scarv at gmail.com> > Cc: Ady <ady-sf at hotmail.com> > Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> > --- > core/fs/xfs/xfs.c | 19 +-- > core/fs/xfs/xfs.h | 155 +++++++++++++++++++----- > core/fs/xfs/xfs_dinode.c | 2 +- > core/fs/xfs/xfs_dir2.c | 296 +++++++++++++++++++++++++--------------------- > core/fs/xfs/xfs_dir2.h | 6 +- > core/fs/xfs/xfs_readdir.c | 151 ++++++++++++++--------- > 6 files changed, 399 insertions(+), 230 deletions(-)> diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c > index de37ef7..f738a58 100644> --- a/core/fs/xfs/xfs_dir2.c > +++ b/core/fs/xfs/xfs_dir2.c> @@ -593,110 +628,99 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent, > xfs_dinode_t *core) > {> - uint32_t hash = 0; > + uint32_t hash;> + uint16_t count;> - int mid = 0; > + int mid;> + if (be16_to_cpu(lhdr->info.magic) == XFS_DIR2_LEAFN_MAGIC) { > + count = be16_to_cpu(lhdr->count); > + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr + > + sizeof(struct xfs_dir2_leaf_hdr)); > + } else if (be16_to_cpu(lhdr->info.magic) == XFS_DIR3_LEAFN_MAGIC) { > + count = be16_to_cpu(((xfs_dir3_leaf_hdr_t *)lhdr)->count); > + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr + > + sizeof(struct xfs_dir3_leaf_hdr)); > + } else { > + xfs_error("Leaf's magic number does not match (0x%04x)!", > + be16_to_cpu(lhdr->info.magic)); > goto out; > } > > - if (!leaf->hdr.count) > - goto out; > + if (!count) > + goto out; > > - for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1; > - low <= high; ) { > + lep = ents; > + low = 0; > + high = count - 1; > + while (low <= high) { > mid = (low + high) >> 1; > - > if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant) > break; > if (hash < hashwant)Paulo, the initialization to zero of hash and mid silences the compiler's warning about potentially unitialized variables since some versions aren't intelligent enough to realize you've checked for the case of (count == 0), initialized low to 0 and therefore high must be equal to or greater than low. Other than this, it should be good. -- -Gene
Paulo Alcantara
2016-Jan-18 13:02 UTC
[syslinux] [PATCH] xfs: Add support for v3 directories
On Fri, January 15, 2016 8:47 pm, Gene Cumm via Syslinux wrote:> On Jan 15, 2016 5:46 PM, "Gene Cumm" <gene.cumm at gmail.com> wrote: >> >> On Jan 8, 2016 8:09 AM, "Ady via Syslinux" <syslinux at zytor.com> wrote: >> > >> > >> > > Besides supporting newer version of xfs file system, this patch also >> > > does some code refactoring and fix completely broken listing and >> > > searching on v2-3 node directories. >> > > >> > >> > > Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> >> > > --- >> > > core/fs/xfs/xfs.c | 19 +-- >> > > core/fs/xfs/xfs.h | 155 +++++++++++++++++++----- >> > > core/fs/xfs/xfs_dinode.c | 2 +- >> > > core/fs/xfs/xfs_dir2.c | 296 > +++++++++++++++++++++++++--------------------- >> > > core/fs/xfs/xfs_dir2.h | 6 +- >> > > core/fs/xfs/xfs_readdir.c | 151 ++++++++++++++--------- >> > > 6 files changed, 399 insertions(+), 230 deletions(-) >> > > >> > >> > Are there any reasons not to commit this patch (sent during 2015Dec)? >> >> It was next on my last actually. >> >> > Additionally: >> > >> > 1_ There was a patch sent by Paulo during 2015Jul: >> > >> > xfs: use cache_read() to read contiguous fs blocks >> > >> > Is it still adequate / relevant / valid / current/ needed / desired? >> >> I'll take a peak and ask Paulo if needed. >> >> --Gene > > Somehow forgot reply all > _______________________________________________ > Syslinux mailing list > Submissions to Syslinux at zytor.com > Unsubscribe or set options at: > http://www.zytor.com/mailman/listinfo/syslinux >The previous "xfs: use cache_read() to read contiguous fs blocks" patch may be ignored since I've already included the cache_read() usage in this patch. Paulo -- Paulo Alcantara, HP Inc. Speaking for myself only.
Paulo Alcantara
2016-Jan-18 13:06 UTC
[syslinux] [PATCH] xfs: Add support for v3 directories
On Mon, January 18, 2016 10:51 am, Gene Cumm wrote:> On Mon, Dec 14, 2015 at 7:54 PM, Paulo Alcantara <pcacjr at gmail.com> wrote: >> Besides supporting newer version of xfs file system, this patch also >> does some code refactoring and fix completely broken listing and >> searching on v2-3 node directories. >> >> Cc: Gene Cumm <gene.cumm at gmail.com> >> Cc: H. Peter Anvin <hpa at zytor.com> >> Cc: Raphael S. Carvalho <raphael.scarv at gmail.com> >> Cc: Ady <ady-sf at hotmail.com> >> Signed-off-by: Paulo Alcantara <pcacjr at zytor.com> >> --- >> core/fs/xfs/xfs.c | 19 +-- >> core/fs/xfs/xfs.h | 155 +++++++++++++++++++----- >> core/fs/xfs/xfs_dinode.c | 2 +- >> core/fs/xfs/xfs_dir2.c | 296 >> +++++++++++++++++++++++++--------------------- >> core/fs/xfs/xfs_dir2.h | 6 +- >> core/fs/xfs/xfs_readdir.c | 151 ++++++++++++++--------- >> 6 files changed, 399 insertions(+), 230 deletions(-) > >> diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c >> index de37ef7..f738a58 100644 > >> --- a/core/fs/xfs/xfs_dir2.c >> +++ b/core/fs/xfs/xfs_dir2.c > >> @@ -593,110 +628,99 @@ struct inode *xfs_dir2_node_find_entry(const char >> *dname, struct inode *parent, >> xfs_dinode_t *core) >> { > >> - uint32_t hash = 0; >> + uint32_t hash; > >> + uint16_t count; > >> - int mid = 0; >> + int mid; > > >> + if (be16_to_cpu(lhdr->info.magic) == XFS_DIR2_LEAFN_MAGIC) { >> + count = be16_to_cpu(lhdr->count); >> + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr + >> + sizeof(struct >> xfs_dir2_leaf_hdr)); >> + } else if (be16_to_cpu(lhdr->info.magic) == XFS_DIR3_LEAFN_MAGIC) { >> + count = be16_to_cpu(((xfs_dir3_leaf_hdr_t *)lhdr)->count); >> + ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr + >> + sizeof(struct >> xfs_dir3_leaf_hdr)); >> + } else { >> + xfs_error("Leaf's magic number does not match (0x%04x)!", >> + be16_to_cpu(lhdr->info.magic)); >> goto out; >> } >> >> - if (!leaf->hdr.count) >> - goto out; >> + if (!count) >> + goto out; >> >> - for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) >> - 1; >> - low <= high; ) { >> + lep = ents; >> + low = 0; >> + high = count - 1; >> + while (low <= high) { >> mid = (low + high) >> 1; >> - >> if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant) >> break; >> if (hash < hashwant) > > Paulo, the initialization to zero of hash and mid silences the > compiler's warning about potentially unitialized variables since some > versions aren't intelligent enough to realize you've checked for the > case of (count == 0), initialized low to 0 and therefore high must be > equal to or greater than low. > > Other than this, it should be good.Gene, thanks for pointing it out. Could you fix that for me, please? You might want to checkout my 'xfs-v3-support' branch to make your life easier. Thanks, Paulo -- Paulo Alcantara, HP Inc. Speaking for myself only.
Possibly Parallel Threads
- [PATCH] xfs: Add support for v3 directories
- [PATCH] xfs: Add support for v3 directories
- [PATCH 1/2] xfs: rename xfs_is_valid_magicnum to xfs_is_valid_sb
- [GIT-PULL] XFS filesystem driver
- [bug report] drm/nouveau/secboot: add gp102/gp104/gp106/gp107 support