16c631e79SDarrick J. Wong // SPDX-License-Identifier: GPL-2.0-or-later 26c631e79SDarrick J. Wong /* 36c631e79SDarrick J. Wong * Copyright (c) 2022-2024 Oracle. All Rights Reserved. 46c631e79SDarrick J. Wong * Author: Darrick J. Wong <djwong@kernel.org> 56c631e79SDarrick J. Wong */ 66c631e79SDarrick J. Wong #include "xfs.h" 76c631e79SDarrick J. Wong #include "xfs_fs.h" 86c631e79SDarrick J. Wong #include "xfs_shared.h" 96c631e79SDarrick J. Wong #include "xfs_format.h" 106c631e79SDarrick J. Wong #include "xfs_log_format.h" 116c631e79SDarrick J. Wong #include "xfs_trans_resv.h" 126c631e79SDarrick J. Wong #include "xfs_mount.h" 136c631e79SDarrick J. Wong #include "xfs_inode.h" 146c631e79SDarrick J. Wong #include "xfs_da_format.h" 156c631e79SDarrick J. Wong #include "xfs_da_btree.h" 166c631e79SDarrick J. Wong #include "xfs_attr.h" 176c631e79SDarrick J. Wong #include "xfs_attr_leaf.h" 186c631e79SDarrick J. Wong #include "xfs_attr_sf.h" 196c631e79SDarrick J. Wong #include "xfs_trans.h" 206c631e79SDarrick J. Wong #include "scrub/scrub.h" 216c631e79SDarrick J. Wong #include "scrub/bitmap.h" 226c631e79SDarrick J. Wong #include "scrub/dab_bitmap.h" 236c631e79SDarrick J. Wong #include "scrub/listxattr.h" 246c631e79SDarrick J. Wong 256c631e79SDarrick J. Wong /* Call a function for every entry in a shortform xattr structure. */ 266c631e79SDarrick J. Wong STATIC int 276c631e79SDarrick J. Wong xchk_xattr_walk_sf( 286c631e79SDarrick J. Wong struct xfs_scrub *sc, 296c631e79SDarrick J. Wong struct xfs_inode *ip, 306c631e79SDarrick J. Wong xchk_xattr_fn attr_fn, 316c631e79SDarrick J. Wong void *priv) 326c631e79SDarrick J. Wong { 336c631e79SDarrick J. Wong struct xfs_attr_sf_hdr *hdr = ip->i_af.if_data; 346c631e79SDarrick J. Wong struct xfs_attr_sf_entry *sfe; 356c631e79SDarrick J. Wong unsigned int i; 366c631e79SDarrick J. Wong int error; 376c631e79SDarrick J. Wong 386c631e79SDarrick J. Wong sfe = xfs_attr_sf_firstentry(hdr); 396c631e79SDarrick J. Wong for (i = 0; i < hdr->count; i++) { 406c631e79SDarrick J. Wong error = attr_fn(sc, ip, sfe->flags, sfe->nameval, sfe->namelen, 416c631e79SDarrick J. Wong &sfe->nameval[sfe->namelen], sfe->valuelen, 426c631e79SDarrick J. Wong priv); 436c631e79SDarrick J. Wong if (error) 446c631e79SDarrick J. Wong return error; 456c631e79SDarrick J. Wong 466c631e79SDarrick J. Wong sfe = xfs_attr_sf_nextentry(sfe); 476c631e79SDarrick J. Wong } 486c631e79SDarrick J. Wong 496c631e79SDarrick J. Wong return 0; 506c631e79SDarrick J. Wong } 516c631e79SDarrick J. Wong 526c631e79SDarrick J. Wong /* Call a function for every entry in this xattr leaf block. */ 536c631e79SDarrick J. Wong STATIC int 546c631e79SDarrick J. Wong xchk_xattr_walk_leaf_entries( 556c631e79SDarrick J. Wong struct xfs_scrub *sc, 566c631e79SDarrick J. Wong struct xfs_inode *ip, 576c631e79SDarrick J. Wong xchk_xattr_fn attr_fn, 586c631e79SDarrick J. Wong struct xfs_buf *bp, 596c631e79SDarrick J. Wong void *priv) 606c631e79SDarrick J. Wong { 616c631e79SDarrick J. Wong struct xfs_attr3_icleaf_hdr ichdr; 626c631e79SDarrick J. Wong struct xfs_mount *mp = sc->mp; 636c631e79SDarrick J. Wong struct xfs_attr_leafblock *leaf = bp->b_addr; 646c631e79SDarrick J. Wong struct xfs_attr_leaf_entry *entry; 656c631e79SDarrick J. Wong unsigned int i; 666c631e79SDarrick J. Wong int error; 676c631e79SDarrick J. Wong 686c631e79SDarrick J. Wong xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf); 696c631e79SDarrick J. Wong entry = xfs_attr3_leaf_entryp(leaf); 706c631e79SDarrick J. Wong 716c631e79SDarrick J. Wong for (i = 0; i < ichdr.count; entry++, i++) { 726c631e79SDarrick J. Wong void *value; 736c631e79SDarrick J. Wong unsigned char *name; 746c631e79SDarrick J. Wong unsigned int namelen, valuelen; 756c631e79SDarrick J. Wong 766c631e79SDarrick J. Wong if (entry->flags & XFS_ATTR_LOCAL) { 776c631e79SDarrick J. Wong struct xfs_attr_leaf_name_local *name_loc; 786c631e79SDarrick J. Wong 796c631e79SDarrick J. Wong name_loc = xfs_attr3_leaf_name_local(leaf, i); 806c631e79SDarrick J. Wong name = name_loc->nameval; 816c631e79SDarrick J. Wong namelen = name_loc->namelen; 826c631e79SDarrick J. Wong value = &name_loc->nameval[name_loc->namelen]; 836c631e79SDarrick J. Wong valuelen = be16_to_cpu(name_loc->valuelen); 846c631e79SDarrick J. Wong } else { 856c631e79SDarrick J. Wong struct xfs_attr_leaf_name_remote *name_rmt; 866c631e79SDarrick J. Wong 876c631e79SDarrick J. Wong name_rmt = xfs_attr3_leaf_name_remote(leaf, i); 886c631e79SDarrick J. Wong name = name_rmt->name; 896c631e79SDarrick J. Wong namelen = name_rmt->namelen; 906c631e79SDarrick J. Wong value = NULL; 916c631e79SDarrick J. Wong valuelen = be32_to_cpu(name_rmt->valuelen); 926c631e79SDarrick J. Wong } 936c631e79SDarrick J. Wong 946c631e79SDarrick J. Wong error = attr_fn(sc, ip, entry->flags, name, namelen, value, 956c631e79SDarrick J. Wong valuelen, priv); 966c631e79SDarrick J. Wong if (error) 976c631e79SDarrick J. Wong return error; 986c631e79SDarrick J. Wong 996c631e79SDarrick J. Wong } 1006c631e79SDarrick J. Wong 1016c631e79SDarrick J. Wong return 0; 1026c631e79SDarrick J. Wong } 1036c631e79SDarrick J. Wong 1046c631e79SDarrick J. Wong /* 1056c631e79SDarrick J. Wong * Call a function for every entry in a leaf-format xattr structure. Avoid 1066c631e79SDarrick J. Wong * memory allocations for the loop detector since there's only one block. 1076c631e79SDarrick J. Wong */ 1086c631e79SDarrick J. Wong STATIC int 1096c631e79SDarrick J. Wong xchk_xattr_walk_leaf( 1106c631e79SDarrick J. Wong struct xfs_scrub *sc, 1116c631e79SDarrick J. Wong struct xfs_inode *ip, 1126c631e79SDarrick J. Wong xchk_xattr_fn attr_fn, 1136c631e79SDarrick J. Wong void *priv) 1146c631e79SDarrick J. Wong { 1156c631e79SDarrick J. Wong struct xfs_buf *leaf_bp; 1166c631e79SDarrick J. Wong int error; 1176c631e79SDarrick J. Wong 1186c631e79SDarrick J. Wong error = xfs_attr3_leaf_read(sc->tp, ip, ip->i_ino, 0, &leaf_bp); 1196c631e79SDarrick J. Wong if (error) 1206c631e79SDarrick J. Wong return error; 1216c631e79SDarrick J. Wong 1226c631e79SDarrick J. Wong error = xchk_xattr_walk_leaf_entries(sc, ip, attr_fn, leaf_bp, priv); 1236c631e79SDarrick J. Wong xfs_trans_brelse(sc->tp, leaf_bp); 1246c631e79SDarrick J. Wong return error; 1256c631e79SDarrick J. Wong } 1266c631e79SDarrick J. Wong 1276c631e79SDarrick J. Wong /* Find the leftmost leaf in the xattr dabtree. */ 1286c631e79SDarrick J. Wong STATIC int 1296c631e79SDarrick J. Wong xchk_xattr_find_leftmost_leaf( 1306c631e79SDarrick J. Wong struct xfs_scrub *sc, 1316c631e79SDarrick J. Wong struct xfs_inode *ip, 1326c631e79SDarrick J. Wong struct xdab_bitmap *seen_dablks, 1336c631e79SDarrick J. Wong struct xfs_buf **leaf_bpp) 1346c631e79SDarrick J. Wong { 1356c631e79SDarrick J. Wong struct xfs_da3_icnode_hdr nodehdr; 1366c631e79SDarrick J. Wong struct xfs_mount *mp = sc->mp; 1376c631e79SDarrick J. Wong struct xfs_trans *tp = sc->tp; 1386c631e79SDarrick J. Wong struct xfs_da_intnode *node; 1396c631e79SDarrick J. Wong struct xfs_da_node_entry *btree; 1406c631e79SDarrick J. Wong struct xfs_buf *bp; 1416c631e79SDarrick J. Wong xfs_failaddr_t fa; 1426c631e79SDarrick J. Wong xfs_dablk_t blkno = 0; 1436c631e79SDarrick J. Wong unsigned int expected_level = 0; 1446c631e79SDarrick J. Wong int error; 1456c631e79SDarrick J. Wong 1466c631e79SDarrick J. Wong for (;;) { 1476c631e79SDarrick J. Wong xfs_extlen_t len = 1; 1486c631e79SDarrick J. Wong uint16_t magic; 1496c631e79SDarrick J. Wong 1506c631e79SDarrick J. Wong /* Make sure we haven't seen this new block already. */ 1516c631e79SDarrick J. Wong if (xdab_bitmap_test(seen_dablks, blkno, &len)) 1526c631e79SDarrick J. Wong return -EFSCORRUPTED; 1536c631e79SDarrick J. Wong 1546c631e79SDarrick J. Wong error = xfs_da3_node_read(tp, ip, blkno, &bp, XFS_ATTR_FORK); 1556c631e79SDarrick J. Wong if (error) 1566c631e79SDarrick J. Wong return error; 1576c631e79SDarrick J. Wong 1586c631e79SDarrick J. Wong node = bp->b_addr; 1596c631e79SDarrick J. Wong magic = be16_to_cpu(node->hdr.info.magic); 1606c631e79SDarrick J. Wong if (magic == XFS_ATTR_LEAF_MAGIC || 1616c631e79SDarrick J. Wong magic == XFS_ATTR3_LEAF_MAGIC) 1626c631e79SDarrick J. Wong break; 1636c631e79SDarrick J. Wong 1646c631e79SDarrick J. Wong error = -EFSCORRUPTED; 1656c631e79SDarrick J. Wong if (magic != XFS_DA_NODE_MAGIC && 1666c631e79SDarrick J. Wong magic != XFS_DA3_NODE_MAGIC) 1676c631e79SDarrick J. Wong goto out_buf; 1686c631e79SDarrick J. Wong 1696c631e79SDarrick J. Wong fa = xfs_da3_node_header_check(bp, ip->i_ino); 1706c631e79SDarrick J. Wong if (fa) 1716c631e79SDarrick J. Wong goto out_buf; 1726c631e79SDarrick J. Wong 1736c631e79SDarrick J. Wong xfs_da3_node_hdr_from_disk(mp, &nodehdr, node); 1746c631e79SDarrick J. Wong 1756c631e79SDarrick J. Wong if (nodehdr.count == 0 || nodehdr.level >= XFS_DA_NODE_MAXDEPTH) 1766c631e79SDarrick J. Wong goto out_buf; 1776c631e79SDarrick J. Wong 1786c631e79SDarrick J. Wong /* Check the level from the root node. */ 1796c631e79SDarrick J. Wong if (blkno == 0) 1806c631e79SDarrick J. Wong expected_level = nodehdr.level - 1; 1816c631e79SDarrick J. Wong else if (expected_level != nodehdr.level) 1826c631e79SDarrick J. Wong goto out_buf; 1836c631e79SDarrick J. Wong else 1846c631e79SDarrick J. Wong expected_level--; 1856c631e79SDarrick J. Wong 1866c631e79SDarrick J. Wong /* Remember that we've seen this node. */ 1876c631e79SDarrick J. Wong error = xdab_bitmap_set(seen_dablks, blkno, 1); 1886c631e79SDarrick J. Wong if (error) 1896c631e79SDarrick J. Wong goto out_buf; 1906c631e79SDarrick J. Wong 1916c631e79SDarrick J. Wong /* Find the next level towards the leaves of the dabtree. */ 1926c631e79SDarrick J. Wong btree = nodehdr.btree; 1936c631e79SDarrick J. Wong blkno = be32_to_cpu(btree->before); 1946c631e79SDarrick J. Wong xfs_trans_brelse(tp, bp); 1956c631e79SDarrick J. Wong } 1966c631e79SDarrick J. Wong 1976c631e79SDarrick J. Wong error = -EFSCORRUPTED; 1986c631e79SDarrick J. Wong fa = xfs_attr3_leaf_header_check(bp, ip->i_ino); 1996c631e79SDarrick J. Wong if (fa) 2006c631e79SDarrick J. Wong goto out_buf; 2016c631e79SDarrick J. Wong 2026c631e79SDarrick J. Wong if (expected_level != 0) 2036c631e79SDarrick J. Wong goto out_buf; 2046c631e79SDarrick J. Wong 2056c631e79SDarrick J. Wong /* Remember that we've seen this leaf. */ 2066c631e79SDarrick J. Wong error = xdab_bitmap_set(seen_dablks, blkno, 1); 2076c631e79SDarrick J. Wong if (error) 2086c631e79SDarrick J. Wong goto out_buf; 2096c631e79SDarrick J. Wong 2106c631e79SDarrick J. Wong *leaf_bpp = bp; 2116c631e79SDarrick J. Wong return 0; 2126c631e79SDarrick J. Wong 2136c631e79SDarrick J. Wong out_buf: 2146c631e79SDarrick J. Wong xfs_trans_brelse(tp, bp); 2156c631e79SDarrick J. Wong return error; 2166c631e79SDarrick J. Wong } 2176c631e79SDarrick J. Wong 2186c631e79SDarrick J. Wong /* Call a function for every entry in a node-format xattr structure. */ 2196c631e79SDarrick J. Wong STATIC int 2206c631e79SDarrick J. Wong xchk_xattr_walk_node( 2216c631e79SDarrick J. Wong struct xfs_scrub *sc, 2226c631e79SDarrick J. Wong struct xfs_inode *ip, 2236c631e79SDarrick J. Wong xchk_xattr_fn attr_fn, 224*6efbbdebSDarrick J. Wong xchk_xattrleaf_fn leaf_fn, 2256c631e79SDarrick J. Wong void *priv) 2266c631e79SDarrick J. Wong { 2276c631e79SDarrick J. Wong struct xfs_attr3_icleaf_hdr leafhdr; 2286c631e79SDarrick J. Wong struct xdab_bitmap seen_dablks; 2296c631e79SDarrick J. Wong struct xfs_mount *mp = sc->mp; 2306c631e79SDarrick J. Wong struct xfs_attr_leafblock *leaf; 2316c631e79SDarrick J. Wong struct xfs_buf *leaf_bp; 2326c631e79SDarrick J. Wong int error; 2336c631e79SDarrick J. Wong 2346c631e79SDarrick J. Wong xdab_bitmap_init(&seen_dablks); 2356c631e79SDarrick J. Wong 2366c631e79SDarrick J. Wong error = xchk_xattr_find_leftmost_leaf(sc, ip, &seen_dablks, &leaf_bp); 2376c631e79SDarrick J. Wong if (error) 2386c631e79SDarrick J. Wong goto out_bitmap; 2396c631e79SDarrick J. Wong 2406c631e79SDarrick J. Wong for (;;) { 2416c631e79SDarrick J. Wong xfs_extlen_t len; 2426c631e79SDarrick J. Wong 2436c631e79SDarrick J. Wong error = xchk_xattr_walk_leaf_entries(sc, ip, attr_fn, leaf_bp, 2446c631e79SDarrick J. Wong priv); 2456c631e79SDarrick J. Wong if (error) 2466c631e79SDarrick J. Wong goto out_leaf; 2476c631e79SDarrick J. Wong 2486c631e79SDarrick J. Wong /* Find the right sibling of this leaf block. */ 2496c631e79SDarrick J. Wong leaf = leaf_bp->b_addr; 2506c631e79SDarrick J. Wong xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); 2516c631e79SDarrick J. Wong if (leafhdr.forw == 0) 2526c631e79SDarrick J. Wong goto out_leaf; 2536c631e79SDarrick J. Wong 2546c631e79SDarrick J. Wong xfs_trans_brelse(sc->tp, leaf_bp); 2556c631e79SDarrick J. Wong 256*6efbbdebSDarrick J. Wong if (leaf_fn) { 257*6efbbdebSDarrick J. Wong error = leaf_fn(sc, priv); 258*6efbbdebSDarrick J. Wong if (error) 259*6efbbdebSDarrick J. Wong goto out_bitmap; 260*6efbbdebSDarrick J. Wong } 261*6efbbdebSDarrick J. Wong 2626c631e79SDarrick J. Wong /* Make sure we haven't seen this new leaf already. */ 2636c631e79SDarrick J. Wong len = 1; 2646c631e79SDarrick J. Wong if (xdab_bitmap_test(&seen_dablks, leafhdr.forw, &len)) { 2656c631e79SDarrick J. Wong error = -EFSCORRUPTED; 2666c631e79SDarrick J. Wong goto out_bitmap; 2676c631e79SDarrick J. Wong } 2686c631e79SDarrick J. Wong 2696c631e79SDarrick J. Wong error = xfs_attr3_leaf_read(sc->tp, ip, ip->i_ino, 2706c631e79SDarrick J. Wong leafhdr.forw, &leaf_bp); 2716c631e79SDarrick J. Wong if (error) 2726c631e79SDarrick J. Wong goto out_bitmap; 2736c631e79SDarrick J. Wong 2746c631e79SDarrick J. Wong /* Remember that we've seen this new leaf. */ 2756c631e79SDarrick J. Wong error = xdab_bitmap_set(&seen_dablks, leafhdr.forw, 1); 2766c631e79SDarrick J. Wong if (error) 2776c631e79SDarrick J. Wong goto out_leaf; 2786c631e79SDarrick J. Wong } 2796c631e79SDarrick J. Wong 2806c631e79SDarrick J. Wong out_leaf: 2816c631e79SDarrick J. Wong xfs_trans_brelse(sc->tp, leaf_bp); 2826c631e79SDarrick J. Wong out_bitmap: 2836c631e79SDarrick J. Wong xdab_bitmap_destroy(&seen_dablks); 2846c631e79SDarrick J. Wong return error; 2856c631e79SDarrick J. Wong } 2866c631e79SDarrick J. Wong 2876c631e79SDarrick J. Wong /* 2886c631e79SDarrick J. Wong * Call a function for every extended attribute in a file. 2896c631e79SDarrick J. Wong * 2906c631e79SDarrick J. Wong * Callers must hold the ILOCK. No validation or cursor restarts allowed. 2916c631e79SDarrick J. Wong * Returns -EFSCORRUPTED on any problem, including loops in the dabtree. 2926c631e79SDarrick J. Wong */ 2936c631e79SDarrick J. Wong int 2946c631e79SDarrick J. Wong xchk_xattr_walk( 2956c631e79SDarrick J. Wong struct xfs_scrub *sc, 2966c631e79SDarrick J. Wong struct xfs_inode *ip, 2976c631e79SDarrick J. Wong xchk_xattr_fn attr_fn, 298*6efbbdebSDarrick J. Wong xchk_xattrleaf_fn leaf_fn, 2996c631e79SDarrick J. Wong void *priv) 3006c631e79SDarrick J. Wong { 3016c631e79SDarrick J. Wong int error; 3026c631e79SDarrick J. Wong 3036c631e79SDarrick J. Wong xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL); 3046c631e79SDarrick J. Wong 3056c631e79SDarrick J. Wong if (!xfs_inode_hasattr(ip)) 3066c631e79SDarrick J. Wong return 0; 3076c631e79SDarrick J. Wong 3086c631e79SDarrick J. Wong if (ip->i_af.if_format == XFS_DINODE_FMT_LOCAL) 3096c631e79SDarrick J. Wong return xchk_xattr_walk_sf(sc, ip, attr_fn, priv); 3106c631e79SDarrick J. Wong 3116c631e79SDarrick J. Wong /* attr functions require that the attr fork is loaded */ 3126c631e79SDarrick J. Wong error = xfs_iread_extents(sc->tp, ip, XFS_ATTR_FORK); 3136c631e79SDarrick J. Wong if (error) 3146c631e79SDarrick J. Wong return error; 3156c631e79SDarrick J. Wong 3166c631e79SDarrick J. Wong if (xfs_attr_is_leaf(ip)) 3176c631e79SDarrick J. Wong return xchk_xattr_walk_leaf(sc, ip, attr_fn, priv); 3186c631e79SDarrick J. Wong 319*6efbbdebSDarrick J. Wong return xchk_xattr_walk_node(sc, ip, attr_fn, leaf_fn, priv); 3206c631e79SDarrick J. Wong } 321