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