[[Directory_Attribute_Btree]] = Variable Length Record B+trees Directories and extended attributes are implemented as a simple key-value record store inside the blocks pointed to by the data or attribute fork of a file. Blocks referenced by either data structure are block offsets of an inode fork, not physical blocks. Directory and attribute data are stored as a linear array of variable-length records in the low blocks of a fork. Both data types share the property that record keys and record values are both arbitrary and unique sequences of bytes. See the respective sections about xref:Directories[directories] or xref:Extended_Attributes[attributes] for more information about the exact record formats. The dir/attr b+tree (or "dabtree"), if present, computes a hash of the record key to produce the b+tree key, and b+tree keys are used to index the fork block in which the record may be found. Unlike the fixed-length b+trees, the variable length b+trees can index the same key multiple times. B+tree keypointers and records both take this format: ---- +---------+--------------+ | hashval | before_block | +---------+--------------+ ---- The "before block" is the block offset in the inode fork of the block in which we can find the record whose hashed key is "hashval". The hash function is as follows: [source, c] ---- #define rol32(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) xfs_dahash_t xfs_da_hashname(const uint8_t *name, int namelen) { xfs_dahash_t hash; /* * Do four characters at a time as long as we can. */ for (hash = 0; namelen >= 4; namelen -= 4, name += 4) hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^ (name[3] << 0) ^ rol32(hash, 7 * 4); /* * Now do the rest of the characters. */ switch (namelen) { case 3: return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^ rol32(hash, 7 * 3); case 2: return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2); case 1: return (name[0] << 0) ^ rol32(hash, 7 * 1); default: /* case 0: */ return hash; } } ---- [[Directory_Attribute_Block_Header]] == Block Headers * Tree nodes, leaf and node xref:Directories[directories], and leaf and node xref:Extended_Attributes[extended attributes] use the +xfs_da_blkinfo_t+ filesystem block header. The structure appears as follows: [source, c] ---- typedef struct xfs_da_blkinfo { __be32 forw; __be32 back; __be16 magic; __be16 pad; } xfs_da_blkinfo_t; ---- *forw*:: Logical block offset of the previous B+tree block at this level. *back*:: Logical block offset of the next B+tree block at this level. *magic*:: Magic number for this directory/attribute block. *pad*:: Padding to maintain alignment. // split lists * On a v5 filesystem, the leaves use the +struct xfs_da3_blkinfo_t+ filesystem block header. This header is used in the same place as +xfs_da_blkinfo_t+: [source, c] ---- struct xfs_da3_blkinfo { /* these values are inside xfs_da_blkinfo */ __be32 forw; __be32 back; __be16 magic; __be16 pad; __be32 crc; __be64 blkno; __be64 lsn; uuid_t uuid; __be64 owner; }; ---- *forw*:: Logical block offset of the previous B+tree block at this level. *back*:: Logical block offset of the next B+tree block at this level. *magic*:: Magic number for this directory/attribute block. *pad*:: Padding to maintain alignment. *crc*:: Checksum of the directory/attribute block. *blkno*:: Block number of this directory/attribute block. *lsn*:: Log sequence number of the last write to this block. *uuid*:: The UUID of this block, which must match either +sb_uuid+ or +sb_meta_uuid+ depending on which features are set. *owner*:: The inode number that this directory/attribute block belongs to. [[Directory_Attribute_Internal_Node]] == Internal Nodes The nodes of a dabtree have the following format: [source, c] ---- typedef struct xfs_da_intnode { struct xfs_da_node_hdr { xfs_da_blkinfo_t info; __uint16_t count; __uint16_t level; } hdr; struct xfs_da_node_entry { xfs_dahash_t hashval; xfs_dablk_t before; } btree[1]; } xfs_da_intnode_t; ---- *info*:: Directory/attribute block info. The magic number is +XFS_DA_NODE_MAGIC+ (0xfebe). *count*:: Number of node entries in this block. *level*:: The level of this block in the B+tree. Levels start at 1 for blocks that point to directory or attribute data blocks and increase towards the root. *hashval*:: The hash value of a particular record. *before*:: The directory/attribute logical block containing all entries up to the corresponding hash value. * On a v5 filesystem, the directory/attribute node blocks have the following structure: [source, c] ---- struct xfs_da3_intnode { struct xfs_da3_node_hdr { struct xfs_da3_blkinfo info; __uint16_t count; __uint16_t level; __uint32_t pad32; } hdr; struct xfs_da_node_entry { xfs_dahash_t hashval; xfs_dablk_t before; } btree[1]; }; ---- *info*:: Directory/attribute block info. The magic number is +XFS_DA3_NODE_MAGIC+ (0x3ebe). *count*:: Number of node entries in this block. *level*:: The level of this block in the B+tree. Levels start at 1 for blocks that point to directory or attribute data blocks, and increase towards the root. *pad32*:: Padding to maintain alignment. *hashval*:: The hash value of a particular record. *before*:: The directory/attribute logical block containing all entries up to the corresponding hash value.