Skip to content

Commit

Permalink
xfs: Add support for v3 directories
Browse files Browse the repository at this point in the history
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@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Raphael S. Carvalho <raphael.scarv@gmail.com>
Cc: Ady <ady-sf@hotmail.com>
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
  • Loading branch information
Paulo Alcantara committed Dec 15, 2015
1 parent 721a0af commit 8535f53
Show file tree
Hide file tree
Showing 6 changed files with 399 additions and 230 deletions.
19 changes: 12 additions & 7 deletions core/fs/xfs/xfs.c
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
155 changes: 125 additions & 30 deletions core/fs/xfs/xfs.h
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -358,24 +372,42 @@ typedef struct xfs_dinode {
#define XFS_BROOT_SIZE_ADJ \
(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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down
2 changes: 1 addition & 1 deletion core/fs/xfs/xfs_dinode.c
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2013 Paulo Alcantara <pcacjr@zytor.com>
* Copyright (c) 2012-2015 Paulo Alcantara <pcacjr@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
Expand Down

0 comments on commit 8535f53

Please sign in to comment.