Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
0004  * Copyright (c) 2013 Red Hat, Inc.
0005  * All Rights Reserved.
0006  */
0007 #include "xfs.h"
0008 #include "xfs_fs.h"
0009 #include "xfs_shared.h"
0010 #include "xfs_format.h"
0011 #include "xfs_log_format.h"
0012 #include "xfs_trans_resv.h"
0013 #include "xfs_mount.h"
0014 #include "xfs_da_format.h"
0015 #include "xfs_inode.h"
0016 #include "xfs_trans.h"
0017 #include "xfs_bmap.h"
0018 #include "xfs_da_btree.h"
0019 #include "xfs_attr.h"
0020 #include "xfs_attr_sf.h"
0021 #include "xfs_attr_leaf.h"
0022 #include "xfs_error.h"
0023 #include "xfs_trace.h"
0024 #include "xfs_dir2.h"
0025 
0026 STATIC int
0027 xfs_attr_shortform_compare(const void *a, const void *b)
0028 {
0029     xfs_attr_sf_sort_t *sa, *sb;
0030 
0031     sa = (xfs_attr_sf_sort_t *)a;
0032     sb = (xfs_attr_sf_sort_t *)b;
0033     if (sa->hash < sb->hash) {
0034         return -1;
0035     } else if (sa->hash > sb->hash) {
0036         return 1;
0037     } else {
0038         return sa->entno - sb->entno;
0039     }
0040 }
0041 
0042 #define XFS_ISRESET_CURSOR(cursor) \
0043     (!((cursor)->initted) && !((cursor)->hashval) && \
0044      !((cursor)->blkno) && !((cursor)->offset))
0045 /*
0046  * Copy out entries of shortform attribute lists for attr_list().
0047  * Shortform attribute lists are not stored in hashval sorted order.
0048  * If the output buffer is not large enough to hold them all, then
0049  * we have to calculate each entries' hashvalue and sort them before
0050  * we can begin returning them to the user.
0051  */
0052 static int
0053 xfs_attr_shortform_list(
0054     struct xfs_attr_list_context    *context)
0055 {
0056     struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
0057     struct xfs_inode        *dp = context->dp;
0058     struct xfs_attr_sf_sort     *sbuf, *sbp;
0059     struct xfs_attr_shortform   *sf;
0060     struct xfs_attr_sf_entry    *sfe;
0061     int             sbsize, nsbuf, count, i;
0062     int             error = 0;
0063 
0064     sf = (struct xfs_attr_shortform *)dp->i_af.if_u1.if_data;
0065     ASSERT(sf != NULL);
0066     if (!sf->hdr.count)
0067         return 0;
0068 
0069     trace_xfs_attr_list_sf(context);
0070 
0071     /*
0072      * If the buffer is large enough and the cursor is at the start,
0073      * do not bother with sorting since we will return everything in
0074      * one buffer and another call using the cursor won't need to be
0075      * made.
0076      * Note the generous fudge factor of 16 overhead bytes per entry.
0077      * If bufsize is zero then put_listent must be a search function
0078      * and can just scan through what we have.
0079      */
0080     if (context->bufsize == 0 ||
0081         (XFS_ISRESET_CURSOR(cursor) &&
0082          (dp->i_af.if_bytes + sf->hdr.count * 16) < context->bufsize)) {
0083         for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
0084             if (XFS_IS_CORRUPT(context->dp->i_mount,
0085                        !xfs_attr_namecheck(sfe->nameval,
0086                                    sfe->namelen)))
0087                 return -EFSCORRUPTED;
0088             context->put_listent(context,
0089                          sfe->flags,
0090                          sfe->nameval,
0091                          (int)sfe->namelen,
0092                          (int)sfe->valuelen);
0093             /*
0094              * Either search callback finished early or
0095              * didn't fit it all in the buffer after all.
0096              */
0097             if (context->seen_enough)
0098                 break;
0099             sfe = xfs_attr_sf_nextentry(sfe);
0100         }
0101         trace_xfs_attr_list_sf_all(context);
0102         return 0;
0103     }
0104 
0105     /* do no more for a search callback */
0106     if (context->bufsize == 0)
0107         return 0;
0108 
0109     /*
0110      * It didn't all fit, so we have to sort everything on hashval.
0111      */
0112     sbsize = sf->hdr.count * sizeof(*sbuf);
0113     sbp = sbuf = kmem_alloc(sbsize, KM_NOFS);
0114 
0115     /*
0116      * Scan the attribute list for the rest of the entries, storing
0117      * the relevant info from only those that match into a buffer.
0118      */
0119     nsbuf = 0;
0120     for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
0121         if (unlikely(
0122             ((char *)sfe < (char *)sf) ||
0123             ((char *)sfe >= ((char *)sf + dp->i_af.if_bytes)))) {
0124             XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
0125                          XFS_ERRLEVEL_LOW,
0126                          context->dp->i_mount, sfe,
0127                          sizeof(*sfe));
0128             kmem_free(sbuf);
0129             return -EFSCORRUPTED;
0130         }
0131 
0132         sbp->entno = i;
0133         sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
0134         sbp->name = sfe->nameval;
0135         sbp->namelen = sfe->namelen;
0136         /* These are bytes, and both on-disk, don't endian-flip */
0137         sbp->valuelen = sfe->valuelen;
0138         sbp->flags = sfe->flags;
0139         sfe = xfs_attr_sf_nextentry(sfe);
0140         sbp++;
0141         nsbuf++;
0142     }
0143 
0144     /*
0145      * Sort the entries on hash then entno.
0146      */
0147     xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
0148 
0149     /*
0150      * Re-find our place IN THE SORTED LIST.
0151      */
0152     count = 0;
0153     cursor->initted = 1;
0154     cursor->blkno = 0;
0155     for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
0156         if (sbp->hash == cursor->hashval) {
0157             if (cursor->offset == count) {
0158                 break;
0159             }
0160             count++;
0161         } else if (sbp->hash > cursor->hashval) {
0162             break;
0163         }
0164     }
0165     if (i == nsbuf)
0166         goto out;
0167 
0168     /*
0169      * Loop putting entries into the user buffer.
0170      */
0171     for ( ; i < nsbuf; i++, sbp++) {
0172         if (cursor->hashval != sbp->hash) {
0173             cursor->hashval = sbp->hash;
0174             cursor->offset = 0;
0175         }
0176         if (XFS_IS_CORRUPT(context->dp->i_mount,
0177                    !xfs_attr_namecheck(sbp->name,
0178                                sbp->namelen))) {
0179             error = -EFSCORRUPTED;
0180             goto out;
0181         }
0182         context->put_listent(context,
0183                      sbp->flags,
0184                      sbp->name,
0185                      sbp->namelen,
0186                      sbp->valuelen);
0187         if (context->seen_enough)
0188             break;
0189         cursor->offset++;
0190     }
0191 out:
0192     kmem_free(sbuf);
0193     return error;
0194 }
0195 
0196 /*
0197  * We didn't find the block & hash mentioned in the cursor state, so
0198  * walk down the attr btree looking for the hash.
0199  */
0200 STATIC int
0201 xfs_attr_node_list_lookup(
0202     struct xfs_attr_list_context    *context,
0203     struct xfs_attrlist_cursor_kern *cursor,
0204     struct xfs_buf          **pbp)
0205 {
0206     struct xfs_da3_icnode_hdr   nodehdr;
0207     struct xfs_da_intnode       *node;
0208     struct xfs_da_node_entry    *btree;
0209     struct xfs_inode        *dp = context->dp;
0210     struct xfs_mount        *mp = dp->i_mount;
0211     struct xfs_trans        *tp = context->tp;
0212     struct xfs_buf          *bp;
0213     int             i;
0214     int             error = 0;
0215     unsigned int            expected_level = 0;
0216     uint16_t            magic;
0217 
0218     ASSERT(*pbp == NULL);
0219     cursor->blkno = 0;
0220     for (;;) {
0221         error = xfs_da3_node_read(tp, dp, cursor->blkno, &bp,
0222                 XFS_ATTR_FORK);
0223         if (error)
0224             return error;
0225         node = bp->b_addr;
0226         magic = be16_to_cpu(node->hdr.info.magic);
0227         if (magic == XFS_ATTR_LEAF_MAGIC ||
0228             magic == XFS_ATTR3_LEAF_MAGIC)
0229             break;
0230         if (magic != XFS_DA_NODE_MAGIC &&
0231             magic != XFS_DA3_NODE_MAGIC) {
0232             XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
0233                     node, sizeof(*node));
0234             goto out_corruptbuf;
0235         }
0236 
0237         xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
0238 
0239         /* Tree taller than we can handle; bail out! */
0240         if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
0241             goto out_corruptbuf;
0242 
0243         /* Check the level from the root node. */
0244         if (cursor->blkno == 0)
0245             expected_level = nodehdr.level - 1;
0246         else if (expected_level != nodehdr.level)
0247             goto out_corruptbuf;
0248         else
0249             expected_level--;
0250 
0251         btree = nodehdr.btree;
0252         for (i = 0; i < nodehdr.count; btree++, i++) {
0253             if (cursor->hashval <= be32_to_cpu(btree->hashval)) {
0254                 cursor->blkno = be32_to_cpu(btree->before);
0255                 trace_xfs_attr_list_node_descend(context,
0256                         btree);
0257                 break;
0258             }
0259         }
0260         xfs_trans_brelse(tp, bp);
0261 
0262         if (i == nodehdr.count)
0263             return 0;
0264 
0265         /* We can't point back to the root. */
0266         if (XFS_IS_CORRUPT(mp, cursor->blkno == 0))
0267             return -EFSCORRUPTED;
0268     }
0269 
0270     if (expected_level != 0)
0271         goto out_corruptbuf;
0272 
0273     *pbp = bp;
0274     return 0;
0275 
0276 out_corruptbuf:
0277     xfs_buf_mark_corrupt(bp);
0278     xfs_trans_brelse(tp, bp);
0279     return -EFSCORRUPTED;
0280 }
0281 
0282 STATIC int
0283 xfs_attr_node_list(
0284     struct xfs_attr_list_context    *context)
0285 {
0286     struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
0287     struct xfs_attr3_icleaf_hdr leafhdr;
0288     struct xfs_attr_leafblock   *leaf;
0289     struct xfs_da_intnode       *node;
0290     struct xfs_buf          *bp;
0291     struct xfs_inode        *dp = context->dp;
0292     struct xfs_mount        *mp = dp->i_mount;
0293     int             error = 0;
0294 
0295     trace_xfs_attr_node_list(context);
0296 
0297     cursor->initted = 1;
0298 
0299     /*
0300      * Do all sorts of validation on the passed-in cursor structure.
0301      * If anything is amiss, ignore the cursor and look up the hashval
0302      * starting from the btree root.
0303      */
0304     bp = NULL;
0305     if (cursor->blkno > 0) {
0306         error = xfs_da3_node_read(context->tp, dp, cursor->blkno, &bp,
0307                 XFS_ATTR_FORK);
0308         if ((error != 0) && (error != -EFSCORRUPTED))
0309             return error;
0310         if (bp) {
0311             struct xfs_attr_leaf_entry *entries;
0312 
0313             node = bp->b_addr;
0314             switch (be16_to_cpu(node->hdr.info.magic)) {
0315             case XFS_DA_NODE_MAGIC:
0316             case XFS_DA3_NODE_MAGIC:
0317                 trace_xfs_attr_list_wrong_blk(context);
0318                 xfs_trans_brelse(context->tp, bp);
0319                 bp = NULL;
0320                 break;
0321             case XFS_ATTR_LEAF_MAGIC:
0322             case XFS_ATTR3_LEAF_MAGIC:
0323                 leaf = bp->b_addr;
0324                 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo,
0325                                  &leafhdr, leaf);
0326                 entries = xfs_attr3_leaf_entryp(leaf);
0327                 if (cursor->hashval > be32_to_cpu(
0328                         entries[leafhdr.count - 1].hashval)) {
0329                     trace_xfs_attr_list_wrong_blk(context);
0330                     xfs_trans_brelse(context->tp, bp);
0331                     bp = NULL;
0332                 } else if (cursor->hashval <= be32_to_cpu(
0333                         entries[0].hashval)) {
0334                     trace_xfs_attr_list_wrong_blk(context);
0335                     xfs_trans_brelse(context->tp, bp);
0336                     bp = NULL;
0337                 }
0338                 break;
0339             default:
0340                 trace_xfs_attr_list_wrong_blk(context);
0341                 xfs_trans_brelse(context->tp, bp);
0342                 bp = NULL;
0343             }
0344         }
0345     }
0346 
0347     /*
0348      * We did not find what we expected given the cursor's contents,
0349      * so we start from the top and work down based on the hash value.
0350      * Note that start of node block is same as start of leaf block.
0351      */
0352     if (bp == NULL) {
0353         error = xfs_attr_node_list_lookup(context, cursor, &bp);
0354         if (error || !bp)
0355             return error;
0356     }
0357     ASSERT(bp != NULL);
0358 
0359     /*
0360      * Roll upward through the blocks, processing each leaf block in
0361      * order.  As long as there is space in the result buffer, keep
0362      * adding the information.
0363      */
0364     for (;;) {
0365         leaf = bp->b_addr;
0366         error = xfs_attr3_leaf_list_int(bp, context);
0367         if (error)
0368             break;
0369         xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
0370         if (context->seen_enough || leafhdr.forw == 0)
0371             break;
0372         cursor->blkno = leafhdr.forw;
0373         xfs_trans_brelse(context->tp, bp);
0374         error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
0375                         &bp);
0376         if (error)
0377             return error;
0378     }
0379     xfs_trans_brelse(context->tp, bp);
0380     return error;
0381 }
0382 
0383 /*
0384  * Copy out attribute list entries for attr_list(), for leaf attribute lists.
0385  */
0386 int
0387 xfs_attr3_leaf_list_int(
0388     struct xfs_buf          *bp,
0389     struct xfs_attr_list_context    *context)
0390 {
0391     struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
0392     struct xfs_attr_leafblock   *leaf;
0393     struct xfs_attr3_icleaf_hdr ichdr;
0394     struct xfs_attr_leaf_entry  *entries;
0395     struct xfs_attr_leaf_entry  *entry;
0396     int             i;
0397     struct xfs_mount        *mp = context->dp->i_mount;
0398 
0399     trace_xfs_attr_list_leaf(context);
0400 
0401     leaf = bp->b_addr;
0402     xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
0403     entries = xfs_attr3_leaf_entryp(leaf);
0404 
0405     cursor->initted = 1;
0406 
0407     /*
0408      * Re-find our place in the leaf block if this is a new syscall.
0409      */
0410     if (context->resynch) {
0411         entry = &entries[0];
0412         for (i = 0; i < ichdr.count; entry++, i++) {
0413             if (be32_to_cpu(entry->hashval) == cursor->hashval) {
0414                 if (cursor->offset == context->dupcnt) {
0415                     context->dupcnt = 0;
0416                     break;
0417                 }
0418                 context->dupcnt++;
0419             } else if (be32_to_cpu(entry->hashval) >
0420                     cursor->hashval) {
0421                 context->dupcnt = 0;
0422                 break;
0423             }
0424         }
0425         if (i == ichdr.count) {
0426             trace_xfs_attr_list_notfound(context);
0427             return 0;
0428         }
0429     } else {
0430         entry = &entries[0];
0431         i = 0;
0432     }
0433     context->resynch = 0;
0434 
0435     /*
0436      * We have found our place, start copying out the new attributes.
0437      */
0438     for (; i < ichdr.count; entry++, i++) {
0439         char *name;
0440         int namelen, valuelen;
0441 
0442         if (be32_to_cpu(entry->hashval) != cursor->hashval) {
0443             cursor->hashval = be32_to_cpu(entry->hashval);
0444             cursor->offset = 0;
0445         }
0446 
0447         if ((entry->flags & XFS_ATTR_INCOMPLETE) &&
0448             !context->allow_incomplete)
0449             continue;
0450 
0451         if (entry->flags & XFS_ATTR_LOCAL) {
0452             xfs_attr_leaf_name_local_t *name_loc;
0453 
0454             name_loc = xfs_attr3_leaf_name_local(leaf, i);
0455             name = name_loc->nameval;
0456             namelen = name_loc->namelen;
0457             valuelen = be16_to_cpu(name_loc->valuelen);
0458         } else {
0459             xfs_attr_leaf_name_remote_t *name_rmt;
0460 
0461             name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
0462             name = name_rmt->name;
0463             namelen = name_rmt->namelen;
0464             valuelen = be32_to_cpu(name_rmt->valuelen);
0465         }
0466 
0467         if (XFS_IS_CORRUPT(context->dp->i_mount,
0468                    !xfs_attr_namecheck(name, namelen)))
0469             return -EFSCORRUPTED;
0470         context->put_listent(context, entry->flags,
0471                           name, namelen, valuelen);
0472         if (context->seen_enough)
0473             break;
0474         cursor->offset++;
0475     }
0476     trace_xfs_attr_list_leaf_end(context);
0477     return 0;
0478 }
0479 
0480 /*
0481  * Copy out attribute entries for attr_list(), for leaf attribute lists.
0482  */
0483 STATIC int
0484 xfs_attr_leaf_list(
0485     struct xfs_attr_list_context    *context)
0486 {
0487     struct xfs_buf          *bp;
0488     int             error;
0489 
0490     trace_xfs_attr_leaf_list(context);
0491 
0492     context->cursor.blkno = 0;
0493     error = xfs_attr3_leaf_read(context->tp, context->dp, 0, &bp);
0494     if (error)
0495         return error;
0496 
0497     error = xfs_attr3_leaf_list_int(bp, context);
0498     xfs_trans_brelse(context->tp, bp);
0499     return error;
0500 }
0501 
0502 int
0503 xfs_attr_list_ilocked(
0504     struct xfs_attr_list_context    *context)
0505 {
0506     struct xfs_inode        *dp = context->dp;
0507 
0508     ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
0509 
0510     /*
0511      * Decide on what work routines to call based on the inode size.
0512      */
0513     if (!xfs_inode_hasattr(dp))
0514         return 0;
0515     if (dp->i_af.if_format == XFS_DINODE_FMT_LOCAL)
0516         return xfs_attr_shortform_list(context);
0517     if (xfs_attr_is_leaf(dp))
0518         return xfs_attr_leaf_list(context);
0519     return xfs_attr_node_list(context);
0520 }
0521 
0522 int
0523 xfs_attr_list(
0524     struct xfs_attr_list_context    *context)
0525 {
0526     struct xfs_inode        *dp = context->dp;
0527     uint                lock_mode;
0528     int             error;
0529 
0530     XFS_STATS_INC(dp->i_mount, xs_attr_list);
0531 
0532     if (xfs_is_shutdown(dp->i_mount))
0533         return -EIO;
0534 
0535     lock_mode = xfs_ilock_attr_map_shared(dp);
0536     error = xfs_attr_list_ilocked(context);
0537     xfs_iunlock(dp, lock_mode);
0538     return error;
0539 }