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-achx @ Mon Jul 31 20:08:12 PDT 2023 Lines: 150 169 88.8 %
Date: 2023-07-31 20:08:12 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  5192861571 : 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  5192861571 :         struct xfs_attr_shortform       *sf;
      34  5192861571 :         struct xfs_attr_sf_entry        *sfe;
      35  5192861571 :         unsigned int                    i;
      36  5192861571 :         int                             error;
      37             : 
      38  5192861571 :         sf = (struct xfs_attr_shortform *)ip->i_af.if_u1.if_data;
      39 11538533554 :         for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
      40  6377353302 :                 error = attr_fn(sc, ip, sfe->flags, sfe->nameval, sfe->namelen,
      41  6377353302 :                                 &sfe->nameval[sfe->namelen], sfe->valuelen,
      42             :                                 priv);
      43  6370020387 :                 if (error)
      44    24348404 :                         return error;
      45             : 
      46  6345671983 :                 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   128580764 : 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   128580764 :         struct xfs_attr3_icleaf_hdr     ichdr;
      62   128580764 :         struct xfs_mount                *mp = sc->mp;
      63   128580764 :         struct xfs_attr_leafblock       *leaf = bp->b_addr;
      64   128580764 :         struct xfs_attr_leaf_entry      *entry;
      65   128580764 :         unsigned int                    i;
      66   128580764 :         int                             error;
      67             : 
      68   128580764 :         xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
      69   128604707 :         entry = xfs_attr3_leaf_entryp(leaf);
      70             : 
      71  1250273422 :         for (i = 0; i < ichdr.count; entry++, i++) {
      72  1121830773 :                 void                    *value;
      73  1121830773 :                 unsigned char           *name;
      74  1121830773 :                 unsigned int            namelen, valuelen;
      75             : 
      76  1121830773 :                 if (entry->flags & XFS_ATTR_LOCAL) {
      77  1121826807 :                         struct xfs_attr_leaf_name_local         *name_loc;
      78             : 
      79  1121826807 :                         name_loc = xfs_attr3_leaf_name_local(leaf, i);
      80  1121826807 :                         name = name_loc->nameval;
      81  1121826807 :                         namelen = name_loc->namelen;
      82  1121826807 :                         value = &name_loc->nameval[name_loc->namelen];
      83  1121826807 :                         valuelen = be16_to_cpu(name_loc->valuelen);
      84             :                 } else {
      85        3966 :                         struct xfs_attr_leaf_name_remote        *name_rmt;
      86             : 
      87        3966 :                         name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
      88        3966 :                         name = name_rmt->name;
      89        3966 :                         namelen = name_rmt->namelen;
      90        3966 :                         value = NULL;
      91        3966 :                         valuelen = be32_to_cpu(name_rmt->valuelen);
      92             :                 }
      93             : 
      94  1121830773 :                 error = attr_fn(sc, ip, entry->flags, name, namelen, value,
      95             :                                 valuelen, priv);
      96  1121784384 :                 if (error)
      97      115669 :                         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   127438454 : 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   127438454 :         struct xfs_buf                  *leaf_bp;
     116   127438454 :         int                             error;
     117             : 
     118   127438454 :         error = xfs_attr3_leaf_read(sc->tp, ip, ip->i_ino, 0, &leaf_bp);
     119   127380471 :         if (error)
     120             :                 return error;
     121             : 
     122   127381397 :         error = xchk_xattr_walk_leaf_entries(sc, ip, attr_fn, leaf_bp, priv);
     123   127407364 :         xfs_trans_brelse(sc->tp, leaf_bp);
     124   127407364 :         return error;
     125             : }
     126             : 
     127             : /* Find the leftmost leaf in the xattr dabtree. */
     128             : STATIC int
     129       52267 : 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       52267 :         struct xfs_da3_icnode_hdr       nodehdr;
     136       52267 :         struct xfs_mount                *mp = sc->mp;
     137       52267 :         struct xfs_trans                *tp = sc->tp;
     138       52267 :         struct xfs_da_intnode           *node;
     139       52267 :         struct xfs_da_node_entry        *btree;
     140       52267 :         struct xfs_buf                  *bp;
     141       52267 :         xfs_failaddr_t                  fa;
     142       52267 :         xfs_dablk_t                     blkno = 0;
     143       52267 :         unsigned int                    expected_level = 0;
     144      101120 :         int                             error;
     145             : 
     146       48853 :         for (;;) {
     147      101120 :                 uint64_t                len = 1;
     148      101120 :                 uint16_t                magic;
     149             : 
     150             :                 /* Make sure we haven't seen this new block already. */
     151      101120 :                 if (xbitmap_test(seen_blocks, blkno, &len))
     152           0 :                         return -EFSCORRUPTED;
     153             : 
     154      101117 :                 error = xfs_da3_node_read(tp, ip, blkno, &bp, XFS_ATTR_FORK);
     155      101122 :                 if (error)
     156           0 :                         return error;
     157             : 
     158      101122 :                 node = bp->b_addr;
     159      101122 :                 magic = be16_to_cpu(node->hdr.info.magic);
     160      101122 :                 if (magic == XFS_ATTR_LEAF_MAGIC ||
     161      101122 :                     magic == XFS_ATTR3_LEAF_MAGIC)
     162             :                         break;
     163             : 
     164       48849 :                 error = -EFSCORRUPTED;
     165       48849 :                 if (magic != XFS_DA_NODE_MAGIC &&
     166       48849 :                     magic != XFS_DA3_NODE_MAGIC)
     167           0 :                         goto out_buf;
     168             : 
     169       48849 :                 fa = xfs_da3_node_header_check(bp, ip->i_ino);
     170       48848 :                 if (fa)
     171           0 :                         goto out_buf;
     172             : 
     173       48848 :                 xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
     174             : 
     175       48844 :                 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       48844 :                 if (blkno == 0)
     180       48565 :                         expected_level = nodehdr.level - 1;
     181         279 :                 else if (expected_level != nodehdr.level)
     182           0 :                         goto out_buf;
     183             :                 else
     184         279 :                         expected_level--;
     185             : 
     186             :                 /* Remember that we've seen this node. */
     187       48844 :                 error = xbitmap_set(seen_blocks, blkno, 1);
     188       48845 :                 if (error)
     189           0 :                         goto out_buf;
     190             : 
     191             :                 /* Find the next level towards the leaves of the dabtree. */
     192       48845 :                 btree = nodehdr.btree;
     193       48845 :                 blkno = be32_to_cpu(btree->before);
     194       48845 :                 xfs_trans_brelse(tp, bp);
     195             :         }
     196             : 
     197       52273 :         error = -EFSCORRUPTED;
     198       52273 :         fa = xfs_attr3_leaf_header_check(bp, ip->i_ino);
     199       52266 :         if (fa)
     200           0 :                 goto out_buf;
     201             : 
     202       52266 :         if (expected_level != 0)
     203           0 :                 goto out_buf;
     204             : 
     205             :         /* Remember that we've seen this leaf. */
     206       52266 :         error = xbitmap_set(seen_blocks, blkno, 1);
     207       52259 :         if (error)
     208           0 :                 goto out_buf;
     209             : 
     210       52259 :         *leaf_bpp = bp;
     211       52259 :         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       52269 : 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       52269 :         struct xfs_attr3_icleaf_hdr     leafhdr;
     228       52269 :         struct xbitmap                  seen_blocks;
     229       52269 :         struct xfs_mount                *mp = sc->mp;
     230       52269 :         struct xfs_attr_leafblock       *leaf;
     231       52269 :         struct xfs_buf                  *leaf_bp;
     232       52269 :         int                             error;
     233             : 
     234       52269 :         xbitmap_init(&seen_blocks);
     235             : 
     236       52271 :         error = xchk_xattr_find_leftmost_leaf(sc, ip, &seen_blocks, &leaf_bp);
     237       52262 :         if (error)
     238           0 :                 goto out_bitmap;
     239             : 
     240     1115943 :         for (;;) {
     241     1168205 :                 uint64_t        len;
     242             : 
     243     1168205 :                 error = xchk_xattr_walk_leaf_entries(sc, ip, attr_fn, leaf_bp,
     244             :                                 priv);
     245     1168217 :                 if (error)
     246          19 :                         goto out_leaf;
     247             : 
     248             :                 /* Find the right sibling of this leaf block. */
     249     1168198 :                 leaf = leaf_bp->b_addr;
     250     1168198 :                 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
     251     1168202 :                 if (leafhdr.forw == 0)
     252       52255 :                         goto out_leaf;
     253             : 
     254     1115947 :                 xfs_trans_brelse(sc->tp, leaf_bp);
     255             : 
     256     1115957 :                 if (leaf_fn) {
     257        2975 :                         error = leaf_fn(sc, priv);
     258        2975 :                         if (error)
     259           0 :                                 goto out_bitmap;
     260             :                 }
     261             : 
     262             :                 /* Make sure we haven't seen this new leaf already. */
     263     1115957 :                 len = 1;
     264     1115957 :                 if (xbitmap_test(&seen_blocks, leafhdr.forw, &len))
     265           0 :                         goto out_bitmap;
     266             : 
     267     1115955 :                 error = xfs_attr3_leaf_read(sc->tp, ip, ip->i_ino,
     268             :                                 leafhdr.forw, &leaf_bp);
     269     1115932 :                 if (error)
     270           0 :                         goto out_bitmap;
     271             : 
     272             :                 /* Remember that we've seen this new leaf. */
     273     1115932 :                 error = xbitmap_set(&seen_blocks, leafhdr.forw, 1);
     274     1115943 :                 if (error)
     275           0 :                         goto out_leaf;
     276             :         }
     277             : 
     278             : out_leaf:
     279       52274 :         xfs_trans_brelse(sc->tp, leaf_bp);
     280       52274 : out_bitmap:
     281       52274 :         xbitmap_destroy(&seen_blocks);
     282       52274 :         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  5339118335 : 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  5339118335 :         int                     error;
     300             : 
     301  5339118335 :         ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
     302             : 
     303  5318671629 :         if (!xfs_inode_hasattr(ip))
     304             :                 return 0;
     305             : 
     306  5319189223 :         if (ip->i_af.if_format == XFS_DINODE_FMT_LOCAL)
     307  5191720689 :                 return xchk_xattr_walk_sf(sc, ip, attr_fn, priv);
     308             : 
     309             :         /* attr functions require that the attr fork is loaded */
     310   127468534 :         error = xfs_iread_extents(sc->tp, ip, XFS_ATTR_FORK);
     311   127460853 :         if (error)
     312             :                 return error;
     313             : 
     314   127464926 :         if (xfs_attr_is_leaf(ip))
     315   127440152 :                 return xchk_xattr_walk_leaf(sc, ip, attr_fn, priv);
     316             : 
     317       52271 :         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  7062856027 : 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  7062856027 :         struct xchk_pptr_walk   *pw = priv;
     338  7062856027 :         const struct xfs_parent_name_rec *rec = (const void *)name;
     339             : 
     340             :         /* Ignore anything that isn't a parent pointer. */
     341  7062856027 :         if (!(attr_flags & XFS_ATTR_PARENT))
     342             :                 return 0;
     343             : 
     344             :         /* Does the ondisk parent pointer structure make sense? */
     345 10371910322 :         if (!xfs_parent_namecheck(sc->mp, rec, namelen, attr_flags) ||
     346  5185770410 :             !xfs_parent_valuecheck(sc->mp, value, valuelen))
     347           0 :                 return -EFSCORRUPTED;
     348             : 
     349  5174768305 :         xfs_parent_irec_from_disk(pw->pptr_buf, rec, value, valuelen);
     350  5184466754 :         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  4990185339 : 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  4990185339 :         struct xchk_pptr_walk           pw = {
     367             :                 .fn                     = pptr_fn,
     368             :                 .pptr_buf               = pptr_buf,
     369             :                 .priv                   = priv,
     370             :         };
     371             : 
     372  4990185339 :         ASSERT(xfs_has_parent(sc->mp));
     373             : 
     374  4990185339 :         return xchk_xattr_walk(sc, ip, xchk_pptr_walk_attr, NULL, &pw);
     375             : }

Generated by: LCOV version 1.14