linux/fs/xfs/libxfs/xfs_attr.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
   3 * All Rights Reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it would be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write the Free Software Foundation,
  16 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17 */
  18#include "xfs.h"
  19#include "xfs_fs.h"
  20#include "xfs_shared.h"
  21#include "xfs_format.h"
  22#include "xfs_log_format.h"
  23#include "xfs_trans_resv.h"
  24#include "xfs_bit.h"
  25#include "xfs_mount.h"
  26#include "xfs_da_format.h"
  27#include "xfs_da_btree.h"
  28#include "xfs_attr_sf.h"
  29#include "xfs_inode.h"
  30#include "xfs_alloc.h"
  31#include "xfs_trans.h"
  32#include "xfs_inode_item.h"
  33#include "xfs_bmap.h"
  34#include "xfs_bmap_util.h"
  35#include "xfs_bmap_btree.h"
  36#include "xfs_attr.h"
  37#include "xfs_attr_leaf.h"
  38#include "xfs_attr_remote.h"
  39#include "xfs_error.h"
  40#include "xfs_quota.h"
  41#include "xfs_trans_space.h"
  42#include "xfs_trace.h"
  43
  44/*
  45 * xfs_attr.c
  46 *
  47 * Provide the external interfaces to manage attribute lists.
  48 */
  49
  50/*========================================================================
  51 * Function prototypes for the kernel.
  52 *========================================================================*/
  53
  54/*
  55 * Internal routines when attribute list fits inside the inode.
  56 */
  57STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
  58
  59/*
  60 * Internal routines when attribute list is one block.
  61 */
  62STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
  63STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
  64STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
  65
  66/*
  67 * Internal routines when attribute list is more than one block.
  68 */
  69STATIC int xfs_attr_node_get(xfs_da_args_t *args);
  70STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
  71STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
  72STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
  73STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
  74
  75
  76STATIC int
  77xfs_attr_args_init(
  78        struct xfs_da_args      *args,
  79        struct xfs_inode        *dp,
  80        const unsigned char     *name,
  81        int                     flags)
  82{
  83
  84        if (!name)
  85                return -EINVAL;
  86
  87        memset(args, 0, sizeof(*args));
  88        args->geo = dp->i_mount->m_attr_geo;
  89        args->whichfork = XFS_ATTR_FORK;
  90        args->dp = dp;
  91        args->flags = flags;
  92        args->name = name;
  93        args->namelen = strlen((const char *)name);
  94        if (args->namelen >= MAXNAMELEN)
  95                return -EFAULT;         /* match IRIX behaviour */
  96
  97        args->hashval = xfs_da_hashname(args->name, args->namelen);
  98        return 0;
  99}
 100
 101int
 102xfs_inode_hasattr(
 103        struct xfs_inode        *ip)
 104{
 105        if (!XFS_IFORK_Q(ip) ||
 106            (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 107             ip->i_d.di_anextents == 0))
 108                return 0;
 109        return 1;
 110}
 111
 112/*========================================================================
 113 * Overall external interface routines.
 114 *========================================================================*/
 115
 116int
 117xfs_attr_get(
 118        struct xfs_inode        *ip,
 119        const unsigned char     *name,
 120        unsigned char           *value,
 121        int                     *valuelenp,
 122        int                     flags)
 123{
 124        struct xfs_da_args      args;
 125        uint                    lock_mode;
 126        int                     error;
 127
 128        XFS_STATS_INC(xs_attr_get);
 129
 130        if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 131                return -EIO;
 132
 133        if (!xfs_inode_hasattr(ip))
 134                return -ENOATTR;
 135
 136        error = xfs_attr_args_init(&args, ip, name, flags);
 137        if (error)
 138                return error;
 139
 140        args.value = value;
 141        args.valuelen = *valuelenp;
 142
 143        lock_mode = xfs_ilock_attr_map_shared(ip);
 144        if (!xfs_inode_hasattr(ip))
 145                error = -ENOATTR;
 146        else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
 147                error = xfs_attr_shortform_getvalue(&args);
 148        else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK))
 149                error = xfs_attr_leaf_get(&args);
 150        else
 151                error = xfs_attr_node_get(&args);
 152        xfs_iunlock(ip, lock_mode);
 153
 154        *valuelenp = args.valuelen;
 155        return error == -EEXIST ? 0 : error;
 156}
 157
 158/*
 159 * Calculate how many blocks we need for the new attribute,
 160 */
 161STATIC int
 162xfs_attr_calc_size(
 163        struct xfs_da_args      *args,
 164        int                     *local)
 165{
 166        struct xfs_mount        *mp = args->dp->i_mount;
 167        int                     size;
 168        int                     nblks;
 169
 170        /*
 171         * Determine space new attribute will use, and if it would be
 172         * "local" or "remote" (note: local != inline).
 173         */
 174        size = xfs_attr_leaf_newentsize(args, local);
 175        nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
 176        if (*local) {
 177                if (size > (args->geo->blksize / 2)) {
 178                        /* Double split possible */
 179                        nblks *= 2;
 180                }
 181        } else {
 182                /*
 183                 * Out of line attribute, cannot double split, but
 184                 * make room for the attribute value itself.
 185                 */
 186                uint    dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen);
 187                nblks += dblocks;
 188                nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
 189        }
 190
 191        return nblks;
 192}
 193
 194int
 195xfs_attr_set(
 196        struct xfs_inode        *dp,
 197        const unsigned char     *name,
 198        unsigned char           *value,
 199        int                     valuelen,
 200        int                     flags)
 201{
 202        struct xfs_mount        *mp = dp->i_mount;
 203        struct xfs_da_args      args;
 204        struct xfs_bmap_free    flist;
 205        struct xfs_trans_res    tres;
 206        xfs_fsblock_t           firstblock;
 207        int                     rsvd = (flags & ATTR_ROOT) != 0;
 208        int                     error, err2, committed, local;
 209
 210        XFS_STATS_INC(xs_attr_set);
 211
 212        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 213                return -EIO;
 214
 215        error = xfs_attr_args_init(&args, dp, name, flags);
 216        if (error)
 217                return error;
 218
 219        args.value = value;
 220        args.valuelen = valuelen;
 221        args.firstblock = &firstblock;
 222        args.flist = &flist;
 223        args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
 224        args.total = xfs_attr_calc_size(&args, &local);
 225
 226        error = xfs_qm_dqattach(dp, 0);
 227        if (error)
 228                return error;
 229
 230        /*
 231         * If the inode doesn't have an attribute fork, add one.
 232         * (inode must not be locked when we call this routine)
 233         */
 234        if (XFS_IFORK_Q(dp) == 0) {
 235                int sf_size = sizeof(xfs_attr_sf_hdr_t) +
 236                        XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
 237
 238                error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
 239                if (error)
 240                        return error;
 241        }
 242
 243        /*
 244         * Start our first transaction of the day.
 245         *
 246         * All future transactions during this code must be "chained" off
 247         * this one via the trans_dup() call.  All transactions will contain
 248         * the inode, and the inode will always be marked with trans_ihold().
 249         * Since the inode will be locked in all transactions, we must log
 250         * the inode in every transaction to let it float upward through
 251         * the log.
 252         */
 253        args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET);
 254
 255        /*
 256         * Root fork attributes can use reserved data blocks for this
 257         * operation if necessary
 258         */
 259
 260        if (rsvd)
 261                args.trans->t_flags |= XFS_TRANS_RESERVE;
 262
 263        tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
 264                         M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
 265        tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
 266        tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
 267        error = xfs_trans_reserve(args.trans, &tres, args.total, 0);
 268        if (error) {
 269                xfs_trans_cancel(args.trans, 0);
 270                return error;
 271        }
 272        xfs_ilock(dp, XFS_ILOCK_EXCL);
 273
 274        error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
 275                                rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
 276                                       XFS_QMOPT_RES_REGBLKS);
 277        if (error) {
 278                xfs_iunlock(dp, XFS_ILOCK_EXCL);
 279                xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
 280                return error;
 281        }
 282
 283        xfs_trans_ijoin(args.trans, dp, 0);
 284
 285        /*
 286         * If the attribute list is non-existent or a shortform list,
 287         * upgrade it to a single-leaf-block attribute list.
 288         */
 289        if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
 290            (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 291             dp->i_d.di_anextents == 0)) {
 292
 293                /*
 294                 * Build initial attribute list (if required).
 295                 */
 296                if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
 297                        xfs_attr_shortform_create(&args);
 298
 299                /*
 300                 * Try to add the attr to the attribute list in
 301                 * the inode.
 302                 */
 303                error = xfs_attr_shortform_addname(&args);
 304                if (error != -ENOSPC) {
 305                        /*
 306                         * Commit the shortform mods, and we're done.
 307                         * NOTE: this is also the error path (EEXIST, etc).
 308                         */
 309                        ASSERT(args.trans != NULL);
 310
 311                        /*
 312                         * If this is a synchronous mount, make sure that
 313                         * the transaction goes to disk before returning
 314                         * to the user.
 315                         */
 316                        if (mp->m_flags & XFS_MOUNT_WSYNC)
 317                                xfs_trans_set_sync(args.trans);
 318
 319                        if (!error && (flags & ATTR_KERNOTIME) == 0) {
 320                                xfs_trans_ichgtime(args.trans, dp,
 321                                                        XFS_ICHGTIME_CHG);
 322                        }
 323                        err2 = xfs_trans_commit(args.trans,
 324                                                 XFS_TRANS_RELEASE_LOG_RES);
 325                        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 326
 327                        return error ? error : err2;
 328                }
 329
 330                /*
 331                 * It won't fit in the shortform, transform to a leaf block.
 332                 * GROT: another possible req'mt for a double-split btree op.
 333                 */
 334                xfs_bmap_init(args.flist, args.firstblock);
 335                error = xfs_attr_shortform_to_leaf(&args);
 336                if (!error) {
 337                        error = xfs_bmap_finish(&args.trans, args.flist,
 338                                                &committed);
 339                }
 340                if (error) {
 341                        ASSERT(committed);
 342                        args.trans = NULL;
 343                        xfs_bmap_cancel(&flist);
 344                        goto out;
 345                }
 346
 347                /*
 348                 * bmap_finish() may have committed the last trans and started
 349                 * a new one.  We need the inode to be in all transactions.
 350                 */
 351                if (committed)
 352                        xfs_trans_ijoin(args.trans, dp, 0);
 353
 354                /*
 355                 * Commit the leaf transformation.  We'll need another (linked)
 356                 * transaction to add the new attribute to the leaf.
 357                 */
 358
 359                error = xfs_trans_roll(&args.trans, dp);
 360                if (error)
 361                        goto out;
 362
 363        }
 364
 365        if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
 366                error = xfs_attr_leaf_addname(&args);
 367        else
 368                error = xfs_attr_node_addname(&args);
 369        if (error)
 370                goto out;
 371
 372        /*
 373         * If this is a synchronous mount, make sure that the
 374         * transaction goes to disk before returning to the user.
 375         */
 376        if (mp->m_flags & XFS_MOUNT_WSYNC)
 377                xfs_trans_set_sync(args.trans);
 378
 379        if ((flags & ATTR_KERNOTIME) == 0)
 380                xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
 381
 382        /*
 383         * Commit the last in the sequence of transactions.
 384         */
 385        xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
 386        error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
 387        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 388
 389        return error;
 390
 391out:
 392        if (args.trans) {
 393                xfs_trans_cancel(args.trans,
 394                        XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
 395        }
 396        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 397        return error;
 398}
 399
 400/*
 401 * Generic handler routine to remove a name from an attribute list.
 402 * Transitions attribute list from Btree to shortform as necessary.
 403 */
 404int
 405xfs_attr_remove(
 406        struct xfs_inode        *dp,
 407        const unsigned char     *name,
 408        int                     flags)
 409{
 410        struct xfs_mount        *mp = dp->i_mount;
 411        struct xfs_da_args      args;
 412        struct xfs_bmap_free    flist;
 413        xfs_fsblock_t           firstblock;
 414        int                     error;
 415
 416        XFS_STATS_INC(xs_attr_remove);
 417
 418        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 419                return -EIO;
 420
 421        if (!xfs_inode_hasattr(dp))
 422                return -ENOATTR;
 423
 424        error = xfs_attr_args_init(&args, dp, name, flags);
 425        if (error)
 426                return error;
 427
 428        args.firstblock = &firstblock;
 429        args.flist = &flist;
 430
 431        /*
 432         * we have no control over the attribute names that userspace passes us
 433         * to remove, so we have to allow the name lookup prior to attribute
 434         * removal to fail.
 435         */
 436        args.op_flags = XFS_DA_OP_OKNOENT;
 437
 438        error = xfs_qm_dqattach(dp, 0);
 439        if (error)
 440                return error;
 441
 442        /*
 443         * Start our first transaction of the day.
 444         *
 445         * All future transactions during this code must be "chained" off
 446         * this one via the trans_dup() call.  All transactions will contain
 447         * the inode, and the inode will always be marked with trans_ihold().
 448         * Since the inode will be locked in all transactions, we must log
 449         * the inode in every transaction to let it float upward through
 450         * the log.
 451         */
 452        args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM);
 453
 454        /*
 455         * Root fork attributes can use reserved data blocks for this
 456         * operation if necessary
 457         */
 458
 459        if (flags & ATTR_ROOT)
 460                args.trans->t_flags |= XFS_TRANS_RESERVE;
 461
 462        error = xfs_trans_reserve(args.trans, &M_RES(mp)->tr_attrrm,
 463                                  XFS_ATTRRM_SPACE_RES(mp), 0);
 464        if (error) {
 465                xfs_trans_cancel(args.trans, 0);
 466                return error;
 467        }
 468
 469        xfs_ilock(dp, XFS_ILOCK_EXCL);
 470        /*
 471         * No need to make quota reservations here. We expect to release some
 472         * blocks not allocate in the common case.
 473         */
 474        xfs_trans_ijoin(args.trans, dp, 0);
 475
 476        if (!xfs_inode_hasattr(dp)) {
 477                error = -ENOATTR;
 478        } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
 479                ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
 480                error = xfs_attr_shortform_remove(&args);
 481        } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
 482                error = xfs_attr_leaf_removename(&args);
 483        } else {
 484                error = xfs_attr_node_removename(&args);
 485        }
 486
 487        if (error)
 488                goto out;
 489
 490        /*
 491         * If this is a synchronous mount, make sure that the
 492         * transaction goes to disk before returning to the user.
 493         */
 494        if (mp->m_flags & XFS_MOUNT_WSYNC)
 495                xfs_trans_set_sync(args.trans);
 496
 497        if ((flags & ATTR_KERNOTIME) == 0)
 498                xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
 499
 500        /*
 501         * Commit the last in the sequence of transactions.
 502         */
 503        xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
 504        error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
 505        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 506
 507        return error;
 508
 509out:
 510        if (args.trans) {
 511                xfs_trans_cancel(args.trans,
 512                        XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
 513        }
 514        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 515        return error;
 516}
 517
 518/*========================================================================
 519 * External routines when attribute list is inside the inode
 520 *========================================================================*/
 521
 522/*
 523 * Add a name to the shortform attribute list structure
 524 * This is the external routine.
 525 */
 526STATIC int
 527xfs_attr_shortform_addname(xfs_da_args_t *args)
 528{
 529        int newsize, forkoff, retval;
 530
 531        trace_xfs_attr_sf_addname(args);
 532
 533        retval = xfs_attr_shortform_lookup(args);
 534        if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
 535                return retval;
 536        } else if (retval == -EEXIST) {
 537                if (args->flags & ATTR_CREATE)
 538                        return retval;
 539                retval = xfs_attr_shortform_remove(args);
 540                ASSERT(retval == 0);
 541        }
 542
 543        if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
 544            args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
 545                return -ENOSPC;
 546
 547        newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
 548        newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
 549
 550        forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
 551        if (!forkoff)
 552                return -ENOSPC;
 553
 554        xfs_attr_shortform_add(args, forkoff);
 555        return 0;
 556}
 557
 558
 559/*========================================================================
 560 * External routines when attribute list is one block
 561 *========================================================================*/
 562
 563/*
 564 * Add a name to the leaf attribute list structure
 565 *
 566 * This leaf block cannot have a "remote" value, we only call this routine
 567 * if bmap_one_block() says there is only one block (ie: no remote blks).
 568 */
 569STATIC int
 570xfs_attr_leaf_addname(xfs_da_args_t *args)
 571{
 572        xfs_inode_t *dp;
 573        struct xfs_buf *bp;
 574        int retval, error, committed, forkoff;
 575
 576        trace_xfs_attr_leaf_addname(args);
 577
 578        /*
 579         * Read the (only) block in the attribute list in.
 580         */
 581        dp = args->dp;
 582        args->blkno = 0;
 583        error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
 584        if (error)
 585                return error;
 586
 587        /*
 588         * Look up the given attribute in the leaf block.  Figure out if
 589         * the given flags produce an error or call for an atomic rename.
 590         */
 591        retval = xfs_attr3_leaf_lookup_int(bp, args);
 592        if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
 593                xfs_trans_brelse(args->trans, bp);
 594                return retval;
 595        } else if (retval == -EEXIST) {
 596                if (args->flags & ATTR_CREATE) {        /* pure create op */
 597                        xfs_trans_brelse(args->trans, bp);
 598                        return retval;
 599                }
 600
 601                trace_xfs_attr_leaf_replace(args);
 602
 603                /* save the attribute state for later removal*/
 604                args->op_flags |= XFS_DA_OP_RENAME;     /* an atomic rename */
 605                args->blkno2 = args->blkno;             /* set 2nd entry info*/
 606                args->index2 = args->index;
 607                args->rmtblkno2 = args->rmtblkno;
 608                args->rmtblkcnt2 = args->rmtblkcnt;
 609                args->rmtvaluelen2 = args->rmtvaluelen;
 610
 611                /*
 612                 * clear the remote attr state now that it is saved so that the
 613                 * values reflect the state of the attribute we are about to
 614                 * add, not the attribute we just found and will remove later.
 615                 */
 616                args->rmtblkno = 0;
 617                args->rmtblkcnt = 0;
 618                args->rmtvaluelen = 0;
 619        }
 620
 621        /*
 622         * Add the attribute to the leaf block, transitioning to a Btree
 623         * if required.
 624         */
 625        retval = xfs_attr3_leaf_add(bp, args);
 626        if (retval == -ENOSPC) {
 627                /*
 628                 * Promote the attribute list to the Btree format, then
 629                 * Commit that transaction so that the node_addname() call
 630                 * can manage its own transactions.
 631                 */
 632                xfs_bmap_init(args->flist, args->firstblock);
 633                error = xfs_attr3_leaf_to_node(args);
 634                if (!error) {
 635                        error = xfs_bmap_finish(&args->trans, args->flist,
 636                                                &committed);
 637                }
 638                if (error) {
 639                        ASSERT(committed);
 640                        args->trans = NULL;
 641                        xfs_bmap_cancel(args->flist);
 642                        return error;
 643                }
 644
 645                /*
 646                 * bmap_finish() may have committed the last trans and started
 647                 * a new one.  We need the inode to be in all transactions.
 648                 */
 649                if (committed)
 650                        xfs_trans_ijoin(args->trans, dp, 0);
 651
 652                /*
 653                 * Commit the current trans (including the inode) and start
 654                 * a new one.
 655                 */
 656                error = xfs_trans_roll(&args->trans, dp);
 657                if (error)
 658                        return error;
 659
 660                /*
 661                 * Fob the whole rest of the problem off on the Btree code.
 662                 */
 663                error = xfs_attr_node_addname(args);
 664                return error;
 665        }
 666
 667        /*
 668         * Commit the transaction that added the attr name so that
 669         * later routines can manage their own transactions.
 670         */
 671        error = xfs_trans_roll(&args->trans, dp);
 672        if (error)
 673                return error;
 674
 675        /*
 676         * If there was an out-of-line value, allocate the blocks we
 677         * identified for its storage and copy the value.  This is done
 678         * after we create the attribute so that we don't overflow the
 679         * maximum size of a transaction and/or hit a deadlock.
 680         */
 681        if (args->rmtblkno > 0) {
 682                error = xfs_attr_rmtval_set(args);
 683                if (error)
 684                        return error;
 685        }
 686
 687        /*
 688         * If this is an atomic rename operation, we must "flip" the
 689         * incomplete flags on the "new" and "old" attribute/value pairs
 690         * so that one disappears and one appears atomically.  Then we
 691         * must remove the "old" attribute/value pair.
 692         */
 693        if (args->op_flags & XFS_DA_OP_RENAME) {
 694                /*
 695                 * In a separate transaction, set the incomplete flag on the
 696                 * "old" attr and clear the incomplete flag on the "new" attr.
 697                 */
 698                error = xfs_attr3_leaf_flipflags(args);
 699                if (error)
 700                        return error;
 701
 702                /*
 703                 * Dismantle the "old" attribute/value pair by removing
 704                 * a "remote" value (if it exists).
 705                 */
 706                args->index = args->index2;
 707                args->blkno = args->blkno2;
 708                args->rmtblkno = args->rmtblkno2;
 709                args->rmtblkcnt = args->rmtblkcnt2;
 710                args->rmtvaluelen = args->rmtvaluelen2;
 711                if (args->rmtblkno) {
 712                        error = xfs_attr_rmtval_remove(args);
 713                        if (error)
 714                                return error;
 715                }
 716
 717                /*
 718                 * Read in the block containing the "old" attr, then
 719                 * remove the "old" attr from that block (neat, huh!)
 720                 */
 721                error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
 722                                           -1, &bp);
 723                if (error)
 724                        return error;
 725
 726                xfs_attr3_leaf_remove(bp, args);
 727
 728                /*
 729                 * If the result is small enough, shrink it all into the inode.
 730                 */
 731                if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
 732                        xfs_bmap_init(args->flist, args->firstblock);
 733                        error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
 734                        /* bp is gone due to xfs_da_shrink_inode */
 735                        if (!error) {
 736                                error = xfs_bmap_finish(&args->trans,
 737                                                        args->flist,
 738                                                        &committed);
 739                        }
 740                        if (error) {
 741                                ASSERT(committed);
 742                                args->trans = NULL;
 743                                xfs_bmap_cancel(args->flist);
 744                                return error;
 745                        }
 746
 747                        /*
 748                         * bmap_finish() may have committed the last trans
 749                         * and started a new one.  We need the inode to be
 750                         * in all transactions.
 751                         */
 752                        if (committed)
 753                                xfs_trans_ijoin(args->trans, dp, 0);
 754                }
 755
 756                /*
 757                 * Commit the remove and start the next trans in series.
 758                 */
 759                error = xfs_trans_roll(&args->trans, dp);
 760
 761        } else if (args->rmtblkno > 0) {
 762                /*
 763                 * Added a "remote" value, just clear the incomplete flag.
 764                 */
 765                error = xfs_attr3_leaf_clearflag(args);
 766        }
 767        return error;
 768}
 769
 770/*
 771 * Remove a name from the leaf attribute list structure
 772 *
 773 * This leaf block cannot have a "remote" value, we only call this routine
 774 * if bmap_one_block() says there is only one block (ie: no remote blks).
 775 */
 776STATIC int
 777xfs_attr_leaf_removename(xfs_da_args_t *args)
 778{
 779        xfs_inode_t *dp;
 780        struct xfs_buf *bp;
 781        int error, committed, forkoff;
 782
 783        trace_xfs_attr_leaf_removename(args);
 784
 785        /*
 786         * Remove the attribute.
 787         */
 788        dp = args->dp;
 789        args->blkno = 0;
 790        error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
 791        if (error)
 792                return error;
 793
 794        error = xfs_attr3_leaf_lookup_int(bp, args);
 795        if (error == -ENOATTR) {
 796                xfs_trans_brelse(args->trans, bp);
 797                return error;
 798        }
 799
 800        xfs_attr3_leaf_remove(bp, args);
 801
 802        /*
 803         * If the result is small enough, shrink it all into the inode.
 804         */
 805        if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
 806                xfs_bmap_init(args->flist, args->firstblock);
 807                error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
 808                /* bp is gone due to xfs_da_shrink_inode */
 809                if (!error) {
 810                        error = xfs_bmap_finish(&args->trans, args->flist,
 811                                                &committed);
 812                }
 813                if (error) {
 814                        ASSERT(committed);
 815                        args->trans = NULL;
 816                        xfs_bmap_cancel(args->flist);
 817                        return error;
 818                }
 819
 820                /*
 821                 * bmap_finish() may have committed the last trans and started
 822                 * a new one.  We need the inode to be in all transactions.
 823                 */
 824                if (committed)
 825                        xfs_trans_ijoin(args->trans, dp, 0);
 826        }
 827        return 0;
 828}
 829
 830/*
 831 * Look up a name in a leaf attribute list structure.
 832 *
 833 * This leaf block cannot have a "remote" value, we only call this routine
 834 * if bmap_one_block() says there is only one block (ie: no remote blks).
 835 */
 836STATIC int
 837xfs_attr_leaf_get(xfs_da_args_t *args)
 838{
 839        struct xfs_buf *bp;
 840        int error;
 841
 842        trace_xfs_attr_leaf_get(args);
 843
 844        args->blkno = 0;
 845        error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
 846        if (error)
 847                return error;
 848
 849        error = xfs_attr3_leaf_lookup_int(bp, args);
 850        if (error != -EEXIST)  {
 851                xfs_trans_brelse(args->trans, bp);
 852                return error;
 853        }
 854        error = xfs_attr3_leaf_getvalue(bp, args);
 855        xfs_trans_brelse(args->trans, bp);
 856        if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {
 857                error = xfs_attr_rmtval_get(args);
 858        }
 859        return error;
 860}
 861
 862/*========================================================================
 863 * External routines when attribute list size > geo->blksize
 864 *========================================================================*/
 865
 866/*
 867 * Add a name to a Btree-format attribute list.
 868 *
 869 * This will involve walking down the Btree, and may involve splitting
 870 * leaf nodes and even splitting intermediate nodes up to and including
 871 * the root node (a special case of an intermediate node).
 872 *
 873 * "Remote" attribute values confuse the issue and atomic rename operations
 874 * add a whole extra layer of confusion on top of that.
 875 */
 876STATIC int
 877xfs_attr_node_addname(xfs_da_args_t *args)
 878{
 879        xfs_da_state_t *state;
 880        xfs_da_state_blk_t *blk;
 881        xfs_inode_t *dp;
 882        xfs_mount_t *mp;
 883        int committed, retval, error;
 884
 885        trace_xfs_attr_node_addname(args);
 886
 887        /*
 888         * Fill in bucket of arguments/results/context to carry around.
 889         */
 890        dp = args->dp;
 891        mp = dp->i_mount;
 892restart:
 893        state = xfs_da_state_alloc();
 894        state->args = args;
 895        state->mp = mp;
 896
 897        /*
 898         * Search to see if name already exists, and get back a pointer
 899         * to where it should go.
 900         */
 901        error = xfs_da3_node_lookup_int(state, &retval);
 902        if (error)
 903                goto out;
 904        blk = &state->path.blk[ state->path.active-1 ];
 905        ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
 906        if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
 907                goto out;
 908        } else if (retval == -EEXIST) {
 909                if (args->flags & ATTR_CREATE)
 910                        goto out;
 911
 912                trace_xfs_attr_node_replace(args);
 913
 914                /* save the attribute state for later removal*/
 915                args->op_flags |= XFS_DA_OP_RENAME;     /* atomic rename op */
 916                args->blkno2 = args->blkno;             /* set 2nd entry info*/
 917                args->index2 = args->index;
 918                args->rmtblkno2 = args->rmtblkno;
 919                args->rmtblkcnt2 = args->rmtblkcnt;
 920                args->rmtvaluelen2 = args->rmtvaluelen;
 921
 922                /*
 923                 * clear the remote attr state now that it is saved so that the
 924                 * values reflect the state of the attribute we are about to
 925                 * add, not the attribute we just found and will remove later.
 926                 */
 927                args->rmtblkno = 0;
 928                args->rmtblkcnt = 0;
 929                args->rmtvaluelen = 0;
 930        }
 931
 932        retval = xfs_attr3_leaf_add(blk->bp, state->args);
 933        if (retval == -ENOSPC) {
 934                if (state->path.active == 1) {
 935                        /*
 936                         * Its really a single leaf node, but it had
 937                         * out-of-line values so it looked like it *might*
 938                         * have been a b-tree.
 939                         */
 940                        xfs_da_state_free(state);
 941                        state = NULL;
 942                        xfs_bmap_init(args->flist, args->firstblock);
 943                        error = xfs_attr3_leaf_to_node(args);
 944                        if (!error) {
 945                                error = xfs_bmap_finish(&args->trans,
 946                                                        args->flist,
 947                                                        &committed);
 948                        }
 949                        if (error) {
 950                                ASSERT(committed);
 951                                args->trans = NULL;
 952                                xfs_bmap_cancel(args->flist);
 953                                goto out;
 954                        }
 955
 956                        /*
 957                         * bmap_finish() may have committed the last trans
 958                         * and started a new one.  We need the inode to be
 959                         * in all transactions.
 960                         */
 961                        if (committed)
 962                                xfs_trans_ijoin(args->trans, dp, 0);
 963
 964                        /*
 965                         * Commit the node conversion and start the next
 966                         * trans in the chain.
 967                         */
 968                        error = xfs_trans_roll(&args->trans, dp);
 969                        if (error)
 970                                goto out;
 971
 972                        goto restart;
 973                }
 974
 975                /*
 976                 * Split as many Btree elements as required.
 977                 * This code tracks the new and old attr's location
 978                 * in the index/blkno/rmtblkno/rmtblkcnt fields and
 979                 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
 980                 */
 981                xfs_bmap_init(args->flist, args->firstblock);
 982                error = xfs_da3_split(state);
 983                if (!error) {
 984                        error = xfs_bmap_finish(&args->trans, args->flist,
 985                                                &committed);
 986                }
 987                if (error) {
 988                        ASSERT(committed);
 989                        args->trans = NULL;
 990                        xfs_bmap_cancel(args->flist);
 991                        goto out;
 992                }
 993
 994                /*
 995                 * bmap_finish() may have committed the last trans and started
 996                 * a new one.  We need the inode to be in all transactions.
 997                 */
 998                if (committed)
 999                        xfs_trans_ijoin(args->trans, dp, 0);
1000        } else {
1001                /*
1002                 * Addition succeeded, update Btree hashvals.
1003                 */
1004                xfs_da3_fixhashpath(state, &state->path);
1005        }
1006
1007        /*
1008         * Kill the state structure, we're done with it and need to
1009         * allow the buffers to come back later.
1010         */
1011        xfs_da_state_free(state);
1012        state = NULL;
1013
1014        /*
1015         * Commit the leaf addition or btree split and start the next
1016         * trans in the chain.
1017         */
1018        error = xfs_trans_roll(&args->trans, dp);
1019        if (error)
1020                goto out;
1021
1022        /*
1023         * If there was an out-of-line value, allocate the blocks we
1024         * identified for its storage and copy the value.  This is done
1025         * after we create the attribute so that we don't overflow the
1026         * maximum size of a transaction and/or hit a deadlock.
1027         */
1028        if (args->rmtblkno > 0) {
1029                error = xfs_attr_rmtval_set(args);
1030                if (error)
1031                        return error;
1032        }
1033
1034        /*
1035         * If this is an atomic rename operation, we must "flip" the
1036         * incomplete flags on the "new" and "old" attribute/value pairs
1037         * so that one disappears and one appears atomically.  Then we
1038         * must remove the "old" attribute/value pair.
1039         */
1040        if (args->op_flags & XFS_DA_OP_RENAME) {
1041                /*
1042                 * In a separate transaction, set the incomplete flag on the
1043                 * "old" attr and clear the incomplete flag on the "new" attr.
1044                 */
1045                error = xfs_attr3_leaf_flipflags(args);
1046                if (error)
1047                        goto out;
1048
1049                /*
1050                 * Dismantle the "old" attribute/value pair by removing
1051                 * a "remote" value (if it exists).
1052                 */
1053                args->index = args->index2;
1054                args->blkno = args->blkno2;
1055                args->rmtblkno = args->rmtblkno2;
1056                args->rmtblkcnt = args->rmtblkcnt2;
1057                args->rmtvaluelen = args->rmtvaluelen2;
1058                if (args->rmtblkno) {
1059                        error = xfs_attr_rmtval_remove(args);
1060                        if (error)
1061                                return error;
1062                }
1063
1064                /*
1065                 * Re-find the "old" attribute entry after any split ops.
1066                 * The INCOMPLETE flag means that we will find the "old"
1067                 * attr, not the "new" one.
1068                 */
1069                args->flags |= XFS_ATTR_INCOMPLETE;
1070                state = xfs_da_state_alloc();
1071                state->args = args;
1072                state->mp = mp;
1073                state->inleaf = 0;
1074                error = xfs_da3_node_lookup_int(state, &retval);
1075                if (error)
1076                        goto out;
1077
1078                /*
1079                 * Remove the name and update the hashvals in the tree.
1080                 */
1081                blk = &state->path.blk[ state->path.active-1 ];
1082                ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1083                error = xfs_attr3_leaf_remove(blk->bp, args);
1084                xfs_da3_fixhashpath(state, &state->path);
1085
1086                /*
1087                 * Check to see if the tree needs to be collapsed.
1088                 */
1089                if (retval && (state->path.active > 1)) {
1090                        xfs_bmap_init(args->flist, args->firstblock);
1091                        error = xfs_da3_join(state);
1092                        if (!error) {
1093                                error = xfs_bmap_finish(&args->trans,
1094                                                        args->flist,
1095                                                        &committed);
1096                        }
1097                        if (error) {
1098                                ASSERT(committed);
1099                                args->trans = NULL;
1100                                xfs_bmap_cancel(args->flist);
1101                                goto out;
1102                        }
1103
1104                        /*
1105                         * bmap_finish() may have committed the last trans
1106                         * and started a new one.  We need the inode to be
1107                         * in all transactions.
1108                         */
1109                        if (committed)
1110                                xfs_trans_ijoin(args->trans, dp, 0);
1111                }
1112
1113                /*
1114                 * Commit and start the next trans in the chain.
1115                 */
1116                error = xfs_trans_roll(&args->trans, dp);
1117                if (error)
1118                        goto out;
1119
1120        } else if (args->rmtblkno > 0) {
1121                /*
1122                 * Added a "remote" value, just clear the incomplete flag.
1123                 */
1124                error = xfs_attr3_leaf_clearflag(args);
1125                if (error)
1126                        goto out;
1127        }
1128        retval = error = 0;
1129
1130out:
1131        if (state)
1132                xfs_da_state_free(state);
1133        if (error)
1134                return error;
1135        return retval;
1136}
1137
1138/*
1139 * Remove a name from a B-tree attribute list.
1140 *
1141 * This will involve walking down the Btree, and may involve joining
1142 * leaf nodes and even joining intermediate nodes up to and including
1143 * the root node (a special case of an intermediate node).
1144 */
1145STATIC int
1146xfs_attr_node_removename(xfs_da_args_t *args)
1147{
1148        xfs_da_state_t *state;
1149        xfs_da_state_blk_t *blk;
1150        xfs_inode_t *dp;
1151        struct xfs_buf *bp;
1152        int retval, error, committed, forkoff;
1153
1154        trace_xfs_attr_node_removename(args);
1155
1156        /*
1157         * Tie a string around our finger to remind us where we are.
1158         */
1159        dp = args->dp;
1160        state = xfs_da_state_alloc();
1161        state->args = args;
1162        state->mp = dp->i_mount;
1163
1164        /*
1165         * Search to see if name exists, and get back a pointer to it.
1166         */
1167        error = xfs_da3_node_lookup_int(state, &retval);
1168        if (error || (retval != -EEXIST)) {
1169                if (error == 0)
1170                        error = retval;
1171                goto out;
1172        }
1173
1174        /*
1175         * If there is an out-of-line value, de-allocate the blocks.
1176         * This is done before we remove the attribute so that we don't
1177         * overflow the maximum size of a transaction and/or hit a deadlock.
1178         */
1179        blk = &state->path.blk[ state->path.active-1 ];
1180        ASSERT(blk->bp != NULL);
1181        ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1182        if (args->rmtblkno > 0) {
1183                /*
1184                 * Fill in disk block numbers in the state structure
1185                 * so that we can get the buffers back after we commit
1186                 * several transactions in the following calls.
1187                 */
1188                error = xfs_attr_fillstate(state);
1189                if (error)
1190                        goto out;
1191
1192                /*
1193                 * Mark the attribute as INCOMPLETE, then bunmapi() the
1194                 * remote value.
1195                 */
1196                error = xfs_attr3_leaf_setflag(args);
1197                if (error)
1198                        goto out;
1199                error = xfs_attr_rmtval_remove(args);
1200                if (error)
1201                        goto out;
1202
1203                /*
1204                 * Refill the state structure with buffers, the prior calls
1205                 * released our buffers.
1206                 */
1207                error = xfs_attr_refillstate(state);
1208                if (error)
1209                        goto out;
1210        }
1211
1212        /*
1213         * Remove the name and update the hashvals in the tree.
1214         */
1215        blk = &state->path.blk[ state->path.active-1 ];
1216        ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1217        retval = xfs_attr3_leaf_remove(blk->bp, args);
1218        xfs_da3_fixhashpath(state, &state->path);
1219
1220        /*
1221         * Check to see if the tree needs to be collapsed.
1222         */
1223        if (retval && (state->path.active > 1)) {
1224                xfs_bmap_init(args->flist, args->firstblock);
1225                error = xfs_da3_join(state);
1226                if (!error) {
1227                        error = xfs_bmap_finish(&args->trans, args->flist,
1228                                                &committed);
1229                }
1230                if (error) {
1231                        ASSERT(committed);
1232                        args->trans = NULL;
1233                        xfs_bmap_cancel(args->flist);
1234                        goto out;
1235                }
1236
1237                /*
1238                 * bmap_finish() may have committed the last trans and started
1239                 * a new one.  We need the inode to be in all transactions.
1240                 */
1241                if (committed)
1242                        xfs_trans_ijoin(args->trans, dp, 0);
1243
1244                /*
1245                 * Commit the Btree join operation and start a new trans.
1246                 */
1247                error = xfs_trans_roll(&args->trans, dp);
1248                if (error)
1249                        goto out;
1250        }
1251
1252        /*
1253         * If the result is small enough, push it all into the inode.
1254         */
1255        if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
1256                /*
1257                 * Have to get rid of the copy of this dabuf in the state.
1258                 */
1259                ASSERT(state->path.active == 1);
1260                ASSERT(state->path.blk[0].bp);
1261                state->path.blk[0].bp = NULL;
1262
1263                error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
1264                if (error)
1265                        goto out;
1266
1267                if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
1268                        xfs_bmap_init(args->flist, args->firstblock);
1269                        error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
1270                        /* bp is gone due to xfs_da_shrink_inode */
1271                        if (!error) {
1272                                error = xfs_bmap_finish(&args->trans,
1273                                                        args->flist,
1274                                                        &committed);
1275                        }
1276                        if (error) {
1277                                ASSERT(committed);
1278                                args->trans = NULL;
1279                                xfs_bmap_cancel(args->flist);
1280                                goto out;
1281                        }
1282
1283                        /*
1284                         * bmap_finish() may have committed the last trans
1285                         * and started a new one.  We need the inode to be
1286                         * in all transactions.
1287                         */
1288                        if (committed)
1289                                xfs_trans_ijoin(args->trans, dp, 0);
1290                } else
1291                        xfs_trans_brelse(args->trans, bp);
1292        }
1293        error = 0;
1294
1295out:
1296        xfs_da_state_free(state);
1297        return error;
1298}
1299
1300/*
1301 * Fill in the disk block numbers in the state structure for the buffers
1302 * that are attached to the state structure.
1303 * This is done so that we can quickly reattach ourselves to those buffers
1304 * after some set of transaction commits have released these buffers.
1305 */
1306STATIC int
1307xfs_attr_fillstate(xfs_da_state_t *state)
1308{
1309        xfs_da_state_path_t *path;
1310        xfs_da_state_blk_t *blk;
1311        int level;
1312
1313        trace_xfs_attr_fillstate(state->args);
1314
1315        /*
1316         * Roll down the "path" in the state structure, storing the on-disk
1317         * block number for those buffers in the "path".
1318         */
1319        path = &state->path;
1320        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1321        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1322                if (blk->bp) {
1323                        blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
1324                        blk->bp = NULL;
1325                } else {
1326                        blk->disk_blkno = 0;
1327                }
1328        }
1329
1330        /*
1331         * Roll down the "altpath" in the state structure, storing the on-disk
1332         * block number for those buffers in the "altpath".
1333         */
1334        path = &state->altpath;
1335        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1336        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1337                if (blk->bp) {
1338                        blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
1339                        blk->bp = NULL;
1340                } else {
1341                        blk->disk_blkno = 0;
1342                }
1343        }
1344
1345        return 0;
1346}
1347
1348/*
1349 * Reattach the buffers to the state structure based on the disk block
1350 * numbers stored in the state structure.
1351 * This is done after some set of transaction commits have released those
1352 * buffers from our grip.
1353 */
1354STATIC int
1355xfs_attr_refillstate(xfs_da_state_t *state)
1356{
1357        xfs_da_state_path_t *path;
1358        xfs_da_state_blk_t *blk;
1359        int level, error;
1360
1361        trace_xfs_attr_refillstate(state->args);
1362
1363        /*
1364         * Roll down the "path" in the state structure, storing the on-disk
1365         * block number for those buffers in the "path".
1366         */
1367        path = &state->path;
1368        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1369        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1370                if (blk->disk_blkno) {
1371                        error = xfs_da3_node_read(state->args->trans,
1372                                                state->args->dp,
1373                                                blk->blkno, blk->disk_blkno,
1374                                                &blk->bp, XFS_ATTR_FORK);
1375                        if (error)
1376                                return error;
1377                } else {
1378                        blk->bp = NULL;
1379                }
1380        }
1381
1382        /*
1383         * Roll down the "altpath" in the state structure, storing the on-disk
1384         * block number for those buffers in the "altpath".
1385         */
1386        path = &state->altpath;
1387        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1388        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1389                if (blk->disk_blkno) {
1390                        error = xfs_da3_node_read(state->args->trans,
1391                                                state->args->dp,
1392                                                blk->blkno, blk->disk_blkno,
1393                                                &blk->bp, XFS_ATTR_FORK);
1394                        if (error)
1395                                return error;
1396                } else {
1397                        blk->bp = NULL;
1398                }
1399        }
1400
1401        return 0;
1402}
1403
1404/*
1405 * Look up a filename in a node attribute list.
1406 *
1407 * This routine gets called for any attribute fork that has more than one
1408 * block, ie: both true Btree attr lists and for single-leaf-blocks with
1409 * "remote" values taking up more blocks.
1410 */
1411STATIC int
1412xfs_attr_node_get(xfs_da_args_t *args)
1413{
1414        xfs_da_state_t *state;
1415        xfs_da_state_blk_t *blk;
1416        int error, retval;
1417        int i;
1418
1419        trace_xfs_attr_node_get(args);
1420
1421        state = xfs_da_state_alloc();
1422        state->args = args;
1423        state->mp = args->dp->i_mount;
1424
1425        /*
1426         * Search to see if name exists, and get back a pointer to it.
1427         */
1428        error = xfs_da3_node_lookup_int(state, &retval);
1429        if (error) {
1430                retval = error;
1431        } else if (retval == -EEXIST) {
1432                blk = &state->path.blk[ state->path.active-1 ];
1433                ASSERT(blk->bp != NULL);
1434                ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1435
1436                /*
1437                 * Get the value, local or "remote"
1438                 */
1439                retval = xfs_attr3_leaf_getvalue(blk->bp, args);
1440                if (!retval && (args->rmtblkno > 0)
1441                    && !(args->flags & ATTR_KERNOVAL)) {
1442                        retval = xfs_attr_rmtval_get(args);
1443                }
1444        }
1445
1446        /*
1447         * If not in a transaction, we have to release all the buffers.
1448         */
1449        for (i = 0; i < state->path.active; i++) {
1450                xfs_trans_brelse(args->trans, state->path.blk[i].bp);
1451                state->path.blk[i].bp = NULL;
1452        }
1453
1454        xfs_da_state_free(state);
1455        return retval;
1456}
1457