10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0 230f712c9SDave Chinner /* 330f712c9SDave Chinner * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. 430f712c9SDave Chinner * Copyright (c) 2013 Red Hat, Inc. 530f712c9SDave Chinner * All Rights Reserved. 630f712c9SDave Chinner */ 730f712c9SDave Chinner #include "xfs.h" 830f712c9SDave Chinner #include "xfs_fs.h" 95467b34bSDarrick J. Wong #include "xfs_shared.h" 1030f712c9SDave Chinner #include "xfs_format.h" 1130f712c9SDave Chinner #include "xfs_log_format.h" 1230f712c9SDave Chinner #include "xfs_trans_resv.h" 1330f712c9SDave Chinner #include "xfs_mount.h" 1430f712c9SDave Chinner #include "xfs_inode.h" 1530f712c9SDave Chinner #include "xfs_dir2.h" 16fdbb8c5bSChristoph Hellwig #include "xfs_dir2_priv.h" 1730f712c9SDave Chinner #include "xfs_error.h" 1830f712c9SDave Chinner #include "xfs_trans.h" 1930f712c9SDave Chinner #include "xfs_buf_item.h" 20a45086e2SBrian Foster #include "xfs_log.h" 2130f712c9SDave Chinner 22e4f45effSDarrick J. Wong static xfs_failaddr_t xfs_dir2_data_freefind_verify( 23e4f45effSDarrick J. Wong struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf, 24e4f45effSDarrick J. Wong struct xfs_dir2_data_unused *dup, 25e4f45effSDarrick J. Wong struct xfs_dir2_data_free **bf_ent); 26e4f45effSDarrick J. Wong 271848b607SChristoph Hellwig struct xfs_dir2_data_free * 281848b607SChristoph Hellwig xfs_dir2_data_bestfree_p( 291848b607SChristoph Hellwig struct xfs_mount *mp, 301848b607SChristoph Hellwig struct xfs_dir2_data_hdr *hdr) 311848b607SChristoph Hellwig { 32ebd9027dSDave Chinner if (xfs_has_crc(mp)) 331848b607SChristoph Hellwig return ((struct xfs_dir3_data_hdr *)hdr)->best_free; 341848b607SChristoph Hellwig return hdr->bestfree; 351848b607SChristoph Hellwig } 361848b607SChristoph Hellwig 3730f712c9SDave Chinner /* 387e8ae7bdSChristoph Hellwig * Pointer to an entry's tag word. 397e8ae7bdSChristoph Hellwig */ 407e8ae7bdSChristoph Hellwig __be16 * 417e8ae7bdSChristoph Hellwig xfs_dir2_data_entry_tag_p( 427e8ae7bdSChristoph Hellwig struct xfs_mount *mp, 437e8ae7bdSChristoph Hellwig struct xfs_dir2_data_entry *dep) 447e8ae7bdSChristoph Hellwig { 457e8ae7bdSChristoph Hellwig return (__be16 *)((char *)dep + 467e8ae7bdSChristoph Hellwig xfs_dir2_data_entsize(mp, dep->namelen) - sizeof(__be16)); 477e8ae7bdSChristoph Hellwig } 487e8ae7bdSChristoph Hellwig 4959b8b465SChristoph Hellwig uint8_t 5059b8b465SChristoph Hellwig xfs_dir2_data_get_ftype( 5159b8b465SChristoph Hellwig struct xfs_mount *mp, 5259b8b465SChristoph Hellwig struct xfs_dir2_data_entry *dep) 5359b8b465SChristoph Hellwig { 54ebd9027dSDave Chinner if (xfs_has_ftype(mp)) { 5559b8b465SChristoph Hellwig uint8_t ftype = dep->name[dep->namelen]; 5659b8b465SChristoph Hellwig 5759b8b465SChristoph Hellwig if (likely(ftype < XFS_DIR3_FT_MAX)) 5859b8b465SChristoph Hellwig return ftype; 5959b8b465SChristoph Hellwig } 6059b8b465SChristoph Hellwig 6159b8b465SChristoph Hellwig return XFS_DIR3_FT_UNKNOWN; 6259b8b465SChristoph Hellwig } 6359b8b465SChristoph Hellwig 6459b8b465SChristoph Hellwig void 6559b8b465SChristoph Hellwig xfs_dir2_data_put_ftype( 6659b8b465SChristoph Hellwig struct xfs_mount *mp, 6759b8b465SChristoph Hellwig struct xfs_dir2_data_entry *dep, 6859b8b465SChristoph Hellwig uint8_t ftype) 6959b8b465SChristoph Hellwig { 7059b8b465SChristoph Hellwig ASSERT(ftype < XFS_DIR3_FT_MAX); 7159b8b465SChristoph Hellwig ASSERT(dep->namelen != 0); 7259b8b465SChristoph Hellwig 73ebd9027dSDave Chinner if (xfs_has_ftype(mp)) 7459b8b465SChristoph Hellwig dep->name[dep->namelen] = ftype; 7559b8b465SChristoph Hellwig } 7659b8b465SChristoph Hellwig 777e8ae7bdSChristoph Hellwig /* 7848a71399SChristoph Hellwig * The number of leaf entries is limited by the size of the block and the amount 7948a71399SChristoph Hellwig * of space used by the data entries. We don't know how much space is used by 8048a71399SChristoph Hellwig * the data entries yet, so just ensure that the count falls somewhere inside 8148a71399SChristoph Hellwig * the block right now. 8248a71399SChristoph Hellwig */ 8348a71399SChristoph Hellwig static inline unsigned int 8448a71399SChristoph Hellwig xfs_dir2_data_max_leaf_entries( 8548a71399SChristoph Hellwig struct xfs_da_geometry *geo) 8648a71399SChristoph Hellwig { 8748a71399SChristoph Hellwig return (geo->blksize - sizeof(struct xfs_dir2_block_tail) - 88d73e1ceeSChristoph Hellwig geo->data_entry_offset) / 8948a71399SChristoph Hellwig sizeof(struct xfs_dir2_leaf_entry); 9048a71399SChristoph Hellwig } 9148a71399SChristoph Hellwig 9248a71399SChristoph Hellwig /* 9330f712c9SDave Chinner * Check the consistency of the data block. 9430f712c9SDave Chinner * The input can also be a block-format directory. 95a6a781a5SDarrick J. Wong * Return NULL if the buffer is good, otherwise the address of the error. 9630f712c9SDave Chinner */ 97a6a781a5SDarrick J. Wong xfs_failaddr_t 9830f712c9SDave Chinner __xfs_dir3_data_check( 9930f712c9SDave Chinner struct xfs_inode *dp, /* incore inode pointer */ 10030f712c9SDave Chinner struct xfs_buf *bp) /* data block's buffer */ 10130f712c9SDave Chinner { 10230f712c9SDave Chinner xfs_dir2_dataptr_t addr; /* addr for leaf lookup */ 10330f712c9SDave Chinner xfs_dir2_data_free_t *bf; /* bestfree table */ 10430f712c9SDave Chinner xfs_dir2_block_tail_t *btp=NULL; /* block tail */ 10530f712c9SDave Chinner int count; /* count of entries found */ 10630f712c9SDave Chinner xfs_dir2_data_hdr_t *hdr; /* data block header */ 10730f712c9SDave Chinner xfs_dir2_data_free_t *dfp; /* bestfree entry */ 10830f712c9SDave Chinner int freeseen; /* mask of bestfrees seen */ 10930f712c9SDave Chinner xfs_dahash_t hash; /* hash of current name */ 11030f712c9SDave Chinner int i; /* leaf index */ 11130f712c9SDave Chinner int lastfree; /* last entry was unused */ 11230f712c9SDave Chinner xfs_dir2_leaf_entry_t *lep=NULL; /* block leaf entries */ 113dbd329f1SChristoph Hellwig struct xfs_mount *mp = bp->b_mount; 11430f712c9SDave Chinner int stale; /* count of stale leaves */ 11530f712c9SDave Chinner struct xfs_name name; 11648a71399SChristoph Hellwig unsigned int offset; 11748a71399SChristoph Hellwig unsigned int end; 11848a71399SChristoph Hellwig struct xfs_da_geometry *geo = mp->m_dir_geo; 11930f712c9SDave Chinner 12030f712c9SDave Chinner /* 12159b8b465SChristoph Hellwig * If this isn't a directory, something is seriously wrong. Bail out. 12230f712c9SDave Chinner */ 12359b8b465SChristoph Hellwig if (dp && !S_ISDIR(VFS_I(dp)->i_mode)) 12446c59736SDarrick J. Wong return __this_address; 12546c59736SDarrick J. Wong 12630f712c9SDave Chinner hdr = bp->b_addr; 127d73e1ceeSChristoph Hellwig offset = geo->data_entry_offset; 12830f712c9SDave Chinner 12930f712c9SDave Chinner switch (hdr->magic) { 13030f712c9SDave Chinner case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): 13130f712c9SDave Chinner case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): 13230f712c9SDave Chinner btp = xfs_dir2_block_tail_p(geo, hdr); 13330f712c9SDave Chinner lep = xfs_dir2_block_leaf_p(btp); 13430f712c9SDave Chinner 1359101d370SDarrick J. Wong if (be32_to_cpu(btp->count) >= 136d73e1ceeSChristoph Hellwig xfs_dir2_data_max_leaf_entries(geo)) 137a6a781a5SDarrick J. Wong return __this_address; 13830f712c9SDave Chinner break; 13930f712c9SDave Chinner case cpu_to_be32(XFS_DIR3_DATA_MAGIC): 14030f712c9SDave Chinner case cpu_to_be32(XFS_DIR2_DATA_MAGIC): 14130f712c9SDave Chinner break; 14230f712c9SDave Chinner default: 143a6a781a5SDarrick J. Wong return __this_address; 14430f712c9SDave Chinner } 1455c072127SChristoph Hellwig end = xfs_dir3_data_end_offset(geo, hdr); 1465c072127SChristoph Hellwig if (!end) 147ce92d29dSDarrick J. Wong return __this_address; 14830f712c9SDave Chinner 14930f712c9SDave Chinner /* 15030f712c9SDave Chinner * Account for zero bestfree entries. 15130f712c9SDave Chinner */ 1521848b607SChristoph Hellwig bf = xfs_dir2_data_bestfree_p(mp, hdr); 15330f712c9SDave Chinner count = lastfree = freeseen = 0; 15430f712c9SDave Chinner if (!bf[0].length) { 1559101d370SDarrick J. Wong if (bf[0].offset) 156a6a781a5SDarrick J. Wong return __this_address; 15730f712c9SDave Chinner freeseen |= 1 << 0; 15830f712c9SDave Chinner } 15930f712c9SDave Chinner if (!bf[1].length) { 1609101d370SDarrick J. Wong if (bf[1].offset) 161a6a781a5SDarrick J. Wong return __this_address; 16230f712c9SDave Chinner freeseen |= 1 << 1; 16330f712c9SDave Chinner } 16430f712c9SDave Chinner if (!bf[2].length) { 1659101d370SDarrick J. Wong if (bf[2].offset) 166a6a781a5SDarrick J. Wong return __this_address; 16730f712c9SDave Chinner freeseen |= 1 << 2; 16830f712c9SDave Chinner } 16930f712c9SDave Chinner 1709101d370SDarrick J. Wong if (be16_to_cpu(bf[0].length) < be16_to_cpu(bf[1].length)) 171a6a781a5SDarrick J. Wong return __this_address; 1729101d370SDarrick J. Wong if (be16_to_cpu(bf[1].length) < be16_to_cpu(bf[2].length)) 173a6a781a5SDarrick J. Wong return __this_address; 17430f712c9SDave Chinner /* 17530f712c9SDave Chinner * Loop over the data/unused entries. 17630f712c9SDave Chinner */ 17748a71399SChristoph Hellwig while (offset < end) { 17848a71399SChristoph Hellwig struct xfs_dir2_data_unused *dup = bp->b_addr + offset; 17948a71399SChristoph Hellwig struct xfs_dir2_data_entry *dep = bp->b_addr + offset; 18048a71399SChristoph Hellwig 18130f712c9SDave Chinner /* 18230f712c9SDave Chinner * If it's unused, look for the space in the bestfree table. 18330f712c9SDave Chinner * If we find it, account for that, else make sure it 18430f712c9SDave Chinner * doesn't need to be there. 18530f712c9SDave Chinner */ 18630f712c9SDave Chinner if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { 187e4f45effSDarrick J. Wong xfs_failaddr_t fa; 188e4f45effSDarrick J. Wong 1899101d370SDarrick J. Wong if (lastfree != 0) 190a6a781a5SDarrick J. Wong return __this_address; 19148a71399SChristoph Hellwig if (offset + be16_to_cpu(dup->length) > end) 192a6a781a5SDarrick J. Wong return __this_address; 1939101d370SDarrick J. Wong if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) != 19448a71399SChristoph Hellwig offset) 195a6a781a5SDarrick J. Wong return __this_address; 196e4f45effSDarrick J. Wong fa = xfs_dir2_data_freefind_verify(hdr, bf, dup, &dfp); 197e4f45effSDarrick J. Wong if (fa) 198e4f45effSDarrick J. Wong return fa; 19930f712c9SDave Chinner if (dfp) { 20030f712c9SDave Chinner i = (int)(dfp - bf); 2019101d370SDarrick J. Wong if ((freeseen & (1 << i)) != 0) 202a6a781a5SDarrick J. Wong return __this_address; 20330f712c9SDave Chinner freeseen |= 1 << i; 20430f712c9SDave Chinner } else { 2059101d370SDarrick J. Wong if (be16_to_cpu(dup->length) > 2069101d370SDarrick J. Wong be16_to_cpu(bf[2].length)) 207a6a781a5SDarrick J. Wong return __this_address; 20830f712c9SDave Chinner } 20948a71399SChristoph Hellwig offset += be16_to_cpu(dup->length); 21030f712c9SDave Chinner lastfree = 1; 21130f712c9SDave Chinner continue; 21230f712c9SDave Chinner } 21330f712c9SDave Chinner /* 21430f712c9SDave Chinner * It's a real entry. Validate the fields. 21530f712c9SDave Chinner * If this is a block directory then make sure it's 21630f712c9SDave Chinner * in the leaf section of the block. 21730f712c9SDave Chinner * The linear search is crude but this is DEBUG code. 21830f712c9SDave Chinner */ 2199101d370SDarrick J. Wong if (dep->namelen == 0) 220a6a781a5SDarrick J. Wong return __this_address; 22139d3c0b5SDave Chinner if (!xfs_verify_dir_ino(mp, be64_to_cpu(dep->inumber))) 222a6a781a5SDarrick J. Wong return __this_address; 223fdbb8c5bSChristoph Hellwig if (offset + xfs_dir2_data_entsize(mp, dep->namelen) > end) 224a6a781a5SDarrick J. Wong return __this_address; 2257e8ae7bdSChristoph Hellwig if (be16_to_cpu(*xfs_dir2_data_entry_tag_p(mp, dep)) != offset) 226a6a781a5SDarrick J. Wong return __this_address; 22759b8b465SChristoph Hellwig if (xfs_dir2_data_get_ftype(mp, dep) >= XFS_DIR3_FT_MAX) 228a6a781a5SDarrick J. Wong return __this_address; 22930f712c9SDave Chinner count++; 23030f712c9SDave Chinner lastfree = 0; 23130f712c9SDave Chinner if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 23230f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { 23330f712c9SDave Chinner addr = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, 23430f712c9SDave Chinner (xfs_dir2_data_aoff_t) 23530f712c9SDave Chinner ((char *)dep - (char *)hdr)); 23630f712c9SDave Chinner name.name = dep->name; 23730f712c9SDave Chinner name.len = dep->namelen; 238d8d11fc7SChristoph Hellwig hash = xfs_dir2_hashname(mp, &name); 23930f712c9SDave Chinner for (i = 0; i < be32_to_cpu(btp->count); i++) { 24030f712c9SDave Chinner if (be32_to_cpu(lep[i].address) == addr && 24130f712c9SDave Chinner be32_to_cpu(lep[i].hashval) == hash) 24230f712c9SDave Chinner break; 24330f712c9SDave Chinner } 2449101d370SDarrick J. Wong if (i >= be32_to_cpu(btp->count)) 245a6a781a5SDarrick J. Wong return __this_address; 24630f712c9SDave Chinner } 247fdbb8c5bSChristoph Hellwig offset += xfs_dir2_data_entsize(mp, dep->namelen); 24830f712c9SDave Chinner } 24930f712c9SDave Chinner /* 25030f712c9SDave Chinner * Need to have seen all the entries and all the bestfree slots. 25130f712c9SDave Chinner */ 2529101d370SDarrick J. Wong if (freeseen != 7) 253a6a781a5SDarrick J. Wong return __this_address; 25430f712c9SDave Chinner if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 25530f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { 25630f712c9SDave Chinner for (i = stale = 0; i < be32_to_cpu(btp->count); i++) { 25730f712c9SDave Chinner if (lep[i].address == 25830f712c9SDave Chinner cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) 25930f712c9SDave Chinner stale++; 2609101d370SDarrick J. Wong if (i > 0 && be32_to_cpu(lep[i].hashval) < 2619101d370SDarrick J. Wong be32_to_cpu(lep[i - 1].hashval)) 262a6a781a5SDarrick J. Wong return __this_address; 26330f712c9SDave Chinner } 2649101d370SDarrick J. Wong if (count != be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)) 265a6a781a5SDarrick J. Wong return __this_address; 2669101d370SDarrick J. Wong if (stale != be32_to_cpu(btp->stale)) 267a6a781a5SDarrick J. Wong return __this_address; 26830f712c9SDave Chinner } 269a6a781a5SDarrick J. Wong return NULL; 27030f712c9SDave Chinner } 27130f712c9SDave Chinner 272a6a781a5SDarrick J. Wong #ifdef DEBUG 273a6a781a5SDarrick J. Wong void 274a6a781a5SDarrick J. Wong xfs_dir3_data_check( 275a6a781a5SDarrick J. Wong struct xfs_inode *dp, 276a6a781a5SDarrick J. Wong struct xfs_buf *bp) 277a6a781a5SDarrick J. Wong { 278a6a781a5SDarrick J. Wong xfs_failaddr_t fa; 279a6a781a5SDarrick J. Wong 280a6a781a5SDarrick J. Wong fa = __xfs_dir3_data_check(dp, bp); 281a6a781a5SDarrick J. Wong if (!fa) 282a6a781a5SDarrick J. Wong return; 283a6a781a5SDarrick J. Wong xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, dp->i_mount, 2842551a530SDarrick J. Wong bp->b_addr, BBTOB(bp->b_length), __FILE__, __LINE__, 2852551a530SDarrick J. Wong fa); 286a6a781a5SDarrick J. Wong ASSERT(0); 287a6a781a5SDarrick J. Wong } 288a6a781a5SDarrick J. Wong #endif 289a6a781a5SDarrick J. Wong 290a6a781a5SDarrick J. Wong static xfs_failaddr_t 29130f712c9SDave Chinner xfs_dir3_data_verify( 29230f712c9SDave Chinner struct xfs_buf *bp) 29330f712c9SDave Chinner { 294dbd329f1SChristoph Hellwig struct xfs_mount *mp = bp->b_mount; 29530f712c9SDave Chinner struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; 29630f712c9SDave Chinner 29739708c20SBrian Foster if (!xfs_verify_magic(bp, hdr3->magic)) 298a6a781a5SDarrick J. Wong return __this_address; 29939708c20SBrian Foster 300ebd9027dSDave Chinner if (xfs_has_crc(mp)) { 301ce748eaaSEric Sandeen if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) 302a6a781a5SDarrick J. Wong return __this_address; 303*9343ee76SDave Chinner if (be64_to_cpu(hdr3->blkno) != xfs_buf_daddr(bp)) 304a6a781a5SDarrick J. Wong return __this_address; 305a45086e2SBrian Foster if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) 306a6a781a5SDarrick J. Wong return __this_address; 30730f712c9SDave Chinner } 3089101d370SDarrick J. Wong return __xfs_dir3_data_check(NULL, bp); 30930f712c9SDave Chinner } 31030f712c9SDave Chinner 31130f712c9SDave Chinner /* 31230f712c9SDave Chinner * Readahead of the first block of the directory when it is opened is completely 31330f712c9SDave Chinner * oblivious to the format of the directory. Hence we can either get a block 31430f712c9SDave Chinner * format buffer or a data format buffer on readahead. 31530f712c9SDave Chinner */ 31630f712c9SDave Chinner static void 31730f712c9SDave Chinner xfs_dir3_data_reada_verify( 31830f712c9SDave Chinner struct xfs_buf *bp) 31930f712c9SDave Chinner { 32030f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr = bp->b_addr; 32130f712c9SDave Chinner 32230f712c9SDave Chinner switch (hdr->magic) { 32330f712c9SDave Chinner case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): 32430f712c9SDave Chinner case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): 32530f712c9SDave Chinner bp->b_ops = &xfs_dir3_block_buf_ops; 32630f712c9SDave Chinner bp->b_ops->verify_read(bp); 32730f712c9SDave Chinner return; 32830f712c9SDave Chinner case cpu_to_be32(XFS_DIR2_DATA_MAGIC): 32930f712c9SDave Chinner case cpu_to_be32(XFS_DIR3_DATA_MAGIC): 3302f123bceSDarrick J. Wong bp->b_ops = &xfs_dir3_data_buf_ops; 3312f123bceSDarrick J. Wong bp->b_ops->verify_read(bp); 33230f712c9SDave Chinner return; 33330f712c9SDave Chinner default: 334bc1a09b8SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, __this_address); 33530f712c9SDave Chinner break; 33630f712c9SDave Chinner } 33730f712c9SDave Chinner } 33830f712c9SDave Chinner 33930f712c9SDave Chinner static void 34030f712c9SDave Chinner xfs_dir3_data_read_verify( 34130f712c9SDave Chinner struct xfs_buf *bp) 34230f712c9SDave Chinner { 343dbd329f1SChristoph Hellwig struct xfs_mount *mp = bp->b_mount; 344bc1a09b8SDarrick J. Wong xfs_failaddr_t fa; 34530f712c9SDave Chinner 34638c26bfdSDave Chinner if (xfs_has_crc(mp) && 34730f712c9SDave Chinner !xfs_buf_verify_cksum(bp, XFS_DIR3_DATA_CRC_OFF)) 348bc1a09b8SDarrick J. Wong xfs_verifier_error(bp, -EFSBADCRC, __this_address); 349bc1a09b8SDarrick J. Wong else { 350bc1a09b8SDarrick J. Wong fa = xfs_dir3_data_verify(bp); 351bc1a09b8SDarrick J. Wong if (fa) 352bc1a09b8SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 353bc1a09b8SDarrick J. Wong } 35430f712c9SDave Chinner } 35530f712c9SDave Chinner 35630f712c9SDave Chinner static void 35730f712c9SDave Chinner xfs_dir3_data_write_verify( 35830f712c9SDave Chinner struct xfs_buf *bp) 35930f712c9SDave Chinner { 360dbd329f1SChristoph Hellwig struct xfs_mount *mp = bp->b_mount; 361fb1755a6SCarlos Maiolino struct xfs_buf_log_item *bip = bp->b_log_item; 36230f712c9SDave Chinner struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; 363bc1a09b8SDarrick J. Wong xfs_failaddr_t fa; 36430f712c9SDave Chinner 365bc1a09b8SDarrick J. Wong fa = xfs_dir3_data_verify(bp); 366bc1a09b8SDarrick J. Wong if (fa) { 367bc1a09b8SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 36830f712c9SDave Chinner return; 36930f712c9SDave Chinner } 37030f712c9SDave Chinner 37138c26bfdSDave Chinner if (!xfs_has_crc(mp)) 37230f712c9SDave Chinner return; 37330f712c9SDave Chinner 37430f712c9SDave Chinner if (bip) 37530f712c9SDave Chinner hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); 37630f712c9SDave Chinner 37730f712c9SDave Chinner xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF); 37830f712c9SDave Chinner } 37930f712c9SDave Chinner 38030f712c9SDave Chinner const struct xfs_buf_ops xfs_dir3_data_buf_ops = { 381233135b7SEric Sandeen .name = "xfs_dir3_data", 38239708c20SBrian Foster .magic = { cpu_to_be32(XFS_DIR2_DATA_MAGIC), 38339708c20SBrian Foster cpu_to_be32(XFS_DIR3_DATA_MAGIC) }, 38430f712c9SDave Chinner .verify_read = xfs_dir3_data_read_verify, 38530f712c9SDave Chinner .verify_write = xfs_dir3_data_write_verify, 386b5572597SDarrick J. Wong .verify_struct = xfs_dir3_data_verify, 38730f712c9SDave Chinner }; 38830f712c9SDave Chinner 38930f712c9SDave Chinner static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = { 390233135b7SEric Sandeen .name = "xfs_dir3_data_reada", 39139708c20SBrian Foster .magic = { cpu_to_be32(XFS_DIR2_DATA_MAGIC), 39239708c20SBrian Foster cpu_to_be32(XFS_DIR3_DATA_MAGIC) }, 39330f712c9SDave Chinner .verify_read = xfs_dir3_data_reada_verify, 39430f712c9SDave Chinner .verify_write = xfs_dir3_data_write_verify, 39530f712c9SDave Chinner }; 39630f712c9SDave Chinner 397a10c21edSDarrick J. Wong static xfs_failaddr_t 398a10c21edSDarrick J. Wong xfs_dir3_data_header_check( 399a10c21edSDarrick J. Wong struct xfs_inode *dp, 400a10c21edSDarrick J. Wong struct xfs_buf *bp) 401a10c21edSDarrick J. Wong { 402a10c21edSDarrick J. Wong struct xfs_mount *mp = dp->i_mount; 403a10c21edSDarrick J. Wong 404ebd9027dSDave Chinner if (xfs_has_crc(mp)) { 405a10c21edSDarrick J. Wong struct xfs_dir3_data_hdr *hdr3 = bp->b_addr; 406a10c21edSDarrick J. Wong 407a10c21edSDarrick J. Wong if (be64_to_cpu(hdr3->hdr.owner) != dp->i_ino) 408a10c21edSDarrick J. Wong return __this_address; 409a10c21edSDarrick J. Wong } 410a10c21edSDarrick J. Wong 411a10c21edSDarrick J. Wong return NULL; 412a10c21edSDarrick J. Wong } 41330f712c9SDave Chinner 41430f712c9SDave Chinner int 41530f712c9SDave Chinner xfs_dir3_data_read( 41630f712c9SDave Chinner struct xfs_trans *tp, 41730f712c9SDave Chinner struct xfs_inode *dp, 41830f712c9SDave Chinner xfs_dablk_t bno, 419cd2c9f1bSChristoph Hellwig unsigned int flags, 42030f712c9SDave Chinner struct xfs_buf **bpp) 42130f712c9SDave Chinner { 422a10c21edSDarrick J. Wong xfs_failaddr_t fa; 42330f712c9SDave Chinner int err; 42430f712c9SDave Chinner 425cd2c9f1bSChristoph Hellwig err = xfs_da_read_buf(tp, dp, bno, flags, bpp, XFS_DATA_FORK, 426cd2c9f1bSChristoph Hellwig &xfs_dir3_data_buf_ops); 427a10c21edSDarrick J. Wong if (err || !*bpp) 428a10c21edSDarrick J. Wong return err; 429a10c21edSDarrick J. Wong 430a10c21edSDarrick J. Wong /* Check things that we can't do in the verifier. */ 431a10c21edSDarrick J. Wong fa = xfs_dir3_data_header_check(dp, *bpp); 432a10c21edSDarrick J. Wong if (fa) { 433a10c21edSDarrick J. Wong __xfs_buf_mark_corrupt(*bpp, fa); 434a10c21edSDarrick J. Wong xfs_trans_brelse(tp, *bpp); 435a10c21edSDarrick J. Wong *bpp = NULL; 436a10c21edSDarrick J. Wong return -EFSCORRUPTED; 437a10c21edSDarrick J. Wong } 438a10c21edSDarrick J. Wong 43930f712c9SDave Chinner xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_DATA_BUF); 44030f712c9SDave Chinner return err; 44130f712c9SDave Chinner } 44230f712c9SDave Chinner 44330f712c9SDave Chinner int 44430f712c9SDave Chinner xfs_dir3_data_readahead( 44530f712c9SDave Chinner struct xfs_inode *dp, 44630f712c9SDave Chinner xfs_dablk_t bno, 44706566fdaSChristoph Hellwig unsigned int flags) 44830f712c9SDave Chinner { 44906566fdaSChristoph Hellwig return xfs_da_reada_buf(dp, bno, flags, XFS_DATA_FORK, 45006566fdaSChristoph Hellwig &xfs_dir3_data_reada_buf_ops); 45130f712c9SDave Chinner } 45230f712c9SDave Chinner 45330f712c9SDave Chinner /* 454e4f45effSDarrick J. Wong * Find the bestfree entry that exactly coincides with unused directory space 455e4f45effSDarrick J. Wong * or a verifier error because the bestfree data are bad. 456e4f45effSDarrick J. Wong */ 457e4f45effSDarrick J. Wong static xfs_failaddr_t 458e4f45effSDarrick J. Wong xfs_dir2_data_freefind_verify( 459e4f45effSDarrick J. Wong struct xfs_dir2_data_hdr *hdr, 460e4f45effSDarrick J. Wong struct xfs_dir2_data_free *bf, 461e4f45effSDarrick J. Wong struct xfs_dir2_data_unused *dup, 462e4f45effSDarrick J. Wong struct xfs_dir2_data_free **bf_ent) 463e4f45effSDarrick J. Wong { 464e4f45effSDarrick J. Wong struct xfs_dir2_data_free *dfp; 465e4f45effSDarrick J. Wong xfs_dir2_data_aoff_t off; 466e4f45effSDarrick J. Wong bool matched = false; 467e4f45effSDarrick J. Wong bool seenzero = false; 468e4f45effSDarrick J. Wong 469e4f45effSDarrick J. Wong *bf_ent = NULL; 470e4f45effSDarrick J. Wong off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); 471e4f45effSDarrick J. Wong 472e4f45effSDarrick J. Wong /* 473e4f45effSDarrick J. Wong * Validate some consistency in the bestfree table. 474e4f45effSDarrick J. Wong * Check order, non-overlapping entries, and if we find the 475e4f45effSDarrick J. Wong * one we're looking for it has to be exact. 476e4f45effSDarrick J. Wong */ 477e4f45effSDarrick J. Wong for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { 478e4f45effSDarrick J. Wong if (!dfp->offset) { 479e4f45effSDarrick J. Wong if (dfp->length) 480e4f45effSDarrick J. Wong return __this_address; 481e4f45effSDarrick J. Wong seenzero = true; 482e4f45effSDarrick J. Wong continue; 483e4f45effSDarrick J. Wong } 484e4f45effSDarrick J. Wong if (seenzero) 485e4f45effSDarrick J. Wong return __this_address; 486e4f45effSDarrick J. Wong if (be16_to_cpu(dfp->offset) == off) { 487e4f45effSDarrick J. Wong matched = true; 488e4f45effSDarrick J. Wong if (dfp->length != dup->length) 489e4f45effSDarrick J. Wong return __this_address; 490e4f45effSDarrick J. Wong } else if (be16_to_cpu(dfp->offset) > off) { 491e4f45effSDarrick J. Wong if (off + be16_to_cpu(dup->length) > 492e4f45effSDarrick J. Wong be16_to_cpu(dfp->offset)) 493e4f45effSDarrick J. Wong return __this_address; 494e4f45effSDarrick J. Wong } else { 495e4f45effSDarrick J. Wong if (be16_to_cpu(dfp->offset) + 496e4f45effSDarrick J. Wong be16_to_cpu(dfp->length) > off) 497e4f45effSDarrick J. Wong return __this_address; 498e4f45effSDarrick J. Wong } 499e4f45effSDarrick J. Wong if (!matched && 500e4f45effSDarrick J. Wong be16_to_cpu(dfp->length) < be16_to_cpu(dup->length)) 501e4f45effSDarrick J. Wong return __this_address; 502e4f45effSDarrick J. Wong if (dfp > &bf[0] && 503e4f45effSDarrick J. Wong be16_to_cpu(dfp[-1].length) < be16_to_cpu(dfp[0].length)) 504e4f45effSDarrick J. Wong return __this_address; 505e4f45effSDarrick J. Wong } 506e4f45effSDarrick J. Wong 507e4f45effSDarrick J. Wong /* Looks ok so far; now try to match up with a bestfree entry. */ 508e4f45effSDarrick J. Wong *bf_ent = xfs_dir2_data_freefind(hdr, bf, dup); 509e4f45effSDarrick J. Wong return NULL; 510e4f45effSDarrick J. Wong } 511e4f45effSDarrick J. Wong 512e4f45effSDarrick J. Wong /* 51330f712c9SDave Chinner * Given a data block and an unused entry from that block, 51430f712c9SDave Chinner * return the bestfree entry if any that corresponds to it. 51530f712c9SDave Chinner */ 51630f712c9SDave Chinner xfs_dir2_data_free_t * 51730f712c9SDave Chinner xfs_dir2_data_freefind( 51830f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr, /* data block header */ 51930f712c9SDave Chinner struct xfs_dir2_data_free *bf, /* bestfree table pointer */ 52030f712c9SDave Chinner struct xfs_dir2_data_unused *dup) /* unused space */ 52130f712c9SDave Chinner { 52230f712c9SDave Chinner xfs_dir2_data_free_t *dfp; /* bestfree entry */ 52330f712c9SDave Chinner xfs_dir2_data_aoff_t off; /* offset value needed */ 52430f712c9SDave Chinner 52530f712c9SDave Chinner off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); 52630f712c9SDave Chinner 52730f712c9SDave Chinner /* 52830f712c9SDave Chinner * If this is smaller than the smallest bestfree entry, 52930f712c9SDave Chinner * it can't be there since they're sorted. 53030f712c9SDave Chinner */ 53130f712c9SDave Chinner if (be16_to_cpu(dup->length) < 53230f712c9SDave Chinner be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length)) 53330f712c9SDave Chinner return NULL; 53430f712c9SDave Chinner /* 53530f712c9SDave Chinner * Look at the three bestfree entries for our guy. 53630f712c9SDave Chinner */ 53730f712c9SDave Chinner for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { 53830f712c9SDave Chinner if (!dfp->offset) 53930f712c9SDave Chinner return NULL; 54030f712c9SDave Chinner if (be16_to_cpu(dfp->offset) == off) 54130f712c9SDave Chinner return dfp; 54230f712c9SDave Chinner } 54330f712c9SDave Chinner /* 54430f712c9SDave Chinner * Didn't find it. This only happens if there are duplicate lengths. 54530f712c9SDave Chinner */ 54630f712c9SDave Chinner return NULL; 54730f712c9SDave Chinner } 54830f712c9SDave Chinner 54930f712c9SDave Chinner /* 55030f712c9SDave Chinner * Insert an unused-space entry into the bestfree table. 55130f712c9SDave Chinner */ 55230f712c9SDave Chinner xfs_dir2_data_free_t * /* entry inserted */ 55330f712c9SDave Chinner xfs_dir2_data_freeinsert( 55430f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr, /* data block pointer */ 55530f712c9SDave Chinner struct xfs_dir2_data_free *dfp, /* bestfree table pointer */ 55630f712c9SDave Chinner struct xfs_dir2_data_unused *dup, /* unused space */ 55730f712c9SDave Chinner int *loghead) /* log the data header (out) */ 55830f712c9SDave Chinner { 55930f712c9SDave Chinner xfs_dir2_data_free_t new; /* new bestfree entry */ 56030f712c9SDave Chinner 56130f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 56230f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 56330f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 56430f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 56530f712c9SDave Chinner 56630f712c9SDave Chinner new.length = dup->length; 56730f712c9SDave Chinner new.offset = cpu_to_be16((char *)dup - (char *)hdr); 56830f712c9SDave Chinner 56930f712c9SDave Chinner /* 57030f712c9SDave Chinner * Insert at position 0, 1, or 2; or not at all. 57130f712c9SDave Chinner */ 57230f712c9SDave Chinner if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) { 57330f712c9SDave Chinner dfp[2] = dfp[1]; 57430f712c9SDave Chinner dfp[1] = dfp[0]; 57530f712c9SDave Chinner dfp[0] = new; 57630f712c9SDave Chinner *loghead = 1; 57730f712c9SDave Chinner return &dfp[0]; 57830f712c9SDave Chinner } 57930f712c9SDave Chinner if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) { 58030f712c9SDave Chinner dfp[2] = dfp[1]; 58130f712c9SDave Chinner dfp[1] = new; 58230f712c9SDave Chinner *loghead = 1; 58330f712c9SDave Chinner return &dfp[1]; 58430f712c9SDave Chinner } 58530f712c9SDave Chinner if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) { 58630f712c9SDave Chinner dfp[2] = new; 58730f712c9SDave Chinner *loghead = 1; 58830f712c9SDave Chinner return &dfp[2]; 58930f712c9SDave Chinner } 59030f712c9SDave Chinner return NULL; 59130f712c9SDave Chinner } 59230f712c9SDave Chinner 59330f712c9SDave Chinner /* 59430f712c9SDave Chinner * Remove a bestfree entry from the table. 59530f712c9SDave Chinner */ 59630f712c9SDave Chinner STATIC void 59730f712c9SDave Chinner xfs_dir2_data_freeremove( 59830f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr, /* data block header */ 59930f712c9SDave Chinner struct xfs_dir2_data_free *bf, /* bestfree table pointer */ 60030f712c9SDave Chinner struct xfs_dir2_data_free *dfp, /* bestfree entry pointer */ 60130f712c9SDave Chinner int *loghead) /* out: log data header */ 60230f712c9SDave Chinner { 60330f712c9SDave Chinner 60430f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 60530f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 60630f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 60730f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 60830f712c9SDave Chinner 60930f712c9SDave Chinner /* 61030f712c9SDave Chinner * It's the first entry, slide the next 2 up. 61130f712c9SDave Chinner */ 61230f712c9SDave Chinner if (dfp == &bf[0]) { 61330f712c9SDave Chinner bf[0] = bf[1]; 61430f712c9SDave Chinner bf[1] = bf[2]; 61530f712c9SDave Chinner } 61630f712c9SDave Chinner /* 61730f712c9SDave Chinner * It's the second entry, slide the 3rd entry up. 61830f712c9SDave Chinner */ 61930f712c9SDave Chinner else if (dfp == &bf[1]) 62030f712c9SDave Chinner bf[1] = bf[2]; 62130f712c9SDave Chinner /* 62230f712c9SDave Chinner * Must be the last entry. 62330f712c9SDave Chinner */ 62430f712c9SDave Chinner else 62530f712c9SDave Chinner ASSERT(dfp == &bf[2]); 62630f712c9SDave Chinner /* 62730f712c9SDave Chinner * Clear the 3rd entry, must be zero now. 62830f712c9SDave Chinner */ 62930f712c9SDave Chinner bf[2].length = 0; 63030f712c9SDave Chinner bf[2].offset = 0; 63130f712c9SDave Chinner *loghead = 1; 63230f712c9SDave Chinner } 63330f712c9SDave Chinner 63430f712c9SDave Chinner /* 63530f712c9SDave Chinner * Given a data block, reconstruct its bestfree map. 63630f712c9SDave Chinner */ 63730f712c9SDave Chinner void 638ae42976dSChristoph Hellwig xfs_dir2_data_freescan( 639fdbb8c5bSChristoph Hellwig struct xfs_mount *mp, 64030f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr, 64130f712c9SDave Chinner int *loghead) 64230f712c9SDave Chinner { 643d73e1ceeSChristoph Hellwig struct xfs_da_geometry *geo = mp->m_dir_geo; 6441848b607SChristoph Hellwig struct xfs_dir2_data_free *bf = xfs_dir2_data_bestfree_p(mp, hdr); 64562479f57SChristoph Hellwig void *addr = hdr; 646d73e1ceeSChristoph Hellwig unsigned int offset = geo->data_entry_offset; 64762479f57SChristoph Hellwig unsigned int end; 64830f712c9SDave Chinner 64930f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 65030f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 65130f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 65230f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 65330f712c9SDave Chinner 65430f712c9SDave Chinner /* 65530f712c9SDave Chinner * Start by clearing the table. 65630f712c9SDave Chinner */ 65730f712c9SDave Chinner memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT); 65830f712c9SDave Chinner *loghead = 1; 65962479f57SChristoph Hellwig 660d73e1ceeSChristoph Hellwig end = xfs_dir3_data_end_offset(geo, addr); 66162479f57SChristoph Hellwig while (offset < end) { 66262479f57SChristoph Hellwig struct xfs_dir2_data_unused *dup = addr + offset; 66362479f57SChristoph Hellwig struct xfs_dir2_data_entry *dep = addr + offset; 66462479f57SChristoph Hellwig 66530f712c9SDave Chinner /* 66630f712c9SDave Chinner * If it's a free entry, insert it. 66730f712c9SDave Chinner */ 66830f712c9SDave Chinner if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { 66962479f57SChristoph Hellwig ASSERT(offset == 67030f712c9SDave Chinner be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup))); 67130f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, dup, loghead); 67262479f57SChristoph Hellwig offset += be16_to_cpu(dup->length); 67362479f57SChristoph Hellwig continue; 67430f712c9SDave Chinner } 67562479f57SChristoph Hellwig 67630f712c9SDave Chinner /* 67730f712c9SDave Chinner * For active entries, check their tags and skip them. 67830f712c9SDave Chinner */ 6797e8ae7bdSChristoph Hellwig ASSERT(offset == 6807e8ae7bdSChristoph Hellwig be16_to_cpu(*xfs_dir2_data_entry_tag_p(mp, dep))); 681fdbb8c5bSChristoph Hellwig offset += xfs_dir2_data_entsize(mp, dep->namelen); 68230f712c9SDave Chinner } 68330f712c9SDave Chinner } 68430f712c9SDave Chinner 68530f712c9SDave Chinner /* 68630f712c9SDave Chinner * Initialize a data block at the given block number in the directory. 68730f712c9SDave Chinner * Give back the buffer for the created block. 68830f712c9SDave Chinner */ 68930f712c9SDave Chinner int /* error */ 69030f712c9SDave Chinner xfs_dir3_data_init( 691ee641d5aSChristoph Hellwig struct xfs_da_args *args, /* directory operation args */ 69230f712c9SDave Chinner xfs_dir2_db_t blkno, /* logical dir block number */ 69330f712c9SDave Chinner struct xfs_buf **bpp) /* output block buffer */ 69430f712c9SDave Chinner { 695ee641d5aSChristoph Hellwig struct xfs_trans *tp = args->trans; 696ee641d5aSChristoph Hellwig struct xfs_inode *dp = args->dp; 697ee641d5aSChristoph Hellwig struct xfs_mount *mp = dp->i_mount; 698d73e1ceeSChristoph Hellwig struct xfs_da_geometry *geo = args->geo; 699ee641d5aSChristoph Hellwig struct xfs_buf *bp; 700ee641d5aSChristoph Hellwig struct xfs_dir2_data_hdr *hdr; 701ee641d5aSChristoph Hellwig struct xfs_dir2_data_unused *dup; 70230f712c9SDave Chinner struct xfs_dir2_data_free *bf; 703ee641d5aSChristoph Hellwig int error; 704ee641d5aSChristoph Hellwig int i; 70530f712c9SDave Chinner 70630f712c9SDave Chinner /* 70730f712c9SDave Chinner * Get the buffer set up for the block. 70830f712c9SDave Chinner */ 70930f712c9SDave Chinner error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno), 7102911edb6SChristoph Hellwig &bp, XFS_DATA_FORK); 71130f712c9SDave Chinner if (error) 71230f712c9SDave Chinner return error; 71330f712c9SDave Chinner bp->b_ops = &xfs_dir3_data_buf_ops; 71430f712c9SDave Chinner xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_DATA_BUF); 71530f712c9SDave Chinner 71630f712c9SDave Chinner /* 71730f712c9SDave Chinner * Initialize the header. 71830f712c9SDave Chinner */ 71930f712c9SDave Chinner hdr = bp->b_addr; 72038c26bfdSDave Chinner if (xfs_has_crc(mp)) { 72130f712c9SDave Chinner struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; 72230f712c9SDave Chinner 72330f712c9SDave Chinner memset(hdr3, 0, sizeof(*hdr3)); 72430f712c9SDave Chinner hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC); 725*9343ee76SDave Chinner hdr3->blkno = cpu_to_be64(xfs_buf_daddr(bp)); 72630f712c9SDave Chinner hdr3->owner = cpu_to_be64(dp->i_ino); 727ce748eaaSEric Sandeen uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid); 72830f712c9SDave Chinner 72930f712c9SDave Chinner } else 73030f712c9SDave Chinner hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC); 73130f712c9SDave Chinner 7321848b607SChristoph Hellwig bf = xfs_dir2_data_bestfree_p(mp, hdr); 733d73e1ceeSChristoph Hellwig bf[0].offset = cpu_to_be16(geo->data_entry_offset); 734d73e1ceeSChristoph Hellwig bf[0].length = cpu_to_be16(geo->blksize - geo->data_entry_offset); 73530f712c9SDave Chinner for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { 73630f712c9SDave Chinner bf[i].length = 0; 73730f712c9SDave Chinner bf[i].offset = 0; 73830f712c9SDave Chinner } 73930f712c9SDave Chinner 74030f712c9SDave Chinner /* 74130f712c9SDave Chinner * Set up an unused entry for the block's body. 74230f712c9SDave Chinner */ 743d73e1ceeSChristoph Hellwig dup = bp->b_addr + geo->data_entry_offset; 74430f712c9SDave Chinner dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); 745ee641d5aSChristoph Hellwig dup->length = bf[0].length; 74630f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr); 747ee641d5aSChristoph Hellwig 74830f712c9SDave Chinner /* 74930f712c9SDave Chinner * Log it and return it. 75030f712c9SDave Chinner */ 75130f712c9SDave Chinner xfs_dir2_data_log_header(args, bp); 75230f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, dup); 75330f712c9SDave Chinner *bpp = bp; 75430f712c9SDave Chinner return 0; 75530f712c9SDave Chinner } 75630f712c9SDave Chinner 75730f712c9SDave Chinner /* 75830f712c9SDave Chinner * Log an active data entry from the block. 75930f712c9SDave Chinner */ 76030f712c9SDave Chinner void 76130f712c9SDave Chinner xfs_dir2_data_log_entry( 76230f712c9SDave Chinner struct xfs_da_args *args, 76330f712c9SDave Chinner struct xfs_buf *bp, 76430f712c9SDave Chinner xfs_dir2_data_entry_t *dep) /* data entry pointer */ 76530f712c9SDave Chinner { 7667e8ae7bdSChristoph Hellwig struct xfs_mount *mp = bp->b_mount; 76730f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr = bp->b_addr; 76830f712c9SDave Chinner 76930f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 77030f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 77130f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 77230f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 77330f712c9SDave Chinner 77430f712c9SDave Chinner xfs_trans_log_buf(args->trans, bp, (uint)((char *)dep - (char *)hdr), 7757e8ae7bdSChristoph Hellwig (uint)((char *)(xfs_dir2_data_entry_tag_p(mp, dep) + 1) - 77630f712c9SDave Chinner (char *)hdr - 1)); 77730f712c9SDave Chinner } 77830f712c9SDave Chinner 77930f712c9SDave Chinner /* 78030f712c9SDave Chinner * Log a data block header. 78130f712c9SDave Chinner */ 78230f712c9SDave Chinner void 78330f712c9SDave Chinner xfs_dir2_data_log_header( 78430f712c9SDave Chinner struct xfs_da_args *args, 78530f712c9SDave Chinner struct xfs_buf *bp) 78630f712c9SDave Chinner { 78730f712c9SDave Chinner #ifdef DEBUG 78830f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr = bp->b_addr; 78930f712c9SDave Chinner 79030f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 79130f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 79230f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 79330f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 79430f712c9SDave Chinner #endif 79530f712c9SDave Chinner 796d73e1ceeSChristoph Hellwig xfs_trans_log_buf(args->trans, bp, 0, args->geo->data_entry_offset - 1); 79730f712c9SDave Chinner } 79830f712c9SDave Chinner 79930f712c9SDave Chinner /* 80030f712c9SDave Chinner * Log a data unused entry. 80130f712c9SDave Chinner */ 80230f712c9SDave Chinner void 80330f712c9SDave Chinner xfs_dir2_data_log_unused( 80430f712c9SDave Chinner struct xfs_da_args *args, 80530f712c9SDave Chinner struct xfs_buf *bp, 80630f712c9SDave Chinner xfs_dir2_data_unused_t *dup) /* data unused pointer */ 80730f712c9SDave Chinner { 80830f712c9SDave Chinner xfs_dir2_data_hdr_t *hdr = bp->b_addr; 80930f712c9SDave Chinner 81030f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 81130f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 81230f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 81330f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 81430f712c9SDave Chinner 81530f712c9SDave Chinner /* 81630f712c9SDave Chinner * Log the first part of the unused entry. 81730f712c9SDave Chinner */ 81830f712c9SDave Chinner xfs_trans_log_buf(args->trans, bp, (uint)((char *)dup - (char *)hdr), 81930f712c9SDave Chinner (uint)((char *)&dup->length + sizeof(dup->length) - 82030f712c9SDave Chinner 1 - (char *)hdr)); 82130f712c9SDave Chinner /* 82230f712c9SDave Chinner * Log the end (tag) of the unused entry. 82330f712c9SDave Chinner */ 82430f712c9SDave Chinner xfs_trans_log_buf(args->trans, bp, 82530f712c9SDave Chinner (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr), 82630f712c9SDave Chinner (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr + 82730f712c9SDave Chinner sizeof(xfs_dir2_data_off_t) - 1)); 82830f712c9SDave Chinner } 82930f712c9SDave Chinner 83030f712c9SDave Chinner /* 83130f712c9SDave Chinner * Make a byte range in the data block unused. 83230f712c9SDave Chinner * Its current contents are unimportant. 83330f712c9SDave Chinner */ 83430f712c9SDave Chinner void 83530f712c9SDave Chinner xfs_dir2_data_make_free( 83630f712c9SDave Chinner struct xfs_da_args *args, 83730f712c9SDave Chinner struct xfs_buf *bp, 83830f712c9SDave Chinner xfs_dir2_data_aoff_t offset, /* starting byte offset */ 83930f712c9SDave Chinner xfs_dir2_data_aoff_t len, /* length in bytes */ 84030f712c9SDave Chinner int *needlogp, /* out: log header */ 84130f712c9SDave Chinner int *needscanp) /* out: regen bestfree */ 84230f712c9SDave Chinner { 84330f712c9SDave Chinner xfs_dir2_data_hdr_t *hdr; /* data block pointer */ 84430f712c9SDave Chinner xfs_dir2_data_free_t *dfp; /* bestfree pointer */ 84530f712c9SDave Chinner int needscan; /* need to regen bestfree */ 84630f712c9SDave Chinner xfs_dir2_data_unused_t *newdup; /* new unused entry */ 84730f712c9SDave Chinner xfs_dir2_data_unused_t *postdup; /* unused entry after us */ 84830f712c9SDave Chinner xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ 8495c072127SChristoph Hellwig unsigned int end; 85030f712c9SDave Chinner struct xfs_dir2_data_free *bf; 85130f712c9SDave Chinner 85230f712c9SDave Chinner hdr = bp->b_addr; 85330f712c9SDave Chinner 85430f712c9SDave Chinner /* 85530f712c9SDave Chinner * Figure out where the end of the data area is. 85630f712c9SDave Chinner */ 8575c072127SChristoph Hellwig end = xfs_dir3_data_end_offset(args->geo, hdr); 8585c072127SChristoph Hellwig ASSERT(end != 0); 85930f712c9SDave Chinner 86030f712c9SDave Chinner /* 86130f712c9SDave Chinner * If this isn't the start of the block, then back up to 86230f712c9SDave Chinner * the previous entry and see if it's free. 86330f712c9SDave Chinner */ 864d73e1ceeSChristoph Hellwig if (offset > args->geo->data_entry_offset) { 86530f712c9SDave Chinner __be16 *tagp; /* tag just before us */ 86630f712c9SDave Chinner 86730f712c9SDave Chinner tagp = (__be16 *)((char *)hdr + offset) - 1; 86830f712c9SDave Chinner prevdup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); 86930f712c9SDave Chinner if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG) 87030f712c9SDave Chinner prevdup = NULL; 87130f712c9SDave Chinner } else 87230f712c9SDave Chinner prevdup = NULL; 87330f712c9SDave Chinner /* 87430f712c9SDave Chinner * If this isn't the end of the block, see if the entry after 87530f712c9SDave Chinner * us is free. 87630f712c9SDave Chinner */ 8775c072127SChristoph Hellwig if (offset + len < end) { 87830f712c9SDave Chinner postdup = 87930f712c9SDave Chinner (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); 88030f712c9SDave Chinner if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG) 88130f712c9SDave Chinner postdup = NULL; 88230f712c9SDave Chinner } else 88330f712c9SDave Chinner postdup = NULL; 88430f712c9SDave Chinner ASSERT(*needscanp == 0); 88530f712c9SDave Chinner needscan = 0; 88630f712c9SDave Chinner /* 88730f712c9SDave Chinner * Previous and following entries are both free, 88830f712c9SDave Chinner * merge everything into a single free entry. 88930f712c9SDave Chinner */ 8901848b607SChristoph Hellwig bf = xfs_dir2_data_bestfree_p(args->dp->i_mount, hdr); 89130f712c9SDave Chinner if (prevdup && postdup) { 89230f712c9SDave Chinner xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ 89330f712c9SDave Chinner 89430f712c9SDave Chinner /* 89530f712c9SDave Chinner * See if prevdup and/or postdup are in bestfree table. 89630f712c9SDave Chinner */ 89730f712c9SDave Chinner dfp = xfs_dir2_data_freefind(hdr, bf, prevdup); 89830f712c9SDave Chinner dfp2 = xfs_dir2_data_freefind(hdr, bf, postdup); 89930f712c9SDave Chinner /* 90030f712c9SDave Chinner * We need a rescan unless there are exactly 2 free entries 90130f712c9SDave Chinner * namely our two. Then we know what's happening, otherwise 90230f712c9SDave Chinner * since the third bestfree is there, there might be more 90330f712c9SDave Chinner * entries. 90430f712c9SDave Chinner */ 90530f712c9SDave Chinner needscan = (bf[2].length != 0); 90630f712c9SDave Chinner /* 90730f712c9SDave Chinner * Fix up the new big freespace. 90830f712c9SDave Chinner */ 90930f712c9SDave Chinner be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length)); 91030f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(prevdup) = 91130f712c9SDave Chinner cpu_to_be16((char *)prevdup - (char *)hdr); 91230f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, prevdup); 91330f712c9SDave Chinner if (!needscan) { 91430f712c9SDave Chinner /* 91530f712c9SDave Chinner * Has to be the case that entries 0 and 1 are 91630f712c9SDave Chinner * dfp and dfp2 (don't know which is which), and 91730f712c9SDave Chinner * entry 2 is empty. 91830f712c9SDave Chinner * Remove entry 1 first then entry 0. 91930f712c9SDave Chinner */ 92030f712c9SDave Chinner ASSERT(dfp && dfp2); 92130f712c9SDave Chinner if (dfp == &bf[1]) { 92230f712c9SDave Chinner dfp = &bf[0]; 92330f712c9SDave Chinner ASSERT(dfp2 == dfp); 92430f712c9SDave Chinner dfp2 = &bf[1]; 92530f712c9SDave Chinner } 92630f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp2, needlogp); 92730f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); 92830f712c9SDave Chinner /* 92930f712c9SDave Chinner * Now insert the new entry. 93030f712c9SDave Chinner */ 93130f712c9SDave Chinner dfp = xfs_dir2_data_freeinsert(hdr, bf, prevdup, 93230f712c9SDave Chinner needlogp); 93330f712c9SDave Chinner ASSERT(dfp == &bf[0]); 93430f712c9SDave Chinner ASSERT(dfp->length == prevdup->length); 93530f712c9SDave Chinner ASSERT(!dfp[1].length); 93630f712c9SDave Chinner ASSERT(!dfp[2].length); 93730f712c9SDave Chinner } 93830f712c9SDave Chinner } 93930f712c9SDave Chinner /* 94030f712c9SDave Chinner * The entry before us is free, merge with it. 94130f712c9SDave Chinner */ 94230f712c9SDave Chinner else if (prevdup) { 94330f712c9SDave Chinner dfp = xfs_dir2_data_freefind(hdr, bf, prevdup); 94430f712c9SDave Chinner be16_add_cpu(&prevdup->length, len); 94530f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(prevdup) = 94630f712c9SDave Chinner cpu_to_be16((char *)prevdup - (char *)hdr); 94730f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, prevdup); 94830f712c9SDave Chinner /* 94930f712c9SDave Chinner * If the previous entry was in the table, the new entry 95030f712c9SDave Chinner * is longer, so it will be in the table too. Remove 95130f712c9SDave Chinner * the old one and add the new one. 95230f712c9SDave Chinner */ 95330f712c9SDave Chinner if (dfp) { 95430f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); 95530f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, prevdup, needlogp); 95630f712c9SDave Chinner } 95730f712c9SDave Chinner /* 95830f712c9SDave Chinner * Otherwise we need a scan if the new entry is big enough. 95930f712c9SDave Chinner */ 96030f712c9SDave Chinner else { 96130f712c9SDave Chinner needscan = be16_to_cpu(prevdup->length) > 96230f712c9SDave Chinner be16_to_cpu(bf[2].length); 96330f712c9SDave Chinner } 96430f712c9SDave Chinner } 96530f712c9SDave Chinner /* 96630f712c9SDave Chinner * The following entry is free, merge with it. 96730f712c9SDave Chinner */ 96830f712c9SDave Chinner else if (postdup) { 96930f712c9SDave Chinner dfp = xfs_dir2_data_freefind(hdr, bf, postdup); 97030f712c9SDave Chinner newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); 97130f712c9SDave Chinner newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); 97230f712c9SDave Chinner newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length)); 97330f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup) = 97430f712c9SDave Chinner cpu_to_be16((char *)newdup - (char *)hdr); 97530f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup); 97630f712c9SDave Chinner /* 97730f712c9SDave Chinner * If the following entry was in the table, the new entry 97830f712c9SDave Chinner * is longer, so it will be in the table too. Remove 97930f712c9SDave Chinner * the old one and add the new one. 98030f712c9SDave Chinner */ 98130f712c9SDave Chinner if (dfp) { 98230f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); 98330f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); 98430f712c9SDave Chinner } 98530f712c9SDave Chinner /* 98630f712c9SDave Chinner * Otherwise we need a scan if the new entry is big enough. 98730f712c9SDave Chinner */ 98830f712c9SDave Chinner else { 98930f712c9SDave Chinner needscan = be16_to_cpu(newdup->length) > 99030f712c9SDave Chinner be16_to_cpu(bf[2].length); 99130f712c9SDave Chinner } 99230f712c9SDave Chinner } 99330f712c9SDave Chinner /* 99430f712c9SDave Chinner * Neither neighbor is free. Make a new entry. 99530f712c9SDave Chinner */ 99630f712c9SDave Chinner else { 99730f712c9SDave Chinner newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); 99830f712c9SDave Chinner newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); 99930f712c9SDave Chinner newdup->length = cpu_to_be16(len); 100030f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup) = 100130f712c9SDave Chinner cpu_to_be16((char *)newdup - (char *)hdr); 100230f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup); 100330f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); 100430f712c9SDave Chinner } 100530f712c9SDave Chinner *needscanp = needscan; 100630f712c9SDave Chinner } 100730f712c9SDave Chinner 10086915ef35SDarrick J. Wong /* Check our free data for obvious signs of corruption. */ 10096915ef35SDarrick J. Wong static inline xfs_failaddr_t 10106915ef35SDarrick J. Wong xfs_dir2_data_check_free( 10116915ef35SDarrick J. Wong struct xfs_dir2_data_hdr *hdr, 10126915ef35SDarrick J. Wong struct xfs_dir2_data_unused *dup, 10136915ef35SDarrick J. Wong xfs_dir2_data_aoff_t offset, 10146915ef35SDarrick J. Wong xfs_dir2_data_aoff_t len) 10156915ef35SDarrick J. Wong { 10166915ef35SDarrick J. Wong if (hdr->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC) && 10176915ef35SDarrick J. Wong hdr->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC) && 10186915ef35SDarrick J. Wong hdr->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) && 10196915ef35SDarrick J. Wong hdr->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) 10206915ef35SDarrick J. Wong return __this_address; 10216915ef35SDarrick J. Wong if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG) 10226915ef35SDarrick J. Wong return __this_address; 10236915ef35SDarrick J. Wong if (offset < (char *)dup - (char *)hdr) 10246915ef35SDarrick J. Wong return __this_address; 10256915ef35SDarrick J. Wong if (offset + len > (char *)dup + be16_to_cpu(dup->length) - (char *)hdr) 10266915ef35SDarrick J. Wong return __this_address; 10276915ef35SDarrick J. Wong if ((char *)dup - (char *)hdr != 10286915ef35SDarrick J. Wong be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup))) 10296915ef35SDarrick J. Wong return __this_address; 10306915ef35SDarrick J. Wong return NULL; 10316915ef35SDarrick J. Wong } 10326915ef35SDarrick J. Wong 10336915ef35SDarrick J. Wong /* Sanity-check a new bestfree entry. */ 10346915ef35SDarrick J. Wong static inline xfs_failaddr_t 10356915ef35SDarrick J. Wong xfs_dir2_data_check_new_free( 10366915ef35SDarrick J. Wong struct xfs_dir2_data_hdr *hdr, 10376915ef35SDarrick J. Wong struct xfs_dir2_data_free *dfp, 10386915ef35SDarrick J. Wong struct xfs_dir2_data_unused *newdup) 10396915ef35SDarrick J. Wong { 10406915ef35SDarrick J. Wong if (dfp == NULL) 10416915ef35SDarrick J. Wong return __this_address; 10426915ef35SDarrick J. Wong if (dfp->length != newdup->length) 10436915ef35SDarrick J. Wong return __this_address; 10446915ef35SDarrick J. Wong if (be16_to_cpu(dfp->offset) != (char *)newdup - (char *)hdr) 10456915ef35SDarrick J. Wong return __this_address; 10466915ef35SDarrick J. Wong return NULL; 10476915ef35SDarrick J. Wong } 10486915ef35SDarrick J. Wong 104930f712c9SDave Chinner /* 105030f712c9SDave Chinner * Take a byte range out of an existing unused space and make it un-free. 105130f712c9SDave Chinner */ 10526915ef35SDarrick J. Wong int 105330f712c9SDave Chinner xfs_dir2_data_use_free( 105430f712c9SDave Chinner struct xfs_da_args *args, 105530f712c9SDave Chinner struct xfs_buf *bp, 105630f712c9SDave Chinner xfs_dir2_data_unused_t *dup, /* unused entry */ 105730f712c9SDave Chinner xfs_dir2_data_aoff_t offset, /* starting offset to use */ 105830f712c9SDave Chinner xfs_dir2_data_aoff_t len, /* length to use */ 105930f712c9SDave Chinner int *needlogp, /* out: need to log header */ 106030f712c9SDave Chinner int *needscanp) /* out: need regen bestfree */ 106130f712c9SDave Chinner { 106230f712c9SDave Chinner xfs_dir2_data_hdr_t *hdr; /* data block header */ 106330f712c9SDave Chinner xfs_dir2_data_free_t *dfp; /* bestfree pointer */ 10646915ef35SDarrick J. Wong xfs_dir2_data_unused_t *newdup; /* new unused entry */ 10656915ef35SDarrick J. Wong xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ 10666915ef35SDarrick J. Wong struct xfs_dir2_data_free *bf; 10676915ef35SDarrick J. Wong xfs_failaddr_t fa; 106830f712c9SDave Chinner int matchback; /* matches end of freespace */ 106930f712c9SDave Chinner int matchfront; /* matches start of freespace */ 107030f712c9SDave Chinner int needscan; /* need to regen bestfree */ 107130f712c9SDave Chinner int oldlen; /* old unused entry's length */ 107230f712c9SDave Chinner 107330f712c9SDave Chinner hdr = bp->b_addr; 10746915ef35SDarrick J. Wong fa = xfs_dir2_data_check_free(hdr, dup, offset, len); 10756915ef35SDarrick J. Wong if (fa) 10766915ef35SDarrick J. Wong goto corrupt; 107730f712c9SDave Chinner /* 107830f712c9SDave Chinner * Look up the entry in the bestfree table. 107930f712c9SDave Chinner */ 108030f712c9SDave Chinner oldlen = be16_to_cpu(dup->length); 10811848b607SChristoph Hellwig bf = xfs_dir2_data_bestfree_p(args->dp->i_mount, hdr); 108230f712c9SDave Chinner dfp = xfs_dir2_data_freefind(hdr, bf, dup); 108330f712c9SDave Chinner ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length)); 108430f712c9SDave Chinner /* 108530f712c9SDave Chinner * Check for alignment with front and back of the entry. 108630f712c9SDave Chinner */ 108730f712c9SDave Chinner matchfront = (char *)dup - (char *)hdr == offset; 108830f712c9SDave Chinner matchback = (char *)dup + oldlen - (char *)hdr == offset + len; 108930f712c9SDave Chinner ASSERT(*needscanp == 0); 109030f712c9SDave Chinner needscan = 0; 109130f712c9SDave Chinner /* 109230f712c9SDave Chinner * If we matched it exactly we just need to get rid of it from 109330f712c9SDave Chinner * the bestfree table. 109430f712c9SDave Chinner */ 109530f712c9SDave Chinner if (matchfront && matchback) { 109630f712c9SDave Chinner if (dfp) { 109730f712c9SDave Chinner needscan = (bf[2].offset != 0); 109830f712c9SDave Chinner if (!needscan) 109930f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, 110030f712c9SDave Chinner needlogp); 110130f712c9SDave Chinner } 110230f712c9SDave Chinner } 110330f712c9SDave Chinner /* 110430f712c9SDave Chinner * We match the first part of the entry. 110530f712c9SDave Chinner * Make a new entry with the remaining freespace. 110630f712c9SDave Chinner */ 110730f712c9SDave Chinner else if (matchfront) { 110830f712c9SDave Chinner newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); 110930f712c9SDave Chinner newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); 111030f712c9SDave Chinner newdup->length = cpu_to_be16(oldlen - len); 111130f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup) = 111230f712c9SDave Chinner cpu_to_be16((char *)newdup - (char *)hdr); 111330f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup); 111430f712c9SDave Chinner /* 111530f712c9SDave Chinner * If it was in the table, remove it and add the new one. 111630f712c9SDave Chinner */ 111730f712c9SDave Chinner if (dfp) { 111830f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); 111930f712c9SDave Chinner dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup, 112030f712c9SDave Chinner needlogp); 11216915ef35SDarrick J. Wong fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup); 11226915ef35SDarrick J. Wong if (fa) 11236915ef35SDarrick J. Wong goto corrupt; 112430f712c9SDave Chinner /* 112530f712c9SDave Chinner * If we got inserted at the last slot, 112630f712c9SDave Chinner * that means we don't know if there was a better 112730f712c9SDave Chinner * choice for the last slot, or not. Rescan. 112830f712c9SDave Chinner */ 112930f712c9SDave Chinner needscan = dfp == &bf[2]; 113030f712c9SDave Chinner } 113130f712c9SDave Chinner } 113230f712c9SDave Chinner /* 113330f712c9SDave Chinner * We match the last part of the entry. 113430f712c9SDave Chinner * Trim the allocated space off the tail of the entry. 113530f712c9SDave Chinner */ 113630f712c9SDave Chinner else if (matchback) { 113730f712c9SDave Chinner newdup = dup; 113830f712c9SDave Chinner newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup); 113930f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup) = 114030f712c9SDave Chinner cpu_to_be16((char *)newdup - (char *)hdr); 114130f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup); 114230f712c9SDave Chinner /* 114330f712c9SDave Chinner * If it was in the table, remove it and add the new one. 114430f712c9SDave Chinner */ 114530f712c9SDave Chinner if (dfp) { 114630f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); 114730f712c9SDave Chinner dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup, 114830f712c9SDave Chinner needlogp); 11496915ef35SDarrick J. Wong fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup); 11506915ef35SDarrick J. Wong if (fa) 11516915ef35SDarrick J. Wong goto corrupt; 115230f712c9SDave Chinner /* 115330f712c9SDave Chinner * If we got inserted at the last slot, 115430f712c9SDave Chinner * that means we don't know if there was a better 115530f712c9SDave Chinner * choice for the last slot, or not. Rescan. 115630f712c9SDave Chinner */ 115730f712c9SDave Chinner needscan = dfp == &bf[2]; 115830f712c9SDave Chinner } 115930f712c9SDave Chinner } 116030f712c9SDave Chinner /* 116130f712c9SDave Chinner * Poking out the middle of an entry. 116230f712c9SDave Chinner * Make two new entries. 116330f712c9SDave Chinner */ 116430f712c9SDave Chinner else { 116530f712c9SDave Chinner newdup = dup; 116630f712c9SDave Chinner newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup); 116730f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup) = 116830f712c9SDave Chinner cpu_to_be16((char *)newdup - (char *)hdr); 116930f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup); 117030f712c9SDave Chinner newdup2 = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); 117130f712c9SDave Chinner newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); 117230f712c9SDave Chinner newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length)); 117330f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup2) = 117430f712c9SDave Chinner cpu_to_be16((char *)newdup2 - (char *)hdr); 117530f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup2); 117630f712c9SDave Chinner /* 117730f712c9SDave Chinner * If the old entry was in the table, we need to scan 117830f712c9SDave Chinner * if the 3rd entry was valid, since these entries 117930f712c9SDave Chinner * are smaller than the old one. 118030f712c9SDave Chinner * If we don't need to scan that means there were 1 or 2 118130f712c9SDave Chinner * entries in the table, and removing the old and adding 118230f712c9SDave Chinner * the 2 new will work. 118330f712c9SDave Chinner */ 118430f712c9SDave Chinner if (dfp) { 118530f712c9SDave Chinner needscan = (bf[2].length != 0); 118630f712c9SDave Chinner if (!needscan) { 118730f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, 118830f712c9SDave Chinner needlogp); 118930f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, newdup, 119030f712c9SDave Chinner needlogp); 119130f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, newdup2, 119230f712c9SDave Chinner needlogp); 119330f712c9SDave Chinner } 119430f712c9SDave Chinner } 119530f712c9SDave Chinner } 119630f712c9SDave Chinner *needscanp = needscan; 11976915ef35SDarrick J. Wong return 0; 11986915ef35SDarrick J. Wong corrupt: 11996915ef35SDarrick J. Wong xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, args->dp->i_mount, 12002551a530SDarrick J. Wong hdr, sizeof(*hdr), __FILE__, __LINE__, fa); 12016915ef35SDarrick J. Wong return -EFSCORRUPTED; 120230f712c9SDave Chinner } 1203ce92d29dSDarrick J. Wong 1204ce92d29dSDarrick J. Wong /* Find the end of the entry data in a data/block format dir block. */ 12055c072127SChristoph Hellwig unsigned int 12065c072127SChristoph Hellwig xfs_dir3_data_end_offset( 1207ce92d29dSDarrick J. Wong struct xfs_da_geometry *geo, 1208ce92d29dSDarrick J. Wong struct xfs_dir2_data_hdr *hdr) 1209ce92d29dSDarrick J. Wong { 12105c072127SChristoph Hellwig void *p; 12115c072127SChristoph Hellwig 1212ce92d29dSDarrick J. Wong switch (hdr->magic) { 1213ce92d29dSDarrick J. Wong case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): 1214ce92d29dSDarrick J. Wong case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): 12155c072127SChristoph Hellwig p = xfs_dir2_block_leaf_p(xfs_dir2_block_tail_p(geo, hdr)); 12165c072127SChristoph Hellwig return p - (void *)hdr; 1217ce92d29dSDarrick J. Wong case cpu_to_be32(XFS_DIR3_DATA_MAGIC): 1218ce92d29dSDarrick J. Wong case cpu_to_be32(XFS_DIR2_DATA_MAGIC): 12195c072127SChristoph Hellwig return geo->blksize; 1220ce92d29dSDarrick J. Wong default: 12215c072127SChristoph Hellwig return 0; 1222ce92d29dSDarrick J. Wong } 1223ce92d29dSDarrick J. Wong } 1224