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-djwa @ Mon Jul 31 20:08:17 PDT 2023 Lines: 234 270 86.7 %
Date: 2023-07-31 20:08:17 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     8382737 : xfs_attr_shortform_compare(const void *a, const void *b)
      28             : {
      29     8382737 :         xfs_attr_sf_sort_t *sa, *sb;
      30             : 
      31     8382737 :         sa = (xfs_attr_sf_sort_t *)a;
      32     8382737 :         sb = (xfs_attr_sf_sort_t *)b;
      33     8382737 :         if (sa->hash < sb->hash) {
      34             :                 return -1;
      35     2437651 :         } 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    50252279 : xfs_attr_shortform_list(
      54             :         struct xfs_attr_list_context    *context)
      55             : {
      56    50252279 :         struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
      57    50252279 :         struct xfs_inode                *dp = context->dp;
      58    50252279 :         struct xfs_attr_sf_sort         *sbuf, *sbp;
      59    50252279 :         struct xfs_attr_shortform       *sf;
      60    50252279 :         struct xfs_attr_sf_entry        *sfe;
      61    50252279 :         int                             sbsize, nsbuf, count, i;
      62    50252279 :         int                             error = 0;
      63             : 
      64    50252279 :         sf = (struct xfs_attr_shortform *)dp->i_af.if_u1.if_data;
      65    50252279 :         ASSERT(sf != NULL);
      66    50252279 :         if (!sf->hdr.count)
      67             :                 return 0;
      68             : 
      69    49869682 :         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    49870356 :         if (context->bufsize == 0 ||
      81    35325598 :             (XFS_ISRESET_CURSOR(cursor) &&
      82    35326176 :              (dp->i_af.if_bytes + sf->hdr.count * 16) < context->bufsize)) {
      83   113855852 :                 for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
      84    66386641 :                         if (XFS_IS_CORRUPT(context->dp->i_mount,
      85             :                                            !xfs_attr_namecheck(sfe->nameval,
      86             :                                                                sfe->namelen)))
      87           4 :                                 return -EFSCORRUPTED;
      88    66387832 :                         context->put_listent(context,
      89    66387832 :                                              sfe->flags,
      90             :                                              sfe->nameval,
      91    66387832 :                                              (int)sfe->namelen,
      92    66387832 :                                              (int)sfe->valuelen);
      93             :                         /*
      94             :                          * Either search callback finished early or
      95             :                          * didn't fit it all in the buffer after all.
      96             :                          */
      97    66390479 :                         if (context->seen_enough)
      98             :                                 break;
      99    66390479 :                         sfe = xfs_attr_sf_nextentry(sfe);
     100             :                 }
     101    47469211 :                 trace_xfs_attr_list_sf_all(context);
     102    47469211 :                 return 0;
     103             :         }
     104             : 
     105             :         /* do no more for a search callback */
     106     2404983 :         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     2404983 :         sbsize = sf->hdr.count * sizeof(*sbuf);
     113     2404983 :         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     2406197 :         nsbuf = 0;
     120     8911492 :         for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
     121     6505284 :                 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     6505284 :                 sbp->entno = i;
     133     6505284 :                 sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
     134     6505295 :                 sbp->name = sfe->nameval;
     135     6505295 :                 sbp->namelen = sfe->namelen;
     136             :                 /* These are bytes, and both on-disk, don't endian-flip */
     137     6505295 :                 sbp->valuelen = sfe->valuelen;
     138     6505295 :                 sbp->flags = sfe->flags;
     139     6505295 :                 sfe = xfs_attr_sf_nextentry(sfe);
     140     6505295 :                 sbp++;
     141     6505295 :                 nsbuf++;
     142             :         }
     143             : 
     144             :         /*
     145             :          * Sort the entries on hash then entno.
     146             :          */
     147     2406208 :         xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
     148             : 
     149             :         /*
     150             :          * Re-find our place IN THE SORTED LIST.
     151             :          */
     152     2406166 :         count = 0;
     153     2406166 :         cursor->initted = 1;
     154     2406166 :         cursor->blkno = 0;
     155     2406172 :         for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
     156     2406205 :                 if (sbp->hash == cursor->hashval) {
     157           0 :                         if (cursor->offset == count) {
     158             :                                 break;
     159             :                         }
     160           0 :                         count++;
     161     2406205 :                 } else if (sbp->hash > cursor->hashval) {
     162             :                         break;
     163             :                 }
     164             :         }
     165     2406166 :         if (i == nsbuf)
     166           0 :                 goto out;
     167             : 
     168             :         /*
     169             :          * Loop putting entries into the user buffer.
     170             :          */
     171     8911269 :         for ( ; i < nsbuf; i++, sbp++) {
     172     6505076 :                 if (cursor->hashval != sbp->hash) {
     173     6505076 :                         cursor->hashval = sbp->hash;
     174     6505076 :                         cursor->offset = 0;
     175             :                 }
     176     6505076 :                 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     6505207 :                 context->put_listent(context,
     183     6505207 :                                      sbp->flags,
     184             :                                      sbp->name,
     185     6505207 :                                      sbp->namelen,
     186     6505207 :                                      sbp->valuelen);
     187     6505111 :                 if (context->seen_enough)
     188             :                         break;
     189     6505103 :                 cursor->offset++;
     190             :         }
     191     2406201 : out:
     192     2406201 :         kmem_free(sbuf);
     193     2406201 :         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      510939 : 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      510939 :         struct xfs_da3_icnode_hdr       nodehdr;
     207      510939 :         struct xfs_da_intnode           *node;
     208      510939 :         struct xfs_da_node_entry        *btree;
     209      510939 :         struct xfs_inode                *dp = context->dp;
     210      510939 :         struct xfs_mount                *mp = dp->i_mount;
     211      510939 :         struct xfs_trans                *tp = context->tp;
     212      510939 :         struct xfs_buf                  *bp;
     213      510939 :         int                             i;
     214      510939 :         int                             error = 0;
     215      510939 :         unsigned int                    expected_level = 0;
     216      510939 :         uint16_t                        magic;
     217             : 
     218      510939 :         ASSERT(*pbp == NULL);
     219      510939 :         cursor->blkno = 0;
     220     1021861 :         for (;;) {
     221     1021861 :                 error = xfs_da3_node_read(tp, dp, cursor->blkno, &bp,
     222             :                                 XFS_ATTR_FORK);
     223     1021849 :                 if (error)
     224           0 :                         return error;
     225     1021849 :                 node = bp->b_addr;
     226     1021849 :                 magic = be16_to_cpu(node->hdr.info.magic);
     227     1021849 :                 if (magic == XFS_ATTR_LEAF_MAGIC ||
     228     1021849 :                     magic == XFS_ATTR3_LEAF_MAGIC)
     229             :                         break;
     230      510913 :                 if (magic != XFS_DA_NODE_MAGIC &&
     231      510913 :                     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      510913 :                 xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
     238             : 
     239             :                 /* Tree taller than we can handle; bail out! */
     240      510921 :                 if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
     241           0 :                         goto out_corruptbuf;
     242             : 
     243             :                 /* Check the level from the root node. */
     244      510921 :                 if (cursor->blkno == 0)
     245      510580 :                         expected_level = nodehdr.level - 1;
     246         341 :                 else if (expected_level != nodehdr.level)
     247           0 :                         goto out_corruptbuf;
     248             :                 else
     249         341 :                         expected_level--;
     250             : 
     251      510921 :                 btree = nodehdr.btree;
     252      510921 :                 for (i = 0; i < nodehdr.count; btree++, i++) {
     253     1021842 :                         if (cursor->hashval <= be32_to_cpu(btree->hashval)) {
     254      510921 :                                 cursor->blkno = be32_to_cpu(btree->before);
     255      510921 :                                 trace_xfs_attr_list_node_descend(context,
     256             :                                                 btree);
     257      510921 :                                 break;
     258             :                         }
     259             :                 }
     260      510921 :                 xfs_trans_brelse(tp, bp);
     261             : 
     262      510922 :                 if (i == nodehdr.count)
     263             :                         return 0;
     264             : 
     265             :                 /* We can't point back to the root. */
     266      510922 :                 if (XFS_IS_CORRUPT(mp, cursor->blkno == 0))
     267           0 :                         return -EFSCORRUPTED;
     268             :         }
     269             : 
     270      510936 :         if (expected_level != 0)
     271           0 :                 goto out_corruptbuf;
     272             : 
     273      510936 :         *pbp = bp;
     274      510936 :         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      510954 : xfs_attr_node_list(
     284             :         struct xfs_attr_list_context    *context)
     285             : {
     286      510954 :         struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
     287      510954 :         struct xfs_attr3_icleaf_hdr     leafhdr;
     288      510954 :         struct xfs_attr_leafblock       *leaf;
     289      510954 :         struct xfs_da_intnode           *node;
     290      510954 :         struct xfs_buf                  *bp;
     291      510954 :         struct xfs_inode                *dp = context->dp;
     292      510954 :         struct xfs_mount                *mp = dp->i_mount;
     293      510954 :         int                             error = 0;
     294             : 
     295      510954 :         trace_xfs_attr_node_list(context);
     296             : 
     297      510959 :         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      510959 :         bp = NULL;
     305      510959 :         if (cursor->blkno > 0) {
     306         345 :                 error = xfs_da3_node_read(context->tp, dp, cursor->blkno, &bp,
     307             :                                 XFS_ATTR_FORK);
     308         345 :                 if ((error != 0) && (error != -EFSCORRUPTED))
     309             :                         return error;
     310         345 :                 if (bp) {
     311         345 :                         struct xfs_attr_leaf_entry *entries;
     312             : 
     313         345 :                         node = bp->b_addr;
     314         345 :                         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         345 :                         case XFS_ATTR_LEAF_MAGIC:
     322             :                         case XFS_ATTR3_LEAF_MAGIC:
     323         345 :                                 leaf = bp->b_addr;
     324         345 :                                 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo,
     325             :                                                              &leafhdr, leaf);
     326         345 :                                 entries = xfs_attr3_leaf_entryp(leaf);
     327         690 :                                 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         690 :                                 } else if (cursor->hashval <= be32_to_cpu(
     333             :                                                 entries[0].hashval)) {
     334         325 :                                         trace_xfs_attr_list_wrong_blk(context);
     335         325 :                                         xfs_trans_brelse(context->tp, bp);
     336         325 :                                         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      510959 :         if (bp == NULL) {
     353      510939 :                 error = xfs_attr_node_list_lookup(context, cursor, &bp);
     354      510937 :                 if (error || !bp)
     355             :                         return error;
     356             :         }
     357      510957 :         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     1742980 :         for (;;) {
     365     1742980 :                 leaf = bp->b_addr;
     366     1742980 :                 error = xfs_attr3_leaf_list_int(bp, context);
     367     1742959 :                 if (error)
     368             :                         break;
     369     1742959 :                 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
     370     1742974 :                 if (context->seen_enough || leafhdr.forw == 0)
     371             :                         break;
     372     1232019 :                 cursor->blkno = leafhdr.forw;
     373     1232019 :                 xfs_trans_brelse(context->tp, bp);
     374     1232022 :                 error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
     375             :                                             &bp);
     376     1232023 :                 if (error)
     377           0 :                         return error;
     378             :         }
     379      510955 :         xfs_trans_brelse(context->tp, bp);
     380      510955 :         return error;
     381             : }
     382             : 
     383             : /*
     384             :  * Copy out attribute list entries for attr_list(), for leaf attribute lists.
     385             :  */
     386             : int
     387    28841031 : xfs_attr3_leaf_list_int(
     388             :         struct xfs_buf                  *bp,
     389             :         struct xfs_attr_list_context    *context)
     390             : {
     391    28841031 :         struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
     392    28841031 :         struct xfs_attr_leafblock       *leaf;
     393    28841031 :         struct xfs_attr3_icleaf_hdr     ichdr;
     394    28841031 :         struct xfs_attr_leaf_entry      *entries;
     395    28841031 :         struct xfs_attr_leaf_entry      *entry;
     396    28841031 :         int                             i;
     397    28841031 :         struct xfs_mount                *mp = context->dp->i_mount;
     398             : 
     399    28841031 :         trace_xfs_attr_list_leaf(context);
     400             : 
     401    28843151 :         leaf = bp->b_addr;
     402    28843151 :         xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
     403    28842287 :         entries = xfs_attr3_leaf_entryp(leaf);
     404             : 
     405    28842287 :         cursor->initted = 1;
     406             : 
     407             :         /*
     408             :          * Re-find our place in the leaf block if this is a new syscall.
     409             :          */
     410    28842287 :         if (context->resynch) {
     411             :                 entry = &entries[0];
     412    37304836 :                 for (i = 0; i < ichdr.count; entry++, i++) {
     413    73405950 :                         if (be32_to_cpu(entry->hashval) == cursor->hashval) {
     414     9091247 :                                 if (cursor->offset == context->dupcnt) {
     415         347 :                                         context->dupcnt = 0;
     416         347 :                                         break;
     417             :                                 }
     418     9090900 :                                 context->dupcnt++;
     419    27611728 :                         } else if (be32_to_cpu(entry->hashval) >
     420             :                                         cursor->hashval) {
     421    27610369 :                                 context->dupcnt = 0;
     422    27610369 :                                 break;
     423             :                         }
     424             :                 }
     425    28212577 :                 if (i == ichdr.count) {
     426      601861 :                         trace_xfs_attr_list_notfound(context);
     427      601861 :                         return 0;
     428             :                 }
     429             :         } else {
     430             :                 entry = &entries[0];
     431             :                 i = 0;
     432             :         }
     433    28240426 :         context->resynch = 0;
     434             : 
     435             :         /*
     436             :          * We have found our place, start copying out the new attributes.
     437             :          */
     438   521493894 :         for (; i < ichdr.count; entry++, i++) {
     439   493255031 :                 char *name;
     440   493255031 :                 int namelen, valuelen;
     441             : 
     442   986510062 :                 if (be32_to_cpu(entry->hashval) != cursor->hashval) {
     443   497227204 :                         cursor->hashval = be32_to_cpu(entry->hashval);
     444   497227204 :                         cursor->offset = 0;
     445             :                 }
     446             : 
     447   493255031 :                 if ((entry->flags & XFS_ATTR_INCOMPLETE) &&
     448           0 :                     !context->allow_incomplete)
     449           0 :                         continue;
     450             : 
     451   493255031 :                 if (entry->flags & XFS_ATTR_LOCAL) {
     452   493254672 :                         xfs_attr_leaf_name_local_t *name_loc;
     453             : 
     454   493254672 :                         name_loc = xfs_attr3_leaf_name_local(leaf, i);
     455   493254672 :                         name = name_loc->nameval;
     456   493254672 :                         namelen = name_loc->namelen;
     457   493254672 :                         valuelen = be16_to_cpu(name_loc->valuelen);
     458             :                 } else {
     459         359 :                         xfs_attr_leaf_name_remote_t *name_rmt;
     460             : 
     461         359 :                         name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
     462         359 :                         name = name_rmt->name;
     463         359 :                         namelen = name_rmt->namelen;
     464         359 :                         valuelen = be32_to_cpu(name_rmt->valuelen);
     465             :                 }
     466             : 
     467   493255031 :                 if (XFS_IS_CORRUPT(context->dp->i_mount,
     468             :                                    !xfs_attr_namecheck(name, namelen)))
     469           0 :                         return -EFSCORRUPTED;
     470   497290201 :                 context->put_listent(context, entry->flags,
     471             :                                               name, namelen, valuelen);
     472   493253815 :                 if (context->seen_enough)
     473             :                         break;
     474   493253468 :                 cursor->offset++;
     475             :         }
     476    28239210 :         trace_xfs_attr_list_leaf_end(context);
     477    28239210 :         return 0;
     478             : }
     479             : 
     480             : /*
     481             :  * Copy out attribute entries for attr_list(), for leaf attribute lists.
     482             :  */
     483             : STATIC int
     484    27097275 : xfs_attr_leaf_list(
     485             :         struct xfs_attr_list_context    *context)
     486             : {
     487    27097275 :         struct xfs_buf                  *bp;
     488    27097275 :         int                             error;
     489             : 
     490    27097275 :         trace_xfs_attr_leaf_list(context);
     491             : 
     492    27099506 :         context->cursor.blkno = 0;
     493    27099506 :         error = xfs_attr3_leaf_read(context->tp, context->dp, 0, &bp);
     494    27100492 :         if (error)
     495             :                 return error;
     496             : 
     497    27100392 :         error = xfs_attr3_leaf_list_int(bp, context);
     498    27096758 :         xfs_trans_brelse(context->tp, bp);
     499    27096758 :         return error;
     500             : }
     501             : 
     502             : int
     503    79565599 : xfs_attr_list_ilocked(
     504             :         struct xfs_attr_list_context    *context)
     505             : {
     506    79565599 :         struct xfs_inode                *dp = context->dp;
     507             : 
     508    79565599 :         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    79570873 :         if (!xfs_inode_hasattr(dp))
     514             :                 return 0;
     515    77862603 :         if (dp->i_af.if_format == XFS_DINODE_FMT_LOCAL)
     516    50251842 :                 return xfs_attr_shortform_list(context);
     517    27610761 :         if (xfs_attr_is_leaf(dp))
     518    27099378 :                 return xfs_attr_leaf_list(context);
     519      510959 :         return xfs_attr_node_list(context);
     520             : }
     521             : 
     522             : int
     523    66251190 : xfs_attr_list(
     524             :         struct xfs_attr_list_context    *context)
     525             : {
     526    66251190 :         struct xfs_inode                *dp = context->dp;
     527    66251190 :         uint                            lock_mode;
     528    66251190 :         int                             error;
     529             : 
     530    66251190 :         XFS_STATS_INC(dp->i_mount, xs_attr_list);
     531             : 
     532   132505422 :         if (xfs_is_shutdown(dp->i_mount))
     533             :                 return -EIO;
     534             : 
     535    66252711 :         lock_mode = xfs_ilock_attr_map_shared(dp);
     536    66257898 :         error = xfs_attr_list_ilocked(context);
     537    66215888 :         xfs_iunlock(dp, lock_mode);
     538    66215888 :         return error;
     539             : }

Generated by: LCOV version 1.14