130f712c9SDave Chinner /* 230f712c9SDave Chinner * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. 330f712c9SDave Chinner * Copyright (c) 2013 Red Hat, Inc. 430f712c9SDave Chinner * All Rights Reserved. 530f712c9SDave Chinner * 630f712c9SDave Chinner * This program is free software; you can redistribute it and/or 730f712c9SDave Chinner * modify it under the terms of the GNU General Public License as 830f712c9SDave Chinner * published by the Free Software Foundation. 930f712c9SDave Chinner * 1030f712c9SDave Chinner * This program is distributed in the hope that it would be useful, 1130f712c9SDave Chinner * but WITHOUT ANY WARRANTY; without even the implied warranty of 1230f712c9SDave Chinner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1330f712c9SDave Chinner * GNU General Public License for more details. 1430f712c9SDave Chinner * 1530f712c9SDave Chinner * You should have received a copy of the GNU General Public License 1630f712c9SDave Chinner * along with this program; if not, write the Free Software Foundation, 1730f712c9SDave Chinner * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 1830f712c9SDave Chinner */ 1930f712c9SDave Chinner #include "xfs.h" 2030f712c9SDave Chinner #include "xfs_fs.h" 2130f712c9SDave Chinner #include "xfs_format.h" 2230f712c9SDave Chinner #include "xfs_log_format.h" 2330f712c9SDave Chinner #include "xfs_trans_resv.h" 2430f712c9SDave Chinner #include "xfs_mount.h" 2530f712c9SDave Chinner #include "xfs_da_format.h" 2630f712c9SDave Chinner #include "xfs_da_btree.h" 2730f712c9SDave Chinner #include "xfs_inode.h" 2830f712c9SDave Chinner #include "xfs_dir2.h" 2930f712c9SDave Chinner #include "xfs_dir2_priv.h" 3030f712c9SDave Chinner #include "xfs_error.h" 3130f712c9SDave Chinner #include "xfs_trans.h" 3230f712c9SDave Chinner #include "xfs_buf_item.h" 3330f712c9SDave Chinner #include "xfs_cksum.h" 34a45086e2SBrian Foster #include "xfs_log.h" 3530f712c9SDave Chinner 36*e4f45effSDarrick J. Wong static xfs_failaddr_t xfs_dir2_data_freefind_verify( 37*e4f45effSDarrick J. Wong struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf, 38*e4f45effSDarrick J. Wong struct xfs_dir2_data_unused *dup, 39*e4f45effSDarrick J. Wong struct xfs_dir2_data_free **bf_ent); 40*e4f45effSDarrick J. Wong 4130f712c9SDave Chinner /* 4230f712c9SDave Chinner * Check the consistency of the data block. 4330f712c9SDave Chinner * The input can also be a block-format directory. 44a6a781a5SDarrick J. Wong * Return NULL if the buffer is good, otherwise the address of the error. 4530f712c9SDave Chinner */ 46a6a781a5SDarrick J. Wong xfs_failaddr_t 4730f712c9SDave Chinner __xfs_dir3_data_check( 4830f712c9SDave Chinner struct xfs_inode *dp, /* incore inode pointer */ 4930f712c9SDave Chinner struct xfs_buf *bp) /* data block's buffer */ 5030f712c9SDave Chinner { 5130f712c9SDave Chinner xfs_dir2_dataptr_t addr; /* addr for leaf lookup */ 5230f712c9SDave Chinner xfs_dir2_data_free_t *bf; /* bestfree table */ 5330f712c9SDave Chinner xfs_dir2_block_tail_t *btp=NULL; /* block tail */ 5430f712c9SDave Chinner int count; /* count of entries found */ 5530f712c9SDave Chinner xfs_dir2_data_hdr_t *hdr; /* data block header */ 5630f712c9SDave Chinner xfs_dir2_data_entry_t *dep; /* data entry */ 5730f712c9SDave Chinner xfs_dir2_data_free_t *dfp; /* bestfree entry */ 5830f712c9SDave Chinner xfs_dir2_data_unused_t *dup; /* unused entry */ 5930f712c9SDave Chinner char *endp; /* end of useful data */ 6030f712c9SDave Chinner int freeseen; /* mask of bestfrees seen */ 6130f712c9SDave Chinner xfs_dahash_t hash; /* hash of current name */ 6230f712c9SDave Chinner int i; /* leaf index */ 6330f712c9SDave Chinner int lastfree; /* last entry was unused */ 6430f712c9SDave Chinner xfs_dir2_leaf_entry_t *lep=NULL; /* block leaf entries */ 6530f712c9SDave Chinner xfs_mount_t *mp; /* filesystem mount point */ 6630f712c9SDave Chinner char *p; /* current data position */ 6730f712c9SDave Chinner int stale; /* count of stale leaves */ 6830f712c9SDave Chinner struct xfs_name name; 6930f712c9SDave Chinner const struct xfs_dir_ops *ops; 7030f712c9SDave Chinner struct xfs_da_geometry *geo; 7130f712c9SDave Chinner 7230f712c9SDave Chinner mp = bp->b_target->bt_mount; 7330f712c9SDave Chinner geo = mp->m_dir_geo; 7430f712c9SDave Chinner 7530f712c9SDave Chinner /* 7630f712c9SDave Chinner * We can be passed a null dp here from a verifier, so we need to go the 7730f712c9SDave Chinner * hard way to get them. 7830f712c9SDave Chinner */ 7930f712c9SDave Chinner ops = xfs_dir_get_ops(mp, dp); 8030f712c9SDave Chinner 8146c59736SDarrick J. Wong /* 8246c59736SDarrick J. Wong * If this isn't a directory, or we don't get handed the dir ops, 8346c59736SDarrick J. Wong * something is seriously wrong. Bail out. 8446c59736SDarrick J. Wong */ 8546c59736SDarrick J. Wong if ((dp && !S_ISDIR(VFS_I(dp)->i_mode)) || 8646c59736SDarrick J. Wong ops != xfs_dir_get_ops(mp, NULL)) 8746c59736SDarrick J. Wong return __this_address; 8846c59736SDarrick J. Wong 8930f712c9SDave Chinner hdr = bp->b_addr; 9030f712c9SDave Chinner p = (char *)ops->data_entry_p(hdr); 9130f712c9SDave Chinner 9230f712c9SDave Chinner switch (hdr->magic) { 9330f712c9SDave Chinner case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): 9430f712c9SDave Chinner case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): 9530f712c9SDave Chinner btp = xfs_dir2_block_tail_p(geo, hdr); 9630f712c9SDave Chinner lep = xfs_dir2_block_leaf_p(btp); 9730f712c9SDave Chinner 9830f712c9SDave Chinner /* 9930f712c9SDave Chinner * The number of leaf entries is limited by the size of the 10030f712c9SDave Chinner * block and the amount of space used by the data entries. 10130f712c9SDave Chinner * We don't know how much space is used by the data entries yet, 10230f712c9SDave Chinner * so just ensure that the count falls somewhere inside the 10330f712c9SDave Chinner * block right now. 10430f712c9SDave Chinner */ 1059101d370SDarrick J. Wong if (be32_to_cpu(btp->count) >= 1069101d370SDarrick J. Wong ((char *)btp - p) / sizeof(struct xfs_dir2_leaf_entry)) 107a6a781a5SDarrick J. Wong return __this_address; 10830f712c9SDave Chinner break; 10930f712c9SDave Chinner case cpu_to_be32(XFS_DIR3_DATA_MAGIC): 11030f712c9SDave Chinner case cpu_to_be32(XFS_DIR2_DATA_MAGIC): 11130f712c9SDave Chinner break; 11230f712c9SDave Chinner default: 113a6a781a5SDarrick J. Wong return __this_address; 11430f712c9SDave Chinner } 115ce92d29dSDarrick J. Wong endp = xfs_dir3_data_endp(geo, hdr); 116ce92d29dSDarrick J. Wong if (!endp) 117ce92d29dSDarrick J. Wong return __this_address; 11830f712c9SDave Chinner 11930f712c9SDave Chinner /* 12030f712c9SDave Chinner * Account for zero bestfree entries. 12130f712c9SDave Chinner */ 12230f712c9SDave Chinner bf = ops->data_bestfree_p(hdr); 12330f712c9SDave Chinner count = lastfree = freeseen = 0; 12430f712c9SDave Chinner if (!bf[0].length) { 1259101d370SDarrick J. Wong if (bf[0].offset) 126a6a781a5SDarrick J. Wong return __this_address; 12730f712c9SDave Chinner freeseen |= 1 << 0; 12830f712c9SDave Chinner } 12930f712c9SDave Chinner if (!bf[1].length) { 1309101d370SDarrick J. Wong if (bf[1].offset) 131a6a781a5SDarrick J. Wong return __this_address; 13230f712c9SDave Chinner freeseen |= 1 << 1; 13330f712c9SDave Chinner } 13430f712c9SDave Chinner if (!bf[2].length) { 1359101d370SDarrick J. Wong if (bf[2].offset) 136a6a781a5SDarrick J. Wong return __this_address; 13730f712c9SDave Chinner freeseen |= 1 << 2; 13830f712c9SDave Chinner } 13930f712c9SDave Chinner 1409101d370SDarrick J. Wong if (be16_to_cpu(bf[0].length) < be16_to_cpu(bf[1].length)) 141a6a781a5SDarrick J. Wong return __this_address; 1429101d370SDarrick J. Wong if (be16_to_cpu(bf[1].length) < be16_to_cpu(bf[2].length)) 143a6a781a5SDarrick J. Wong return __this_address; 14430f712c9SDave Chinner /* 14530f712c9SDave Chinner * Loop over the data/unused entries. 14630f712c9SDave Chinner */ 14730f712c9SDave Chinner while (p < endp) { 14830f712c9SDave Chinner dup = (xfs_dir2_data_unused_t *)p; 14930f712c9SDave Chinner /* 15030f712c9SDave Chinner * If it's unused, look for the space in the bestfree table. 15130f712c9SDave Chinner * If we find it, account for that, else make sure it 15230f712c9SDave Chinner * doesn't need to be there. 15330f712c9SDave Chinner */ 15430f712c9SDave Chinner if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { 155*e4f45effSDarrick J. Wong xfs_failaddr_t fa; 156*e4f45effSDarrick J. Wong 1579101d370SDarrick J. Wong if (lastfree != 0) 158a6a781a5SDarrick J. Wong return __this_address; 1599101d370SDarrick J. Wong if (endp < p + be16_to_cpu(dup->length)) 160a6a781a5SDarrick J. Wong return __this_address; 1619101d370SDarrick J. Wong if (be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) != 1629101d370SDarrick J. Wong (char *)dup - (char *)hdr) 163a6a781a5SDarrick J. Wong return __this_address; 164*e4f45effSDarrick J. Wong fa = xfs_dir2_data_freefind_verify(hdr, bf, dup, &dfp); 165*e4f45effSDarrick J. Wong if (fa) 166*e4f45effSDarrick J. Wong return fa; 16730f712c9SDave Chinner if (dfp) { 16830f712c9SDave Chinner i = (int)(dfp - bf); 1699101d370SDarrick J. Wong if ((freeseen & (1 << i)) != 0) 170a6a781a5SDarrick J. Wong return __this_address; 17130f712c9SDave Chinner freeseen |= 1 << i; 17230f712c9SDave Chinner } else { 1739101d370SDarrick J. Wong if (be16_to_cpu(dup->length) > 1749101d370SDarrick J. Wong be16_to_cpu(bf[2].length)) 175a6a781a5SDarrick J. Wong return __this_address; 17630f712c9SDave Chinner } 17730f712c9SDave Chinner p += be16_to_cpu(dup->length); 17830f712c9SDave Chinner lastfree = 1; 17930f712c9SDave Chinner continue; 18030f712c9SDave Chinner } 18130f712c9SDave Chinner /* 18230f712c9SDave Chinner * It's a real entry. Validate the fields. 18330f712c9SDave Chinner * If this is a block directory then make sure it's 18430f712c9SDave Chinner * in the leaf section of the block. 18530f712c9SDave Chinner * The linear search is crude but this is DEBUG code. 18630f712c9SDave Chinner */ 18730f712c9SDave Chinner dep = (xfs_dir2_data_entry_t *)p; 1889101d370SDarrick J. Wong if (dep->namelen == 0) 189a6a781a5SDarrick J. Wong return __this_address; 1909101d370SDarrick J. Wong if (xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber))) 191a6a781a5SDarrick J. Wong return __this_address; 1929101d370SDarrick J. Wong if (endp < p + ops->data_entsize(dep->namelen)) 193a6a781a5SDarrick J. Wong return __this_address; 1949101d370SDarrick J. Wong if (be16_to_cpu(*ops->data_entry_tag_p(dep)) != 1959101d370SDarrick J. Wong (char *)dep - (char *)hdr) 196a6a781a5SDarrick J. Wong return __this_address; 1979101d370SDarrick J. Wong if (ops->data_get_ftype(dep) >= XFS_DIR3_FT_MAX) 198a6a781a5SDarrick J. Wong return __this_address; 19930f712c9SDave Chinner count++; 20030f712c9SDave Chinner lastfree = 0; 20130f712c9SDave Chinner if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 20230f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { 20330f712c9SDave Chinner addr = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, 20430f712c9SDave Chinner (xfs_dir2_data_aoff_t) 20530f712c9SDave Chinner ((char *)dep - (char *)hdr)); 20630f712c9SDave Chinner name.name = dep->name; 20730f712c9SDave Chinner name.len = dep->namelen; 20830f712c9SDave Chinner hash = mp->m_dirnameops->hashname(&name); 20930f712c9SDave Chinner for (i = 0; i < be32_to_cpu(btp->count); i++) { 21030f712c9SDave Chinner if (be32_to_cpu(lep[i].address) == addr && 21130f712c9SDave Chinner be32_to_cpu(lep[i].hashval) == hash) 21230f712c9SDave Chinner break; 21330f712c9SDave Chinner } 2149101d370SDarrick J. Wong if (i >= be32_to_cpu(btp->count)) 215a6a781a5SDarrick J. Wong return __this_address; 21630f712c9SDave Chinner } 21730f712c9SDave Chinner p += ops->data_entsize(dep->namelen); 21830f712c9SDave Chinner } 21930f712c9SDave Chinner /* 22030f712c9SDave Chinner * Need to have seen all the entries and all the bestfree slots. 22130f712c9SDave Chinner */ 2229101d370SDarrick J. Wong if (freeseen != 7) 223a6a781a5SDarrick J. Wong return __this_address; 22430f712c9SDave Chinner if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 22530f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { 22630f712c9SDave Chinner for (i = stale = 0; i < be32_to_cpu(btp->count); i++) { 22730f712c9SDave Chinner if (lep[i].address == 22830f712c9SDave Chinner cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) 22930f712c9SDave Chinner stale++; 2309101d370SDarrick J. Wong if (i > 0 && be32_to_cpu(lep[i].hashval) < 2319101d370SDarrick J. Wong be32_to_cpu(lep[i - 1].hashval)) 232a6a781a5SDarrick J. Wong return __this_address; 23330f712c9SDave Chinner } 2349101d370SDarrick J. Wong if (count != be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)) 235a6a781a5SDarrick J. Wong return __this_address; 2369101d370SDarrick J. Wong if (stale != be32_to_cpu(btp->stale)) 237a6a781a5SDarrick J. Wong return __this_address; 23830f712c9SDave Chinner } 239a6a781a5SDarrick J. Wong return NULL; 24030f712c9SDave Chinner } 24130f712c9SDave Chinner 242a6a781a5SDarrick J. Wong #ifdef DEBUG 243a6a781a5SDarrick J. Wong void 244a6a781a5SDarrick J. Wong xfs_dir3_data_check( 245a6a781a5SDarrick J. Wong struct xfs_inode *dp, 246a6a781a5SDarrick J. Wong struct xfs_buf *bp) 247a6a781a5SDarrick J. Wong { 248a6a781a5SDarrick J. Wong xfs_failaddr_t fa; 249a6a781a5SDarrick J. Wong 250a6a781a5SDarrick J. Wong fa = __xfs_dir3_data_check(dp, bp); 251a6a781a5SDarrick J. Wong if (!fa) 252a6a781a5SDarrick J. Wong return; 253a6a781a5SDarrick J. Wong xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, dp->i_mount, 254a6a781a5SDarrick J. Wong bp->b_addr, __FILE__, __LINE__, fa); 255a6a781a5SDarrick J. Wong ASSERT(0); 256a6a781a5SDarrick J. Wong } 257a6a781a5SDarrick J. Wong #endif 258a6a781a5SDarrick J. Wong 259a6a781a5SDarrick J. Wong static xfs_failaddr_t 26030f712c9SDave Chinner xfs_dir3_data_verify( 26130f712c9SDave Chinner struct xfs_buf *bp) 26230f712c9SDave Chinner { 26330f712c9SDave Chinner struct xfs_mount *mp = bp->b_target->bt_mount; 26430f712c9SDave Chinner struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; 26530f712c9SDave Chinner 26630f712c9SDave Chinner if (xfs_sb_version_hascrc(&mp->m_sb)) { 26730f712c9SDave Chinner if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC)) 268a6a781a5SDarrick J. Wong return __this_address; 269ce748eaaSEric Sandeen if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) 270a6a781a5SDarrick J. Wong return __this_address; 27130f712c9SDave Chinner if (be64_to_cpu(hdr3->blkno) != bp->b_bn) 272a6a781a5SDarrick J. Wong return __this_address; 273a45086e2SBrian Foster if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) 274a6a781a5SDarrick J. Wong return __this_address; 27530f712c9SDave Chinner } else { 27630f712c9SDave Chinner if (hdr3->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC)) 277a6a781a5SDarrick J. Wong return __this_address; 27830f712c9SDave Chinner } 2799101d370SDarrick J. Wong return __xfs_dir3_data_check(NULL, bp); 28030f712c9SDave Chinner } 28130f712c9SDave Chinner 28230f712c9SDave Chinner /* 28330f712c9SDave Chinner * Readahead of the first block of the directory when it is opened is completely 28430f712c9SDave Chinner * oblivious to the format of the directory. Hence we can either get a block 28530f712c9SDave Chinner * format buffer or a data format buffer on readahead. 28630f712c9SDave Chinner */ 28730f712c9SDave Chinner static void 28830f712c9SDave Chinner xfs_dir3_data_reada_verify( 28930f712c9SDave Chinner struct xfs_buf *bp) 29030f712c9SDave Chinner { 29130f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr = bp->b_addr; 29230f712c9SDave Chinner 29330f712c9SDave Chinner switch (hdr->magic) { 29430f712c9SDave Chinner case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): 29530f712c9SDave Chinner case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): 29630f712c9SDave Chinner bp->b_ops = &xfs_dir3_block_buf_ops; 29730f712c9SDave Chinner bp->b_ops->verify_read(bp); 29830f712c9SDave Chinner return; 29930f712c9SDave Chinner case cpu_to_be32(XFS_DIR2_DATA_MAGIC): 30030f712c9SDave Chinner case cpu_to_be32(XFS_DIR3_DATA_MAGIC): 3012f123bceSDarrick J. Wong bp->b_ops = &xfs_dir3_data_buf_ops; 3022f123bceSDarrick J. Wong bp->b_ops->verify_read(bp); 30330f712c9SDave Chinner return; 30430f712c9SDave Chinner default: 305bc1a09b8SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, __this_address); 30630f712c9SDave Chinner break; 30730f712c9SDave Chinner } 30830f712c9SDave Chinner } 30930f712c9SDave Chinner 31030f712c9SDave Chinner static void 31130f712c9SDave Chinner xfs_dir3_data_read_verify( 31230f712c9SDave Chinner struct xfs_buf *bp) 31330f712c9SDave Chinner { 31430f712c9SDave Chinner struct xfs_mount *mp = bp->b_target->bt_mount; 315bc1a09b8SDarrick J. Wong xfs_failaddr_t fa; 31630f712c9SDave Chinner 31730f712c9SDave Chinner if (xfs_sb_version_hascrc(&mp->m_sb) && 31830f712c9SDave Chinner !xfs_buf_verify_cksum(bp, XFS_DIR3_DATA_CRC_OFF)) 319bc1a09b8SDarrick J. Wong xfs_verifier_error(bp, -EFSBADCRC, __this_address); 320bc1a09b8SDarrick J. Wong else { 321bc1a09b8SDarrick J. Wong fa = xfs_dir3_data_verify(bp); 322bc1a09b8SDarrick J. Wong if (fa) 323bc1a09b8SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 324bc1a09b8SDarrick J. Wong } 32530f712c9SDave Chinner } 32630f712c9SDave Chinner 32730f712c9SDave Chinner static void 32830f712c9SDave Chinner xfs_dir3_data_write_verify( 32930f712c9SDave Chinner struct xfs_buf *bp) 33030f712c9SDave Chinner { 33130f712c9SDave Chinner struct xfs_mount *mp = bp->b_target->bt_mount; 332fb1755a6SCarlos Maiolino struct xfs_buf_log_item *bip = bp->b_log_item; 33330f712c9SDave Chinner struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; 334bc1a09b8SDarrick J. Wong xfs_failaddr_t fa; 33530f712c9SDave Chinner 336bc1a09b8SDarrick J. Wong fa = xfs_dir3_data_verify(bp); 337bc1a09b8SDarrick J. Wong if (fa) { 338bc1a09b8SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 33930f712c9SDave Chinner return; 34030f712c9SDave Chinner } 34130f712c9SDave Chinner 34230f712c9SDave Chinner if (!xfs_sb_version_hascrc(&mp->m_sb)) 34330f712c9SDave Chinner return; 34430f712c9SDave Chinner 34530f712c9SDave Chinner if (bip) 34630f712c9SDave Chinner hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); 34730f712c9SDave Chinner 34830f712c9SDave Chinner xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF); 34930f712c9SDave Chinner } 35030f712c9SDave Chinner 35130f712c9SDave Chinner const struct xfs_buf_ops xfs_dir3_data_buf_ops = { 352233135b7SEric Sandeen .name = "xfs_dir3_data", 35330f712c9SDave Chinner .verify_read = xfs_dir3_data_read_verify, 35430f712c9SDave Chinner .verify_write = xfs_dir3_data_write_verify, 355b5572597SDarrick J. Wong .verify_struct = xfs_dir3_data_verify, 35630f712c9SDave Chinner }; 35730f712c9SDave Chinner 35830f712c9SDave Chinner static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = { 359233135b7SEric Sandeen .name = "xfs_dir3_data_reada", 36030f712c9SDave Chinner .verify_read = xfs_dir3_data_reada_verify, 36130f712c9SDave Chinner .verify_write = xfs_dir3_data_write_verify, 36230f712c9SDave Chinner }; 36330f712c9SDave Chinner 36430f712c9SDave Chinner 36530f712c9SDave Chinner int 36630f712c9SDave Chinner xfs_dir3_data_read( 36730f712c9SDave Chinner struct xfs_trans *tp, 36830f712c9SDave Chinner struct xfs_inode *dp, 36930f712c9SDave Chinner xfs_dablk_t bno, 37030f712c9SDave Chinner xfs_daddr_t mapped_bno, 37130f712c9SDave Chinner struct xfs_buf **bpp) 37230f712c9SDave Chinner { 37330f712c9SDave Chinner int err; 37430f712c9SDave Chinner 37530f712c9SDave Chinner err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp, 37630f712c9SDave Chinner XFS_DATA_FORK, &xfs_dir3_data_buf_ops); 37796a3aefbSDarrick J. Wong if (!err && tp && *bpp) 37830f712c9SDave Chinner xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_DATA_BUF); 37930f712c9SDave Chinner return err; 38030f712c9SDave Chinner } 38130f712c9SDave Chinner 38230f712c9SDave Chinner int 38330f712c9SDave Chinner xfs_dir3_data_readahead( 38430f712c9SDave Chinner struct xfs_inode *dp, 38530f712c9SDave Chinner xfs_dablk_t bno, 38630f712c9SDave Chinner xfs_daddr_t mapped_bno) 38730f712c9SDave Chinner { 38830f712c9SDave Chinner return xfs_da_reada_buf(dp, bno, mapped_bno, 38930f712c9SDave Chinner XFS_DATA_FORK, &xfs_dir3_data_reada_buf_ops); 39030f712c9SDave Chinner } 39130f712c9SDave Chinner 39230f712c9SDave Chinner /* 393*e4f45effSDarrick J. Wong * Find the bestfree entry that exactly coincides with unused directory space 394*e4f45effSDarrick J. Wong * or a verifier error because the bestfree data are bad. 395*e4f45effSDarrick J. Wong */ 396*e4f45effSDarrick J. Wong static xfs_failaddr_t 397*e4f45effSDarrick J. Wong xfs_dir2_data_freefind_verify( 398*e4f45effSDarrick J. Wong struct xfs_dir2_data_hdr *hdr, 399*e4f45effSDarrick J. Wong struct xfs_dir2_data_free *bf, 400*e4f45effSDarrick J. Wong struct xfs_dir2_data_unused *dup, 401*e4f45effSDarrick J. Wong struct xfs_dir2_data_free **bf_ent) 402*e4f45effSDarrick J. Wong { 403*e4f45effSDarrick J. Wong struct xfs_dir2_data_free *dfp; 404*e4f45effSDarrick J. Wong xfs_dir2_data_aoff_t off; 405*e4f45effSDarrick J. Wong bool matched = false; 406*e4f45effSDarrick J. Wong bool seenzero = false; 407*e4f45effSDarrick J. Wong 408*e4f45effSDarrick J. Wong *bf_ent = NULL; 409*e4f45effSDarrick J. Wong off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); 410*e4f45effSDarrick J. Wong 411*e4f45effSDarrick J. Wong /* 412*e4f45effSDarrick J. Wong * Validate some consistency in the bestfree table. 413*e4f45effSDarrick J. Wong * Check order, non-overlapping entries, and if we find the 414*e4f45effSDarrick J. Wong * one we're looking for it has to be exact. 415*e4f45effSDarrick J. Wong */ 416*e4f45effSDarrick J. Wong for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { 417*e4f45effSDarrick J. Wong if (!dfp->offset) { 418*e4f45effSDarrick J. Wong if (dfp->length) 419*e4f45effSDarrick J. Wong return __this_address; 420*e4f45effSDarrick J. Wong seenzero = true; 421*e4f45effSDarrick J. Wong continue; 422*e4f45effSDarrick J. Wong } 423*e4f45effSDarrick J. Wong if (seenzero) 424*e4f45effSDarrick J. Wong return __this_address; 425*e4f45effSDarrick J. Wong if (be16_to_cpu(dfp->offset) == off) { 426*e4f45effSDarrick J. Wong matched = true; 427*e4f45effSDarrick J. Wong if (dfp->length != dup->length) 428*e4f45effSDarrick J. Wong return __this_address; 429*e4f45effSDarrick J. Wong } else if (be16_to_cpu(dfp->offset) > off) { 430*e4f45effSDarrick J. Wong if (off + be16_to_cpu(dup->length) > 431*e4f45effSDarrick J. Wong be16_to_cpu(dfp->offset)) 432*e4f45effSDarrick J. Wong return __this_address; 433*e4f45effSDarrick J. Wong } else { 434*e4f45effSDarrick J. Wong if (be16_to_cpu(dfp->offset) + 435*e4f45effSDarrick J. Wong be16_to_cpu(dfp->length) > off) 436*e4f45effSDarrick J. Wong return __this_address; 437*e4f45effSDarrick J. Wong } 438*e4f45effSDarrick J. Wong if (!matched && 439*e4f45effSDarrick J. Wong be16_to_cpu(dfp->length) < be16_to_cpu(dup->length)) 440*e4f45effSDarrick J. Wong return __this_address; 441*e4f45effSDarrick J. Wong if (dfp > &bf[0] && 442*e4f45effSDarrick J. Wong be16_to_cpu(dfp[-1].length) < be16_to_cpu(dfp[0].length)) 443*e4f45effSDarrick J. Wong return __this_address; 444*e4f45effSDarrick J. Wong } 445*e4f45effSDarrick J. Wong 446*e4f45effSDarrick J. Wong /* Looks ok so far; now try to match up with a bestfree entry. */ 447*e4f45effSDarrick J. Wong *bf_ent = xfs_dir2_data_freefind(hdr, bf, dup); 448*e4f45effSDarrick J. Wong return NULL; 449*e4f45effSDarrick J. Wong } 450*e4f45effSDarrick J. Wong 451*e4f45effSDarrick J. Wong /* 45230f712c9SDave Chinner * Given a data block and an unused entry from that block, 45330f712c9SDave Chinner * return the bestfree entry if any that corresponds to it. 45430f712c9SDave Chinner */ 45530f712c9SDave Chinner xfs_dir2_data_free_t * 45630f712c9SDave Chinner xfs_dir2_data_freefind( 45730f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr, /* data block header */ 45830f712c9SDave Chinner struct xfs_dir2_data_free *bf, /* bestfree table pointer */ 45930f712c9SDave Chinner struct xfs_dir2_data_unused *dup) /* unused space */ 46030f712c9SDave Chinner { 46130f712c9SDave Chinner xfs_dir2_data_free_t *dfp; /* bestfree entry */ 46230f712c9SDave Chinner xfs_dir2_data_aoff_t off; /* offset value needed */ 46330f712c9SDave Chinner 46430f712c9SDave Chinner off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); 46530f712c9SDave Chinner 46630f712c9SDave Chinner /* 46730f712c9SDave Chinner * If this is smaller than the smallest bestfree entry, 46830f712c9SDave Chinner * it can't be there since they're sorted. 46930f712c9SDave Chinner */ 47030f712c9SDave Chinner if (be16_to_cpu(dup->length) < 47130f712c9SDave Chinner be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length)) 47230f712c9SDave Chinner return NULL; 47330f712c9SDave Chinner /* 47430f712c9SDave Chinner * Look at the three bestfree entries for our guy. 47530f712c9SDave Chinner */ 47630f712c9SDave Chinner for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { 47730f712c9SDave Chinner if (!dfp->offset) 47830f712c9SDave Chinner return NULL; 47930f712c9SDave Chinner if (be16_to_cpu(dfp->offset) == off) 48030f712c9SDave Chinner return dfp; 48130f712c9SDave Chinner } 48230f712c9SDave Chinner /* 48330f712c9SDave Chinner * Didn't find it. This only happens if there are duplicate lengths. 48430f712c9SDave Chinner */ 48530f712c9SDave Chinner return NULL; 48630f712c9SDave Chinner } 48730f712c9SDave Chinner 48830f712c9SDave Chinner /* 48930f712c9SDave Chinner * Insert an unused-space entry into the bestfree table. 49030f712c9SDave Chinner */ 49130f712c9SDave Chinner xfs_dir2_data_free_t * /* entry inserted */ 49230f712c9SDave Chinner xfs_dir2_data_freeinsert( 49330f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr, /* data block pointer */ 49430f712c9SDave Chinner struct xfs_dir2_data_free *dfp, /* bestfree table pointer */ 49530f712c9SDave Chinner struct xfs_dir2_data_unused *dup, /* unused space */ 49630f712c9SDave Chinner int *loghead) /* log the data header (out) */ 49730f712c9SDave Chinner { 49830f712c9SDave Chinner xfs_dir2_data_free_t new; /* new bestfree entry */ 49930f712c9SDave Chinner 50030f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 50130f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 50230f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 50330f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 50430f712c9SDave Chinner 50530f712c9SDave Chinner new.length = dup->length; 50630f712c9SDave Chinner new.offset = cpu_to_be16((char *)dup - (char *)hdr); 50730f712c9SDave Chinner 50830f712c9SDave Chinner /* 50930f712c9SDave Chinner * Insert at position 0, 1, or 2; or not at all. 51030f712c9SDave Chinner */ 51130f712c9SDave Chinner if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) { 51230f712c9SDave Chinner dfp[2] = dfp[1]; 51330f712c9SDave Chinner dfp[1] = dfp[0]; 51430f712c9SDave Chinner dfp[0] = new; 51530f712c9SDave Chinner *loghead = 1; 51630f712c9SDave Chinner return &dfp[0]; 51730f712c9SDave Chinner } 51830f712c9SDave Chinner if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) { 51930f712c9SDave Chinner dfp[2] = dfp[1]; 52030f712c9SDave Chinner dfp[1] = new; 52130f712c9SDave Chinner *loghead = 1; 52230f712c9SDave Chinner return &dfp[1]; 52330f712c9SDave Chinner } 52430f712c9SDave Chinner if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) { 52530f712c9SDave Chinner dfp[2] = new; 52630f712c9SDave Chinner *loghead = 1; 52730f712c9SDave Chinner return &dfp[2]; 52830f712c9SDave Chinner } 52930f712c9SDave Chinner return NULL; 53030f712c9SDave Chinner } 53130f712c9SDave Chinner 53230f712c9SDave Chinner /* 53330f712c9SDave Chinner * Remove a bestfree entry from the table. 53430f712c9SDave Chinner */ 53530f712c9SDave Chinner STATIC void 53630f712c9SDave Chinner xfs_dir2_data_freeremove( 53730f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr, /* data block header */ 53830f712c9SDave Chinner struct xfs_dir2_data_free *bf, /* bestfree table pointer */ 53930f712c9SDave Chinner struct xfs_dir2_data_free *dfp, /* bestfree entry pointer */ 54030f712c9SDave Chinner int *loghead) /* out: log data header */ 54130f712c9SDave Chinner { 54230f712c9SDave Chinner 54330f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 54430f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 54530f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 54630f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 54730f712c9SDave Chinner 54830f712c9SDave Chinner /* 54930f712c9SDave Chinner * It's the first entry, slide the next 2 up. 55030f712c9SDave Chinner */ 55130f712c9SDave Chinner if (dfp == &bf[0]) { 55230f712c9SDave Chinner bf[0] = bf[1]; 55330f712c9SDave Chinner bf[1] = bf[2]; 55430f712c9SDave Chinner } 55530f712c9SDave Chinner /* 55630f712c9SDave Chinner * It's the second entry, slide the 3rd entry up. 55730f712c9SDave Chinner */ 55830f712c9SDave Chinner else if (dfp == &bf[1]) 55930f712c9SDave Chinner bf[1] = bf[2]; 56030f712c9SDave Chinner /* 56130f712c9SDave Chinner * Must be the last entry. 56230f712c9SDave Chinner */ 56330f712c9SDave Chinner else 56430f712c9SDave Chinner ASSERT(dfp == &bf[2]); 56530f712c9SDave Chinner /* 56630f712c9SDave Chinner * Clear the 3rd entry, must be zero now. 56730f712c9SDave Chinner */ 56830f712c9SDave Chinner bf[2].length = 0; 56930f712c9SDave Chinner bf[2].offset = 0; 57030f712c9SDave Chinner *loghead = 1; 57130f712c9SDave Chinner } 57230f712c9SDave Chinner 57330f712c9SDave Chinner /* 57430f712c9SDave Chinner * Given a data block, reconstruct its bestfree map. 57530f712c9SDave Chinner */ 57630f712c9SDave Chinner void 577523b2e76SDarrick J. Wong xfs_dir2_data_freescan_int( 578523b2e76SDarrick J. Wong struct xfs_da_geometry *geo, 579523b2e76SDarrick J. Wong const struct xfs_dir_ops *ops, 58030f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr, 58130f712c9SDave Chinner int *loghead) 58230f712c9SDave Chinner { 58330f712c9SDave Chinner xfs_dir2_data_entry_t *dep; /* active data entry */ 58430f712c9SDave Chinner xfs_dir2_data_unused_t *dup; /* unused data entry */ 58530f712c9SDave Chinner struct xfs_dir2_data_free *bf; 58630f712c9SDave Chinner char *endp; /* end of block's data */ 58730f712c9SDave Chinner char *p; /* current entry pointer */ 58830f712c9SDave Chinner 58930f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 59030f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 59130f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 59230f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 59330f712c9SDave Chinner 59430f712c9SDave Chinner /* 59530f712c9SDave Chinner * Start by clearing the table. 59630f712c9SDave Chinner */ 597523b2e76SDarrick J. Wong bf = ops->data_bestfree_p(hdr); 59830f712c9SDave Chinner memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT); 59930f712c9SDave Chinner *loghead = 1; 60030f712c9SDave Chinner /* 60130f712c9SDave Chinner * Set up pointers. 60230f712c9SDave Chinner */ 603523b2e76SDarrick J. Wong p = (char *)ops->data_entry_p(hdr); 604ce92d29dSDarrick J. Wong endp = xfs_dir3_data_endp(geo, hdr); 60530f712c9SDave Chinner /* 60630f712c9SDave Chinner * Loop over the block's entries. 60730f712c9SDave Chinner */ 60830f712c9SDave Chinner while (p < endp) { 60930f712c9SDave Chinner dup = (xfs_dir2_data_unused_t *)p; 61030f712c9SDave Chinner /* 61130f712c9SDave Chinner * If it's a free entry, insert it. 61230f712c9SDave Chinner */ 61330f712c9SDave Chinner if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { 61430f712c9SDave Chinner ASSERT((char *)dup - (char *)hdr == 61530f712c9SDave Chinner be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup))); 61630f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, dup, loghead); 61730f712c9SDave Chinner p += be16_to_cpu(dup->length); 61830f712c9SDave Chinner } 61930f712c9SDave Chinner /* 62030f712c9SDave Chinner * For active entries, check their tags and skip them. 62130f712c9SDave Chinner */ 62230f712c9SDave Chinner else { 62330f712c9SDave Chinner dep = (xfs_dir2_data_entry_t *)p; 62430f712c9SDave Chinner ASSERT((char *)dep - (char *)hdr == 625523b2e76SDarrick J. Wong be16_to_cpu(*ops->data_entry_tag_p(dep))); 626523b2e76SDarrick J. Wong p += ops->data_entsize(dep->namelen); 62730f712c9SDave Chinner } 62830f712c9SDave Chinner } 62930f712c9SDave Chinner } 63030f712c9SDave Chinner 631523b2e76SDarrick J. Wong void 632523b2e76SDarrick J. Wong xfs_dir2_data_freescan( 633523b2e76SDarrick J. Wong struct xfs_inode *dp, 634523b2e76SDarrick J. Wong struct xfs_dir2_data_hdr *hdr, 635523b2e76SDarrick J. Wong int *loghead) 636523b2e76SDarrick J. Wong { 637523b2e76SDarrick J. Wong return xfs_dir2_data_freescan_int(dp->i_mount->m_dir_geo, dp->d_ops, 638523b2e76SDarrick J. Wong hdr, loghead); 639523b2e76SDarrick J. Wong } 640523b2e76SDarrick J. Wong 64130f712c9SDave Chinner /* 64230f712c9SDave Chinner * Initialize a data block at the given block number in the directory. 64330f712c9SDave Chinner * Give back the buffer for the created block. 64430f712c9SDave Chinner */ 64530f712c9SDave Chinner int /* error */ 64630f712c9SDave Chinner xfs_dir3_data_init( 64730f712c9SDave Chinner xfs_da_args_t *args, /* directory operation args */ 64830f712c9SDave Chinner xfs_dir2_db_t blkno, /* logical dir block number */ 64930f712c9SDave Chinner struct xfs_buf **bpp) /* output block buffer */ 65030f712c9SDave Chinner { 65130f712c9SDave Chinner struct xfs_buf *bp; /* block buffer */ 65230f712c9SDave Chinner xfs_dir2_data_hdr_t *hdr; /* data block header */ 65330f712c9SDave Chinner xfs_inode_t *dp; /* incore directory inode */ 65430f712c9SDave Chinner xfs_dir2_data_unused_t *dup; /* unused entry pointer */ 65530f712c9SDave Chinner struct xfs_dir2_data_free *bf; 65630f712c9SDave Chinner int error; /* error return value */ 65730f712c9SDave Chinner int i; /* bestfree index */ 65830f712c9SDave Chinner xfs_mount_t *mp; /* filesystem mount point */ 65930f712c9SDave Chinner xfs_trans_t *tp; /* transaction pointer */ 66030f712c9SDave Chinner int t; /* temp */ 66130f712c9SDave Chinner 66230f712c9SDave Chinner dp = args->dp; 66330f712c9SDave Chinner mp = dp->i_mount; 66430f712c9SDave Chinner tp = args->trans; 66530f712c9SDave Chinner /* 66630f712c9SDave Chinner * Get the buffer set up for the block. 66730f712c9SDave Chinner */ 66830f712c9SDave Chinner error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno), 66930f712c9SDave Chinner -1, &bp, XFS_DATA_FORK); 67030f712c9SDave Chinner if (error) 67130f712c9SDave Chinner return error; 67230f712c9SDave Chinner bp->b_ops = &xfs_dir3_data_buf_ops; 67330f712c9SDave Chinner xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_DATA_BUF); 67430f712c9SDave Chinner 67530f712c9SDave Chinner /* 67630f712c9SDave Chinner * Initialize the header. 67730f712c9SDave Chinner */ 67830f712c9SDave Chinner hdr = bp->b_addr; 67930f712c9SDave Chinner if (xfs_sb_version_hascrc(&mp->m_sb)) { 68030f712c9SDave Chinner struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; 68130f712c9SDave Chinner 68230f712c9SDave Chinner memset(hdr3, 0, sizeof(*hdr3)); 68330f712c9SDave Chinner hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC); 68430f712c9SDave Chinner hdr3->blkno = cpu_to_be64(bp->b_bn); 68530f712c9SDave Chinner hdr3->owner = cpu_to_be64(dp->i_ino); 686ce748eaaSEric Sandeen uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid); 68730f712c9SDave Chinner 68830f712c9SDave Chinner } else 68930f712c9SDave Chinner hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC); 69030f712c9SDave Chinner 69130f712c9SDave Chinner bf = dp->d_ops->data_bestfree_p(hdr); 69230f712c9SDave Chinner bf[0].offset = cpu_to_be16(dp->d_ops->data_entry_offset); 69330f712c9SDave Chinner for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { 69430f712c9SDave Chinner bf[i].length = 0; 69530f712c9SDave Chinner bf[i].offset = 0; 69630f712c9SDave Chinner } 69730f712c9SDave Chinner 69830f712c9SDave Chinner /* 69930f712c9SDave Chinner * Set up an unused entry for the block's body. 70030f712c9SDave Chinner */ 70130f712c9SDave Chinner dup = dp->d_ops->data_unused_p(hdr); 70230f712c9SDave Chinner dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); 70330f712c9SDave Chinner 70430f712c9SDave Chinner t = args->geo->blksize - (uint)dp->d_ops->data_entry_offset; 70530f712c9SDave Chinner bf[0].length = cpu_to_be16(t); 70630f712c9SDave Chinner dup->length = cpu_to_be16(t); 70730f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr); 70830f712c9SDave Chinner /* 70930f712c9SDave Chinner * Log it and return it. 71030f712c9SDave Chinner */ 71130f712c9SDave Chinner xfs_dir2_data_log_header(args, bp); 71230f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, dup); 71330f712c9SDave Chinner *bpp = bp; 71430f712c9SDave Chinner return 0; 71530f712c9SDave Chinner } 71630f712c9SDave Chinner 71730f712c9SDave Chinner /* 71830f712c9SDave Chinner * Log an active data entry from the block. 71930f712c9SDave Chinner */ 72030f712c9SDave Chinner void 72130f712c9SDave Chinner xfs_dir2_data_log_entry( 72230f712c9SDave Chinner struct xfs_da_args *args, 72330f712c9SDave Chinner struct xfs_buf *bp, 72430f712c9SDave Chinner xfs_dir2_data_entry_t *dep) /* data entry pointer */ 72530f712c9SDave Chinner { 72630f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr = bp->b_addr; 72730f712c9SDave Chinner 72830f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 72930f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 73030f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 73130f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 73230f712c9SDave Chinner 73330f712c9SDave Chinner xfs_trans_log_buf(args->trans, bp, (uint)((char *)dep - (char *)hdr), 73430f712c9SDave Chinner (uint)((char *)(args->dp->d_ops->data_entry_tag_p(dep) + 1) - 73530f712c9SDave Chinner (char *)hdr - 1)); 73630f712c9SDave Chinner } 73730f712c9SDave Chinner 73830f712c9SDave Chinner /* 73930f712c9SDave Chinner * Log a data block header. 74030f712c9SDave Chinner */ 74130f712c9SDave Chinner void 74230f712c9SDave Chinner xfs_dir2_data_log_header( 74330f712c9SDave Chinner struct xfs_da_args *args, 74430f712c9SDave Chinner struct xfs_buf *bp) 74530f712c9SDave Chinner { 74630f712c9SDave Chinner #ifdef DEBUG 74730f712c9SDave Chinner struct xfs_dir2_data_hdr *hdr = bp->b_addr; 74830f712c9SDave Chinner 74930f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 75030f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 75130f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 75230f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 75330f712c9SDave Chinner #endif 75430f712c9SDave Chinner 75530f712c9SDave Chinner xfs_trans_log_buf(args->trans, bp, 0, 75630f712c9SDave Chinner args->dp->d_ops->data_entry_offset - 1); 75730f712c9SDave Chinner } 75830f712c9SDave Chinner 75930f712c9SDave Chinner /* 76030f712c9SDave Chinner * Log a data unused entry. 76130f712c9SDave Chinner */ 76230f712c9SDave Chinner void 76330f712c9SDave Chinner xfs_dir2_data_log_unused( 76430f712c9SDave Chinner struct xfs_da_args *args, 76530f712c9SDave Chinner struct xfs_buf *bp, 76630f712c9SDave Chinner xfs_dir2_data_unused_t *dup) /* data unused pointer */ 76730f712c9SDave Chinner { 76830f712c9SDave Chinner xfs_dir2_data_hdr_t *hdr = bp->b_addr; 76930f712c9SDave Chinner 77030f712c9SDave Chinner ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 77130f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 77230f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || 77330f712c9SDave Chinner hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 77430f712c9SDave Chinner 77530f712c9SDave Chinner /* 77630f712c9SDave Chinner * Log the first part of the unused entry. 77730f712c9SDave Chinner */ 77830f712c9SDave Chinner xfs_trans_log_buf(args->trans, bp, (uint)((char *)dup - (char *)hdr), 77930f712c9SDave Chinner (uint)((char *)&dup->length + sizeof(dup->length) - 78030f712c9SDave Chinner 1 - (char *)hdr)); 78130f712c9SDave Chinner /* 78230f712c9SDave Chinner * Log the end (tag) of the unused entry. 78330f712c9SDave Chinner */ 78430f712c9SDave Chinner xfs_trans_log_buf(args->trans, bp, 78530f712c9SDave Chinner (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr), 78630f712c9SDave Chinner (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr + 78730f712c9SDave Chinner sizeof(xfs_dir2_data_off_t) - 1)); 78830f712c9SDave Chinner } 78930f712c9SDave Chinner 79030f712c9SDave Chinner /* 79130f712c9SDave Chinner * Make a byte range in the data block unused. 79230f712c9SDave Chinner * Its current contents are unimportant. 79330f712c9SDave Chinner */ 79430f712c9SDave Chinner void 79530f712c9SDave Chinner xfs_dir2_data_make_free( 79630f712c9SDave Chinner struct xfs_da_args *args, 79730f712c9SDave Chinner struct xfs_buf *bp, 79830f712c9SDave Chinner xfs_dir2_data_aoff_t offset, /* starting byte offset */ 79930f712c9SDave Chinner xfs_dir2_data_aoff_t len, /* length in bytes */ 80030f712c9SDave Chinner int *needlogp, /* out: log header */ 80130f712c9SDave Chinner int *needscanp) /* out: regen bestfree */ 80230f712c9SDave Chinner { 80330f712c9SDave Chinner xfs_dir2_data_hdr_t *hdr; /* data block pointer */ 80430f712c9SDave Chinner xfs_dir2_data_free_t *dfp; /* bestfree pointer */ 80530f712c9SDave Chinner char *endptr; /* end of data area */ 80630f712c9SDave Chinner int needscan; /* need to regen bestfree */ 80730f712c9SDave Chinner xfs_dir2_data_unused_t *newdup; /* new unused entry */ 80830f712c9SDave Chinner xfs_dir2_data_unused_t *postdup; /* unused entry after us */ 80930f712c9SDave Chinner xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ 81030f712c9SDave Chinner struct xfs_dir2_data_free *bf; 81130f712c9SDave Chinner 81230f712c9SDave Chinner hdr = bp->b_addr; 81330f712c9SDave Chinner 81430f712c9SDave Chinner /* 81530f712c9SDave Chinner * Figure out where the end of the data area is. 81630f712c9SDave Chinner */ 817ce92d29dSDarrick J. Wong endptr = xfs_dir3_data_endp(args->geo, hdr); 818ce92d29dSDarrick J. Wong ASSERT(endptr != NULL); 81930f712c9SDave Chinner 82030f712c9SDave Chinner /* 82130f712c9SDave Chinner * If this isn't the start of the block, then back up to 82230f712c9SDave Chinner * the previous entry and see if it's free. 82330f712c9SDave Chinner */ 82430f712c9SDave Chinner if (offset > args->dp->d_ops->data_entry_offset) { 82530f712c9SDave Chinner __be16 *tagp; /* tag just before us */ 82630f712c9SDave Chinner 82730f712c9SDave Chinner tagp = (__be16 *)((char *)hdr + offset) - 1; 82830f712c9SDave Chinner prevdup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); 82930f712c9SDave Chinner if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG) 83030f712c9SDave Chinner prevdup = NULL; 83130f712c9SDave Chinner } else 83230f712c9SDave Chinner prevdup = NULL; 83330f712c9SDave Chinner /* 83430f712c9SDave Chinner * If this isn't the end of the block, see if the entry after 83530f712c9SDave Chinner * us is free. 83630f712c9SDave Chinner */ 83730f712c9SDave Chinner if ((char *)hdr + offset + len < endptr) { 83830f712c9SDave Chinner postdup = 83930f712c9SDave Chinner (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); 84030f712c9SDave Chinner if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG) 84130f712c9SDave Chinner postdup = NULL; 84230f712c9SDave Chinner } else 84330f712c9SDave Chinner postdup = NULL; 84430f712c9SDave Chinner ASSERT(*needscanp == 0); 84530f712c9SDave Chinner needscan = 0; 84630f712c9SDave Chinner /* 84730f712c9SDave Chinner * Previous and following entries are both free, 84830f712c9SDave Chinner * merge everything into a single free entry. 84930f712c9SDave Chinner */ 85030f712c9SDave Chinner bf = args->dp->d_ops->data_bestfree_p(hdr); 85130f712c9SDave Chinner if (prevdup && postdup) { 85230f712c9SDave Chinner xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ 85330f712c9SDave Chinner 85430f712c9SDave Chinner /* 85530f712c9SDave Chinner * See if prevdup and/or postdup are in bestfree table. 85630f712c9SDave Chinner */ 85730f712c9SDave Chinner dfp = xfs_dir2_data_freefind(hdr, bf, prevdup); 85830f712c9SDave Chinner dfp2 = xfs_dir2_data_freefind(hdr, bf, postdup); 85930f712c9SDave Chinner /* 86030f712c9SDave Chinner * We need a rescan unless there are exactly 2 free entries 86130f712c9SDave Chinner * namely our two. Then we know what's happening, otherwise 86230f712c9SDave Chinner * since the third bestfree is there, there might be more 86330f712c9SDave Chinner * entries. 86430f712c9SDave Chinner */ 86530f712c9SDave Chinner needscan = (bf[2].length != 0); 86630f712c9SDave Chinner /* 86730f712c9SDave Chinner * Fix up the new big freespace. 86830f712c9SDave Chinner */ 86930f712c9SDave Chinner be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length)); 87030f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(prevdup) = 87130f712c9SDave Chinner cpu_to_be16((char *)prevdup - (char *)hdr); 87230f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, prevdup); 87330f712c9SDave Chinner if (!needscan) { 87430f712c9SDave Chinner /* 87530f712c9SDave Chinner * Has to be the case that entries 0 and 1 are 87630f712c9SDave Chinner * dfp and dfp2 (don't know which is which), and 87730f712c9SDave Chinner * entry 2 is empty. 87830f712c9SDave Chinner * Remove entry 1 first then entry 0. 87930f712c9SDave Chinner */ 88030f712c9SDave Chinner ASSERT(dfp && dfp2); 88130f712c9SDave Chinner if (dfp == &bf[1]) { 88230f712c9SDave Chinner dfp = &bf[0]; 88330f712c9SDave Chinner ASSERT(dfp2 == dfp); 88430f712c9SDave Chinner dfp2 = &bf[1]; 88530f712c9SDave Chinner } 88630f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp2, needlogp); 88730f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); 88830f712c9SDave Chinner /* 88930f712c9SDave Chinner * Now insert the new entry. 89030f712c9SDave Chinner */ 89130f712c9SDave Chinner dfp = xfs_dir2_data_freeinsert(hdr, bf, prevdup, 89230f712c9SDave Chinner needlogp); 89330f712c9SDave Chinner ASSERT(dfp == &bf[0]); 89430f712c9SDave Chinner ASSERT(dfp->length == prevdup->length); 89530f712c9SDave Chinner ASSERT(!dfp[1].length); 89630f712c9SDave Chinner ASSERT(!dfp[2].length); 89730f712c9SDave Chinner } 89830f712c9SDave Chinner } 89930f712c9SDave Chinner /* 90030f712c9SDave Chinner * The entry before us is free, merge with it. 90130f712c9SDave Chinner */ 90230f712c9SDave Chinner else if (prevdup) { 90330f712c9SDave Chinner dfp = xfs_dir2_data_freefind(hdr, bf, prevdup); 90430f712c9SDave Chinner be16_add_cpu(&prevdup->length, len); 90530f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(prevdup) = 90630f712c9SDave Chinner cpu_to_be16((char *)prevdup - (char *)hdr); 90730f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, prevdup); 90830f712c9SDave Chinner /* 90930f712c9SDave Chinner * If the previous entry was in the table, the new entry 91030f712c9SDave Chinner * is longer, so it will be in the table too. Remove 91130f712c9SDave Chinner * the old one and add the new one. 91230f712c9SDave Chinner */ 91330f712c9SDave Chinner if (dfp) { 91430f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); 91530f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, prevdup, needlogp); 91630f712c9SDave Chinner } 91730f712c9SDave Chinner /* 91830f712c9SDave Chinner * Otherwise we need a scan if the new entry is big enough. 91930f712c9SDave Chinner */ 92030f712c9SDave Chinner else { 92130f712c9SDave Chinner needscan = be16_to_cpu(prevdup->length) > 92230f712c9SDave Chinner be16_to_cpu(bf[2].length); 92330f712c9SDave Chinner } 92430f712c9SDave Chinner } 92530f712c9SDave Chinner /* 92630f712c9SDave Chinner * The following entry is free, merge with it. 92730f712c9SDave Chinner */ 92830f712c9SDave Chinner else if (postdup) { 92930f712c9SDave Chinner dfp = xfs_dir2_data_freefind(hdr, bf, postdup); 93030f712c9SDave Chinner newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); 93130f712c9SDave Chinner newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); 93230f712c9SDave Chinner newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length)); 93330f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup) = 93430f712c9SDave Chinner cpu_to_be16((char *)newdup - (char *)hdr); 93530f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup); 93630f712c9SDave Chinner /* 93730f712c9SDave Chinner * If the following entry was in the table, the new entry 93830f712c9SDave Chinner * is longer, so it will be in the table too. Remove 93930f712c9SDave Chinner * the old one and add the new one. 94030f712c9SDave Chinner */ 94130f712c9SDave Chinner if (dfp) { 94230f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); 94330f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); 94430f712c9SDave Chinner } 94530f712c9SDave Chinner /* 94630f712c9SDave Chinner * Otherwise we need a scan if the new entry is big enough. 94730f712c9SDave Chinner */ 94830f712c9SDave Chinner else { 94930f712c9SDave Chinner needscan = be16_to_cpu(newdup->length) > 95030f712c9SDave Chinner be16_to_cpu(bf[2].length); 95130f712c9SDave Chinner } 95230f712c9SDave Chinner } 95330f712c9SDave Chinner /* 95430f712c9SDave Chinner * Neither neighbor is free. Make a new entry. 95530f712c9SDave Chinner */ 95630f712c9SDave Chinner else { 95730f712c9SDave Chinner newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); 95830f712c9SDave Chinner newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); 95930f712c9SDave Chinner newdup->length = cpu_to_be16(len); 96030f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup) = 96130f712c9SDave Chinner cpu_to_be16((char *)newdup - (char *)hdr); 96230f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup); 96330f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); 96430f712c9SDave Chinner } 96530f712c9SDave Chinner *needscanp = needscan; 96630f712c9SDave Chinner } 96730f712c9SDave Chinner 9686915ef35SDarrick J. Wong /* Check our free data for obvious signs of corruption. */ 9696915ef35SDarrick J. Wong static inline xfs_failaddr_t 9706915ef35SDarrick J. Wong xfs_dir2_data_check_free( 9716915ef35SDarrick J. Wong struct xfs_dir2_data_hdr *hdr, 9726915ef35SDarrick J. Wong struct xfs_dir2_data_unused *dup, 9736915ef35SDarrick J. Wong xfs_dir2_data_aoff_t offset, 9746915ef35SDarrick J. Wong xfs_dir2_data_aoff_t len) 9756915ef35SDarrick J. Wong { 9766915ef35SDarrick J. Wong if (hdr->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC) && 9776915ef35SDarrick J. Wong hdr->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC) && 9786915ef35SDarrick J. Wong hdr->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) && 9796915ef35SDarrick J. Wong hdr->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) 9806915ef35SDarrick J. Wong return __this_address; 9816915ef35SDarrick J. Wong if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG) 9826915ef35SDarrick J. Wong return __this_address; 9836915ef35SDarrick J. Wong if (offset < (char *)dup - (char *)hdr) 9846915ef35SDarrick J. Wong return __this_address; 9856915ef35SDarrick J. Wong if (offset + len > (char *)dup + be16_to_cpu(dup->length) - (char *)hdr) 9866915ef35SDarrick J. Wong return __this_address; 9876915ef35SDarrick J. Wong if ((char *)dup - (char *)hdr != 9886915ef35SDarrick J. Wong be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup))) 9896915ef35SDarrick J. Wong return __this_address; 9906915ef35SDarrick J. Wong return NULL; 9916915ef35SDarrick J. Wong } 9926915ef35SDarrick J. Wong 9936915ef35SDarrick J. Wong /* Sanity-check a new bestfree entry. */ 9946915ef35SDarrick J. Wong static inline xfs_failaddr_t 9956915ef35SDarrick J. Wong xfs_dir2_data_check_new_free( 9966915ef35SDarrick J. Wong struct xfs_dir2_data_hdr *hdr, 9976915ef35SDarrick J. Wong struct xfs_dir2_data_free *dfp, 9986915ef35SDarrick J. Wong struct xfs_dir2_data_unused *newdup) 9996915ef35SDarrick J. Wong { 10006915ef35SDarrick J. Wong if (dfp == NULL) 10016915ef35SDarrick J. Wong return __this_address; 10026915ef35SDarrick J. Wong if (dfp->length != newdup->length) 10036915ef35SDarrick J. Wong return __this_address; 10046915ef35SDarrick J. Wong if (be16_to_cpu(dfp->offset) != (char *)newdup - (char *)hdr) 10056915ef35SDarrick J. Wong return __this_address; 10066915ef35SDarrick J. Wong return NULL; 10076915ef35SDarrick J. Wong } 10086915ef35SDarrick J. Wong 100930f712c9SDave Chinner /* 101030f712c9SDave Chinner * Take a byte range out of an existing unused space and make it un-free. 101130f712c9SDave Chinner */ 10126915ef35SDarrick J. Wong int 101330f712c9SDave Chinner xfs_dir2_data_use_free( 101430f712c9SDave Chinner struct xfs_da_args *args, 101530f712c9SDave Chinner struct xfs_buf *bp, 101630f712c9SDave Chinner xfs_dir2_data_unused_t *dup, /* unused entry */ 101730f712c9SDave Chinner xfs_dir2_data_aoff_t offset, /* starting offset to use */ 101830f712c9SDave Chinner xfs_dir2_data_aoff_t len, /* length to use */ 101930f712c9SDave Chinner int *needlogp, /* out: need to log header */ 102030f712c9SDave Chinner int *needscanp) /* out: need regen bestfree */ 102130f712c9SDave Chinner { 102230f712c9SDave Chinner xfs_dir2_data_hdr_t *hdr; /* data block header */ 102330f712c9SDave Chinner xfs_dir2_data_free_t *dfp; /* bestfree pointer */ 10246915ef35SDarrick J. Wong xfs_dir2_data_unused_t *newdup; /* new unused entry */ 10256915ef35SDarrick J. Wong xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ 10266915ef35SDarrick J. Wong struct xfs_dir2_data_free *bf; 10276915ef35SDarrick J. Wong xfs_failaddr_t fa; 102830f712c9SDave Chinner int matchback; /* matches end of freespace */ 102930f712c9SDave Chinner int matchfront; /* matches start of freespace */ 103030f712c9SDave Chinner int needscan; /* need to regen bestfree */ 103130f712c9SDave Chinner int oldlen; /* old unused entry's length */ 103230f712c9SDave Chinner 103330f712c9SDave Chinner hdr = bp->b_addr; 10346915ef35SDarrick J. Wong fa = xfs_dir2_data_check_free(hdr, dup, offset, len); 10356915ef35SDarrick J. Wong if (fa) 10366915ef35SDarrick J. Wong goto corrupt; 103730f712c9SDave Chinner /* 103830f712c9SDave Chinner * Look up the entry in the bestfree table. 103930f712c9SDave Chinner */ 104030f712c9SDave Chinner oldlen = be16_to_cpu(dup->length); 104130f712c9SDave Chinner bf = args->dp->d_ops->data_bestfree_p(hdr); 104230f712c9SDave Chinner dfp = xfs_dir2_data_freefind(hdr, bf, dup); 104330f712c9SDave Chinner ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length)); 104430f712c9SDave Chinner /* 104530f712c9SDave Chinner * Check for alignment with front and back of the entry. 104630f712c9SDave Chinner */ 104730f712c9SDave Chinner matchfront = (char *)dup - (char *)hdr == offset; 104830f712c9SDave Chinner matchback = (char *)dup + oldlen - (char *)hdr == offset + len; 104930f712c9SDave Chinner ASSERT(*needscanp == 0); 105030f712c9SDave Chinner needscan = 0; 105130f712c9SDave Chinner /* 105230f712c9SDave Chinner * If we matched it exactly we just need to get rid of it from 105330f712c9SDave Chinner * the bestfree table. 105430f712c9SDave Chinner */ 105530f712c9SDave Chinner if (matchfront && matchback) { 105630f712c9SDave Chinner if (dfp) { 105730f712c9SDave Chinner needscan = (bf[2].offset != 0); 105830f712c9SDave Chinner if (!needscan) 105930f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, 106030f712c9SDave Chinner needlogp); 106130f712c9SDave Chinner } 106230f712c9SDave Chinner } 106330f712c9SDave Chinner /* 106430f712c9SDave Chinner * We match the first part of the entry. 106530f712c9SDave Chinner * Make a new entry with the remaining freespace. 106630f712c9SDave Chinner */ 106730f712c9SDave Chinner else if (matchfront) { 106830f712c9SDave Chinner newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); 106930f712c9SDave Chinner newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); 107030f712c9SDave Chinner newdup->length = cpu_to_be16(oldlen - len); 107130f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup) = 107230f712c9SDave Chinner cpu_to_be16((char *)newdup - (char *)hdr); 107330f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup); 107430f712c9SDave Chinner /* 107530f712c9SDave Chinner * If it was in the table, remove it and add the new one. 107630f712c9SDave Chinner */ 107730f712c9SDave Chinner if (dfp) { 107830f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); 107930f712c9SDave Chinner dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup, 108030f712c9SDave Chinner needlogp); 10816915ef35SDarrick J. Wong fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup); 10826915ef35SDarrick J. Wong if (fa) 10836915ef35SDarrick J. Wong goto corrupt; 108430f712c9SDave Chinner /* 108530f712c9SDave Chinner * If we got inserted at the last slot, 108630f712c9SDave Chinner * that means we don't know if there was a better 108730f712c9SDave Chinner * choice for the last slot, or not. Rescan. 108830f712c9SDave Chinner */ 108930f712c9SDave Chinner needscan = dfp == &bf[2]; 109030f712c9SDave Chinner } 109130f712c9SDave Chinner } 109230f712c9SDave Chinner /* 109330f712c9SDave Chinner * We match the last part of the entry. 109430f712c9SDave Chinner * Trim the allocated space off the tail of the entry. 109530f712c9SDave Chinner */ 109630f712c9SDave Chinner else if (matchback) { 109730f712c9SDave Chinner newdup = dup; 109830f712c9SDave Chinner newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup); 109930f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup) = 110030f712c9SDave Chinner cpu_to_be16((char *)newdup - (char *)hdr); 110130f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup); 110230f712c9SDave Chinner /* 110330f712c9SDave Chinner * If it was in the table, remove it and add the new one. 110430f712c9SDave Chinner */ 110530f712c9SDave Chinner if (dfp) { 110630f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); 110730f712c9SDave Chinner dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup, 110830f712c9SDave Chinner needlogp); 11096915ef35SDarrick J. Wong fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup); 11106915ef35SDarrick J. Wong if (fa) 11116915ef35SDarrick J. Wong goto corrupt; 111230f712c9SDave Chinner /* 111330f712c9SDave Chinner * If we got inserted at the last slot, 111430f712c9SDave Chinner * that means we don't know if there was a better 111530f712c9SDave Chinner * choice for the last slot, or not. Rescan. 111630f712c9SDave Chinner */ 111730f712c9SDave Chinner needscan = dfp == &bf[2]; 111830f712c9SDave Chinner } 111930f712c9SDave Chinner } 112030f712c9SDave Chinner /* 112130f712c9SDave Chinner * Poking out the middle of an entry. 112230f712c9SDave Chinner * Make two new entries. 112330f712c9SDave Chinner */ 112430f712c9SDave Chinner else { 112530f712c9SDave Chinner newdup = dup; 112630f712c9SDave Chinner newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup); 112730f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup) = 112830f712c9SDave Chinner cpu_to_be16((char *)newdup - (char *)hdr); 112930f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup); 113030f712c9SDave Chinner newdup2 = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); 113130f712c9SDave Chinner newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); 113230f712c9SDave Chinner newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length)); 113330f712c9SDave Chinner *xfs_dir2_data_unused_tag_p(newdup2) = 113430f712c9SDave Chinner cpu_to_be16((char *)newdup2 - (char *)hdr); 113530f712c9SDave Chinner xfs_dir2_data_log_unused(args, bp, newdup2); 113630f712c9SDave Chinner /* 113730f712c9SDave Chinner * If the old entry was in the table, we need to scan 113830f712c9SDave Chinner * if the 3rd entry was valid, since these entries 113930f712c9SDave Chinner * are smaller than the old one. 114030f712c9SDave Chinner * If we don't need to scan that means there were 1 or 2 114130f712c9SDave Chinner * entries in the table, and removing the old and adding 114230f712c9SDave Chinner * the 2 new will work. 114330f712c9SDave Chinner */ 114430f712c9SDave Chinner if (dfp) { 114530f712c9SDave Chinner needscan = (bf[2].length != 0); 114630f712c9SDave Chinner if (!needscan) { 114730f712c9SDave Chinner xfs_dir2_data_freeremove(hdr, bf, dfp, 114830f712c9SDave Chinner needlogp); 114930f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, newdup, 115030f712c9SDave Chinner needlogp); 115130f712c9SDave Chinner xfs_dir2_data_freeinsert(hdr, bf, newdup2, 115230f712c9SDave Chinner needlogp); 115330f712c9SDave Chinner } 115430f712c9SDave Chinner } 115530f712c9SDave Chinner } 115630f712c9SDave Chinner *needscanp = needscan; 11576915ef35SDarrick J. Wong return 0; 11586915ef35SDarrick J. Wong corrupt: 11596915ef35SDarrick J. Wong xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, args->dp->i_mount, 11606915ef35SDarrick J. Wong hdr, __FILE__, __LINE__, fa); 11616915ef35SDarrick J. Wong return -EFSCORRUPTED; 116230f712c9SDave Chinner } 1163ce92d29dSDarrick J. Wong 1164ce92d29dSDarrick J. Wong /* Find the end of the entry data in a data/block format dir block. */ 1165ce92d29dSDarrick J. Wong void * 1166ce92d29dSDarrick J. Wong xfs_dir3_data_endp( 1167ce92d29dSDarrick J. Wong struct xfs_da_geometry *geo, 1168ce92d29dSDarrick J. Wong struct xfs_dir2_data_hdr *hdr) 1169ce92d29dSDarrick J. Wong { 1170ce92d29dSDarrick J. Wong switch (hdr->magic) { 1171ce92d29dSDarrick J. Wong case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): 1172ce92d29dSDarrick J. Wong case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): 1173ce92d29dSDarrick J. Wong return xfs_dir2_block_leaf_p(xfs_dir2_block_tail_p(geo, hdr)); 1174ce92d29dSDarrick J. Wong case cpu_to_be32(XFS_DIR3_DATA_MAGIC): 1175ce92d29dSDarrick J. Wong case cpu_to_be32(XFS_DIR2_DATA_MAGIC): 1176ce92d29dSDarrick J. Wong return (char *)hdr + geo->blksize; 1177ce92d29dSDarrick J. Wong default: 1178ce92d29dSDarrick J. Wong return NULL; 1179ce92d29dSDarrick J. Wong } 1180ce92d29dSDarrick J. Wong } 1181