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