LCOV - code coverage report
Current view: top level - fs/xfs/scrub - listxattr.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-acha @ Mon Jul 31 20:08:06 PDT 2023 Lines: 147 169 87.0 %
Date: 2023-07-31 20:08:07 Functions: 8 8 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 2022-2023 Oracle.  All Rights Reserved.
       4             :  * Author: Darrick J. Wong <djwong@kernel.org>
       5             :  */
       6             : #include "xfs.h"
       7             : #include "xfs_fs.h"
       8             : #include "xfs_shared.h"
       9             : #include "xfs_format.h"
      10             : #include "xfs_log_format.h"
      11             : #include "xfs_trans_resv.h"
      12             : #include "xfs_mount.h"
      13             : #include "xfs_inode.h"
      14             : #include "xfs_da_format.h"
      15             : #include "xfs_da_btree.h"
      16             : #include "xfs_attr.h"
      17             : #include "xfs_attr_leaf.h"
      18             : #include "xfs_attr_sf.h"
      19             : #include "xfs_trans.h"
      20             : #include "xfs_parent.h"
      21             : #include "scrub/scrub.h"
      22             : #include "scrub/bitmap.h"
      23             : #include "scrub/listxattr.h"
      24             : 
      25             : /* Call a function for every entry in a shortform xattr structure. */
      26             : STATIC int
      27  1910213199 : xchk_xattr_walk_sf(
      28             :         struct xfs_scrub                *sc,
      29             :         struct xfs_inode                *ip,
      30             :         xchk_xattr_fn                   attr_fn,
      31             :         void                            *priv)
      32             : {
      33  1910213199 :         struct xfs_attr_shortform       *sf;
      34  1910213199 :         struct xfs_attr_sf_entry        *sfe;
      35  1910213199 :         unsigned int                    i;
      36  1910213199 :         int                             error;
      37             : 
      38  1910213199 :         sf = (struct xfs_attr_shortform *)ip->i_af.if_u1.if_data;
      39  4033347211 :         for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
      40  2124631961 :                 error = attr_fn(sc, ip, sfe->flags, sfe->nameval, sfe->namelen,
      41  2124631961 :                                 &sfe->nameval[sfe->namelen], sfe->valuelen,
      42             :                                 priv);
      43  2137478238 :                 if (error)
      44    14344226 :                         return error;
      45             : 
      46  2123134012 :                 sfe = xfs_attr_sf_nextentry(sfe);
      47             :         }
      48             : 
      49             :         return 0;
      50             : }
      51             : 
      52             : /* Call a function for every entry in this xattr leaf block. */
      53             : STATIC int
      54     6065932 : xchk_xattr_walk_leaf_entries(
      55             :         struct xfs_scrub                *sc,
      56             :         struct xfs_inode                *ip,
      57             :         xchk_xattr_fn                   attr_fn,
      58             :         struct xfs_buf                  *bp,
      59             :         void                            *priv)
      60             : {
      61     6065932 :         struct xfs_attr3_icleaf_hdr     ichdr;
      62     6065932 :         struct xfs_mount                *mp = sc->mp;
      63     6065932 :         struct xfs_attr_leafblock       *leaf = bp->b_addr;
      64     6065932 :         struct xfs_attr_leaf_entry      *entry;
      65     6065932 :         unsigned int                    i;
      66     6065932 :         int                             error;
      67             : 
      68     6065932 :         xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
      69     6066704 :         entry = xfs_attr3_leaf_entryp(leaf);
      70             : 
      71    79159451 :         for (i = 0; i < ichdr.count; entry++, i++) {
      72    73116278 :                 void                    *value;
      73    73116278 :                 unsigned char           *name;
      74    73116278 :                 unsigned int            namelen, valuelen;
      75             : 
      76    73116278 :                 if (entry->flags & XFS_ATTR_LOCAL) {
      77    73115883 :                         struct xfs_attr_leaf_name_local         *name_loc;
      78             : 
      79    73115883 :                         name_loc = xfs_attr3_leaf_name_local(leaf, i);
      80    73115883 :                         name = name_loc->nameval;
      81    73115883 :                         namelen = name_loc->namelen;
      82    73115883 :                         value = &name_loc->nameval[name_loc->namelen];
      83    73115883 :                         valuelen = be16_to_cpu(name_loc->valuelen);
      84             :                 } else {
      85         395 :                         struct xfs_attr_leaf_name_remote        *name_rmt;
      86             : 
      87         395 :                         name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
      88         395 :                         name = name_rmt->name;
      89         395 :                         namelen = name_rmt->namelen;
      90         395 :                         value = NULL;
      91         395 :                         valuelen = be32_to_cpu(name_rmt->valuelen);
      92             :                 }
      93             : 
      94    73116278 :                 error = attr_fn(sc, ip, entry->flags, name, namelen, value,
      95             :                                 valuelen, priv);
      96    73116204 :                 if (error)
      97       23457 :                         return error;
      98             : 
      99             :         }
     100             : 
     101             :         return 0;
     102             : }
     103             : 
     104             : /*
     105             :  * Call a function for every entry in a leaf-format xattr structure.  Avoid
     106             :  * memory allocations for the loop detector since there's only one block.
     107             :  */
     108             : STATIC int
     109     5932852 : xchk_xattr_walk_leaf(
     110             :         struct xfs_scrub                *sc,
     111             :         struct xfs_inode                *ip,
     112             :         xchk_xattr_fn                   attr_fn,
     113             :         void                            *priv)
     114             : {
     115     5932852 :         struct xfs_buf                  *leaf_bp;
     116     5932852 :         int                             error;
     117             : 
     118     5932852 :         error = xfs_attr3_leaf_read(sc->tp, ip, ip->i_ino, 0, &leaf_bp);
     119     5931570 :         if (error)
     120             :                 return error;
     121             : 
     122     5931635 :         error = xchk_xattr_walk_leaf_entries(sc, ip, attr_fn, leaf_bp, priv);
     123     5932512 :         xfs_trans_brelse(sc->tp, leaf_bp);
     124     5932512 :         return error;
     125             : }
     126             : 
     127             : /* Find the leftmost leaf in the xattr dabtree. */
     128             : STATIC int
     129       42557 : xchk_xattr_find_leftmost_leaf(
     130             :         struct xfs_scrub                *sc,
     131             :         struct xfs_inode                *ip,
     132             :         struct xbitmap                  *seen_blocks,
     133             :         struct xfs_buf                  **leaf_bpp)
     134             : {
     135       42557 :         struct xfs_da3_icnode_hdr       nodehdr;
     136       42557 :         struct xfs_mount                *mp = sc->mp;
     137       42557 :         struct xfs_trans                *tp = sc->tp;
     138       42557 :         struct xfs_da_intnode           *node;
     139       42557 :         struct xfs_da_node_entry        *btree;
     140       42557 :         struct xfs_buf                  *bp;
     141       42557 :         xfs_failaddr_t                  fa;
     142       42557 :         xfs_dablk_t                     blkno = 0;
     143       42557 :         unsigned int                    expected_level = 0;
     144       84727 :         int                             error;
     145             : 
     146       42170 :         for (;;) {
     147       84727 :                 uint64_t                len = 1;
     148       84727 :                 uint16_t                magic;
     149             : 
     150             :                 /* Make sure we haven't seen this new block already. */
     151       84727 :                 if (xbitmap_test(seen_blocks, blkno, &len))
     152           0 :                         return -EFSCORRUPTED;
     153             : 
     154       84727 :                 error = xfs_da3_node_read(tp, ip, blkno, &bp, XFS_ATTR_FORK);
     155       84727 :                 if (error)
     156           0 :                         return error;
     157             : 
     158       84727 :                 node = bp->b_addr;
     159       84727 :                 magic = be16_to_cpu(node->hdr.info.magic);
     160       84727 :                 if (magic == XFS_ATTR_LEAF_MAGIC ||
     161       84727 :                     magic == XFS_ATTR3_LEAF_MAGIC)
     162             :                         break;
     163             : 
     164       42170 :                 error = -EFSCORRUPTED;
     165       42170 :                 if (magic != XFS_DA_NODE_MAGIC &&
     166       42170 :                     magic != XFS_DA3_NODE_MAGIC)
     167           0 :                         goto out_buf;
     168             : 
     169       42170 :                 fa = xfs_da3_node_header_check(bp, ip->i_ino);
     170       42170 :                 if (fa)
     171           0 :                         goto out_buf;
     172             : 
     173       42170 :                 xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
     174             : 
     175       42170 :                 if (nodehdr.count == 0 || nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
     176           0 :                         goto out_buf;
     177             : 
     178             :                 /* Check the level from the root node. */
     179       42170 :                 if (blkno == 0)
     180       42162 :                         expected_level = nodehdr.level - 1;
     181           8 :                 else if (expected_level != nodehdr.level)
     182           0 :                         goto out_buf;
     183             :                 else
     184           8 :                         expected_level--;
     185             : 
     186             :                 /* Remember that we've seen this node. */
     187       42170 :                 error = xbitmap_set(seen_blocks, blkno, 1);
     188       42170 :                 if (error)
     189           0 :                         goto out_buf;
     190             : 
     191             :                 /* Find the next level towards the leaves of the dabtree. */
     192       42170 :                 btree = nodehdr.btree;
     193       42170 :                 blkno = be32_to_cpu(btree->before);
     194       42170 :                 xfs_trans_brelse(tp, bp);
     195             :         }
     196             : 
     197       42557 :         error = -EFSCORRUPTED;
     198       42557 :         fa = xfs_attr3_leaf_header_check(bp, ip->i_ino);
     199       42557 :         if (fa)
     200           0 :                 goto out_buf;
     201             : 
     202       42557 :         if (expected_level != 0)
     203           0 :                 goto out_buf;
     204             : 
     205             :         /* Remember that we've seen this leaf. */
     206       42557 :         error = xbitmap_set(seen_blocks, blkno, 1);
     207       42557 :         if (error)
     208           0 :                 goto out_buf;
     209             : 
     210       42557 :         *leaf_bpp = bp;
     211       42557 :         return 0;
     212             : 
     213           0 : out_buf:
     214           0 :         xfs_trans_brelse(tp, bp);
     215           0 :         return error;
     216             : }
     217             : 
     218             : /* Call a function for every entry in a node-format xattr structure. */
     219             : STATIC int
     220       42557 : xchk_xattr_walk_node(
     221             :         struct xfs_scrub                *sc,
     222             :         struct xfs_inode                *ip,
     223             :         xchk_xattr_fn                   attr_fn,
     224             :         xchk_xattrleaf_fn               leaf_fn,
     225             :         void                            *priv)
     226             : {
     227       42557 :         struct xfs_attr3_icleaf_hdr     leafhdr;
     228       42557 :         struct xbitmap                  seen_blocks;
     229       42557 :         struct xfs_mount                *mp = sc->mp;
     230       42557 :         struct xfs_attr_leafblock       *leaf;
     231       42557 :         struct xfs_buf                  *leaf_bp;
     232       42557 :         int                             error;
     233             : 
     234       42557 :         xbitmap_init(&seen_blocks);
     235             : 
     236       42557 :         error = xchk_xattr_find_leftmost_leaf(sc, ip, &seen_blocks, &leaf_bp);
     237       42557 :         if (error)
     238           0 :                 goto out_bitmap;
     239             : 
     240       91817 :         for (;;) {
     241      134374 :                 uint64_t        len;
     242             : 
     243      134374 :                 error = xchk_xattr_walk_leaf_entries(sc, ip, attr_fn, leaf_bp,
     244             :                                 priv);
     245      134372 :                 if (error)
     246           0 :                         goto out_leaf;
     247             : 
     248             :                 /* Find the right sibling of this leaf block. */
     249      134372 :                 leaf = leaf_bp->b_addr;
     250      134372 :                 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
     251      134374 :                 if (leafhdr.forw == 0)
     252       42557 :                         goto out_leaf;
     253             : 
     254       91817 :                 xfs_trans_brelse(sc->tp, leaf_bp);
     255             : 
     256       91817 :                 if (leaf_fn) {
     257           0 :                         error = leaf_fn(sc, priv);
     258           0 :                         if (error)
     259           0 :                                 goto out_bitmap;
     260             :                 }
     261             : 
     262             :                 /* Make sure we haven't seen this new leaf already. */
     263       91817 :                 len = 1;
     264       91817 :                 if (xbitmap_test(&seen_blocks, leafhdr.forw, &len))
     265           0 :                         goto out_bitmap;
     266             : 
     267       91817 :                 error = xfs_attr3_leaf_read(sc->tp, ip, ip->i_ino,
     268             :                                 leafhdr.forw, &leaf_bp);
     269       91817 :                 if (error)
     270           0 :                         goto out_bitmap;
     271             : 
     272             :                 /* Remember that we've seen this new leaf. */
     273       91817 :                 error = xbitmap_set(&seen_blocks, leafhdr.forw, 1);
     274       91817 :                 if (error)
     275           0 :                         goto out_leaf;
     276             :         }
     277             : 
     278             : out_leaf:
     279       42557 :         xfs_trans_brelse(sc->tp, leaf_bp);
     280       42557 : out_bitmap:
     281       42557 :         xbitmap_destroy(&seen_blocks);
     282       42557 :         return error;
     283             : }
     284             : 
     285             : /*
     286             :  * Call a function for every extended attribute in a file.
     287             :  *
     288             :  * Callers must hold the ILOCK.  No validation or cursor restarts allowed.
     289             :  * Returns -EFSCORRUPTED on any problem, including loops in the dabtree.
     290             :  */
     291             : int
     292  1926145263 : xchk_xattr_walk(
     293             :         struct xfs_scrub        *sc,
     294             :         struct xfs_inode        *ip,
     295             :         xchk_xattr_fn           attr_fn,
     296             :         xchk_xattrleaf_fn       leaf_fn,
     297             :         void                    *priv)
     298             : {
     299  1926145263 :         int                     error;
     300             : 
     301  1926145263 :         ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
     302             : 
     303  1926320594 :         if (!xfs_inode_hasattr(ip))
     304             :                 return 0;
     305             : 
     306  1928151028 :         if (ip->i_af.if_format == XFS_DINODE_FMT_LOCAL)
     307  1922175440 :                 return xchk_xattr_walk_sf(sc, ip, attr_fn, priv);
     308             : 
     309             :         /* attr functions require that the attr fork is loaded */
     310     5975588 :         error = xfs_iread_extents(sc->tp, ip, XFS_ATTR_FORK);
     311     5976283 :         if (error)
     312             :                 return error;
     313             : 
     314     5976206 :         if (xfs_attr_is_leaf(ip))
     315     5932531 :                 return xchk_xattr_walk_leaf(sc, ip, attr_fn, priv);
     316             : 
     317       42557 :         return xchk_xattr_walk_node(sc, ip, attr_fn, leaf_fn, priv);
     318             : }
     319             : 
     320             : struct xchk_pptr_walk {
     321             :         struct xfs_parent_name_irec     *pptr_buf;
     322             :         xchk_pptr_fn                    fn;
     323             :         void                            *priv;
     324             : };
     325             : 
     326             : STATIC int
     327  1928397943 : xchk_pptr_walk_attr(
     328             :         struct xfs_scrub        *sc,
     329             :         struct xfs_inode        *ip,
     330             :         unsigned int            attr_flags,
     331             :         const unsigned char     *name,
     332             :         unsigned int            namelen,
     333             :         const void              *value,
     334             :         unsigned int            valuelen,
     335             :         void                    *priv)
     336             : {
     337  1928397943 :         struct xchk_pptr_walk   *pw = priv;
     338  1928397943 :         const struct xfs_parent_name_rec *rec = (const void *)name;
     339             : 
     340             :         /* Ignore anything that isn't a parent pointer. */
     341  1928397943 :         if (!(attr_flags & XFS_ATTR_PARENT))
     342             :                 return 0;
     343             : 
     344             :         /* Does the ondisk parent pointer structure make sense? */
     345  3626012550 :         if (!xfs_parent_namecheck(sc->mp, rec, namelen, attr_flags) ||
     346  1814238328 :             !xfs_parent_valuecheck(sc->mp, value, valuelen))
     347           0 :                 return -EFSCORRUPTED;
     348             : 
     349  1814497251 :         xfs_parent_irec_from_disk(pw->pptr_buf, rec, value, valuelen);
     350  1814251074 :         return pw->fn(sc, ip, pw->pptr_buf, pw->priv);
     351             : }
     352             : 
     353             : /*
     354             :  * Walk every parent pointer of this file.  The parent pointer will be
     355             :  * formatted into the provided pptr_buf, which is then passed to the callback
     356             :  * function.
     357             :  */
     358             : int
     359  1711437947 : xchk_pptr_walk(
     360             :         struct xfs_scrub                *sc,
     361             :         struct xfs_inode                *ip,
     362             :         xchk_pptr_fn                    pptr_fn,
     363             :         struct xfs_parent_name_irec     *pptr_buf,
     364             :         void                            *priv)
     365             : {
     366  1711437947 :         struct xchk_pptr_walk           pw = {
     367             :                 .fn                     = pptr_fn,
     368             :                 .pptr_buf               = pptr_buf,
     369             :                 .priv                   = priv,
     370             :         };
     371             : 
     372  1711437947 :         ASSERT(xfs_has_parent(sc->mp));
     373             : 
     374  1711437947 :         return xchk_xattr_walk(sc, ip, xchk_pptr_walk_attr, NULL, &pw);
     375             : }

Generated by: LCOV version 1.14