/* * Copyright (c) 2012-2015 Paulo Alcantara * * 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 #include #include #include "xfs_types.h" #include "xfs_ag.h" #define xfs_error(fmt, args...) \ ({ \ dprintf("%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_sb(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_ */