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_format.h"
  10#include "xfs_log_format.h"
  11#include "xfs_trans_resv.h"
  12#include "xfs_bit.h"
  13#include "xfs_mount.h"
  14#include "xfs_da_format.h"
  15#include "xfs_da_btree.h"
  16#include "xfs_inode.h"
  17#include "xfs_trans.h"
  18#include "xfs_inode_item.h"
  19#include "xfs_bmap.h"
  20#include "xfs_attr.h"
  21#include "xfs_attr_sf.h"
  22#include "xfs_attr_remote.h"
  23#include "xfs_attr_leaf.h"
  24#include "xfs_error.h"
  25#include "xfs_trace.h"
  26#include "xfs_buf_item.h"
  27#include "xfs_cksum.h"
  28#include "xfs_dir2.h"
  29
  30STATIC int
  31xfs_attr_shortform_compare(const void *a, const void *b)
  32{
  33        xfs_attr_sf_sort_t *sa, *sb;
  34
  35        sa = (xfs_attr_sf_sort_t *)a;
  36        sb = (xfs_attr_sf_sort_t *)b;
  37        if (sa->hash < sb->hash) {
  38                return -1;
  39        } else if (sa->hash > sb->hash) {
  40                return 1;
  41        } else {
  42                return sa->entno - sb->entno;
  43        }
  44}
  45
  46#define XFS_ISRESET_CURSOR(cursor) \
  47        (!((cursor)->initted) && !((cursor)->hashval) && \
  48         !((cursor)->blkno) && !((cursor)->offset))
  49/*
  50 * Copy out entries of shortform attribute lists for attr_list().
  51 * Shortform attribute lists are not stored in hashval sorted order.
  52 * If the output buffer is not large enough to hold them all, then we
  53 * we have to calculate each entries' hashvalue and sort them before
  54 * we can begin returning them to the user.
  55 */
  56static int
  57xfs_attr_shortform_list(xfs_attr_list_context_t *context)
  58{
  59        attrlist_cursor_kern_t *cursor;
  60        xfs_attr_sf_sort_t *sbuf, *sbp;
  61        xfs_attr_shortform_t *sf;
  62        xfs_attr_sf_entry_t *sfe;
  63        xfs_inode_t *dp;
  64        int sbsize, nsbuf, count, i;
  65
  66        ASSERT(context != NULL);
  67        dp = context->dp;
  68        ASSERT(dp != NULL);
  69        ASSERT(dp->i_afp != NULL);
  70        sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
  71        ASSERT(sf != NULL);
  72        if (!sf->hdr.count)
  73                return 0;
  74        cursor = context->cursor;
  75        ASSERT(cursor != NULL);
  76
  77        trace_xfs_attr_list_sf(context);
  78
  79        /*
  80         * If the buffer is large enough and the cursor is at the start,
  81         * do not bother with sorting since we will return everything in
  82         * one buffer and another call using the cursor won't need to be
  83         * made.
  84         * Note the generous fudge factor of 16 overhead bytes per entry.
  85         * If bufsize is zero then put_listent must be a search function
  86         * and can just scan through what we have.
  87         */
  88        if (context->bufsize == 0 ||
  89            (XFS_ISRESET_CURSOR(cursor) &&
  90             (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
  91                for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
  92                        context->put_listent(context,
  93                                             sfe->flags,
  94                                             sfe->nameval,
  95                                             (int)sfe->namelen,
  96                                             (int)sfe->valuelen);
  97                        /*
  98                         * Either search callback finished early or
  99                         * didn't fit it all in the buffer after all.
 100                         */
 101                        if (context->seen_enough)
 102                                break;
 103                        sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
 104                }
 105                trace_xfs_attr_list_sf_all(context);
 106                return 0;
 107        }
 108
 109        /* do no more for a search callback */
 110        if (context->bufsize == 0)
 111                return 0;
 112
 113        /*
 114         * It didn't all fit, so we have to sort everything on hashval.
 115         */
 116        sbsize = sf->hdr.count * sizeof(*sbuf);
 117        sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP | KM_NOFS);
 118
 119        /*
 120         * Scan the attribute list for the rest of the entries, storing
 121         * the relevant info from only those that match into a buffer.
 122         */
 123        nsbuf = 0;
 124        for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
 125                if (unlikely(
 126                    ((char *)sfe < (char *)sf) ||
 127                    ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) {
 128                        XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
 129                                             XFS_ERRLEVEL_LOW,
 130                                             context->dp->i_mount, sfe,
 131                                             sizeof(*sfe));
 132                        kmem_free(sbuf);
 133                        return -EFSCORRUPTED;
 134                }
 135
 136                sbp->entno = i;
 137                sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
 138                sbp->name = sfe->nameval;
 139                sbp->namelen = sfe->namelen;
 140                /* These are bytes, and both on-disk, don't endian-flip */
 141                sbp->valuelen = sfe->valuelen;
 142                sbp->flags = sfe->flags;
 143                sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
 144                sbp++;
 145                nsbuf++;
 146        }
 147
 148        /*
 149         * Sort the entries on hash then entno.
 150         */
 151        xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
 152
 153        /*
 154         * Re-find our place IN THE SORTED LIST.
 155         */
 156        count = 0;
 157        cursor->initted = 1;
 158        cursor->blkno = 0;
 159        for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
 160                if (sbp->hash == cursor->hashval) {
 161                        if (cursor->offset == count) {
 162                                break;
 163                        }
 164                        count++;
 165                } else if (sbp->hash > cursor->hashval) {
 166                        break;
 167                }
 168        }
 169        if (i == nsbuf) {
 170                kmem_free(sbuf);
 171                return 0;
 172        }
 173
 174        /*
 175         * Loop putting entries into the user buffer.
 176         */
 177        for ( ; i < nsbuf; i++, sbp++) {
 178                if (cursor->hashval != sbp->hash) {
 179                        cursor->hashval = sbp->hash;
 180                        cursor->offset = 0;
 181                }
 182                context->put_listent(context,
 183                                     sbp->flags,
 184                                     sbp->name,
 185                                     sbp->namelen,
 186                                     sbp->valuelen);
 187                if (context->seen_enough)
 188                        break;
 189                cursor->offset++;
 190        }
 191
 192        kmem_free(sbuf);
 193        return 0;
 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 */
 200STATIC int
 201xfs_attr_node_list_lookup(
 202        struct xfs_attr_list_context    *context,
 203        struct attrlist_cursor_kern     *cursor,
 204        struct xfs_buf                  **pbp)
 205{
 206        struct xfs_da3_icnode_hdr       nodehdr;
 207        struct xfs_da_intnode           *node;
 208        struct xfs_da_node_entry        *btree;
 209        struct xfs_inode                *dp = context->dp;
 210        struct xfs_mount                *mp = dp->i_mount;
 211        struct xfs_trans                *tp = context->tp;
 212        struct xfs_buf                  *bp;
 213        int                             i;
 214        int                             error = 0;
 215        unsigned int                    expected_level = 0;
 216        uint16_t                        magic;
 217
 218        ASSERT(*pbp == NULL);
 219        cursor->blkno = 0;
 220        for (;;) {
 221                error = xfs_da3_node_read(tp, dp, cursor->blkno, -1, &bp,
 222                                XFS_ATTR_FORK);
 223                if (error)
 224                        return error;
 225                node = bp->b_addr;
 226                magic = be16_to_cpu(node->hdr.info.magic);
 227                if (magic == XFS_ATTR_LEAF_MAGIC ||
 228                    magic == XFS_ATTR3_LEAF_MAGIC)
 229                        break;
 230                if (magic != XFS_DA_NODE_MAGIC &&
 231                    magic != XFS_DA3_NODE_MAGIC) {
 232                        XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
 233                                        node, sizeof(*node));
 234                        goto out_corruptbuf;
 235                }
 236
 237                dp->d_ops->node_hdr_from_disk(&nodehdr, node);
 238
 239                /* Tree taller than we can handle; bail out! */
 240                if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
 241                        goto out_corruptbuf;
 242
 243                /* Check the level from the root node. */
 244                if (cursor->blkno == 0)
 245                        expected_level = nodehdr.level - 1;
 246                else if (expected_level != nodehdr.level)
 247                        goto out_corruptbuf;
 248                else
 249                        expected_level--;
 250
 251                btree = dp->d_ops->node_tree_p(node);
 252                for (i = 0; i < nodehdr.count; btree++, i++) {
 253                        if (cursor->hashval <= be32_to_cpu(btree->hashval)) {
 254                                cursor->blkno = be32_to_cpu(btree->before);
 255                                trace_xfs_attr_list_node_descend(context,
 256                                                btree);
 257                                break;
 258                        }
 259                }
 260                xfs_trans_brelse(tp, bp);
 261
 262                if (i == nodehdr.count)
 263                        return 0;
 264
 265                /* We can't point back to the root. */
 266                if (cursor->blkno == 0)
 267                        return -EFSCORRUPTED;
 268        }
 269
 270        if (expected_level != 0)
 271                goto out_corruptbuf;
 272
 273        *pbp = bp;
 274        return 0;
 275
 276out_corruptbuf:
 277        xfs_trans_brelse(tp, bp);
 278        return -EFSCORRUPTED;
 279}
 280
 281STATIC int
 282xfs_attr_node_list(
 283        struct xfs_attr_list_context    *context)
 284{
 285        struct xfs_attr3_icleaf_hdr     leafhdr;
 286        struct attrlist_cursor_kern     *cursor;
 287        struct xfs_attr_leafblock       *leaf;
 288        struct xfs_da_intnode           *node;
 289        struct xfs_buf                  *bp;
 290        struct xfs_inode                *dp = context->dp;
 291        struct xfs_mount                *mp = dp->i_mount;
 292        int                             error;
 293
 294        trace_xfs_attr_node_list(context);
 295
 296        cursor = context->cursor;
 297        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        bp = NULL;
 305        if (cursor->blkno > 0) {
 306                error = xfs_da3_node_read(context->tp, dp, cursor->blkno, -1,
 307                                              &bp, XFS_ATTR_FORK);
 308                if ((error != 0) && (error != -EFSCORRUPTED))
 309                        return error;
 310                if (bp) {
 311                        struct xfs_attr_leaf_entry *entries;
 312
 313                        node = bp->b_addr;
 314                        switch (be16_to_cpu(node->hdr.info.magic)) {
 315                        case XFS_DA_NODE_MAGIC:
 316                        case XFS_DA3_NODE_MAGIC:
 317                                trace_xfs_attr_list_wrong_blk(context);
 318                                xfs_trans_brelse(context->tp, bp);
 319                                bp = NULL;
 320                                break;
 321                        case XFS_ATTR_LEAF_MAGIC:
 322                        case XFS_ATTR3_LEAF_MAGIC:
 323                                leaf = bp->b_addr;
 324                                xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo,
 325                                                             &leafhdr, leaf);
 326                                entries = xfs_attr3_leaf_entryp(leaf);
 327                                if (cursor->hashval > be32_to_cpu(
 328                                                entries[leafhdr.count - 1].hashval)) {
 329                                        trace_xfs_attr_list_wrong_blk(context);
 330                                        xfs_trans_brelse(context->tp, bp);
 331                                        bp = NULL;
 332                                } else if (cursor->hashval <= be32_to_cpu(
 333                                                entries[0].hashval)) {
 334                                        trace_xfs_attr_list_wrong_blk(context);
 335                                        xfs_trans_brelse(context->tp, bp);
 336                                        bp = NULL;
 337                                }
 338                                break;
 339                        default:
 340                                trace_xfs_attr_list_wrong_blk(context);
 341                                xfs_trans_brelse(context->tp, bp);
 342                                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        if (bp == NULL) {
 353                error = xfs_attr_node_list_lookup(context, cursor, &bp);
 354                if (error || !bp)
 355                        return error;
 356        }
 357        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        for (;;) {
 365                leaf = bp->b_addr;
 366                xfs_attr3_leaf_list_int(bp, context);
 367                xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
 368                if (context->seen_enough || leafhdr.forw == 0)
 369                        break;
 370                cursor->blkno = leafhdr.forw;
 371                xfs_trans_brelse(context->tp, bp);
 372                error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno, -1, &bp);
 373                if (error)
 374                        return error;
 375        }
 376        xfs_trans_brelse(context->tp, bp);
 377        return 0;
 378}
 379
 380/*
 381 * Copy out attribute list entries for attr_list(), for leaf attribute lists.
 382 */
 383void
 384xfs_attr3_leaf_list_int(
 385        struct xfs_buf                  *bp,
 386        struct xfs_attr_list_context    *context)
 387{
 388        struct attrlist_cursor_kern     *cursor;
 389        struct xfs_attr_leafblock       *leaf;
 390        struct xfs_attr3_icleaf_hdr     ichdr;
 391        struct xfs_attr_leaf_entry      *entries;
 392        struct xfs_attr_leaf_entry      *entry;
 393        int                             i;
 394        struct xfs_mount                *mp = context->dp->i_mount;
 395
 396        trace_xfs_attr_list_leaf(context);
 397
 398        leaf = bp->b_addr;
 399        xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
 400        entries = xfs_attr3_leaf_entryp(leaf);
 401
 402        cursor = context->cursor;
 403        cursor->initted = 1;
 404
 405        /*
 406         * Re-find our place in the leaf block if this is a new syscall.
 407         */
 408        if (context->resynch) {
 409                entry = &entries[0];
 410                for (i = 0; i < ichdr.count; entry++, i++) {
 411                        if (be32_to_cpu(entry->hashval) == cursor->hashval) {
 412                                if (cursor->offset == context->dupcnt) {
 413                                        context->dupcnt = 0;
 414                                        break;
 415                                }
 416                                context->dupcnt++;
 417                        } else if (be32_to_cpu(entry->hashval) >
 418                                        cursor->hashval) {
 419                                context->dupcnt = 0;
 420                                break;
 421                        }
 422                }
 423                if (i == ichdr.count) {
 424                        trace_xfs_attr_list_notfound(context);
 425                        return;
 426                }
 427        } else {
 428                entry = &entries[0];
 429                i = 0;
 430        }
 431        context->resynch = 0;
 432
 433        /*
 434         * We have found our place, start copying out the new attributes.
 435         */
 436        for (; i < ichdr.count; entry++, i++) {
 437                char *name;
 438                int namelen, valuelen;
 439
 440                if (be32_to_cpu(entry->hashval) != cursor->hashval) {
 441                        cursor->hashval = be32_to_cpu(entry->hashval);
 442                        cursor->offset = 0;
 443                }
 444
 445                if ((entry->flags & XFS_ATTR_INCOMPLETE) &&
 446                    !(context->flags & ATTR_INCOMPLETE))
 447                        continue;               /* skip incomplete entries */
 448
 449                if (entry->flags & XFS_ATTR_LOCAL) {
 450                        xfs_attr_leaf_name_local_t *name_loc;
 451
 452                        name_loc = xfs_attr3_leaf_name_local(leaf, i);
 453                        name = name_loc->nameval;
 454                        namelen = name_loc->namelen;
 455                        valuelen = be16_to_cpu(name_loc->valuelen);
 456                } else {
 457                        xfs_attr_leaf_name_remote_t *name_rmt;
 458
 459                        name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
 460                        name = name_rmt->name;
 461                        namelen = name_rmt->namelen;
 462                        valuelen = be32_to_cpu(name_rmt->valuelen);
 463                }
 464
 465                context->put_listent(context, entry->flags,
 466                                              name, namelen, valuelen);
 467                if (context->seen_enough)
 468                        break;
 469                cursor->offset++;
 470        }
 471        trace_xfs_attr_list_leaf_end(context);
 472        return;
 473}
 474
 475/*
 476 * Copy out attribute entries for attr_list(), for leaf attribute lists.
 477 */
 478STATIC int
 479xfs_attr_leaf_list(xfs_attr_list_context_t *context)
 480{
 481        int error;
 482        struct xfs_buf *bp;
 483
 484        trace_xfs_attr_leaf_list(context);
 485
 486        context->cursor->blkno = 0;
 487        error = xfs_attr3_leaf_read(context->tp, context->dp, 0, -1, &bp);
 488        if (error)
 489                return error;
 490
 491        xfs_attr3_leaf_list_int(bp, context);
 492        xfs_trans_brelse(context->tp, bp);
 493        return 0;
 494}
 495
 496int
 497xfs_attr_list_int_ilocked(
 498        struct xfs_attr_list_context    *context)
 499{
 500        struct xfs_inode                *dp = context->dp;
 501
 502        ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
 503
 504        /*
 505         * Decide on what work routines to call based on the inode size.
 506         */
 507        if (!xfs_inode_hasattr(dp))
 508                return 0;
 509        else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
 510                return xfs_attr_shortform_list(context);
 511        else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
 512                return xfs_attr_leaf_list(context);
 513        return xfs_attr_node_list(context);
 514}
 515
 516int
 517xfs_attr_list_int(
 518        xfs_attr_list_context_t *context)
 519{
 520        int error;
 521        xfs_inode_t *dp = context->dp;
 522        uint            lock_mode;
 523
 524        XFS_STATS_INC(dp->i_mount, xs_attr_list);
 525
 526        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 527                return -EIO;
 528
 529        lock_mode = xfs_ilock_attr_map_shared(dp);
 530        error = xfs_attr_list_int_ilocked(context);
 531        xfs_iunlock(dp, lock_mode);
 532        return error;
 533}
 534
 535#define ATTR_ENTBASESIZE                /* minimum bytes used by an attr */ \
 536        (((struct attrlist_ent *) 0)->a_name - (char *) 0)
 537#define ATTR_ENTSIZE(namelen)           /* actual bytes used by an attr */ \
 538        ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(uint32_t)-1) \
 539         & ~(sizeof(uint32_t)-1))
 540
 541/*
 542 * Format an attribute and copy it out to the user's buffer.
 543 * Take care to check values and protect against them changing later,
 544 * we may be reading them directly out of a user buffer.
 545 */
 546STATIC void
 547xfs_attr_put_listent(
 548        xfs_attr_list_context_t *context,
 549        int             flags,
 550        unsigned char   *name,
 551        int             namelen,
 552        int             valuelen)
 553{
 554        struct attrlist *alist = (struct attrlist *)context->alist;
 555        attrlist_ent_t *aep;
 556        int arraytop;
 557
 558        ASSERT(!(context->flags & ATTR_KERNOVAL));
 559        ASSERT(context->count >= 0);
 560        ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
 561        ASSERT(context->firstu >= sizeof(*alist));
 562        ASSERT(context->firstu <= context->bufsize);
 563
 564        /*
 565         * Only list entries in the right namespace.
 566         */
 567        if (((context->flags & ATTR_SECURE) == 0) !=
 568            ((flags & XFS_ATTR_SECURE) == 0))
 569                return;
 570        if (((context->flags & ATTR_ROOT) == 0) !=
 571            ((flags & XFS_ATTR_ROOT) == 0))
 572                return;
 573
 574        arraytop = sizeof(*alist) +
 575                        context->count * sizeof(alist->al_offset[0]);
 576        context->firstu -= ATTR_ENTSIZE(namelen);
 577        if (context->firstu < arraytop) {
 578                trace_xfs_attr_list_full(context);
 579                alist->al_more = 1;
 580                context->seen_enough = 1;
 581                return;
 582        }
 583
 584        aep = (attrlist_ent_t *)&context->alist[context->firstu];
 585        aep->a_valuelen = valuelen;
 586        memcpy(aep->a_name, name, namelen);
 587        aep->a_name[namelen] = 0;
 588        alist->al_offset[context->count++] = context->firstu;
 589        alist->al_count = context->count;
 590        trace_xfs_attr_list_add(context);
 591        return;
 592}
 593
 594/*
 595 * Generate a list of extended attribute names and optionally
 596 * also value lengths.  Positive return value follows the XFS
 597 * convention of being an error, zero or negative return code
 598 * is the length of the buffer returned (negated), indicating
 599 * success.
 600 */
 601int
 602xfs_attr_list(
 603        xfs_inode_t     *dp,
 604        char            *buffer,
 605        int             bufsize,
 606        int             flags,
 607        attrlist_cursor_kern_t *cursor)
 608{
 609        xfs_attr_list_context_t context;
 610        struct attrlist *alist;
 611        int error;
 612
 613        /*
 614         * Validate the cursor.
 615         */
 616        if (cursor->pad1 || cursor->pad2)
 617                return -EINVAL;
 618        if ((cursor->initted == 0) &&
 619            (cursor->hashval || cursor->blkno || cursor->offset))
 620                return -EINVAL;
 621
 622        /* Only internal consumers can retrieve incomplete attrs. */
 623        if (flags & ATTR_INCOMPLETE)
 624                return -EINVAL;
 625
 626        /*
 627         * Check for a properly aligned buffer.
 628         */
 629        if (((long)buffer) & (sizeof(int)-1))
 630                return -EFAULT;
 631        if (flags & ATTR_KERNOVAL)
 632                bufsize = 0;
 633
 634        /*
 635         * Initialize the output buffer.
 636         */
 637        memset(&context, 0, sizeof(context));
 638        context.dp = dp;
 639        context.cursor = cursor;
 640        context.resynch = 1;
 641        context.flags = flags;
 642        context.alist = buffer;
 643        context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */
 644        context.firstu = context.bufsize;
 645        context.put_listent = xfs_attr_put_listent;
 646
 647        alist = (struct attrlist *)context.alist;
 648        alist->al_count = 0;
 649        alist->al_more = 0;
 650        alist->al_offset[0] = context.bufsize;
 651
 652        error = xfs_attr_list_int(&context);
 653        ASSERT(error <= 0);
 654        return error;
 655}
 656