758 lines
25 KiB
C
758 lines
25 KiB
C
/*
|
|
* Copyright (c) 2012-2013 Paulo Alcantara <pcacjr@zytor.com>
|
|
*
|
|
* Some parts borrowed from Linux kernel tree (linux/fs/xfs):
|
|
*
|
|
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it would be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#ifndef XFS_H_
|
|
#define XFS_H_
|
|
|
|
#include <disk.h>
|
|
#include <fs.h>
|
|
#include <dprintf.h>
|
|
|
|
#include "xfs_types.h"
|
|
#include "xfs_ag.h"
|
|
|
|
#define xfs_error(fmt, args...) \
|
|
({ \
|
|
printf("%s:%u: xfs - [ERROR] " fmt "\n", __func__, __LINE__, ## args); \
|
|
})
|
|
|
|
#define xfs_debug(fmt, args...) \
|
|
({ \
|
|
dprintf("%s:%u: xfs - [DEBUG] " fmt "\n", __func__, __LINE__, \
|
|
## args); \
|
|
})
|
|
|
|
struct xfs_fs_info;
|
|
|
|
#define XFS_INFO(fs) ((struct xfs_fs_info *)((fs)->fs_info))
|
|
#define XFS_PVT(ino) ((struct xfs_inode *)((ino)->pvt))
|
|
|
|
#define XFS_INO_MASK(k) (uint32_t)((1ULL << (k)) - 1)
|
|
#define XFS_INO_OFFSET_BITS(fs) (fs)->inopb_shift
|
|
#define XFS_INO_AGINO_BITS(fs) \
|
|
(XFS_INFO((fs))->inopb_shift + XFS_INFO((fs))->agblk_shift)
|
|
|
|
#define XFS_INO_TO_AGINO(fs, i) \
|
|
((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(fs)))
|
|
|
|
#define XFS_INO_TO_AGNO(fs, ino) \
|
|
((xfs_agnumber_t)((ino) >> (XFS_INFO((fs))->inopb_shift + \
|
|
XFS_INFO((fs))->agblk_shift)))
|
|
|
|
#define XFS_INO_TO_OFFSET(fs, i) \
|
|
((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(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))))
|
|
|
|
#define XFS_GET_DIR_INO4(di) \
|
|
(((uint32_t)(di).i[0] << 24) | ((di).i[1] << 16) | ((di).i[2] << 8) | \
|
|
((di).i[3]))
|
|
|
|
#define XFS_DI_HI(di) \
|
|
(((uint32_t)(di).i[1] << 16) | ((di).i[2] << 8) | ((di).i[3]))
|
|
|
|
#define XFS_DI_LO(di) \
|
|
(((uint32_t)(di).i[4] << 24) | ((di).i[5] << 16) | ((di).i[6] << 8) | \
|
|
((di).i[7]))
|
|
|
|
#define XFS_GET_DIR_INO8(di) \
|
|
(((xfs_ino_t)XFS_DI_LO(di) & 0xffffffffULL) | \
|
|
((xfs_ino_t)XFS_DI_HI(di) << 32))
|
|
|
|
#define XFS_FSB_TO_AGNO(fs, fsbno) \
|
|
((xfs_agnumber_t)((fsbno) >> XFS_INFO((fs))->agblk_shift))
|
|
#define XFS_FSB_TO_AGBNO(fs, fsbno) \
|
|
((xfs_agblock_t)((fsbno) & (uint32_t)((1ULL << \
|
|
XFS_INFO((fs))->agblk_shift) - 1)))
|
|
|
|
#define agblock_to_bytes(fs, x) \
|
|
((uint64_t)(x) << BLOCK_SHIFT((fs)))
|
|
#define agino_to_bytes(fs, x) \
|
|
((uint64_t)(x) << XFS_INFO((fs))->inode_shift)
|
|
#define agnumber_to_bytes(fs, x) \
|
|
agblock_to_bytes(fs, (uint64_t)(x) * XFS_INFO((fs))->agblocks)
|
|
#define fsblock_to_bytes(fs,x) \
|
|
(agnumber_to_bytes(fs, XFS_FSB_TO_AGNO(fs, (x))) + \
|
|
agblock_to_bytes(fs, XFS_FSB_TO_AGBNO(fs, (x))))
|
|
#define ino_to_bytes(fs, x) \
|
|
(agnumber_to_bytes(fs, XFS_INO_TO_AGNO(fs, (x))) + \
|
|
agino_to_bytes(fs, XFS_INO_TO_AGINO(fs, (x))))
|
|
|
|
/* 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"
|
|
|
|
#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 */
|
|
|
|
#define XFS_DIR2_NULL_DATAPTR ((uint32_t)0)
|
|
|
|
/* 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
|
|
|
|
#define MAXPATHLEN 1024
|
|
/*
|
|
* NOTE: The fields in the superblock are stored in big-endian format on disk.
|
|
*/
|
|
typedef struct xfs_sb {
|
|
uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */
|
|
uint32_t sb_blocksize; /* logical block size, bytes */
|
|
xfs_drfsbno_t sb_dblocks; /* number of data blocks */
|
|
xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */
|
|
xfs_drtbno_t sb_rextents; /* number of realtime extents */
|
|
uuid_t sb_uuid; /* file system unique id */
|
|
xfs_dfsbno_t sb_logstart; /* starting block of log if internal */
|
|
xfs_ino_t sb_rootino; /* root inode number */
|
|
xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */
|
|
xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */
|
|
xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */
|
|
xfs_agblock_t sb_agblocks; /* size of an allocation group */
|
|
xfs_agnumber_t sb_agcount; /* number of allocation groups */
|
|
xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */
|
|
xfs_extlen_t sb_logblocks; /* number of log blocks */
|
|
uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */
|
|
uint16_t sb_sectsize; /* volume sector size, bytes */
|
|
uint16_t sb_inodesize; /* inode size, bytes */
|
|
uint16_t sb_inopblock; /* inodes per block */
|
|
char sb_fname[12]; /* file system name */
|
|
uint8_t sb_blocklog; /* log2 of sb_blocksize */
|
|
uint8_t sb_sectlog; /* log2 of sb_sectsize */
|
|
uint8_t sb_inodelog; /* log2 of sb_inodesize */
|
|
uint8_t sb_inopblog; /* log2 of sb_inopblock */
|
|
uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */
|
|
uint8_t sb_rextslog; /* log2 of sb_rextents */
|
|
uint8_t sb_inprogress; /* mkfs is in progress, don't mount */
|
|
uint8_t sb_imax_pct; /* max % of fs for inode space */
|
|
/* statistics */
|
|
/*
|
|
* These fields must remain contiguous. If you really
|
|
* want to change their layout, make sure you fix the
|
|
* code in xfs_trans_apply_sb_deltas().
|
|
*/
|
|
uint64_t sb_icount; /* allocated inodes */
|
|
uint64_t sb_ifree; /* free inodes */
|
|
uint64_t sb_fdblocks; /* free data blocks */
|
|
uint64_t sb_frextents; /* free realtime extents */
|
|
/*
|
|
* End contiguous fields.
|
|
*/
|
|
xfs_ino_t sb_uquotino; /* user quota inode */
|
|
xfs_ino_t sb_gquotino; /* group quota inode */
|
|
uint16_t sb_qflags; /* quota flags */
|
|
uint8_t sb_flags; /* misc. flags */
|
|
uint8_t sb_shared_vn; /* shared version number */
|
|
xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */
|
|
uint32_t sb_unit; /* stripe or raid unit */
|
|
uint32_t sb_width; /* stripe or raid width */
|
|
uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */
|
|
uint8_t sb_logsectlog; /* log2 of the log sector size */
|
|
uint16_t sb_logsectsize; /* sector size for the log, bytes */
|
|
uint32_t sb_logsunit; /* stripe unit size for the log */
|
|
uint32_t sb_features2; /* additional feature bits */
|
|
|
|
/*
|
|
* bad features2 field as a result of failing to pad the sb
|
|
* structure to 64 bits. Some machines will be using this field
|
|
* for features2 bits. Easiest just to mark it bad and not use
|
|
* it for anything else.
|
|
*/
|
|
uint32_t sb_bad_features2;
|
|
uint8_t pad[304]; /* must be padded to a sector boundary */
|
|
} __attribute__((__packed__)) xfs_sb_t;
|
|
|
|
/* In-memory structure that stores filesystem-specific information.
|
|
* The information stored is basically retrieved from the XFS superblock
|
|
* to be used statically around the driver.
|
|
*/
|
|
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;
|
|
uint32_t dirleafblk;
|
|
|
|
/* AG number bits (MSB of the inode number) */
|
|
uint8_t ag_number_ino_shift;
|
|
|
|
xfs_ino_t rootino; /* Root inode number for the filesystem */
|
|
xfs_agblock_t agblocks; /* Size of each AG in blocks */
|
|
uint8_t agblocks_shift; /* agblocks in bits */
|
|
xfs_agnumber_t agcount; /* Number of AGs in the filesytem */
|
|
uint16_t inodesize; /* Size of the inode in bytes */
|
|
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;
|
|
|
|
/*
|
|
* 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;
|
|
uint64_t l1;
|
|
} __attribute__((__packed__)) xfs_bmbt_rec_t;
|
|
|
|
typedef xfs_bmbt_rec_t xfs_bmdr_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 */
|
|
} __attribute__((__packed__)) 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;
|
|
} __attribute__((__packed__)) xfs_timestamp_t;
|
|
|
|
/*
|
|
* Fork identifiers.
|
|
*/
|
|
#define XFS_DATA_FORK 0
|
|
#define xFS_ATTR_FORK 1
|
|
|
|
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 */
|
|
uint8_t di_literal_area[1];
|
|
} __attribute__((packed)) xfs_dinode_t;
|
|
|
|
/*
|
|
* Inode size for given fs.
|
|
*/
|
|
#define XFS_LITINO(fs) \
|
|
((int)((XFS_INFO(fs)->inodesize) - sizeof(struct xfs_dinode) - 1))
|
|
|
|
#define XFS_BROOT_SIZE_ADJ \
|
|
(XFS_BTREE_LBLOCK_LEN - sizeof(xfs_bmdr_block_t))
|
|
|
|
/*
|
|
* 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))
|
|
|
|
struct xfs_inode {
|
|
xfs_agblock_t i_agblock;
|
|
block_t i_ino_blk;
|
|
uint64_t i_block_offset;
|
|
uint64_t i_offset;
|
|
uint32_t i_cur_extent;
|
|
uint32_t i_btree_offset;
|
|
uint16_t i_leaf_ent_offset;
|
|
};
|
|
|
|
typedef struct { uint8_t i[8]; } __attribute__((__packed__)) xfs_dir2_ino8_t;
|
|
typedef struct { uint8_t i[4]; } __attribute__((__packed__)) xfs_dir2_ino4_t;
|
|
|
|
typedef union {
|
|
xfs_dir2_ino8_t i8;
|
|
xfs_dir2_ino4_t i4;
|
|
} __attribute__((__packed__)) xfs_dir2_inou_t;
|
|
|
|
typedef struct { uint8_t i[2]; } __attribute__((__packed__)) xfs_dir2_sf_off_t;
|
|
|
|
typedef struct xfs_dir2_sf_hdr {
|
|
uint8_t count; /* count of entries */
|
|
uint8_t i8count; /* count of 8-byte inode #s */
|
|
xfs_dir2_inou_t parent; /* parent dir inode number */
|
|
} __attribute__((__packed__)) xfs_dir2_sf_hdr_t;
|
|
|
|
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 */
|
|
} __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 */
|
|
} __attribute__((__packed__)) xfs_dir2_sf_t;
|
|
|
|
typedef xfs_ino_t xfs_intino_t;
|
|
|
|
static inline xfs_intino_t xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp,
|
|
xfs_dir2_inou_t *from)
|
|
{
|
|
return ((sfp)->hdr.i8count == 0 ? \
|
|
(xfs_intino_t)XFS_GET_DIR_INO4((from)->i4) : \
|
|
(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
|
|
|
|
/*
|
|
* Directory address space divided into sections.
|
|
* spaces separated by 32GB.
|
|
*/
|
|
#define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG))
|
|
|
|
typedef struct xfs_dir2_data_free {
|
|
uint16_t offset;
|
|
uint16_t length;
|
|
} __attribute__((__packed__)) 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];
|
|
} __attribute__((__packed__)) 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 */
|
|
} __attribute__((__packed__)) 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 */
|
|
} __attribute__((__packed__)) xfs_dir2_data_unused_t;
|
|
|
|
/**
|
|
* rol32 - rotate a 32-bit value left
|
|
* @word: value to rotate
|
|
* @shift: bits to roll
|
|
*/
|
|
static inline uint32_t rol32(uint32_t word, signed int shift)
|
|
{
|
|
return (word << shift) | (word >> (32 - shift));
|
|
}
|
|
|
|
#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 */
|
|
} __attribute__((__packed__)) 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;
|
|
}
|
|
|
|
static inline uint32_t
|
|
xfs_dir2_db_to_da(struct fs_info *fs, uint32_t db)
|
|
{
|
|
return db << XFS_INFO(fs)->dirblklog;
|
|
}
|
|
|
|
static inline int64_t
|
|
xfs_dir2_dataptr_to_byte(uint32_t dp)
|
|
{
|
|
return (int64_t)dp << XFS_DIR2_DATA_ALIGN_LOG;
|
|
}
|
|
|
|
static inline uint32_t
|
|
xfs_dir2_byte_to_db(struct fs_info *fs, int64_t by)
|
|
{
|
|
return (uint32_t)
|
|
(by >> (XFS_INFO(fs)->block_shift + XFS_INFO(fs)->dirblklog));
|
|
}
|
|
|
|
static inline uint32_t
|
|
xfs_dir2_dataptr_to_db(struct fs_info *fs, uint32_t dp)
|
|
{
|
|
return xfs_dir2_byte_to_db(fs, xfs_dir2_dataptr_to_byte(dp));
|
|
}
|
|
|
|
static inline unsigned int
|
|
xfs_dir2_byte_to_off(struct fs_info *fs, int64_t by)
|
|
{
|
|
return (unsigned int)(by &
|
|
(( 1 << (XFS_INFO(fs)->block_shift + XFS_INFO(fs)->dirblklog)) - 1));
|
|
}
|
|
|
|
static inline unsigned int
|
|
xfs_dir2_dataptr_to_off(struct fs_info *fs, uint32_t dp)
|
|
{
|
|
return xfs_dir2_byte_to_off(fs, xfs_dir2_dataptr_to_byte(dp));
|
|
}
|
|
|
|
#define XFS_DIR2_LEAF_SPACE 1
|
|
#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE)
|
|
#define XFS_DIR2_LEAF_FIRSTDB(fs) \
|
|
xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET)
|
|
|
|
typedef struct xfs_da_blkinfo {
|
|
uint32_t forw;
|
|
uint32_t back;
|
|
uint16_t magic;
|
|
uint16_t pad;
|
|
} __attribute__((__packed__)) xfs_da_blkinfo_t;
|
|
|
|
typedef struct xfs_dir2_leaf_hdr {
|
|
xfs_da_blkinfo_t info;
|
|
uint16_t count;
|
|
uint16_t stale;
|
|
} __attribute__((__packed__)) xfs_dir2_leaf_hdr_t;
|
|
|
|
typedef struct xfs_dir2_leaf_entry {
|
|
uint32_t hashval; /* hash value of name */
|
|
uint32_t address; /* address of data entry */
|
|
} __attribute__((__packed__)) xfs_dir2_leaf_entry_t;
|
|
|
|
typedef struct xfs_dir2_leaf {
|
|
xfs_dir2_leaf_hdr_t hdr; /* leaf header */
|
|
xfs_dir2_leaf_entry_t ents[]; /* entries */
|
|
} __attribute__((__packed__)) xfs_dir2_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 */
|
|
|
|
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];
|
|
} __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;
|
|
|
|
static inline bool xfs_is_valid_magicnum(const xfs_sb_t *sb)
|
|
{
|
|
return sb->sb_magicnum == *(uint32_t *)XFS_SB_MAGIC;
|
|
}
|
|
|
|
static inline bool xfs_is_valid_agi(xfs_agi_t *agi)
|
|
{
|
|
return agi->agi_magicnum == *(uint32_t *)XFS_AGI_MAGIC;
|
|
}
|
|
|
|
static inline struct inode *xfs_new_inode(struct fs_info *fs)
|
|
{
|
|
struct inode *inode;
|
|
|
|
inode = alloc_inode(fs, 0, sizeof(struct xfs_inode));
|
|
if (!inode)
|
|
malloc_error("xfs_inode structure");
|
|
|
|
return inode;
|
|
}
|
|
|
|
static inline void fill_xfs_inode_pvt(struct fs_info *fs, struct inode *inode,
|
|
xfs_ino_t ino)
|
|
{
|
|
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(XFS_INFO(fs), ino) <<
|
|
XFS_INFO(fs)->inode_shift;
|
|
}
|
|
|
|
/*
|
|
* Generic btree header.
|
|
*
|
|
* This is a combination of the actual format used on disk for short and long
|
|
* format btrees. The first three fields are shared by both format, but
|
|
* the pointers are different and should be used with care.
|
|
*
|
|
* To get the size of the actual short or long form headers please use
|
|
* the size macros belows. Never use sizeof(xfs_btree_block);
|
|
*/
|
|
typedef struct xfs_btree_block {
|
|
uint32_t bb_magic; /* magic number for block type */
|
|
uint16_t bb_level; /* 0 is a leaf */
|
|
uint16_t bb_numrecs; /* current # of data records */
|
|
union {
|
|
struct {
|
|
uint32_t bb_leftsib;
|
|
uint32_t bb_rightsib;
|
|
} s; /* short form pointers */
|
|
struct {
|
|
uint64_t bb_leftsib;
|
|
uint64_t bb_rightsib;
|
|
} l; /* long form pointers */
|
|
} bb_u; /* rest */
|
|
} xfs_btree_block_t;
|
|
|
|
#define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */
|
|
#define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */
|
|
|
|
/*
|
|
* Bmap root header, on-disk form only.
|
|
*/
|
|
typedef struct xfs_bmdr_block {
|
|
uint16_t bb_level; /* 0 is a leaf */
|
|
uint16_t bb_numrecs; /* current # of data records */
|
|
} xfs_bmdr_block_t;
|
|
|
|
/*
|
|
* Key structure for non-leaf levels of the tree.
|
|
*/
|
|
typedef struct xfs_bmbt_key {
|
|
uint64_t br_startoff; /* starting file offset */
|
|
} xfs_bmbt_key_t, xfs_bmdr_key_t;
|
|
|
|
/* btree pointer type */
|
|
typedef uint64_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
|
|
|
|
/*
|
|
* Btree block header size depends on a superblock flag.
|
|
*
|
|
* (not quite yet, but soon)
|
|
*/
|
|
#define XFS_BMBT_BLOCK_LEN(fs) XFS_BTREE_LBLOCK_LEN
|
|
|
|
#define XFS_BMBT_REC_ADDR(fs, block, index) \
|
|
((xfs_bmbt_rec_t *) \
|
|
((char *)(block) + \
|
|
XFS_BMBT_BLOCK_LEN(fs) + \
|
|
((index) - 1) * sizeof(xfs_bmbt_rec_t)))
|
|
|
|
#define XFS_BMBT_KEY_ADDR(fs, block, index) \
|
|
((xfs_bmbt_key_t *) \
|
|
((char *)(block) + \
|
|
XFS_BMBT_BLOCK_LEN(fs) + \
|
|
((index) - 1) * sizeof(xfs_bmbt_key_t)))
|
|
|
|
#define XFS_BMBT_PTR_ADDR(fs, block, index, maxrecs) \
|
|
((xfs_bmbt_ptr_t *) \
|
|
((char *)(block) + \
|
|
XFS_BMBT_BLOCK_LEN(fs) + \
|
|
(maxrecs) * sizeof(xfs_bmbt_key_t) + \
|
|
((index) - 1) * sizeof(xfs_bmbt_ptr_t)))
|
|
|
|
#define XFS_BMDR_REC_ADDR(block, index) \
|
|
((xfs_bmdr_rec_t *) \
|
|
((char *)(block) + \
|
|
sizeof(struct xfs_bmdr_block) + \
|
|
((index) - 1) * sizeof(xfs_bmdr_rec_t)))
|
|
|
|
#define XFS_BMDR_KEY_ADDR(block, index) \
|
|
((xfs_bmdr_key_t *) \
|
|
((char *)(block) + \
|
|
sizeof(struct xfs_bmdr_block) + \
|
|
((index) - 1) * sizeof(xfs_bmdr_key_t)))
|
|
|
|
#define XFS_BMDR_PTR_ADDR(block, index, maxrecs) \
|
|
((xfs_bmdr_ptr_t *) \
|
|
((char *)(block) + \
|
|
sizeof(struct xfs_bmdr_block) + \
|
|
(maxrecs) * sizeof(xfs_bmdr_key_t) + \
|
|
((index) - 1) * sizeof(xfs_bmdr_ptr_t)))
|
|
|
|
/*
|
|
* Calculate number of records in a bmap btree inode root.
|
|
*/
|
|
static inline int
|
|
xfs_bmdr_maxrecs(int blocklen, int leaf)
|
|
{
|
|
blocklen -= sizeof(xfs_bmdr_block_t);
|
|
|
|
if (leaf)
|
|
return blocklen / sizeof(xfs_bmdr_rec_t);
|
|
|
|
return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
|
|
}
|
|
|
|
#endif /* XFS_H_ */
|