linux-old/fs/xfs/xfs_attr.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify it
   5 * under the terms of version 2 of the GNU General Public License as
   6 * published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it would be useful, but
   9 * WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11 *
  12 * Further, this software is distributed without any warranty that it is
  13 * free of the rightful claim of any third person regarding infringement
  14 * or the like.  Any license provided herein, whether implied or
  15 * otherwise, applies only to this software file.  Patent licenses, if
  16 * any, provided herein do not apply to combinations of this program with
  17 * other software, or any other product whatsoever.
  18 *
  19 * You should have received a copy of the GNU General Public License along
  20 * with this program; if not, write the Free Software Foundation, Inc., 59
  21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
  22 *
  23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
  24 * Mountain View, CA  94043, or:
  25 *
  26 * http://www.sgi.com
  27 *
  28 * For further information regarding this notice, see:
  29 *
  30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  31 */
  32
  33#include "xfs.h"
  34
  35#include "xfs_macros.h"
  36#include "xfs_types.h"
  37#include "xfs_inum.h"
  38#include "xfs_log.h"
  39#include "xfs_trans.h"
  40#include "xfs_sb.h"
  41#include "xfs_ag.h"
  42#include "xfs_dir.h"
  43#include "xfs_dir2.h"
  44#include "xfs_dmapi.h"
  45#include "xfs_mount.h"
  46#include "xfs_alloc_btree.h"
  47#include "xfs_bmap_btree.h"
  48#include "xfs_ialloc_btree.h"
  49#include "xfs_alloc.h"
  50#include "xfs_btree.h"
  51#include "xfs_attr_sf.h"
  52#include "xfs_dir_sf.h"
  53#include "xfs_dir2_sf.h"
  54#include "xfs_dinode.h"
  55#include "xfs_inode_item.h"
  56#include "xfs_inode.h"
  57#include "xfs_bmap.h"
  58#include "xfs_da_btree.h"
  59#include "xfs_attr.h"
  60#include "xfs_attr_leaf.h"
  61#include "xfs_error.h"
  62#include "xfs_bit.h"
  63#include "xfs_quota.h"
  64#include "xfs_rw.h"
  65#include "xfs_trans_space.h"
  66#include "xfs_acl.h"
  67
  68/*
  69 * xfs_attr.c
  70 *
  71 * Provide the external interfaces to manage attribute lists.
  72 */
  73
  74/*========================================================================
  75 * Function prototypes for the kernel.
  76 *========================================================================*/
  77
  78/*
  79 * Internal routines when attribute list fits inside the inode.
  80 */
  81STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
  82
  83/*
  84 * Internal routines when attribute list is one block.
  85 */
  86STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
  87STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
  88STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context);
  89
  90/*
  91 * Internal routines when attribute list is more than one block.
  92 */
  93STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
  94STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
  95STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context);
  96STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
  97STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
  98
  99/*
 100 * Routines to manipulate out-of-line attribute values.
 101 */
 102STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args);
 103STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args);
 104STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args);
 105
 106#define ATTR_RMTVALUE_MAPSIZE   1       /* # of map entries at once */
 107
 108#if defined(XFS_ATTR_TRACE)
 109ktrace_t *xfs_attr_trace_buf;
 110#endif
 111
 112
 113/*========================================================================
 114 * Overall external interface routines.
 115 *========================================================================*/
 116
 117int
 118xfs_attr_fetch(xfs_inode_t *ip, char *name, int namelen,
 119               char *value, int *valuelenp, int flags, struct cred *cred)
 120{
 121        xfs_da_args_t   args;
 122        int             error;
 123
 124        if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 125                return(EIO);
 126
 127        if ((XFS_IFORK_Q(ip) == 0) ||
 128            (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 129             ip->i_d.di_anextents == 0))
 130                return(ENOATTR);
 131
 132        if (!(flags & ATTR_KERNACCESS)) {
 133                xfs_ilock(ip, XFS_ILOCK_SHARED);
 134
 135                if (!(flags & ATTR_SECURE) &&
 136                    ((error = xfs_iaccess(ip, S_IRUSR, cred)))) {
 137                        xfs_iunlock(ip, XFS_ILOCK_SHARED);
 138                        return(XFS_ERROR(error));
 139                }
 140        }
 141
 142        /*
 143         * Fill in the arg structure for this request.
 144         */
 145        memset((char *)&args, 0, sizeof(args));
 146        args.name = name;
 147        args.namelen = namelen;
 148        args.value = value;
 149        args.valuelen = *valuelenp;
 150        args.flags = flags;
 151        args.hashval = xfs_da_hashname(args.name, args.namelen);
 152        args.dp = ip;
 153        args.whichfork = XFS_ATTR_FORK;
 154
 155        /*
 156         * Decide on what work routines to call based on the inode size.
 157         */
 158        if (XFS_IFORK_Q(ip) == 0 ||
 159            (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 160             ip->i_d.di_anextents == 0)) {
 161                error = XFS_ERROR(ENOATTR);
 162        } else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
 163                error = xfs_attr_shortform_getvalue(&args);
 164        } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {
 165                error = xfs_attr_leaf_get(&args);
 166        } else {
 167                error = xfs_attr_node_get(&args);
 168        }
 169
 170        if (!(flags & ATTR_KERNACCESS))
 171                xfs_iunlock(ip, XFS_ILOCK_SHARED);
 172
 173        /*
 174         * Return the number of bytes in the value to the caller.
 175         */
 176        *valuelenp = args.valuelen;
 177
 178        if (error == EEXIST)
 179                error = 0;
 180        return(error);
 181}
 182
 183int
 184xfs_attr_get(bhv_desc_t *bdp, char *name, char *value, int *valuelenp,
 185             int flags, struct cred *cred)
 186{
 187        xfs_inode_t     *ip = XFS_BHVTOI(bdp);
 188        int             namelen;
 189
 190        XFS_STATS_INC(xs_attr_get);
 191
 192        if (!name)
 193                return(EINVAL);
 194        namelen = strlen(name);
 195        if (namelen >= MAXNAMELEN)
 196                return(EFAULT);         /* match IRIX behaviour */
 197
 198        return xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, cred);
 199}
 200
 201/*ARGSUSED*/
 202int                                                             /* error */
 203xfs_attr_set(bhv_desc_t *bdp, char *name, char *value, int valuelen, int flags,
 204                     struct cred *cred)
 205{
 206        xfs_da_args_t   args;
 207        xfs_inode_t     *dp;
 208        xfs_fsblock_t   firstblock;
 209        xfs_bmap_free_t flist;
 210        int             error, err2, committed;
 211        int             local, size;
 212        uint            nblks;
 213        xfs_mount_t     *mp;
 214        int             rsvd = (flags & ATTR_ROOT) != 0;
 215        int             namelen;
 216
 217        namelen = strlen(name);
 218        if (namelen >= MAXNAMELEN)
 219                return EFAULT;          /* match IRIX behaviour */
 220
 221        XFS_STATS_INC(xs_attr_set);
 222
 223        dp = XFS_BHVTOI(bdp);
 224        mp = dp->i_mount;
 225        if (XFS_FORCED_SHUTDOWN(mp))
 226                return (EIO);
 227
 228        xfs_ilock(dp, XFS_ILOCK_SHARED);
 229        if (!(flags & ATTR_SECURE) &&
 230             (error = xfs_iaccess(dp, S_IWUSR, cred))) {
 231                xfs_iunlock(dp, XFS_ILOCK_SHARED);
 232                return(XFS_ERROR(error));
 233        }
 234        xfs_iunlock(dp, XFS_ILOCK_SHARED);
 235
 236        /*
 237         * Attach the dquots to the inode.
 238         */
 239        if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
 240                return (error);
 241
 242        /*
 243         * If the inode doesn't have an attribute fork, add one.
 244         * (inode must not be locked when we call this routine)
 245         */
 246        if (XFS_IFORK_Q(dp) == 0) {
 247                error = xfs_bmap_add_attrfork(dp, rsvd);
 248                if (error)
 249                        return(error);
 250        }
 251
 252        /*
 253         * Fill in the arg structure for this request.
 254         */
 255        memset((char *)&args, 0, sizeof(args));
 256        args.name = name;
 257        args.namelen = namelen;
 258        args.value = value;
 259        args.valuelen = valuelen;
 260        args.flags = flags;
 261        args.hashval = xfs_da_hashname(args.name, args.namelen);
 262        args.dp = dp;
 263        args.firstblock = &firstblock;
 264        args.flist = &flist;
 265        args.whichfork = XFS_ATTR_FORK;
 266        args.oknoent = 1;
 267
 268        /* Determine space new attribute will use, and if it will be inline
 269         * or out of line.
 270         */
 271        size = xfs_attr_leaf_newentsize(&args, mp->m_sb.sb_blocksize, &local);
 272
 273        nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
 274        if (local) {
 275                if (size > (mp->m_sb.sb_blocksize >> 1)) {
 276                        /* Double split possible */
 277                        nblks <<= 1;
 278                }
 279        } else {
 280                uint    dblocks = XFS_B_TO_FSB(mp, valuelen);
 281                /* Out of line attribute, cannot double split, but make
 282                 * room for the attribute value itself.
 283                 */
 284                nblks += dblocks;
 285                nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
 286        }
 287
 288        /* Size is now blocks for attribute data */
 289        args.total = nblks;
 290
 291        /*
 292         * Start our first transaction of the day.
 293         *
 294         * All future transactions during this code must be "chained" off
 295         * this one via the trans_dup() call.  All transactions will contain
 296         * the inode, and the inode will always be marked with trans_ihold().
 297         * Since the inode will be locked in all transactions, we must log
 298         * the inode in every transaction to let it float upward through
 299         * the log.
 300         */
 301        args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET);
 302
 303        /*
 304         * Root fork attributes can use reserved data blocks for this
 305         * operation if necessary
 306         */
 307
 308        if (rsvd)
 309                args.trans->t_flags |= XFS_TRANS_RESERVE;
 310
 311        if ((error = xfs_trans_reserve(args.trans, (uint) nblks,
 312                                      XFS_ATTRSET_LOG_RES(mp, nblks),
 313                                      0, XFS_TRANS_PERM_LOG_RES,
 314                                      XFS_ATTRSET_LOG_COUNT))) {
 315                xfs_trans_cancel(args.trans, 0);
 316                return(error);
 317        }
 318        xfs_ilock(dp, XFS_ILOCK_EXCL);
 319
 320        error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0,
 321                         rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
 322                                XFS_QMOPT_RES_REGBLKS);
 323        if (error) {
 324                xfs_iunlock(dp, XFS_ILOCK_EXCL);
 325                xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
 326                return (error);
 327        }
 328
 329        xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
 330        xfs_trans_ihold(args.trans, dp);
 331
 332        /*
 333         * If the attribute list is non-existant or a shortform list,
 334         * upgrade it to a single-leaf-block attribute list.
 335         */
 336        if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
 337            ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) &&
 338             (dp->i_d.di_anextents == 0))) {
 339
 340                /*
 341                 * Build initial attribute list (if required).
 342                 */
 343                if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
 344                        (void)xfs_attr_shortform_create(&args);
 345
 346                /*
 347                 * Try to add the attr to the attribute list in
 348                 * the inode.
 349                 */
 350                error = xfs_attr_shortform_addname(&args);
 351                if (error != ENOSPC) {
 352                        /*
 353                         * Commit the shortform mods, and we're done.
 354                         * NOTE: this is also the error path (EEXIST, etc).
 355                         */
 356                        ASSERT(args.trans != NULL);
 357
 358                        /*
 359                         * If this is a synchronous mount, make sure that
 360                         * the transaction goes to disk before returning
 361                         * to the user.
 362                         */
 363                        if (mp->m_flags & XFS_MOUNT_WSYNC) {
 364                                xfs_trans_set_sync(args.trans);
 365                        }
 366                        err2 = xfs_trans_commit(args.trans,
 367                                                 XFS_TRANS_RELEASE_LOG_RES,
 368                                                 NULL);
 369                        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 370
 371                        /*
 372                         * Hit the inode change time.
 373                         */
 374                        if (!error && (flags & ATTR_KERNOTIME) == 0) {
 375                                xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
 376                        }
 377                        return(error == 0 ? err2 : error);
 378                }
 379
 380                /*
 381                 * It won't fit in the shortform, transform to a leaf block.
 382                 * GROT: another possible req'mt for a double-split btree op.
 383                 */
 384                XFS_BMAP_INIT(args.flist, args.firstblock);
 385                error = xfs_attr_shortform_to_leaf(&args);
 386                if (!error) {
 387                        error = xfs_bmap_finish(&args.trans, args.flist,
 388                                                *args.firstblock, &committed);
 389                }
 390                if (error) {
 391                        ASSERT(committed);
 392                        args.trans = NULL;
 393                        xfs_bmap_cancel(&flist);
 394                        goto out;
 395                }
 396
 397                /*
 398                 * bmap_finish() may have committed the last trans and started
 399                 * a new one.  We need the inode to be in all transactions.
 400                 */
 401                if (committed) {
 402                        xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
 403                        xfs_trans_ihold(args.trans, dp);
 404                }
 405
 406                /*
 407                 * Commit the leaf transformation.  We'll need another (linked)
 408                 * transaction to add the new attribute to the leaf.
 409                 */
 410                if ((error = xfs_attr_rolltrans(&args.trans, dp)))
 411                        goto out;
 412
 413        }
 414
 415        if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
 416                error = xfs_attr_leaf_addname(&args);
 417        } else {
 418                error = xfs_attr_node_addname(&args);
 419        }
 420        if (error) {
 421                goto out;
 422        }
 423
 424        /*
 425         * If this is a synchronous mount, make sure that the
 426         * transaction goes to disk before returning to the user.
 427         */
 428        if (mp->m_flags & XFS_MOUNT_WSYNC) {
 429                xfs_trans_set_sync(args.trans);
 430        }
 431
 432        /*
 433         * Commit the last in the sequence of transactions.
 434         */
 435        xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
 436        error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
 437                                 NULL);
 438        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 439
 440        /*
 441         * Hit the inode change time.
 442         */
 443        if (!error && (flags & ATTR_KERNOTIME) == 0) {
 444                xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
 445        }
 446
 447        return(error);
 448
 449out:
 450        if (args.trans)
 451                xfs_trans_cancel(args.trans,
 452                        XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
 453        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 454        return(error);
 455}
 456
 457/*
 458 * Generic handler routine to remove a name from an attribute list.
 459 * Transitions attribute list from Btree to shortform as necessary.
 460 */
 461/*ARGSUSED*/
 462int                                                             /* error */
 463xfs_attr_remove(bhv_desc_t *bdp, char *name, int flags, struct cred *cred)
 464{
 465        xfs_da_args_t       args;
 466        xfs_inode_t         *dp;
 467        xfs_fsblock_t       firstblock;
 468        xfs_bmap_free_t     flist;
 469        int                 error;
 470        xfs_mount_t         *mp;
 471        int                 namelen;
 472
 473        ASSERT(MAXNAMELEN-1<=0xff); /* length is stored in uint8 */
 474        namelen = strlen(name);
 475        if (namelen>=MAXNAMELEN)
 476                return EFAULT; /* match irix behaviour */
 477
 478        XFS_STATS_INC(xs_attr_remove);
 479
 480        dp = XFS_BHVTOI(bdp);
 481        mp = dp->i_mount;
 482        if (XFS_FORCED_SHUTDOWN(mp))
 483                return (EIO);
 484
 485        xfs_ilock(dp, XFS_ILOCK_SHARED);
 486        if (!(flags & ATTR_SECURE) &&
 487             (error = xfs_iaccess(dp, S_IWUSR, cred))) {
 488                xfs_iunlock(dp, XFS_ILOCK_SHARED);
 489                return(XFS_ERROR(error));
 490        } else if (XFS_IFORK_Q(dp) == 0 ||
 491                   (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 492                    dp->i_d.di_anextents == 0)) {
 493                xfs_iunlock(dp, XFS_ILOCK_SHARED);
 494                return(XFS_ERROR(ENOATTR));
 495        }
 496        xfs_iunlock(dp, XFS_ILOCK_SHARED);
 497
 498        /*
 499         * Fill in the arg structure for this request.
 500         */
 501        memset((char *)&args, 0, sizeof(args));
 502        args.name = name;
 503        args.namelen = namelen;
 504        args.flags = flags;
 505        args.hashval = xfs_da_hashname(args.name, args.namelen);
 506        args.dp = dp;
 507        args.firstblock = &firstblock;
 508        args.flist = &flist;
 509        args.total = 0;
 510        args.whichfork = XFS_ATTR_FORK;
 511
 512        /*
 513         * Attach the dquots to the inode.
 514         */
 515        if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
 516                return (error);
 517
 518        /*
 519         * Start our first transaction of the day.
 520         *
 521         * All future transactions during this code must be "chained" off
 522         * this one via the trans_dup() call.  All transactions will contain
 523         * the inode, and the inode will always be marked with trans_ihold().
 524         * Since the inode will be locked in all transactions, we must log
 525         * the inode in every transaction to let it float upward through
 526         * the log.
 527         */
 528        args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM);
 529
 530        /*
 531         * Root fork attributes can use reserved data blocks for this
 532         * operation if necessary
 533         */
 534
 535        if (flags & ATTR_ROOT)
 536                args.trans->t_flags |= XFS_TRANS_RESERVE;
 537
 538        if ((error = xfs_trans_reserve(args.trans,
 539                                      XFS_ATTRRM_SPACE_RES(mp),
 540                                      XFS_ATTRRM_LOG_RES(mp),
 541                                      0, XFS_TRANS_PERM_LOG_RES,
 542                                      XFS_ATTRRM_LOG_COUNT))) {
 543                xfs_trans_cancel(args.trans, 0);
 544                return(error);
 545
 546        }
 547
 548        xfs_ilock(dp, XFS_ILOCK_EXCL);
 549        /*
 550         * No need to make quota reservations here. We expect to release some
 551         * blocks not allocate in the common case.
 552         */
 553        xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
 554        xfs_trans_ihold(args.trans, dp);
 555
 556        /*
 557         * Decide on what work routines to call based on the inode size.
 558         */
 559        if (XFS_IFORK_Q(dp) == 0 ||
 560            (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 561             dp->i_d.di_anextents == 0)) {
 562                error = XFS_ERROR(ENOATTR);
 563                goto out;
 564        }
 565        if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
 566                ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
 567                error = xfs_attr_shortform_remove(&args);
 568                if (error) {
 569                        goto out;
 570                }
 571        } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
 572                error = xfs_attr_leaf_removename(&args);
 573        } else {
 574                error = xfs_attr_node_removename(&args);
 575        }
 576        if (error) {
 577                goto out;
 578        }
 579
 580        /*
 581         * If this is a synchronous mount, make sure that the
 582         * transaction goes to disk before returning to the user.
 583         */
 584        if (mp->m_flags & XFS_MOUNT_WSYNC) {
 585                xfs_trans_set_sync(args.trans);
 586        }
 587
 588        /*
 589         * Commit the last in the sequence of transactions.
 590         */
 591        xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
 592        error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
 593                                 NULL);
 594        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 595
 596        /*
 597         * Hit the inode change time.
 598         */
 599        if (!error && (flags & ATTR_KERNOTIME) == 0) {
 600                xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
 601        }
 602
 603        return(error);
 604
 605out:
 606        if (args.trans)
 607                xfs_trans_cancel(args.trans,
 608                        XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
 609        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 610        return(error);
 611}
 612
 613/*
 614 * Generate a list of extended attribute names and optionally
 615 * also value lengths.  Positive return value follows the XFS
 616 * convention of being an error, zero or negative return code
 617 * is the length of the buffer returned (negated), indicating
 618 * success.
 619 */
 620int
 621xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,
 622                      attrlist_cursor_kern_t *cursor, struct cred *cred)
 623{
 624        xfs_attr_list_context_t context;
 625        xfs_inode_t *dp;
 626        int error;
 627
 628        XFS_STATS_INC(xs_attr_list);
 629
 630        /*
 631         * Validate the cursor.
 632         */
 633        if (cursor->pad1 || cursor->pad2)
 634                return(XFS_ERROR(EINVAL));
 635        if ((cursor->initted == 0) &&
 636            (cursor->hashval || cursor->blkno || cursor->offset))
 637                return(XFS_ERROR(EINVAL));
 638
 639        /*
 640         * Check for a properly aligned buffer.
 641         */
 642        if (((long)buffer) & (sizeof(int)-1))
 643                return(XFS_ERROR(EFAULT));
 644        if (flags & ATTR_KERNOVAL)
 645                bufsize = 0;
 646
 647        /*
 648         * Initialize the output buffer.
 649         */
 650        context.dp = dp = XFS_BHVTOI(bdp);
 651        context.cursor = cursor;
 652        context.count = 0;
 653        context.dupcnt = 0;
 654        context.resynch = 1;
 655        context.flags = flags;
 656        if (!(flags & ATTR_KERNAMELS)) {
 657                context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */
 658                context.firstu = context.bufsize;
 659                context.alist = (attrlist_t *)buffer;
 660                context.alist->al_count = 0;
 661                context.alist->al_more = 0;
 662                context.alist->al_offset[0] = context.bufsize;
 663        }
 664        else {
 665                context.bufsize = bufsize;
 666                context.firstu = context.bufsize;
 667                context.alist = (attrlist_t *)buffer;
 668        }
 669
 670        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 671                return (EIO);
 672
 673        xfs_ilock(dp, XFS_ILOCK_SHARED);
 674        if (!(flags & ATTR_SECURE) &&
 675             (error = xfs_iaccess(dp, S_IRUSR, cred))) {
 676                xfs_iunlock(dp, XFS_ILOCK_SHARED);
 677                return(XFS_ERROR(error));
 678        }
 679
 680        /*
 681         * Decide on what work routines to call based on the inode size.
 682         */
 683        xfs_attr_trace_l_c("syscall start", &context);
 684        if (XFS_IFORK_Q(dp) == 0 ||
 685            (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 686             dp->i_d.di_anextents == 0)) {
 687                error = 0;
 688        } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
 689                error = xfs_attr_shortform_list(&context);
 690        } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
 691                error = xfs_attr_leaf_list(&context);
 692        } else {
 693                error = xfs_attr_node_list(&context);
 694        }
 695        xfs_iunlock(dp, XFS_ILOCK_SHARED);
 696        xfs_attr_trace_l_c("syscall end", &context);
 697
 698        if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) {
 699                ASSERT(error >= 0);
 700        }
 701        else {  /* must return negated buffer size or the error */
 702                if (context.count < 0)
 703                        error = XFS_ERROR(ERANGE);
 704                else
 705                        error = -context.count;
 706        }
 707
 708        return(error);
 709}
 710
 711int                                                             /* error */
 712xfs_attr_inactive(xfs_inode_t *dp)
 713{
 714        xfs_trans_t *trans;
 715        xfs_mount_t *mp;
 716        int error;
 717
 718        mp = dp->i_mount;
 719        ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
 720
 721        /* XXXsup - why on earth are we taking ILOCK_EXCL here??? */
 722        xfs_ilock(dp, XFS_ILOCK_EXCL);
 723        if ((XFS_IFORK_Q(dp) == 0) ||
 724            (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
 725            (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 726             dp->i_d.di_anextents == 0)) {
 727                xfs_iunlock(dp, XFS_ILOCK_EXCL);
 728                return(0);
 729        }
 730        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 731
 732        /*
 733         * Start our first transaction of the day.
 734         *
 735         * All future transactions during this code must be "chained" off
 736         * this one via the trans_dup() call.  All transactions will contain
 737         * the inode, and the inode will always be marked with trans_ihold().
 738         * Since the inode will be locked in all transactions, we must log
 739         * the inode in every transaction to let it float upward through
 740         * the log.
 741         */
 742        trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL);
 743        if ((error = xfs_trans_reserve(trans, 0, XFS_ATTRINVAL_LOG_RES(mp), 0,
 744                                      XFS_TRANS_PERM_LOG_RES,
 745                                      XFS_ATTRINVAL_LOG_COUNT))) {
 746                xfs_trans_cancel(trans, 0);
 747                return(error);
 748        }
 749        xfs_ilock(dp, XFS_ILOCK_EXCL);
 750
 751        /*
 752         * No need to make quota reservations here. We expect to release some
 753         * blocks, not allocate, in the common case.
 754         */
 755        xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL);
 756        xfs_trans_ihold(trans, dp);
 757
 758        /*
 759         * Decide on what work routines to call based on the inode size.
 760         */
 761        if ((XFS_IFORK_Q(dp) == 0) ||
 762            (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
 763            (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
 764             dp->i_d.di_anextents == 0)) {
 765                error = 0;
 766                goto out;
 767        }
 768        error = xfs_attr_root_inactive(&trans, dp);
 769        if (error)
 770                goto out;
 771        /*
 772         * signal synchronous inactive transactions unless this
 773         * is a synchronous mount filesystem in which case we
 774         * know that we're here because we've been called out of
 775         * xfs_inactive which means that the last reference is gone
 776         * and the unlink transaction has already hit the disk so
 777         * async inactive transactions are safe.
 778         */
 779        if ((error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK,
 780                                (!(mp->m_flags & XFS_MOUNT_WSYNC)
 781                                 ? 1 : 0))))
 782                goto out;
 783
 784        /*
 785         * Commit the last in the sequence of transactions.
 786         */
 787        xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE);
 788        error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES,
 789                                 NULL);
 790        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 791
 792        return(error);
 793
 794out:
 795        xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
 796        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 797        return(error);
 798}
 799
 800
 801
 802/*========================================================================
 803 * External routines when attribute list is inside the inode
 804 *========================================================================*/
 805
 806/*
 807 * Add a name to the shortform attribute list structure
 808 * This is the external routine.
 809 */
 810STATIC int
 811xfs_attr_shortform_addname(xfs_da_args_t *args)
 812{
 813        int newsize, retval;
 814
 815        retval = xfs_attr_shortform_lookup(args);
 816        if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
 817                return(retval);
 818        } else if (retval == EEXIST) {
 819                if (args->flags & ATTR_CREATE)
 820                        return(retval);
 821                retval = xfs_attr_shortform_remove(args);
 822                ASSERT(retval == 0);
 823        }
 824
 825        newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
 826        newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
 827        if ((newsize <= XFS_IFORK_ASIZE(args->dp)) &&
 828            (args->namelen < XFS_ATTR_SF_ENTSIZE_MAX) &&
 829            (args->valuelen < XFS_ATTR_SF_ENTSIZE_MAX)) {
 830                retval = xfs_attr_shortform_add(args);
 831                ASSERT(retval == 0);
 832        } else {
 833                return(XFS_ERROR(ENOSPC));
 834        }
 835        return(0);
 836}
 837
 838
 839/*========================================================================
 840 * External routines when attribute list is one block
 841 *========================================================================*/
 842
 843/*
 844 * Add a name to the leaf attribute list structure
 845 *
 846 * This leaf block cannot have a "remote" value, we only call this routine
 847 * if bmap_one_block() says there is only one block (ie: no remote blks).
 848 */
 849int
 850xfs_attr_leaf_addname(xfs_da_args_t *args)
 851{
 852        xfs_inode_t *dp;
 853        xfs_dabuf_t *bp;
 854        int retval, error, committed;
 855
 856        /*
 857         * Read the (only) block in the attribute list in.
 858         */
 859        dp = args->dp;
 860        args->blkno = 0;
 861        error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
 862                                             XFS_ATTR_FORK);
 863        if (error)
 864                return(error);
 865        ASSERT(bp != NULL);
 866
 867        /*
 868         * Look up the given attribute in the leaf block.  Figure out if
 869         * the given flags produce an error or call for an atomic rename.
 870         */
 871        retval = xfs_attr_leaf_lookup_int(bp, args);
 872        if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
 873                xfs_da_brelse(args->trans, bp);
 874                return(retval);
 875        } else if (retval == EEXIST) {
 876                if (args->flags & ATTR_CREATE) {        /* pure create op */
 877                        xfs_da_brelse(args->trans, bp);
 878                        return(retval);
 879                }
 880                args->rename = 1;                       /* an atomic rename */
 881                args->blkno2 = args->blkno;             /* set 2nd entry info*/
 882                args->index2 = args->index;
 883                args->rmtblkno2 = args->rmtblkno;
 884                args->rmtblkcnt2 = args->rmtblkcnt;
 885        }
 886
 887        /*
 888         * Add the attribute to the leaf block, transitioning to a Btree
 889         * if required.
 890         */
 891        retval = xfs_attr_leaf_add(bp, args);
 892        xfs_da_buf_done(bp);
 893        if (retval == ENOSPC) {
 894                /*
 895                 * Promote the attribute list to the Btree format, then
 896                 * Commit that transaction so that the node_addname() call
 897                 * can manage its own transactions.
 898                 */
 899                XFS_BMAP_INIT(args->flist, args->firstblock);
 900                error = xfs_attr_leaf_to_node(args);
 901                if (!error) {
 902                        error = xfs_bmap_finish(&args->trans, args->flist,
 903                                                *args->firstblock, &committed);
 904                }
 905                if (error) {
 906                        ASSERT(committed);
 907                        args->trans = NULL;
 908                        xfs_bmap_cancel(args->flist);
 909                        return(error);
 910                }
 911
 912                /*
 913                 * bmap_finish() may have committed the last trans and started
 914                 * a new one.  We need the inode to be in all transactions.
 915                 */
 916                if (committed) {
 917                        xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
 918                        xfs_trans_ihold(args->trans, dp);
 919                }
 920
 921                /*
 922                 * Commit the current trans (including the inode) and start
 923                 * a new one.
 924                 */
 925                if ((error = xfs_attr_rolltrans(&args->trans, dp)))
 926                        return (error);
 927
 928                /*
 929                 * Fob the whole rest of the problem off on the Btree code.
 930                 */
 931                error = xfs_attr_node_addname(args);
 932                return(error);
 933        }
 934
 935        /*
 936         * Commit the transaction that added the attr name so that
 937         * later routines can manage their own transactions.
 938         */
 939        if ((error = xfs_attr_rolltrans(&args->trans, dp)))
 940                return (error);
 941
 942        /*
 943         * If there was an out-of-line value, allocate the blocks we
 944         * identified for its storage and copy the value.  This is done
 945         * after we create the attribute so that we don't overflow the
 946         * maximum size of a transaction and/or hit a deadlock.
 947         */
 948        if (args->rmtblkno > 0) {
 949                error = xfs_attr_rmtval_set(args);
 950                if (error)
 951                        return(error);
 952        }
 953
 954        /*
 955         * If this is an atomic rename operation, we must "flip" the
 956         * incomplete flags on the "new" and "old" attribute/value pairs
 957         * so that one disappears and one appears atomically.  Then we
 958         * must remove the "old" attribute/value pair.
 959         */
 960        if (args->rename) {
 961                /*
 962                 * In a separate transaction, set the incomplete flag on the
 963                 * "old" attr and clear the incomplete flag on the "new" attr.
 964                 */
 965                error = xfs_attr_leaf_flipflags(args);
 966                if (error)
 967                        return(error);
 968
 969                /*
 970                 * Dismantle the "old" attribute/value pair by removing
 971                 * a "remote" value (if it exists).
 972                 */
 973                args->index = args->index2;
 974                args->blkno = args->blkno2;
 975                args->rmtblkno = args->rmtblkno2;
 976                args->rmtblkcnt = args->rmtblkcnt2;
 977                if (args->rmtblkno) {
 978                        error = xfs_attr_rmtval_remove(args);
 979                        if (error)
 980                                return(error);
 981                }
 982
 983                /*
 984                 * Read in the block containing the "old" attr, then
 985                 * remove the "old" attr from that block (neat, huh!)
 986                 */
 987                error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1,
 988                                                     &bp, XFS_ATTR_FORK);
 989                if (error)
 990                        return(error);
 991                ASSERT(bp != NULL);
 992                (void)xfs_attr_leaf_remove(bp, args);
 993
 994                /*
 995                 * If the result is small enough, shrink it all into the inode.
 996                 */
 997                if (xfs_attr_shortform_allfit(bp, dp)) {
 998                        XFS_BMAP_INIT(args->flist, args->firstblock);
 999                        error = xfs_attr_leaf_to_shortform(bp, args);
1000                        /* bp is gone due to xfs_da_shrink_inode */
1001                        if (!error) {
1002                                error = xfs_bmap_finish(&args->trans,
1003                                                        args->flist,
1004                                                        *args->firstblock,
1005                                                        &committed);
1006                        }
1007                        if (error) {
1008                                ASSERT(committed);
1009                                args->trans = NULL;
1010                                xfs_bmap_cancel(args->flist);
1011                                return(error);
1012                        }
1013
1014                        /*
1015                         * bmap_finish() may have committed the last trans
1016                         * and started a new one.  We need the inode to be
1017                         * in all transactions.
1018                         */
1019                        if (committed) {
1020                                xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1021                                xfs_trans_ihold(args->trans, dp);
1022                        }
1023                } else
1024                        xfs_da_buf_done(bp);
1025
1026                /*
1027                 * Commit the remove and start the next trans in series.
1028                 */
1029                error = xfs_attr_rolltrans(&args->trans, dp);
1030
1031        } else if (args->rmtblkno > 0) {
1032                /*
1033                 * Added a "remote" value, just clear the incomplete flag.
1034                 */
1035                error = xfs_attr_leaf_clearflag(args);
1036        }
1037        return(error);
1038}
1039
1040/*
1041 * Remove a name from the leaf attribute list structure
1042 *
1043 * This leaf block cannot have a "remote" value, we only call this routine
1044 * if bmap_one_block() says there is only one block (ie: no remote blks).
1045 */
1046STATIC int
1047xfs_attr_leaf_removename(xfs_da_args_t *args)
1048{
1049        xfs_inode_t *dp;
1050        xfs_dabuf_t *bp;
1051        int committed;
1052        int error;
1053
1054        /*
1055         * Remove the attribute.
1056         */
1057        dp = args->dp;
1058        args->blkno = 0;
1059        error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
1060                                             XFS_ATTR_FORK);
1061        if (error) {
1062                return(error);
1063        }
1064
1065        ASSERT(bp != NULL);
1066        error = xfs_attr_leaf_lookup_int(bp, args);
1067        if (error == ENOATTR) {
1068                xfs_da_brelse(args->trans, bp);
1069                return(error);
1070        }
1071
1072        (void)xfs_attr_leaf_remove(bp, args);
1073
1074        /*
1075         * If the result is small enough, shrink it all into the inode.
1076         */
1077        if (xfs_attr_shortform_allfit(bp, dp)) {
1078                XFS_BMAP_INIT(args->flist, args->firstblock);
1079                error = xfs_attr_leaf_to_shortform(bp, args);
1080                /* bp is gone due to xfs_da_shrink_inode */
1081                if (!error) {
1082                        error = xfs_bmap_finish(&args->trans, args->flist,
1083                                                *args->firstblock, &committed);
1084                }
1085                if (error) {
1086                        ASSERT(committed);
1087                        args->trans = NULL;
1088                        xfs_bmap_cancel(args->flist);
1089                        return(error);
1090                }
1091
1092                /*
1093                 * bmap_finish() may have committed the last trans and started
1094                 * a new one.  We need the inode to be in all transactions.
1095                 */
1096                if (committed) {
1097                        xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1098                        xfs_trans_ihold(args->trans, dp);
1099                }
1100        } else
1101                xfs_da_buf_done(bp);
1102        return(0);
1103}
1104
1105/*
1106 * Look up a name in a leaf attribute list structure.
1107 *
1108 * This leaf block cannot have a "remote" value, we only call this routine
1109 * if bmap_one_block() says there is only one block (ie: no remote blks).
1110 */
1111int
1112xfs_attr_leaf_get(xfs_da_args_t *args)
1113{
1114        xfs_dabuf_t *bp;
1115        int error;
1116
1117        args->blkno = 0;
1118        error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
1119                                             XFS_ATTR_FORK);
1120        if (error)
1121                return(error);
1122        ASSERT(bp != NULL);
1123
1124        error = xfs_attr_leaf_lookup_int(bp, args);
1125        if (error != EEXIST)  {
1126                xfs_da_brelse(args->trans, bp);
1127                return(error);
1128        }
1129        error = xfs_attr_leaf_getvalue(bp, args);
1130        xfs_da_brelse(args->trans, bp);
1131        if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {
1132                error = xfs_attr_rmtval_get(args);
1133        }
1134        return(error);
1135}
1136
1137/*
1138 * Copy out attribute entries for attr_list(), for leaf attribute lists.
1139 */
1140STATIC int
1141xfs_attr_leaf_list(xfs_attr_list_context_t *context)
1142{
1143        xfs_attr_leafblock_t *leaf;
1144        int error;
1145        xfs_dabuf_t *bp;
1146
1147        context->cursor->blkno = 0;
1148        error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK);
1149        if (error)
1150                return(error);
1151        ASSERT(bp != NULL);
1152        leaf = bp->data;
1153        if (unlikely(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
1154                                                != XFS_ATTR_LEAF_MAGIC)) {
1155                XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,
1156                                     context->dp->i_mount, leaf);
1157                xfs_da_brelse(NULL, bp);
1158                return(XFS_ERROR(EFSCORRUPTED));
1159        }
1160
1161        (void)xfs_attr_leaf_list_int(bp, context);
1162        xfs_da_brelse(NULL, bp);
1163        return(0);
1164}
1165
1166
1167/*========================================================================
1168 * External routines when attribute list size > XFS_LBSIZE(mp).
1169 *========================================================================*/
1170
1171/*
1172 * Add a name to a Btree-format attribute list.
1173 *
1174 * This will involve walking down the Btree, and may involve splitting
1175 * leaf nodes and even splitting intermediate nodes up to and including
1176 * the root node (a special case of an intermediate node).
1177 *
1178 * "Remote" attribute values confuse the issue and atomic rename operations
1179 * add a whole extra layer of confusion on top of that.
1180 */
1181STATIC int
1182xfs_attr_node_addname(xfs_da_args_t *args)
1183{
1184        xfs_da_state_t *state;
1185        xfs_da_state_blk_t *blk;
1186        xfs_inode_t *dp;
1187        xfs_mount_t *mp;
1188        int committed, retval, error;
1189
1190        /*
1191         * Fill in bucket of arguments/results/context to carry around.
1192         */
1193        dp = args->dp;
1194        mp = dp->i_mount;
1195restart:
1196        state = xfs_da_state_alloc();
1197        state->args = args;
1198        state->mp = mp;
1199        state->blocksize = state->mp->m_sb.sb_blocksize;
1200        state->node_ents = state->mp->m_attr_node_ents;
1201
1202        /*
1203         * Search to see if name already exists, and get back a pointer
1204         * to where it should go.
1205         */
1206        error = xfs_da_node_lookup_int(state, &retval);
1207        if (error)
1208                goto out;
1209        blk = &state->path.blk[ state->path.active-1 ];
1210        ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1211        if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
1212                goto out;
1213        } else if (retval == EEXIST) {
1214                if (args->flags & ATTR_CREATE)
1215                        goto out;
1216                args->rename = 1;                       /* atomic rename op */
1217                args->blkno2 = args->blkno;             /* set 2nd entry info*/
1218                args->index2 = args->index;
1219                args->rmtblkno2 = args->rmtblkno;
1220                args->rmtblkcnt2 = args->rmtblkcnt;
1221                args->rmtblkno = 0;
1222                args->rmtblkcnt = 0;
1223        }
1224
1225        retval = xfs_attr_leaf_add(blk->bp, state->args);
1226        if (retval == ENOSPC) {
1227                if (state->path.active == 1) {
1228                        /*
1229                         * Its really a single leaf node, but it had
1230                         * out-of-line values so it looked like it *might*
1231                         * have been a b-tree.
1232                         */
1233                        xfs_da_state_free(state);
1234                        XFS_BMAP_INIT(args->flist, args->firstblock);
1235                        error = xfs_attr_leaf_to_node(args);
1236                        if (!error) {
1237                                error = xfs_bmap_finish(&args->trans,
1238                                                        args->flist,
1239                                                        *args->firstblock,
1240                                                        &committed);
1241                        }
1242                        if (error) {
1243                                ASSERT(committed);
1244                                args->trans = NULL;
1245                                xfs_bmap_cancel(args->flist);
1246                                goto out;
1247                        }
1248
1249                        /*
1250                         * bmap_finish() may have committed the last trans
1251                         * and started a new one.  We need the inode to be
1252                         * in all transactions.
1253                         */
1254                        if (committed) {
1255                                xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1256                                xfs_trans_ihold(args->trans, dp);
1257                        }
1258
1259                        /*
1260                         * Commit the node conversion and start the next
1261                         * trans in the chain.
1262                         */
1263                        if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1264                                goto out;
1265
1266                        goto restart;
1267                }
1268
1269                /*
1270                 * Split as many Btree elements as required.
1271                 * This code tracks the new and old attr's location
1272                 * in the index/blkno/rmtblkno/rmtblkcnt fields and
1273                 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
1274                 */
1275                XFS_BMAP_INIT(args->flist, args->firstblock);
1276                error = xfs_da_split(state);
1277                if (!error) {
1278                        error = xfs_bmap_finish(&args->trans, args->flist,
1279                                                *args->firstblock, &committed);
1280                }
1281                if (error) {
1282                        ASSERT(committed);
1283                        args->trans = NULL;
1284                        xfs_bmap_cancel(args->flist);
1285                        goto out;
1286                }
1287
1288                /*
1289                 * bmap_finish() may have committed the last trans and started
1290                 * a new one.  We need the inode to be in all transactions.
1291                 */
1292                if (committed) {
1293                        xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1294                        xfs_trans_ihold(args->trans, dp);
1295                }
1296        } else {
1297                /*
1298                 * Addition succeeded, update Btree hashvals.
1299                 */
1300                xfs_da_fixhashpath(state, &state->path);
1301        }
1302
1303        /*
1304         * Kill the state structure, we're done with it and need to
1305         * allow the buffers to come back later.
1306         */
1307        xfs_da_state_free(state);
1308        state = NULL;
1309
1310        /*
1311         * Commit the leaf addition or btree split and start the next
1312         * trans in the chain.
1313         */
1314        if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1315                goto out;
1316
1317        /*
1318         * If there was an out-of-line value, allocate the blocks we
1319         * identified for its storage and copy the value.  This is done
1320         * after we create the attribute so that we don't overflow the
1321         * maximum size of a transaction and/or hit a deadlock.
1322         */
1323        if (args->rmtblkno > 0) {
1324                error = xfs_attr_rmtval_set(args);
1325                if (error)
1326                        return(error);
1327        }
1328
1329        /*
1330         * If this is an atomic rename operation, we must "flip" the
1331         * incomplete flags on the "new" and "old" attribute/value pairs
1332         * so that one disappears and one appears atomically.  Then we
1333         * must remove the "old" attribute/value pair.
1334         */
1335        if (args->rename) {
1336                /*
1337                 * In a separate transaction, set the incomplete flag on the
1338                 * "old" attr and clear the incomplete flag on the "new" attr.
1339                 */
1340                error = xfs_attr_leaf_flipflags(args);
1341                if (error)
1342                        goto out;
1343
1344                /*
1345                 * Dismantle the "old" attribute/value pair by removing
1346                 * a "remote" value (if it exists).
1347                 */
1348                args->index = args->index2;
1349                args->blkno = args->blkno2;
1350                args->rmtblkno = args->rmtblkno2;
1351                args->rmtblkcnt = args->rmtblkcnt2;
1352                if (args->rmtblkno) {
1353                        error = xfs_attr_rmtval_remove(args);
1354                        if (error)
1355                                return(error);
1356                }
1357
1358                /*
1359                 * Re-find the "old" attribute entry after any split ops.
1360                 * The INCOMPLETE flag means that we will find the "old"
1361                 * attr, not the "new" one.
1362                 */
1363                args->flags |= XFS_ATTR_INCOMPLETE;
1364                state = xfs_da_state_alloc();
1365                state->args = args;
1366                state->mp = mp;
1367                state->blocksize = state->mp->m_sb.sb_blocksize;
1368                state->node_ents = state->mp->m_attr_node_ents;
1369                state->inleaf = 0;
1370                error = xfs_da_node_lookup_int(state, &retval);
1371                if (error)
1372                        goto out;
1373
1374                /*
1375                 * Remove the name and update the hashvals in the tree.
1376                 */
1377                blk = &state->path.blk[ state->path.active-1 ];
1378                ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1379                error = xfs_attr_leaf_remove(blk->bp, args);
1380                xfs_da_fixhashpath(state, &state->path);
1381
1382                /*
1383                 * Check to see if the tree needs to be collapsed.
1384                 */
1385                if (retval && (state->path.active > 1)) {
1386                        XFS_BMAP_INIT(args->flist, args->firstblock);
1387                        error = xfs_da_join(state);
1388                        if (!error) {
1389                                error = xfs_bmap_finish(&args->trans,
1390                                                        args->flist,
1391                                                        *args->firstblock,
1392                                                        &committed);
1393                        }
1394                        if (error) {
1395                                ASSERT(committed);
1396                                args->trans = NULL;
1397                                xfs_bmap_cancel(args->flist);
1398                                goto out;
1399                        }
1400
1401                        /*
1402                         * bmap_finish() may have committed the last trans
1403                         * and started a new one.  We need the inode to be
1404                         * in all transactions.
1405                         */
1406                        if (committed) {
1407                                xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1408                                xfs_trans_ihold(args->trans, dp);
1409                        }
1410                }
1411
1412                /*
1413                 * Commit and start the next trans in the chain.
1414                 */
1415                if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1416                        goto out;
1417
1418        } else if (args->rmtblkno > 0) {
1419                /*
1420                 * Added a "remote" value, just clear the incomplete flag.
1421                 */
1422                error = xfs_attr_leaf_clearflag(args);
1423                if (error)
1424                        goto out;
1425        }
1426        retval = error = 0;
1427
1428out:
1429        if (state)
1430                xfs_da_state_free(state);
1431        if (error)
1432                return(error);
1433        return(retval);
1434}
1435
1436/*
1437 * Remove a name from a B-tree attribute list.
1438 *
1439 * This will involve walking down the Btree, and may involve joining
1440 * leaf nodes and even joining intermediate nodes up to and including
1441 * the root node (a special case of an intermediate node).
1442 */
1443STATIC int
1444xfs_attr_node_removename(xfs_da_args_t *args)
1445{
1446        xfs_da_state_t *state;
1447        xfs_da_state_blk_t *blk;
1448        xfs_inode_t *dp;
1449        xfs_dabuf_t *bp;
1450        int retval, error, committed;
1451
1452        /*
1453         * Tie a string around our finger to remind us where we are.
1454         */
1455        dp = args->dp;
1456        state = xfs_da_state_alloc();
1457        state->args = args;
1458        state->mp = dp->i_mount;
1459        state->blocksize = state->mp->m_sb.sb_blocksize;
1460        state->node_ents = state->mp->m_attr_node_ents;
1461
1462        /*
1463         * Search to see if name exists, and get back a pointer to it.
1464         */
1465        error = xfs_da_node_lookup_int(state, &retval);
1466        if (error || (retval != EEXIST)) {
1467                if (error == 0)
1468                        error = retval;
1469                goto out;
1470        }
1471
1472        /*
1473         * If there is an out-of-line value, de-allocate the blocks.
1474         * This is done before we remove the attribute so that we don't
1475         * overflow the maximum size of a transaction and/or hit a deadlock.
1476         */
1477        blk = &state->path.blk[ state->path.active-1 ];
1478        ASSERT(blk->bp != NULL);
1479        ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1480        if (args->rmtblkno > 0) {
1481                /*
1482                 * Fill in disk block numbers in the state structure
1483                 * so that we can get the buffers back after we commit
1484                 * several transactions in the following calls.
1485                 */
1486                error = xfs_attr_fillstate(state);
1487                if (error)
1488                        goto out;
1489
1490                /*
1491                 * Mark the attribute as INCOMPLETE, then bunmapi() the
1492                 * remote value.
1493                 */
1494                error = xfs_attr_leaf_setflag(args);
1495                if (error)
1496                        goto out;
1497                error = xfs_attr_rmtval_remove(args);
1498                if (error)
1499                        goto out;
1500
1501                /*
1502                 * Refill the state structure with buffers, the prior calls
1503                 * released our buffers.
1504                 */
1505                error = xfs_attr_refillstate(state);
1506                if (error)
1507                        goto out;
1508        }
1509
1510        /*
1511         * Remove the name and update the hashvals in the tree.
1512         */
1513        blk = &state->path.blk[ state->path.active-1 ];
1514        ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1515        retval = xfs_attr_leaf_remove(blk->bp, args);
1516        xfs_da_fixhashpath(state, &state->path);
1517
1518        /*
1519         * Check to see if the tree needs to be collapsed.
1520         */
1521        if (retval && (state->path.active > 1)) {
1522                XFS_BMAP_INIT(args->flist, args->firstblock);
1523                error = xfs_da_join(state);
1524                if (!error) {
1525                        error = xfs_bmap_finish(&args->trans, args->flist,
1526                                                *args->firstblock, &committed);
1527                }
1528                if (error) {
1529                        ASSERT(committed);
1530                        args->trans = NULL;
1531                        xfs_bmap_cancel(args->flist);
1532                        goto out;
1533                }
1534
1535                /*
1536                 * bmap_finish() may have committed the last trans and started
1537                 * a new one.  We need the inode to be in all transactions.
1538                 */
1539                if (committed) {
1540                        xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1541                        xfs_trans_ihold(args->trans, dp);
1542                }
1543
1544                /*
1545                 * Commit the Btree join operation and start a new trans.
1546                 */
1547                if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1548                        goto out;
1549        }
1550
1551        /*
1552         * If the result is small enough, push it all into the inode.
1553         */
1554        if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
1555                /*
1556                 * Have to get rid of the copy of this dabuf in the state.
1557                 */
1558                ASSERT(state->path.active == 1);
1559                ASSERT(state->path.blk[0].bp);
1560                xfs_da_buf_done(state->path.blk[0].bp);
1561                state->path.blk[0].bp = NULL;
1562
1563                error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
1564                                                     XFS_ATTR_FORK);
1565                if (error)
1566                        goto out;
1567                ASSERT(INT_GET(((xfs_attr_leafblock_t *)
1568                                      bp->data)->hdr.info.magic, ARCH_CONVERT)
1569                                                       == XFS_ATTR_LEAF_MAGIC);
1570
1571                if (xfs_attr_shortform_allfit(bp, dp)) {
1572                        XFS_BMAP_INIT(args->flist, args->firstblock);
1573                        error = xfs_attr_leaf_to_shortform(bp, args);
1574                        /* bp is gone due to xfs_da_shrink_inode */
1575                        if (!error) {
1576                                error = xfs_bmap_finish(&args->trans,
1577                                                        args->flist,
1578                                                        *args->firstblock,
1579                                                        &committed);
1580                        }
1581                        if (error) {
1582                                ASSERT(committed);
1583                                args->trans = NULL;
1584                                xfs_bmap_cancel(args->flist);
1585                                goto out;
1586                        }
1587
1588                        /*
1589                         * bmap_finish() may have committed the last trans
1590                         * and started a new one.  We need the inode to be
1591                         * in all transactions.
1592                         */
1593                        if (committed) {
1594                                xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1595                                xfs_trans_ihold(args->trans, dp);
1596                        }
1597                } else
1598                        xfs_da_brelse(args->trans, bp);
1599        }
1600        error = 0;
1601
1602out:
1603        xfs_da_state_free(state);
1604        return(error);
1605}
1606
1607/*
1608 * Fill in the disk block numbers in the state structure for the buffers
1609 * that are attached to the state structure.
1610 * This is done so that we can quickly reattach ourselves to those buffers
1611 * after some set of transaction commit's has released these buffers.
1612 */
1613STATIC int
1614xfs_attr_fillstate(xfs_da_state_t *state)
1615{
1616        xfs_da_state_path_t *path;
1617        xfs_da_state_blk_t *blk;
1618        int level;
1619
1620        /*
1621         * Roll down the "path" in the state structure, storing the on-disk
1622         * block number for those buffers in the "path".
1623         */
1624        path = &state->path;
1625        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1626        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1627                if (blk->bp) {
1628                        blk->disk_blkno = xfs_da_blkno(blk->bp);
1629                        xfs_da_buf_done(blk->bp);
1630                        blk->bp = NULL;
1631                } else {
1632                        blk->disk_blkno = 0;
1633                }
1634        }
1635
1636        /*
1637         * Roll down the "altpath" in the state structure, storing the on-disk
1638         * block number for those buffers in the "altpath".
1639         */
1640        path = &state->altpath;
1641        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1642        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1643                if (blk->bp) {
1644                        blk->disk_blkno = xfs_da_blkno(blk->bp);
1645                        xfs_da_buf_done(blk->bp);
1646                        blk->bp = NULL;
1647                } else {
1648                        blk->disk_blkno = 0;
1649                }
1650        }
1651
1652        return(0);
1653}
1654
1655/*
1656 * Reattach the buffers to the state structure based on the disk block
1657 * numbers stored in the state structure.
1658 * This is done after some set of transaction commit's has released those
1659 * buffers from our grip.
1660 */
1661STATIC int
1662xfs_attr_refillstate(xfs_da_state_t *state)
1663{
1664        xfs_da_state_path_t *path;
1665        xfs_da_state_blk_t *blk;
1666        int level, error;
1667
1668        /*
1669         * Roll down the "path" in the state structure, storing the on-disk
1670         * block number for those buffers in the "path".
1671         */
1672        path = &state->path;
1673        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1674        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1675                if (blk->disk_blkno) {
1676                        error = xfs_da_read_buf(state->args->trans,
1677                                                state->args->dp,
1678                                                blk->blkno, blk->disk_blkno,
1679                                                &blk->bp, XFS_ATTR_FORK);
1680                        if (error)
1681                                return(error);
1682                } else {
1683                        blk->bp = NULL;
1684                }
1685        }
1686
1687        /*
1688         * Roll down the "altpath" in the state structure, storing the on-disk
1689         * block number for those buffers in the "altpath".
1690         */
1691        path = &state->altpath;
1692        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1693        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1694                if (blk->disk_blkno) {
1695                        error = xfs_da_read_buf(state->args->trans,
1696                                                state->args->dp,
1697                                                blk->blkno, blk->disk_blkno,
1698                                                &blk->bp, XFS_ATTR_FORK);
1699                        if (error)
1700                                return(error);
1701                } else {
1702                        blk->bp = NULL;
1703                }
1704        }
1705
1706        return(0);
1707}
1708
1709/*
1710 * Look up a filename in a node attribute list.
1711 *
1712 * This routine gets called for any attribute fork that has more than one
1713 * block, ie: both true Btree attr lists and for single-leaf-blocks with
1714 * "remote" values taking up more blocks.
1715 */
1716int
1717xfs_attr_node_get(xfs_da_args_t *args)
1718{
1719        xfs_da_state_t *state;
1720        xfs_da_state_blk_t *blk;
1721        int error, retval;
1722        int i;
1723
1724        state = xfs_da_state_alloc();
1725        state->args = args;
1726        state->mp = args->dp->i_mount;
1727        state->blocksize = state->mp->m_sb.sb_blocksize;
1728        state->node_ents = state->mp->m_attr_node_ents;
1729
1730        /*
1731         * Search to see if name exists, and get back a pointer to it.
1732         */
1733        error = xfs_da_node_lookup_int(state, &retval);
1734        if (error) {
1735                retval = error;
1736        } else if (retval == EEXIST) {
1737                blk = &state->path.blk[ state->path.active-1 ];
1738                ASSERT(blk->bp != NULL);
1739                ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1740
1741                /*
1742                 * Get the value, local or "remote"
1743                 */
1744                retval = xfs_attr_leaf_getvalue(blk->bp, args);
1745                if (!retval && (args->rmtblkno > 0)
1746                    && !(args->flags & ATTR_KERNOVAL)) {
1747                        retval = xfs_attr_rmtval_get(args);
1748                }
1749        }
1750
1751        /*
1752         * If not in a transaction, we have to release all the buffers.
1753         */
1754        for (i = 0; i < state->path.active; i++) {
1755                xfs_da_brelse(args->trans, state->path.blk[i].bp);
1756                state->path.blk[i].bp = NULL;
1757        }
1758
1759        xfs_da_state_free(state);
1760        return(retval);
1761}
1762
1763STATIC int                                                      /* error */
1764xfs_attr_node_list(xfs_attr_list_context_t *context)
1765{
1766        attrlist_cursor_kern_t *cursor;
1767        xfs_attr_leafblock_t *leaf;
1768        xfs_da_intnode_t *node;
1769        xfs_da_node_entry_t *btree;
1770        int error, i;
1771        xfs_dabuf_t *bp;
1772
1773        cursor = context->cursor;
1774        cursor->initted = 1;
1775
1776        /*
1777         * Do all sorts of validation on the passed-in cursor structure.
1778         * If anything is amiss, ignore the cursor and look up the hashval
1779         * starting from the btree root.
1780         */
1781        bp = NULL;
1782        if (cursor->blkno > 0) {
1783                error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
1784                                              &bp, XFS_ATTR_FORK);
1785                if ((error != 0) && (error != EFSCORRUPTED))
1786                        return(error);
1787                if (bp) {
1788                        node = bp->data;
1789                        switch (INT_GET(node->hdr.info.magic, ARCH_CONVERT)) {
1790                        case XFS_DA_NODE_MAGIC:
1791                                xfs_attr_trace_l_cn("wrong blk", context, node);
1792                                xfs_da_brelse(NULL, bp);
1793                                bp = NULL;
1794                                break;
1795                        case XFS_ATTR_LEAF_MAGIC:
1796                                leaf = bp->data;
1797                                if (cursor->hashval >
1798                                    INT_GET(leaf->entries[
1799                                         INT_GET(leaf->hdr.count,
1800                                                ARCH_CONVERT)-1].hashval,
1801                                                        ARCH_CONVERT)) {
1802                                        xfs_attr_trace_l_cl("wrong blk",
1803                                                           context, leaf);
1804                                        xfs_da_brelse(NULL, bp);
1805                                        bp = NULL;
1806                                } else if (cursor->hashval <=
1807                                             INT_GET(leaf->entries[0].hashval,
1808                                                        ARCH_CONVERT)) {
1809                                        xfs_attr_trace_l_cl("maybe wrong blk",
1810                                                           context, leaf);
1811                                        xfs_da_brelse(NULL, bp);
1812                                        bp = NULL;
1813                                }
1814                                break;
1815                        default:
1816                                xfs_attr_trace_l_c("wrong blk - ??", context);
1817                                xfs_da_brelse(NULL, bp);
1818                                bp = NULL;
1819                        }
1820                }
1821        }
1822
1823        /*
1824         * We did not find what we expected given the cursor's contents,
1825         * so we start from the top and work down based on the hash value.
1826         * Note that start of node block is same as start of leaf block.
1827         */
1828        if (bp == NULL) {
1829                cursor->blkno = 0;
1830                for (;;) {
1831                        error = xfs_da_read_buf(NULL, context->dp,
1832                                                      cursor->blkno, -1, &bp,
1833                                                      XFS_ATTR_FORK);
1834                        if (error)
1835                                return(error);
1836                        if (unlikely(bp == NULL)) {
1837                                XFS_ERROR_REPORT("xfs_attr_node_list(2)",
1838                                                 XFS_ERRLEVEL_LOW,
1839                                                 context->dp->i_mount);
1840                                return(XFS_ERROR(EFSCORRUPTED));
1841                        }
1842                        node = bp->data;
1843                        if (INT_GET(node->hdr.info.magic, ARCH_CONVERT)
1844                                                        == XFS_ATTR_LEAF_MAGIC)
1845                                break;
1846                        if (unlikely(INT_GET(node->hdr.info.magic, ARCH_CONVERT)
1847                                                        != XFS_DA_NODE_MAGIC)) {
1848                                XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)",
1849                                                     XFS_ERRLEVEL_LOW,
1850                                                     context->dp->i_mount,
1851                                                     node);
1852                                xfs_da_brelse(NULL, bp);
1853                                return(XFS_ERROR(EFSCORRUPTED));
1854                        }
1855                        btree = node->btree;
1856                        for (i = 0;
1857                                i < INT_GET(node->hdr.count, ARCH_CONVERT);
1858                                                                btree++, i++) {
1859                                if (cursor->hashval
1860                                                <= INT_GET(btree->hashval,
1861                                                            ARCH_CONVERT)) {
1862                                        cursor->blkno = INT_GET(btree->before, ARCH_CONVERT);
1863                                        xfs_attr_trace_l_cb("descending",
1864                                                            context, btree);
1865                                        break;
1866                                }
1867                        }
1868                        if (i == INT_GET(node->hdr.count, ARCH_CONVERT)) {
1869                                xfs_da_brelse(NULL, bp);
1870                                return(0);
1871                        }
1872                        xfs_da_brelse(NULL, bp);
1873                }
1874        }
1875        ASSERT(bp != NULL);
1876
1877        /*
1878         * Roll upward through the blocks, processing each leaf block in
1879         * order.  As long as there is space in the result buffer, keep
1880         * adding the information.
1881         */
1882        for (;;) {
1883                leaf = bp->data;
1884                if (unlikely(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
1885                                                != XFS_ATTR_LEAF_MAGIC)) {
1886                        XFS_CORRUPTION_ERROR("xfs_attr_node_list(4)",
1887                                             XFS_ERRLEVEL_LOW,
1888                                             context->dp->i_mount, leaf);
1889                        xfs_da_brelse(NULL, bp);
1890                        return(XFS_ERROR(EFSCORRUPTED));
1891                }
1892                error = xfs_attr_leaf_list_int(bp, context);
1893                if (error || (INT_ISZERO(leaf->hdr.info.forw, ARCH_CONVERT)))
1894                        break;  /* not really an error, buffer full or EOF */
1895                cursor->blkno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
1896                xfs_da_brelse(NULL, bp);
1897                error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
1898                                              &bp, XFS_ATTR_FORK);
1899                if (error)
1900                        return(error);
1901                if (unlikely((bp == NULL))) {
1902                        XFS_ERROR_REPORT("xfs_attr_node_list(5)",
1903                                         XFS_ERRLEVEL_LOW,
1904                                         context->dp->i_mount);
1905                        return(XFS_ERROR(EFSCORRUPTED));
1906                }
1907        }
1908        xfs_da_brelse(NULL, bp);
1909        return(0);
1910}
1911
1912
1913/*========================================================================
1914 * External routines for manipulating out-of-line attribute values.
1915 *========================================================================*/
1916
1917/*
1918 * Read the value associated with an attribute from the out-of-line buffer
1919 * that we stored it in.
1920 */
1921STATIC int
1922xfs_attr_rmtval_get(xfs_da_args_t *args)
1923{
1924        xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE];
1925        xfs_mount_t *mp;
1926        xfs_daddr_t dblkno;
1927        xfs_caddr_t dst;
1928        xfs_buf_t *bp;
1929        int nmap, error, tmp, valuelen, blkcnt, i;
1930        xfs_dablk_t lblkno;
1931
1932        ASSERT(!(args->flags & ATTR_KERNOVAL));
1933
1934        mp = args->dp->i_mount;
1935        dst = args->value;
1936        valuelen = args->valuelen;
1937        lblkno = args->rmtblkno;
1938        while (valuelen > 0) {
1939                nmap = ATTR_RMTVALUE_MAPSIZE;
1940                error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno,
1941                                  args->rmtblkcnt,
1942                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
1943                                  NULL, 0, map, &nmap, NULL);
1944                if (error)
1945                        return(error);
1946                ASSERT(nmap >= 1);
1947
1948                for (i = 0; (i < nmap) && (valuelen > 0); i++) {
1949                        ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
1950                               (map[i].br_startblock != HOLESTARTBLOCK));
1951                        dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
1952                        blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
1953                        error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno,
1954                                             blkcnt, XFS_BUF_LOCK, &bp);
1955                        if (error)
1956                                return(error);
1957
1958                        tmp = (valuelen < XFS_BUF_SIZE(bp))
1959                                ? valuelen : XFS_BUF_SIZE(bp);
1960                        xfs_biomove(bp, 0, tmp, dst, XFS_B_READ);
1961                        xfs_buf_relse(bp);
1962                        dst += tmp;
1963                        valuelen -= tmp;
1964
1965                        lblkno += map[i].br_blockcount;
1966                }
1967        }
1968        ASSERT(valuelen == 0);
1969        return(0);
1970}
1971
1972/*
1973 * Write the value associated with an attribute into the out-of-line buffer
1974 * that we have defined for it.
1975 */
1976STATIC int
1977xfs_attr_rmtval_set(xfs_da_args_t *args)
1978{
1979        xfs_mount_t *mp;
1980        xfs_fileoff_t lfileoff;
1981        xfs_inode_t *dp;
1982        xfs_bmbt_irec_t map;
1983        xfs_daddr_t dblkno;
1984        xfs_caddr_t src;
1985        xfs_buf_t *bp;
1986        xfs_dablk_t lblkno;
1987        int blkcnt, valuelen, nmap, error, tmp, committed;
1988
1989        dp = args->dp;
1990        mp = dp->i_mount;
1991        src = args->value;
1992
1993        /*
1994         * Find a "hole" in the attribute address space large enough for
1995         * us to drop the new attribute's value into.
1996         */
1997        blkcnt = XFS_B_TO_FSB(mp, args->valuelen);
1998        lfileoff = 0;
1999        error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
2000                                                   XFS_ATTR_FORK);
2001        if (error) {
2002                return(error);
2003        }
2004        args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
2005        args->rmtblkcnt = blkcnt;
2006
2007        /*
2008         * Roll through the "value", allocating blocks on disk as required.
2009         */
2010        while (blkcnt > 0) {
2011                /*
2012                 * Allocate a single extent, up to the size of the value.
2013                 */
2014                XFS_BMAP_INIT(args->flist, args->firstblock);
2015                nmap = 1;
2016                error = xfs_bmapi(args->trans, dp, (xfs_fileoff_t)lblkno,
2017                                  blkcnt,
2018                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA |
2019                                                        XFS_BMAPI_WRITE,
2020                                  args->firstblock, args->total, &map, &nmap,
2021                                  args->flist);
2022                if (!error) {
2023                        error = xfs_bmap_finish(&args->trans, args->flist,
2024                                                *args->firstblock, &committed);
2025                }
2026                if (error) {
2027                        ASSERT(committed);
2028                        args->trans = NULL;
2029                        xfs_bmap_cancel(args->flist);
2030                        return(error);
2031                }
2032
2033                /*
2034                 * bmap_finish() may have committed the last trans and started
2035                 * a new one.  We need the inode to be in all transactions.
2036                 */
2037                if (committed) {
2038                        xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
2039                        xfs_trans_ihold(args->trans, dp);
2040                }
2041
2042                ASSERT(nmap == 1);
2043                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
2044                       (map.br_startblock != HOLESTARTBLOCK));
2045                lblkno += map.br_blockcount;
2046                blkcnt -= map.br_blockcount;
2047
2048                /*
2049                 * Start the next trans in the chain.
2050                 */
2051                if ((error = xfs_attr_rolltrans(&args->trans, dp)))
2052                        return (error);
2053        }
2054
2055        /*
2056         * Roll through the "value", copying the attribute value to the
2057         * already-allocated blocks.  Blocks are written synchronously
2058         * so that we can know they are all on disk before we turn off
2059         * the INCOMPLETE flag.
2060         */
2061        lblkno = args->rmtblkno;
2062        valuelen = args->valuelen;
2063        while (valuelen > 0) {
2064                /*
2065                 * Try to remember where we decided to put the value.
2066                 */
2067                XFS_BMAP_INIT(args->flist, args->firstblock);
2068                nmap = 1;
2069                error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno,
2070                                  args->rmtblkcnt,
2071                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
2072                                  args->firstblock, 0, &map, &nmap, NULL);
2073                if (error) {
2074                        return(error);
2075                }
2076                ASSERT(nmap == 1);
2077                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
2078                       (map.br_startblock != HOLESTARTBLOCK));
2079
2080                dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
2081                blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
2082
2083                bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno,
2084                                                        blkcnt, XFS_BUF_LOCK);
2085                ASSERT(bp);
2086                ASSERT(!XFS_BUF_GETERROR(bp));
2087
2088                tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen :
2089                                                        XFS_BUF_SIZE(bp);
2090                xfs_biomove(bp, 0, tmp, src, XFS_B_WRITE);
2091                if (tmp < XFS_BUF_SIZE(bp))
2092                        xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp);
2093                if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */
2094                        return (error);
2095                }
2096                src += tmp;
2097                valuelen -= tmp;
2098
2099                lblkno += map.br_blockcount;
2100        }
2101        ASSERT(valuelen == 0);
2102        return(0);
2103}
2104
2105/*
2106 * Remove the value associated with an attribute by deleting the
2107 * out-of-line buffer that it is stored on.
2108 */
2109STATIC int
2110xfs_attr_rmtval_remove(xfs_da_args_t *args)
2111{
2112        xfs_mount_t *mp;
2113        xfs_bmbt_irec_t map;
2114        xfs_buf_t *bp;
2115        xfs_daddr_t dblkno;
2116        xfs_dablk_t lblkno;
2117        int valuelen, blkcnt, nmap, error, done, committed;
2118
2119        mp = args->dp->i_mount;
2120
2121        /*
2122         * Roll through the "value", invalidating the attribute value's
2123         * blocks.
2124         */
2125        lblkno = args->rmtblkno;
2126        valuelen = args->rmtblkcnt;
2127        while (valuelen > 0) {
2128                /*
2129                 * Try to remember where we decided to put the value.
2130                 */
2131                XFS_BMAP_INIT(args->flist, args->firstblock);
2132                nmap = 1;
2133                error = xfs_bmapi(NULL, args->dp, (xfs_fileoff_t)lblkno,
2134                                        args->rmtblkcnt,
2135                                        XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
2136                                        args->firstblock, 0, &map, &nmap,
2137                                        args->flist);
2138                if (error) {
2139                        return(error);
2140                }
2141                ASSERT(nmap == 1);
2142                ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
2143                       (map.br_startblock != HOLESTARTBLOCK));
2144
2145                dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
2146                blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
2147
2148                /*
2149                 * If the "remote" value is in the cache, remove it.
2150                 */
2151                bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt,
2152                                XFS_INCORE_TRYLOCK);
2153                if (bp) {
2154                        XFS_BUF_STALE(bp);
2155                        XFS_BUF_UNDELAYWRITE(bp);
2156                        xfs_buf_relse(bp);
2157                        bp = NULL;
2158                }
2159
2160                valuelen -= map.br_blockcount;
2161
2162                lblkno += map.br_blockcount;
2163        }
2164
2165        /*
2166         * Keep de-allocating extents until the remote-value region is gone.
2167         */
2168        lblkno = args->rmtblkno;
2169        blkcnt = args->rmtblkcnt;
2170        done = 0;
2171        while (!done) {
2172                XFS_BMAP_INIT(args->flist, args->firstblock);
2173                error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
2174                                    XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
2175                                    1, args->firstblock, args->flist, &done);
2176                if (!error) {
2177                        error = xfs_bmap_finish(&args->trans, args->flist,
2178                                                *args->firstblock, &committed);
2179                }
2180                if (error) {
2181                        ASSERT(committed);
2182                        args->trans = NULL;
2183                        xfs_bmap_cancel(args->flist);
2184                        return(error);
2185                }
2186
2187                /*
2188                 * bmap_finish() may have committed the last trans and started
2189                 * a new one.  We need the inode to be in all transactions.
2190                 */
2191                if (committed) {
2192                        xfs_trans_ijoin(args->trans, args->dp, XFS_ILOCK_EXCL);
2193                        xfs_trans_ihold(args->trans, args->dp);
2194                }
2195
2196                /*
2197                 * Close out trans and start the next one in the chain.
2198                 */
2199                if ((error = xfs_attr_rolltrans(&args->trans, args->dp)))
2200                        return (error);
2201        }
2202        return(0);
2203}
2204
2205#if defined(XFS_ATTR_TRACE)
2206/*
2207 * Add a trace buffer entry for an attr_list context structure.
2208 */
2209void
2210xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context)
2211{
2212        xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where,
2213                (__psunsigned_t)context->dp,
2214                (__psunsigned_t)context->cursor->hashval,
2215                (__psunsigned_t)context->cursor->blkno,
2216                (__psunsigned_t)context->cursor->offset,
2217                (__psunsigned_t)context->alist,
2218                (__psunsigned_t)context->bufsize,
2219                (__psunsigned_t)context->count,
2220                (__psunsigned_t)context->firstu,
2221                (__psunsigned_t)
2222                        ((context->count > 0) &&
2223                        !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2224                                ? (ATTR_ENTRY(context->alist,
2225                                              context->count-1)->a_valuelen)
2226                                : 0,
2227                (__psunsigned_t)context->dupcnt,
2228                (__psunsigned_t)context->flags,
2229                (__psunsigned_t)NULL,
2230                (__psunsigned_t)NULL,
2231                (__psunsigned_t)NULL);
2232}
2233
2234/*
2235 * Add a trace buffer entry for a context structure and a Btree node.
2236 */
2237void
2238xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context,
2239                         struct xfs_da_intnode *node)
2240{
2241        xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where,
2242                (__psunsigned_t)context->dp,
2243                (__psunsigned_t)context->cursor->hashval,
2244                (__psunsigned_t)context->cursor->blkno,
2245                (__psunsigned_t)context->cursor->offset,
2246                (__psunsigned_t)context->alist,
2247                (__psunsigned_t)context->bufsize,
2248                (__psunsigned_t)context->count,
2249                (__psunsigned_t)context->firstu,
2250                (__psunsigned_t)
2251                        ((context->count > 0) &&
2252                        !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2253                                ? (ATTR_ENTRY(context->alist,
2254                                              context->count-1)->a_valuelen)
2255                                : 0,
2256                (__psunsigned_t)context->dupcnt,
2257                (__psunsigned_t)context->flags,
2258                (__psunsigned_t)INT_GET(node->hdr.count, ARCH_CONVERT),
2259                (__psunsigned_t)INT_GET(node->btree[0].hashval, ARCH_CONVERT),
2260                (__psunsigned_t)INT_GET(node->btree[INT_GET(node->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT));
2261}
2262
2263/*
2264 * Add a trace buffer entry for a context structure and a Btree element.
2265 */
2266void
2267xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context,
2268                          struct xfs_da_node_entry *btree)
2269{
2270        xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where,
2271                (__psunsigned_t)context->dp,
2272                (__psunsigned_t)context->cursor->hashval,
2273                (__psunsigned_t)context->cursor->blkno,
2274                (__psunsigned_t)context->cursor->offset,
2275                (__psunsigned_t)context->alist,
2276                (__psunsigned_t)context->bufsize,
2277                (__psunsigned_t)context->count,
2278                (__psunsigned_t)context->firstu,
2279                (__psunsigned_t)
2280                        ((context->count > 0) &&
2281                        !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2282                                ? (ATTR_ENTRY(context->alist,
2283                                              context->count-1)->a_valuelen)
2284                                : 0,
2285                (__psunsigned_t)context->dupcnt,
2286                (__psunsigned_t)context->flags,
2287                (__psunsigned_t)INT_GET(btree->hashval, ARCH_CONVERT),
2288                (__psunsigned_t)INT_GET(btree->before, ARCH_CONVERT),
2289                (__psunsigned_t)NULL);
2290}
2291
2292/*
2293 * Add a trace buffer entry for a context structure and a leaf block.
2294 */
2295void
2296xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context,
2297                              struct xfs_attr_leafblock *leaf)
2298{
2299        xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where,
2300                (__psunsigned_t)context->dp,
2301                (__psunsigned_t)context->cursor->hashval,
2302                (__psunsigned_t)context->cursor->blkno,
2303                (__psunsigned_t)context->cursor->offset,
2304                (__psunsigned_t)context->alist,
2305                (__psunsigned_t)context->bufsize,
2306                (__psunsigned_t)context->count,
2307                (__psunsigned_t)context->firstu,
2308                (__psunsigned_t)
2309                        ((context->count > 0) &&
2310                        !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
2311                                ? (ATTR_ENTRY(context->alist,
2312                                              context->count-1)->a_valuelen)
2313                                : 0,
2314                (__psunsigned_t)context->dupcnt,
2315                (__psunsigned_t)context->flags,
2316                (__psunsigned_t)INT_GET(leaf->hdr.count, ARCH_CONVERT),
2317                (__psunsigned_t)INT_GET(leaf->entries[0].hashval, ARCH_CONVERT),
2318                (__psunsigned_t)INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT));
2319}
2320
2321/*
2322 * Add a trace buffer entry for the arguments given to the routine,
2323 * generic form.
2324 */
2325void
2326xfs_attr_trace_enter(int type, char *where,
2327                         __psunsigned_t a2, __psunsigned_t a3,
2328                         __psunsigned_t a4, __psunsigned_t a5,
2329                         __psunsigned_t a6, __psunsigned_t a7,
2330                         __psunsigned_t a8, __psunsigned_t a9,
2331                         __psunsigned_t a10, __psunsigned_t a11,
2332                         __psunsigned_t a12, __psunsigned_t a13,
2333                         __psunsigned_t a14, __psunsigned_t a15)
2334{
2335        ASSERT(xfs_attr_trace_buf);
2336        ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type),
2337                                         (void *)where,
2338                                         (void *)a2,  (void *)a3,  (void *)a4,
2339                                         (void *)a5,  (void *)a6,  (void *)a7,
2340                                         (void *)a8,  (void *)a9,  (void *)a10,
2341                                         (void *)a11, (void *)a12, (void *)a13,
2342                                         (void *)a14, (void *)a15);
2343}
2344#endif  /* XFS_ATTR_TRACE */
2345
2346
2347/*========================================================================
2348 * System (pseudo) namespace attribute interface routines.
2349 *========================================================================*/
2350
2351STATIC int
2352posix_acl_access_set(
2353        vnode_t *vp, char *name, void *data, size_t size, int xflags)
2354{
2355        return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
2356}
2357
2358STATIC int
2359posix_acl_access_remove(
2360        struct vnode *vp, char *name, int xflags)
2361{
2362        return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
2363}
2364
2365STATIC int
2366posix_acl_access_get(
2367        vnode_t *vp, char *name, void *data, size_t size, int xflags)
2368{
2369        return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
2370}
2371
2372STATIC int
2373posix_acl_access_exists(
2374        vnode_t *vp)
2375{
2376        return xfs_acl_vhasacl_access(vp);
2377}
2378
2379STATIC int
2380posix_acl_default_set(
2381        vnode_t *vp, char *name, void *data, size_t size, int xflags)
2382{
2383        return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
2384}
2385
2386STATIC int
2387posix_acl_default_get(
2388        vnode_t *vp, char *name, void *data, size_t size, int xflags)
2389{
2390        return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
2391}
2392
2393STATIC int
2394posix_acl_default_remove(
2395        struct vnode *vp, char *name, int xflags)
2396{
2397        return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT);
2398}
2399
2400STATIC int
2401posix_acl_default_exists(
2402        vnode_t *vp)
2403{
2404        return xfs_acl_vhasacl_default(vp);
2405}
2406
2407struct attrnames posix_acl_access = {
2408        .attr_name      = "posix_acl_access",
2409        .attr_namelen   = sizeof("posix_acl_access") - 1,
2410        .attr_get       = posix_acl_access_get,
2411        .attr_set       = posix_acl_access_set,
2412        .attr_remove    = posix_acl_access_remove,
2413        .attr_exists    = posix_acl_access_exists,
2414};
2415
2416struct attrnames posix_acl_default = {
2417        .attr_name      = "posix_acl_default",
2418        .attr_namelen   = sizeof("posix_acl_default") - 1,
2419        .attr_get       = posix_acl_default_get,
2420        .attr_set       = posix_acl_default_set,
2421        .attr_remove    = posix_acl_default_remove,
2422        .attr_exists    = posix_acl_default_exists,
2423};
2424
2425struct attrnames *attr_system_names[] =
2426        { &posix_acl_access, &posix_acl_default };
2427
2428
2429/*========================================================================
2430 * Namespace-prefix-style attribute name interface routines.
2431 *========================================================================*/
2432
2433STATIC int
2434attr_generic_set(
2435        struct vnode *vp, char *name, void *data, size_t size, int xflags)
2436{
2437        int     error;
2438
2439        VOP_ATTR_SET(vp, name, data, size, xflags, NULL, error);
2440        return -error;
2441}
2442
2443STATIC int
2444attr_generic_get(
2445        struct vnode *vp, char *name, void *data, size_t size, int xflags)
2446{
2447        int     error, asize = size;
2448
2449        VOP_ATTR_GET(vp, name, data, &asize, xflags, NULL, error);
2450        if (!error)
2451                return asize;
2452        return -error;
2453}
2454
2455STATIC int
2456attr_generic_remove(
2457        struct vnode *vp, char *name, int xflags)
2458{
2459        int     error;
2460
2461        VOP_ATTR_REMOVE(vp, name, xflags, NULL, error);
2462        return -error;
2463}
2464
2465STATIC int
2466attr_generic_listadd(
2467        attrnames_t             *prefix,
2468        attrnames_t             *namesp,
2469        void                    *data,
2470        size_t                  size,
2471        ssize_t                 *result)
2472{
2473        char                    *p = data + *result;
2474
2475        *result += prefix->attr_namelen;
2476        *result += namesp->attr_namelen + 1;
2477        if (!size)
2478                return 0;
2479        if (*result > size)
2480                return -ERANGE;
2481        strcpy(p, prefix->attr_name);
2482        p += prefix->attr_namelen;
2483        strcpy(p, namesp->attr_name);
2484        p += namesp->attr_namelen + 1;
2485        return 0;
2486}
2487
2488STATIC int
2489attr_system_list(
2490        struct vnode            *vp,
2491        void                    *data,
2492        size_t                  size,
2493        ssize_t                 *result)
2494{
2495        attrnames_t             *namesp;
2496        int                     i, error = 0;
2497
2498        for (i = 0; i < ATTR_SYSCOUNT; i++) {
2499                namesp = attr_system_names[i];
2500                if (!namesp->attr_exists || !namesp->attr_exists(vp))
2501                        continue;
2502                error = attr_generic_listadd(&attr_system, namesp,
2503                                                data, size, result);
2504                if (error)
2505                        break;
2506        }
2507        return error;
2508}
2509
2510int
2511attr_generic_list(
2512        struct vnode *vp, void *data, size_t size, int xflags, ssize_t *result)
2513{
2514        attrlist_cursor_kern_t  cursor = { 0 };
2515        int                     error;
2516
2517        VOP_ATTR_LIST(vp, data, size, xflags, &cursor, NULL, error);
2518        if (error > 0)
2519                return -error;
2520        *result = -error;
2521        return attr_system_list(vp, data, size, result);
2522}
2523
2524attrnames_t *
2525attr_lookup_namespace(
2526        char                    *name,
2527        struct attrnames        **names,
2528        int                     nnames)
2529{
2530        int                     i;
2531
2532        for (i = 0; i < nnames; i++)
2533                if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen))
2534                        return names[i];
2535        return NULL;
2536}
2537
2538/*
2539 * Some checks to prevent people abusing EAs to get over quota:
2540 * - Don't allow modifying user EAs on devices/symlinks;
2541 * - Don't allow modifying user EAs if sticky bit set;
2542 */
2543STATIC int
2544attr_user_capable(
2545        struct vnode    *vp,
2546        cred_t          *cred)
2547{
2548        struct inode    *inode = LINVFS_GET_IP(vp);
2549
2550        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
2551                return -EPERM;
2552        if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) &&
2553            !capable(CAP_SYS_ADMIN))
2554                return -EPERM;
2555        if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
2556            (current_fsuid(cred) != inode->i_uid) && !capable(CAP_FOWNER))
2557                return -EPERM;
2558        return 0;
2559}
2560
2561STATIC int
2562attr_trusted_capable(
2563        struct vnode    *vp,
2564        cred_t          *cred)
2565{
2566        struct inode    *inode = LINVFS_GET_IP(vp);
2567
2568        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
2569                return -EPERM;
2570        if (!capable(CAP_SYS_ADMIN))
2571                return -EPERM;
2572        return 0;
2573}
2574
2575STATIC int
2576attr_secure_capable(
2577        struct vnode    *vp,
2578        cred_t          *cred)
2579{
2580        return -ENOSECURITY;
2581}
2582
2583STATIC int
2584attr_system_set(
2585        struct vnode *vp, char *name, void *data, size_t size, int xflags)
2586{
2587        attrnames_t     *namesp;
2588        int             error;
2589
2590        if (xflags & ATTR_CREATE)
2591                return -EINVAL;
2592
2593        namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
2594        if (!namesp)
2595                return -EOPNOTSUPP;
2596        error = namesp->attr_set(vp, name, data, size, xflags);
2597        if (!error)
2598                error = vn_revalidate(vp);
2599        return error;
2600}
2601
2602STATIC int
2603attr_system_get(
2604        struct vnode *vp, char *name, void *data, size_t size, int xflags)
2605{
2606        attrnames_t     *namesp;
2607
2608        namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
2609        if (!namesp)
2610                return -EOPNOTSUPP;
2611        return namesp->attr_get(vp, name, data, size, xflags);
2612}
2613
2614STATIC int
2615attr_system_remove(
2616        struct vnode *vp, char *name, int xflags)
2617{
2618        attrnames_t     *namesp;
2619
2620        namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
2621        if (!namesp)
2622                return -EOPNOTSUPP;
2623        return namesp->attr_remove(vp, name, xflags);
2624}
2625
2626struct attrnames attr_system = {
2627        .attr_name      = "system.",
2628        .attr_namelen   = sizeof("system.") - 1,
2629        .attr_flag      = ATTR_SYSTEM,
2630        .attr_get       = attr_system_get,
2631        .attr_set       = attr_system_set,
2632        .attr_remove    = attr_system_remove,
2633        .attr_capable   = (attrcapable_t)fs_noerr,
2634};
2635
2636struct attrnames attr_trusted = {
2637        .attr_name      = "trusted.",
2638        .attr_namelen   = sizeof("trusted.") - 1,
2639        .attr_flag      = ATTR_ROOT,
2640        .attr_get       = attr_generic_get,
2641        .attr_set       = attr_generic_set,
2642        .attr_remove    = attr_generic_remove,
2643        .attr_capable   = attr_trusted_capable,
2644};
2645
2646struct attrnames attr_secure = {
2647        .attr_name      = "security.",
2648        .attr_namelen   = sizeof("security.") - 1,
2649        .attr_flag      = ATTR_SECURE,
2650        .attr_get       = attr_generic_get,
2651        .attr_set       = attr_generic_set,
2652        .attr_remove    = attr_generic_remove,
2653        .attr_capable   = attr_secure_capable,
2654};
2655
2656struct attrnames attr_user = {
2657        .attr_name      = "user.",
2658        .attr_namelen   = sizeof("user.") - 1,
2659        .attr_get       = attr_generic_get,
2660        .attr_set       = attr_generic_set,
2661        .attr_remove    = attr_generic_remove,
2662        .attr_capable   = attr_user_capable,
2663};
2664
2665struct attrnames *attr_namespaces[] =
2666        { &attr_system, &attr_trusted, &attr_secure, &attr_user };
2667
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.