LCOV - code coverage report
Current view: top level - fs/xfs - xfs_attr_list.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwx @ Mon Jul 31 20:08:22 PDT 2023 Lines: 234 270 86.7 %
Date: 2023-07-31 20:08:22 Functions: 8 8 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
       4             :  * Copyright (c) 2013 Red Hat, Inc.
       5             :  * All Rights Reserved.
       6             :  */
       7             : #include "xfs.h"
       8             : #include "xfs_fs.h"
       9             : #include "xfs_shared.h"
      10             : #include "xfs_format.h"
      11             : #include "xfs_log_format.h"
      12             : #include "xfs_trans_resv.h"
      13             : #include "xfs_mount.h"
      14             : #include "xfs_da_format.h"
      15             : #include "xfs_inode.h"
      16             : #include "xfs_trans.h"
      17             : #include "xfs_bmap.h"
      18             : #include "xfs_da_btree.h"
      19             : #include "xfs_attr.h"
      20             : #include "xfs_attr_sf.h"
      21             : #include "xfs_attr_leaf.h"
      22             : #include "xfs_error.h"
      23             : #include "xfs_trace.h"
      24             : #include "xfs_dir2.h"
      25             : 
      26             : STATIC int
      27     9636188 : xfs_attr_shortform_compare(const void *a, const void *b)
      28             : {
      29     9636188 :         xfs_attr_sf_sort_t *sa, *sb;
      30             : 
      31     9636188 :         sa = (xfs_attr_sf_sort_t *)a;
      32     9636188 :         sb = (xfs_attr_sf_sort_t *)b;
      33     9636188 :         if (sa->hash < sb->hash) {
      34             :                 return -1;
      35     2789353 :         } else if (sa->hash > sb->hash) {
      36             :                 return 1;
      37             :         } else {
      38           0 :                 return sa->entno - sb->entno;
      39             :         }
      40             : }
      41             : 
      42             : #define XFS_ISRESET_CURSOR(cursor) \
      43             :         (!((cursor)->initted) && !((cursor)->hashval) && \
      44             :          !((cursor)->blkno) && !((cursor)->offset))
      45             : /*
      46             :  * Copy out entries of shortform attribute lists for attr_list().
      47             :  * Shortform attribute lists are not stored in hashval sorted order.
      48             :  * If the output buffer is not large enough to hold them all, then
      49             :  * we have to calculate each entries' hashvalue and sort them before
      50             :  * we can begin returning them to the user.
      51             :  */
      52             : static int
      53    67197726 : xfs_attr_shortform_list(
      54             :         struct xfs_attr_list_context    *context)
      55             : {
      56    67197726 :         struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
      57    67197726 :         struct xfs_inode                *dp = context->dp;
      58    67197726 :         struct xfs_attr_sf_sort         *sbuf, *sbp;
      59    67197726 :         struct xfs_attr_shortform       *sf;
      60    67197726 :         struct xfs_attr_sf_entry        *sfe;
      61    67197726 :         int                             sbsize, nsbuf, count, i;
      62    67197726 :         int                             error = 0;
      63             : 
      64    67197726 :         sf = (struct xfs_attr_shortform *)dp->i_af.if_u1.if_data;
      65    67197726 :         ASSERT(sf != NULL);
      66    67197726 :         if (!sf->hdr.count)
      67             :                 return 0;
      68             : 
      69    66794787 :         trace_xfs_attr_list_sf(context);
      70             : 
      71             :         /*
      72             :          * If the buffer is large enough and the cursor is at the start,
      73             :          * do not bother with sorting since we will return everything in
      74             :          * one buffer and another call using the cursor won't need to be
      75             :          * made.
      76             :          * Note the generous fudge factor of 16 overhead bytes per entry.
      77             :          * If bufsize is zero then put_listent must be a search function
      78             :          * and can just scan through what we have.
      79             :          */
      80    66795012 :         if (context->bufsize == 0 ||
      81    46858830 :             (XFS_ISRESET_CURSOR(cursor) &&
      82    46870723 :              (dp->i_af.if_bytes + sf->hdr.count * 16) < context->bufsize)) {
      83   151439333 :                 for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
      84    87483234 :                         if (XFS_IS_CORRUPT(context->dp->i_mount,
      85             :                                            !xfs_attr_namecheck(sfe->nameval,
      86             :                                                                sfe->namelen)))
      87          22 :                                 return -EFSCORRUPTED;
      88    87650156 :                         context->put_listent(context,
      89    87650156 :                                              sfe->flags,
      90             :                                              sfe->nameval,
      91    87650156 :                                              (int)sfe->namelen,
      92    87650156 :                                              (int)sfe->valuelen);
      93             :                         /*
      94             :                          * Either search callback finished early or
      95             :                          * didn't fit it all in the buffer after all.
      96             :                          */
      97    87521334 :                         if (context->seen_enough)
      98             :                                 break;
      99    87521334 :                         sfe = xfs_attr_sf_nextentry(sfe);
     100             :                 }
     101    63956099 :                 trace_xfs_attr_list_sf_all(context);
     102    63956099 :                 return 0;
     103             :         }
     104             : 
     105             :         /* do no more for a search callback */
     106     2877013 :         if (context->bufsize == 0)
     107             :                 return 0;
     108             : 
     109             :         /*
     110             :          * It didn't all fit, so we have to sort everything on hashval.
     111             :          */
     112     2877013 :         sbsize = sf->hdr.count * sizeof(*sbuf);
     113     2877013 :         sbp = sbuf = kmem_alloc(sbsize, KM_NOFS);
     114             : 
     115             :         /*
     116             :          * Scan the attribute list for the rest of the entries, storing
     117             :          * the relevant info from only those that match into a buffer.
     118             :          */
     119     2893951 :         nsbuf = 0;
     120    10531032 :         for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
     121     7637103 :                 if (unlikely(
     122             :                     ((char *)sfe < (char *)sf) ||
     123             :                     ((char *)sfe >= ((char *)sf + dp->i_af.if_bytes)))) {
     124           0 :                         XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
     125             :                                              XFS_ERRLEVEL_LOW,
     126             :                                              context->dp->i_mount, sfe,
     127             :                                              sizeof(*sfe));
     128           0 :                         kmem_free(sbuf);
     129           0 :                         return -EFSCORRUPTED;
     130             :                 }
     131             : 
     132     7637103 :                 sbp->entno = i;
     133     7637103 :                 sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
     134     7637081 :                 sbp->name = sfe->nameval;
     135     7637081 :                 sbp->namelen = sfe->namelen;
     136             :                 /* These are bytes, and both on-disk, don't endian-flip */
     137     7637081 :                 sbp->valuelen = sfe->valuelen;
     138     7637081 :                 sbp->flags = sfe->flags;
     139     7637081 :                 sfe = xfs_attr_sf_nextentry(sfe);
     140     7637081 :                 sbp++;
     141     7637081 :                 nsbuf++;
     142             :         }
     143             : 
     144             :         /*
     145             :          * Sort the entries on hash then entno.
     146             :          */
     147     2893929 :         xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
     148             : 
     149             :         /*
     150             :          * Re-find our place IN THE SORTED LIST.
     151             :          */
     152     2894000 :         count = 0;
     153     2894000 :         cursor->initted = 1;
     154     2894000 :         cursor->blkno = 0;
     155     2894028 :         for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
     156     2893931 :                 if (sbp->hash == cursor->hashval) {
     157           0 :                         if (cursor->offset == count) {
     158             :                                 break;
     159             :                         }
     160           0 :                         count++;
     161     2893931 :                 } else if (sbp->hash > cursor->hashval) {
     162             :                         break;
     163             :                 }
     164             :         }
     165     2894000 :         if (i == nsbuf)
     166           0 :                 goto out;
     167             : 
     168             :         /*
     169             :          * Loop putting entries into the user buffer.
     170             :          */
     171    10531139 :         for ( ; i < nsbuf; i++, sbp++) {
     172     7637137 :                 if (cursor->hashval != sbp->hash) {
     173     7637137 :                         cursor->hashval = sbp->hash;
     174     7637137 :                         cursor->offset = 0;
     175             :                 }
     176     7637137 :                 if (XFS_IS_CORRUPT(context->dp->i_mount,
     177             :                                    !xfs_attr_namecheck(sbp->name,
     178             :                                                        sbp->namelen))) {
     179           0 :                         error = -EFSCORRUPTED;
     180           0 :                         goto out;
     181             :                 }
     182     7637171 :                 context->put_listent(context,
     183     7637171 :                                      sbp->flags,
     184             :                                      sbp->name,
     185     7637171 :                                      sbp->namelen,
     186     7637171 :                                      sbp->valuelen);
     187     7637183 :                 if (context->seen_enough)
     188             :                         break;
     189     7637139 :                 cursor->offset++;
     190             :         }
     191     2894046 : out:
     192     2894046 :         kmem_free(sbuf);
     193     2894046 :         return error;
     194             : }
     195             : 
     196             : /*
     197             :  * We didn't find the block & hash mentioned in the cursor state, so
     198             :  * walk down the attr btree looking for the hash.
     199             :  */
     200             : STATIC int
     201      562278 : xfs_attr_node_list_lookup(
     202             :         struct xfs_attr_list_context    *context,
     203             :         struct xfs_attrlist_cursor_kern *cursor,
     204             :         struct xfs_buf                  **pbp)
     205             : {
     206      562278 :         struct xfs_da3_icnode_hdr       nodehdr;
     207      562278 :         struct xfs_da_intnode           *node;
     208      562278 :         struct xfs_da_node_entry        *btree;
     209      562278 :         struct xfs_inode                *dp = context->dp;
     210      562278 :         struct xfs_mount                *mp = dp->i_mount;
     211      562278 :         struct xfs_trans                *tp = context->tp;
     212      562278 :         struct xfs_buf                  *bp;
     213      562278 :         int                             i;
     214      562278 :         int                             error = 0;
     215      562278 :         unsigned int                    expected_level = 0;
     216      562278 :         uint16_t                        magic;
     217             : 
     218      562278 :         ASSERT(*pbp == NULL);
     219      562278 :         cursor->blkno = 0;
     220     1124411 :         for (;;) {
     221     1124411 :                 error = xfs_da3_node_read(tp, dp, cursor->blkno, &bp,
     222             :                                 XFS_ATTR_FORK);
     223     1124463 :                 if (error)
     224           0 :                         return error;
     225     1124463 :                 node = bp->b_addr;
     226     1124463 :                 magic = be16_to_cpu(node->hdr.info.magic);
     227     1124463 :                 if (magic == XFS_ATTR_LEAF_MAGIC ||
     228     1124463 :                     magic == XFS_ATTR3_LEAF_MAGIC)
     229             :                         break;
     230      562161 :                 if (magic != XFS_DA_NODE_MAGIC &&
     231      562161 :                     magic != XFS_DA3_NODE_MAGIC) {
     232           0 :                         XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
     233             :                                         node, sizeof(*node));
     234           0 :                         goto out_corruptbuf;
     235             :                 }
     236             : 
     237      562161 :                 xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
     238             : 
     239             :                 /* Tree taller than we can handle; bail out! */
     240      562146 :                 if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
     241           0 :                         goto out_corruptbuf;
     242             : 
     243             :                 /* Check the level from the root node. */
     244      562146 :                 if (cursor->blkno == 0)
     245      561047 :                         expected_level = nodehdr.level - 1;
     246        1099 :                 else if (expected_level != nodehdr.level)
     247           0 :                         goto out_corruptbuf;
     248             :                 else
     249        1099 :                         expected_level--;
     250             : 
     251      562146 :                 btree = nodehdr.btree;
     252      562146 :                 for (i = 0; i < nodehdr.count; btree++, i++) {
     253      562151 :                         if (cursor->hashval <= be32_to_cpu(btree->hashval)) {
     254      562151 :                                 cursor->blkno = be32_to_cpu(btree->before);
     255      562151 :                                 trace_xfs_attr_list_node_descend(context,
     256             :                                                 btree);
     257      562151 :                                 break;
     258             :                         }
     259             :                 }
     260      562144 :                 xfs_trans_brelse(tp, bp);
     261             : 
     262      562133 :                 if (i == nodehdr.count)
     263             :                         return 0;
     264             : 
     265             :                 /* We can't point back to the root. */
     266      562133 :                 if (XFS_IS_CORRUPT(mp, cursor->blkno == 0))
     267           0 :                         return -EFSCORRUPTED;
     268             :         }
     269             : 
     270      562302 :         if (expected_level != 0)
     271           0 :                 goto out_corruptbuf;
     272             : 
     273      562302 :         *pbp = bp;
     274      562302 :         return 0;
     275             : 
     276           0 : out_corruptbuf:
     277           0 :         xfs_buf_mark_corrupt(bp);
     278           0 :         xfs_trans_brelse(tp, bp);
     279           0 :         return -EFSCORRUPTED;
     280             : }
     281             : 
     282             : STATIC int
     283      562330 : xfs_attr_node_list(
     284             :         struct xfs_attr_list_context    *context)
     285             : {
     286      562330 :         struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
     287      562330 :         struct xfs_attr3_icleaf_hdr     leafhdr;
     288      562330 :         struct xfs_attr_leafblock       *leaf;
     289      562330 :         struct xfs_da_intnode           *node;
     290      562330 :         struct xfs_buf                  *bp;
     291      562330 :         struct xfs_inode                *dp = context->dp;
     292      562330 :         struct xfs_mount                *mp = dp->i_mount;
     293      562330 :         int                             error = 0;
     294             : 
     295      562330 :         trace_xfs_attr_node_list(context);
     296             : 
     297      562330 :         cursor->initted = 1;
     298             : 
     299             :         /*
     300             :          * Do all sorts of validation on the passed-in cursor structure.
     301             :          * If anything is amiss, ignore the cursor and look up the hashval
     302             :          * starting from the btree root.
     303             :          */
     304      562330 :         bp = NULL;
     305      562330 :         if (cursor->blkno > 0) {
     306        1026 :                 error = xfs_da3_node_read(context->tp, dp, cursor->blkno, &bp,
     307             :                                 XFS_ATTR_FORK);
     308        1026 :                 if ((error != 0) && (error != -EFSCORRUPTED))
     309             :                         return error;
     310        1026 :                 if (bp) {
     311        1026 :                         struct xfs_attr_leaf_entry *entries;
     312             : 
     313        1026 :                         node = bp->b_addr;
     314        1026 :                         switch (be16_to_cpu(node->hdr.info.magic)) {
     315           0 :                         case XFS_DA_NODE_MAGIC:
     316             :                         case XFS_DA3_NODE_MAGIC:
     317           0 :                                 trace_xfs_attr_list_wrong_blk(context);
     318           0 :                                 xfs_trans_brelse(context->tp, bp);
     319           0 :                                 bp = NULL;
     320           0 :                                 break;
     321        1026 :                         case XFS_ATTR_LEAF_MAGIC:
     322             :                         case XFS_ATTR3_LEAF_MAGIC:
     323        1026 :                                 leaf = bp->b_addr;
     324        1026 :                                 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo,
     325             :                                                              &leafhdr, leaf);
     326        1026 :                                 entries = xfs_attr3_leaf_entryp(leaf);
     327        1026 :                                 if (cursor->hashval > be32_to_cpu(
     328             :                                                 entries[leafhdr.count - 1].hashval)) {
     329           0 :                                         trace_xfs_attr_list_wrong_blk(context);
     330           0 :                                         xfs_trans_brelse(context->tp, bp);
     331           0 :                                         bp = NULL;
     332        1026 :                                 } else if (cursor->hashval <= be32_to_cpu(
     333             :                                                 entries[0].hashval)) {
     334         975 :                                         trace_xfs_attr_list_wrong_blk(context);
     335         975 :                                         xfs_trans_brelse(context->tp, bp);
     336         975 :                                         bp = NULL;
     337             :                                 }
     338             :                                 break;
     339           0 :                         default:
     340           0 :                                 trace_xfs_attr_list_wrong_blk(context);
     341           0 :                                 xfs_trans_brelse(context->tp, bp);
     342           0 :                                 bp = NULL;
     343             :                         }
     344             :                 }
     345             :         }
     346             : 
     347             :         /*
     348             :          * We did not find what we expected given the cursor's contents,
     349             :          * so we start from the top and work down based on the hash value.
     350             :          * Note that start of node block is same as start of leaf block.
     351             :          */
     352      562330 :         if (bp == NULL) {
     353      562280 :                 error = xfs_attr_node_list_lookup(context, cursor, &bp);
     354      562294 :                 if (error || !bp)
     355             :                         return error;
     356             :         }
     357      562344 :         ASSERT(bp != NULL);
     358             : 
     359             :         /*
     360             :          * Roll upward through the blocks, processing each leaf block in
     361             :          * order.  As long as there is space in the result buffer, keep
     362             :          * adding the information.
     363             :          */
     364     2550894 :         for (;;) {
     365     2550894 :                 leaf = bp->b_addr;
     366     2550894 :                 error = xfs_attr3_leaf_list_int(bp, context);
     367     2550902 :                 if (error)
     368             :                         break;
     369     2550902 :                 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
     370     2550896 :                 if (context->seen_enough || leafhdr.forw == 0)
     371             :                         break;
     372     1988541 :                 cursor->blkno = leafhdr.forw;
     373     1988541 :                 xfs_trans_brelse(context->tp, bp);
     374     1988558 :                 error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
     375             :                                             &bp);
     376     1988550 :                 if (error)
     377           0 :                         return error;
     378             :         }
     379      562355 :         xfs_trans_brelse(context->tp, bp);
     380      562355 :         return error;
     381             : }
     382             : 
     383             : /*
     384             :  * Copy out attribute list entries for attr_list(), for leaf attribute lists.
     385             :  */
     386             : int
     387    33281525 : xfs_attr3_leaf_list_int(
     388             :         struct xfs_buf                  *bp,
     389             :         struct xfs_attr_list_context    *context)
     390             : {
     391    33281525 :         struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
     392    33281525 :         struct xfs_attr_leafblock       *leaf;
     393    33281525 :         struct xfs_attr3_icleaf_hdr     ichdr;
     394    33281525 :         struct xfs_attr_leaf_entry      *entries;
     395    33281525 :         struct xfs_attr_leaf_entry      *entry;
     396    33281525 :         int                             i;
     397    33281525 :         struct xfs_mount                *mp = context->dp->i_mount;
     398             : 
     399    33281525 :         trace_xfs_attr_list_leaf(context);
     400             : 
     401    33221332 :         leaf = bp->b_addr;
     402    33221332 :         xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
     403    33246264 :         entries = xfs_attr3_leaf_entryp(leaf);
     404             : 
     405    33246264 :         cursor->initted = 1;
     406             : 
     407             :         /*
     408             :          * Re-find our place in the leaf block if this is a new syscall.
     409             :          */
     410    33246264 :         if (context->resynch) {
     411             :                 entry = &entries[0];
     412    40379068 :                 for (i = 0; i < ichdr.count; entry++, i++) {
     413    39365748 :                         if (be32_to_cpu(entry->hashval) == cursor->hashval) {
     414     8109136 :                                 if (cursor->offset == context->dupcnt) {
     415        1036 :                                         context->dupcnt = 0;
     416        1036 :                                         break;
     417             :                                 }
     418     8108100 :                                 context->dupcnt++;
     419    31256612 :                         } else if (be32_to_cpu(entry->hashval) >
     420             :                                         cursor->hashval) {
     421    31256645 :                                 context->dupcnt = 0;
     422    31256645 :                                 break;
     423             :                         }
     424             :                 }
     425    32271001 :                 if (i == ichdr.count) {
     426     1013320 :                         trace_xfs_attr_list_notfound(context);
     427     1013320 :                         return 0;
     428             :                 }
     429             :         } else {
     430             :                 entry = &entries[0];
     431             :                 i = 0;
     432             :         }
     433    32232944 :         context->resynch = 0;
     434             : 
     435             :         /*
     436             :          * We have found our place, start copying out the new attributes.
     437             :          */
     438   583099247 :         for (; i < ichdr.count; entry++, i++) {
     439   550793435 :                 char *name;
     440   550793435 :                 int namelen, valuelen;
     441             : 
     442   550793435 :                 if (be32_to_cpu(entry->hashval) != cursor->hashval) {
     443   549799490 :                         cursor->hashval = be32_to_cpu(entry->hashval);
     444   549799490 :                         cursor->offset = 0;
     445             :                 }
     446             : 
     447   550793435 :                 if ((entry->flags & XFS_ATTR_INCOMPLETE) &&
     448           0 :                     !context->allow_incomplete)
     449           0 :                         continue;
     450             : 
     451   550793435 :                 if (entry->flags & XFS_ATTR_LOCAL) {
     452   550791721 :                         xfs_attr_leaf_name_local_t *name_loc;
     453             : 
     454   550791721 :                         name_loc = xfs_attr3_leaf_name_local(leaf, i);
     455   550791721 :                         name = name_loc->nameval;
     456   550791721 :                         namelen = name_loc->namelen;
     457   550791721 :                         valuelen = be16_to_cpu(name_loc->valuelen);
     458             :                 } else {
     459        1714 :                         xfs_attr_leaf_name_remote_t *name_rmt;
     460             : 
     461        1714 :                         name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
     462        1714 :                         name = name_rmt->name;
     463        1714 :                         namelen = name_rmt->namelen;
     464        1714 :                         valuelen = be32_to_cpu(name_rmt->valuelen);
     465             :                 }
     466             : 
     467   550793435 :                 if (XFS_IS_CORRUPT(context->dp->i_mount,
     468             :                                    !xfs_attr_namecheck(name, namelen)))
     469           0 :                         return -EFSCORRUPTED;
     470   550809038 :                 context->put_listent(context, entry->flags,
     471             :                                               name, namelen, valuelen);
     472   550867339 :                 if (context->seen_enough)
     473             :                         break;
     474   550866303 :                 cursor->offset++;
     475             :         }
     476    32306848 :         trace_xfs_attr_list_leaf_end(context);
     477    32306848 :         return 0;
     478             : }
     479             : 
     480             : /*
     481             :  * Copy out attribute entries for attr_list(), for leaf attribute lists.
     482             :  */
     483             : STATIC int
     484    30740818 : xfs_attr_leaf_list(
     485             :         struct xfs_attr_list_context    *context)
     486             : {
     487    30740818 :         struct xfs_buf                  *bp;
     488    30740818 :         int                             error;
     489             : 
     490    30740818 :         trace_xfs_attr_leaf_list(context);
     491             : 
     492    30712751 :         context->cursor.blkno = 0;
     493    30712751 :         error = xfs_attr3_leaf_read(context->tp, context->dp, 0, &bp);
     494    30733836 :         if (error)
     495             :                 return error;
     496             : 
     497    30734005 :         error = xfs_attr3_leaf_list_int(bp, context);
     498    30752988 :         xfs_trans_brelse(context->tp, bp);
     499    30752988 :         return error;
     500             : }
     501             : 
     502             : int
     503   101077003 : xfs_attr_list_ilocked(
     504             :         struct xfs_attr_list_context    *context)
     505             : {
     506   101077003 :         struct xfs_inode                *dp = context->dp;
     507             : 
     508   101077003 :         ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
     509             : 
     510             :         /*
     511             :          * Decide on what work routines to call based on the inode size.
     512             :          */
     513   100763257 :         if (!xfs_inode_hasattr(dp))
     514             :                 return 0;
     515    98474583 :         if (dp->i_af.if_format == XFS_DINODE_FMT_LOCAL)
     516    67201833 :                 return xfs_attr_shortform_list(context);
     517    31272750 :         if (xfs_attr_is_leaf(dp))
     518    30747021 :                 return xfs_attr_leaf_list(context);
     519      562340 :         return xfs_attr_node_list(context);
     520             : }
     521             : 
     522             : int
     523    82526348 : xfs_attr_list(
     524             :         struct xfs_attr_list_context    *context)
     525             : {
     526    82526348 :         struct xfs_inode                *dp = context->dp;
     527    82526348 :         uint                            lock_mode;
     528    82526348 :         int                             error;
     529             : 
     530    82526348 :         XFS_STATS_INC(dp->i_mount, xs_attr_list);
     531             : 
     532   164797202 :         if (xfs_is_shutdown(dp->i_mount))
     533             :                 return -EIO;
     534             : 
     535    82398597 :         lock_mode = xfs_ilock_attr_map_shared(dp);
     536    82454539 :         error = xfs_attr_list_ilocked(context);
     537    82506775 :         xfs_iunlock(dp, lock_mode);
     538    82506775 :         return error;
     539             : }

Generated by: LCOV version 1.14