xfs_attr.c revision 180208
1169689Skan/* 2169689Skan * Copyright (c) 2000-2005 Silicon Graphics, Inc. 390075Sobrien * All Rights Reserved. 4132718Skan * 590075Sobrien * This program is free software; you can redistribute it and/or 6132718Skan * modify it under the terms of the GNU General Public License as 790075Sobrien * published by the Free Software Foundation. 890075Sobrien * 990075Sobrien * This program is distributed in the hope that it would be useful, 1090075Sobrien * but WITHOUT ANY WARRANTY; without even the implied warranty of 11132718Skan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1290075Sobrien * GNU General Public License for more details. 1390075Sobrien * 1490075Sobrien * You should have received a copy of the GNU General Public License 1590075Sobrien * along with this program; if not, write the Free Software Foundation, 1690075Sobrien * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17132718Skan */ 18169689Skan 19169689Skan//#include <linux/capability.h> 2090075Sobrien 2190075Sobrien#include "xfs.h" 2290075Sobrien#include "xfs_fs.h" 2390075Sobrien#include "xfs_types.h" 2490075Sobrien#include "xfs_bit.h" 2590075Sobrien#include "xfs_log.h" 2690075Sobrien#include "xfs_inum.h" 2790075Sobrien#include "xfs_trans.h" 2890075Sobrien#include "xfs_sb.h" 29169689Skan#include "xfs_ag.h" 3090075Sobrien#include "xfs_dir.h" 3190075Sobrien#include "xfs_dir2.h" 3290075Sobrien#include "xfs_dmapi.h" 3390075Sobrien#include "xfs_mount.h" 34117395Skan#include "xfs_da_btree.h" 35117395Skan#include "xfs_bmap_btree.h" 36117395Skan#include "xfs_alloc_btree.h" 37117395Skan#include "xfs_ialloc_btree.h" 3890075Sobrien#include "xfs_dir_sf.h" 3990075Sobrien#include "xfs_dir2_sf.h" 4090075Sobrien#include "xfs_attr_sf.h" 41169689Skan#include "xfs_dinode.h" 42242182Skan#include "xfs_inode.h" 43169689Skan#include "xfs_alloc.h" 44242182Skan#include "xfs_btree.h" 4590075Sobrien#include "xfs_inode_item.h" 46169689Skan#include "xfs_bmap.h" 47169689Skan#include "xfs_attr.h" 48169689Skan#include "xfs_attr_leaf.h" 49169689Skan#include "xfs_error.h" 50132718Skan#include "xfs_quota.h" 51169689Skan#include "xfs_trans_space.h" 5290075Sobrien#include "xfs_acl.h" 5390075Sobrien#include "xfs_rw.h" 5490075Sobrien 5590075Sobrien/* 5690075Sobrien * xfs_attr.c 5790075Sobrien * 5890075Sobrien * Provide the external interfaces to manage attribute lists. 5990075Sobrien */ 6090075Sobrien 6190075Sobrien#define ATTR_SYSCOUNT 2 6290075SobrienSTATIC struct attrnames posix_acl_access; 6390075SobrienSTATIC struct attrnames posix_acl_default; 6490075SobrienSTATIC struct attrnames *attr_system_names[ATTR_SYSCOUNT]; 6590075Sobrien 6690075Sobrien/*======================================================================== 6790075Sobrien * Function prototypes for the kernel. 6890075Sobrien *========================================================================*/ 6990075Sobrien 7090075Sobrien/* 7190075Sobrien * Internal routines when attribute list fits inside the inode. 7290075Sobrien */ 7390075SobrienSTATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); 7490075Sobrien 7590075Sobrien/* 7690075Sobrien * Internal routines when attribute list is one block. 7790075Sobrien */ 7890075SobrienSTATIC int xfs_attr_leaf_get(xfs_da_args_t *args); 7990075SobrienSTATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); 8090075SobrienSTATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); 8190075SobrienSTATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context); 8290075Sobrien 8390075Sobrien/* 8490075Sobrien * Internal routines when attribute list is more than one block. 8590075Sobrien */ 8690075SobrienSTATIC int xfs_attr_node_get(xfs_da_args_t *args); 8790075SobrienSTATIC int xfs_attr_node_addname(xfs_da_args_t *args); 8890075SobrienSTATIC int xfs_attr_node_removename(xfs_da_args_t *args); 8990075SobrienSTATIC int xfs_attr_node_list(xfs_attr_list_context_t *context); 9090075SobrienSTATIC int xfs_attr_fillstate(xfs_da_state_t *state); 9190075SobrienSTATIC int xfs_attr_refillstate(xfs_da_state_t *state); 9290075Sobrien 93169689Skan/* 94169689Skan * Routines to manipulate out-of-line attribute values. 95169689Skan */ 96169689SkanSTATIC int xfs_attr_rmtval_get(xfs_da_args_t *args); 97169689SkanSTATIC int xfs_attr_rmtval_set(xfs_da_args_t *args); 98169689SkanSTATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); 99169689Skan 10090075Sobrien#define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ 10190075Sobrien 10290075Sobrien#if defined(XFS_ATTR_TRACE) 10390075Sobrienktrace_t *xfs_attr_trace_buf; 104169689Skan#endif 10590075Sobrien 10690075Sobrien 10790075Sobrien/*======================================================================== 10890075Sobrien * Overall external interface routines. 10990075Sobrien *========================================================================*/ 110169689Skan 11190075Sobrienint 11290075Sobrienxfs_attr_fetch(xfs_inode_t *ip, const char *name, int namelen, 11390075Sobrien char *value, int *valuelenp, int flags, struct cred *cred) 11490075Sobrien{ 11590075Sobrien xfs_da_args_t args; 116169689Skan int error; 11790075Sobrien 11890075Sobrien if ((XFS_IFORK_Q(ip) == 0) || 11990075Sobrien (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 12090075Sobrien ip->i_d.di_anextents == 0)) 12190075Sobrien return(ENOATTR); 122169689Skan 12390075Sobrien /* 12490075Sobrien * Fill in the arg structure for this request. 12590075Sobrien */ 12690075Sobrien memset((char *)&args, 0, sizeof(args)); 12790075Sobrien args.name = name; 128169689Skan args.namelen = namelen; 12990075Sobrien args.value = value; 13090075Sobrien args.valuelen = *valuelenp; 13190075Sobrien args.flags = flags; 13290075Sobrien args.hashval = xfs_da_hashname(args.name, args.namelen); 13390075Sobrien args.dp = ip; 134169689Skan args.whichfork = XFS_ATTR_FORK; 13590075Sobrien 13690075Sobrien /* 13790075Sobrien * Decide on what work routines to call based on the inode size. 13890075Sobrien */ 13990075Sobrien if (XFS_IFORK_Q(ip) == 0 || 140169689Skan (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 14190075Sobrien ip->i_d.di_anextents == 0)) { 14290075Sobrien error = XFS_ERROR(ENOATTR); 14390075Sobrien } else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { 14490075Sobrien error = xfs_attr_shortform_getvalue(&args); 14590075Sobrien } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) { 146169689Skan error = xfs_attr_leaf_get(&args); 14790075Sobrien } else { 14890075Sobrien error = xfs_attr_node_get(&args); 14990075Sobrien } 15090075Sobrien 15190075Sobrien /* 152169689Skan * Return the number of bytes in the value to the caller. 15390075Sobrien */ 15490075Sobrien *valuelenp = args.valuelen; 15590075Sobrien 15690075Sobrien if (error == EEXIST) 15790075Sobrien error = 0; 15890075Sobrien return(error); 15990075Sobrien} 160169689Skan 16190075Sobrienint 16290075Sobrienxfs_attr_get(bhv_desc_t *bdp, const char *name, char *value, int *valuelenp, 16390075Sobrien int flags, struct cred *cred) 16490075Sobrien{ 16590075Sobrien xfs_inode_t *ip = XFS_BHVTOI(bdp); 166169689Skan int error, namelen; 16790075Sobrien 16890075Sobrien XFS_STATS_INC(xs_attr_get); 16990075Sobrien 17090075Sobrien if (!name) 17190075Sobrien return(EINVAL); 172169689Skan namelen = strlen(name); 17390075Sobrien if (namelen >= MAXNAMELEN) 17490075Sobrien return(EFAULT); /* match IRIX behaviour */ 17590075Sobrien 17690075Sobrien if (XFS_FORCED_SHUTDOWN(ip->i_mount)) 17790075Sobrien return(EIO); 178169689Skan 17990075Sobrien xfs_ilock(ip, XFS_ILOCK_SHARED); 18090075Sobrien error = xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, cred); 18190075Sobrien xfs_iunlock(ip, XFS_ILOCK_SHARED); 18290075Sobrien return(error); 18390075Sobrien} 184169689Skan 18590075SobrienSTATIC int 18690075Sobrienxfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, 18790075Sobrien char *value, int valuelen, int flags) 18890075Sobrien{ 18990075Sobrien xfs_da_args_t args; 190169689Skan xfs_fsblock_t firstblock; 19190075Sobrien xfs_bmap_free_t flist; 19290075Sobrien int error, err2, committed; 19390075Sobrien int local, size; 19490075Sobrien uint nblks; 19590075Sobrien xfs_mount_t *mp = dp->i_mount; 196169689Skan int rsvd = (flags & ATTR_ROOT) != 0; 19790075Sobrien 19890075Sobrien /* 19990075Sobrien * Attach the dquots to the inode. 20090075Sobrien */ 20190075Sobrien if ((error = XFS_QM_DQATTACH(mp, dp, 0))) 202169689Skan return (error); 20390075Sobrien 20490075Sobrien /* 20590075Sobrien * Determine space new attribute will use, and if it would be 20690075Sobrien * "local" or "remote" (note: local != inline). 20790075Sobrien */ 208169689Skan size = xfs_attr_leaf_newentsize(namelen, valuelen, 20990075Sobrien mp->m_sb.sb_blocksize, &local); 21090075Sobrien 21190075Sobrien /* 21290075Sobrien * If the inode doesn't have an attribute fork, add one. 21390075Sobrien * (inode must not be locked when we call this routine) 21490075Sobrien */ 21590075Sobrien if (XFS_IFORK_Q(dp) == 0) { 216169689Skan if ((error = xfs_bmap_add_attrfork(dp, size, rsvd))) 21790075Sobrien return(error); 21890075Sobrien } 21990075Sobrien 22090075Sobrien /* 22190075Sobrien * Fill in the arg structure for this request. 222169689Skan */ 22390075Sobrien memset((char *)&args, 0, sizeof(args)); 22490075Sobrien args.name = name; 22590075Sobrien args.namelen = namelen; 22690075Sobrien args.value = value; 22790075Sobrien args.valuelen = valuelen; 228169689Skan args.flags = flags; 22990075Sobrien args.hashval = xfs_da_hashname(args.name, args.namelen); 23090075Sobrien args.dp = dp; 23190075Sobrien args.firstblock = &firstblock; 23290075Sobrien args.flist = &flist; 23390075Sobrien args.whichfork = XFS_ATTR_FORK; 234169689Skan args.addname = 1; 23590075Sobrien args.oknoent = 1; 23690075Sobrien 23790075Sobrien nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); 23890075Sobrien if (local) { 23990075Sobrien if (size > (mp->m_sb.sb_blocksize >> 1)) { 24090075Sobrien /* Double split possible */ 24190075Sobrien nblks <<= 1; 24290075Sobrien } 24390075Sobrien } else { 244169689Skan uint dblocks = XFS_B_TO_FSB(mp, valuelen); 24590075Sobrien /* Out of line attribute, cannot double split, but make 24690075Sobrien * room for the attribute value itself. 24790075Sobrien */ 24890075Sobrien nblks += dblocks; 24990075Sobrien nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); 250169689Skan } 25190075Sobrien 25290075Sobrien /* Size is now blocks for attribute data */ 25390075Sobrien args.total = nblks; 25490075Sobrien 25590075Sobrien /* 256169689Skan * Start our first transaction of the day. 25790075Sobrien * 25890075Sobrien * All future transactions during this code must be "chained" off 25990075Sobrien * this one via the trans_dup() call. All transactions will contain 26090075Sobrien * the inode, and the inode will always be marked with trans_ihold(). 26190075Sobrien * Since the inode will be locked in all transactions, we must log 262169689Skan * the inode in every transaction to let it float upward through 26390075Sobrien * the log. 26490075Sobrien */ 265107590Sobrien args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET); 266107590Sobrien 267107590Sobrien /* 268107590Sobrien * Root fork attributes can use reserved data blocks for this 269107590Sobrien * operation if necessary 27090075Sobrien */ 27190075Sobrien 272169689Skan if (rsvd) 27390075Sobrien args.trans->t_flags |= XFS_TRANS_RESERVE; 27490075Sobrien 275107590Sobrien if ((error = xfs_trans_reserve(args.trans, (uint) nblks, 276107590Sobrien XFS_ATTRSET_LOG_RES(mp, nblks), 277107590Sobrien 0, XFS_TRANS_PERM_LOG_RES, 278107590Sobrien XFS_ATTRSET_LOG_COUNT))) { 279107590Sobrien xfs_trans_cancel(args.trans, 0); 28090075Sobrien return(error); 28190075Sobrien } 282169689Skan xfs_ilock(dp, XFS_ILOCK_EXCL); 28390075Sobrien 28490075Sobrien error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0, 28590075Sobrien rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : 28690075Sobrien XFS_QMOPT_RES_REGBLKS); 28790075Sobrien if (error) { 288169689Skan xfs_iunlock(dp, XFS_ILOCK_EXCL); 28990075Sobrien xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); 29090075Sobrien return (error); 29190075Sobrien } 29290075Sobrien 29390075Sobrien xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); 294169689Skan xfs_trans_ihold(args.trans, dp); 29590075Sobrien 29690075Sobrien /* 29790075Sobrien * If the attribute list is non-existent or a shortform list, 29890075Sobrien * upgrade it to a single-leaf-block attribute list. 29990075Sobrien */ 300169689Skan if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || 30190075Sobrien ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) && 30290075Sobrien (dp->i_d.di_anextents == 0))) { 303107590Sobrien 304107590Sobrien /* 305107590Sobrien * Build initial attribute list (if required). 306107590Sobrien */ 307107590Sobrien if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) 30890075Sobrien xfs_attr_shortform_create(&args); 30990075Sobrien 310169689Skan /* 31190075Sobrien * Try to add the attr to the attribute list in 31290075Sobrien * the inode. 313107590Sobrien */ 314107590Sobrien error = xfs_attr_shortform_addname(&args); 315107590Sobrien if (error != ENOSPC) { 316107590Sobrien /* 317107590Sobrien * Commit the shortform mods, and we're done. 31890075Sobrien * NOTE: this is also the error path (EEXIST, etc). 31990075Sobrien */ 320169689Skan ASSERT(args.trans != NULL); 32190075Sobrien 32290075Sobrien /* 32390075Sobrien * If this is a synchronous mount, make sure that 32490075Sobrien * the transaction goes to disk before returning 32590075Sobrien * to the user. 326169689Skan */ 32790075Sobrien if (mp->m_flags & XFS_MOUNT_WSYNC) { 32890075Sobrien xfs_trans_set_sync(args.trans); 32990075Sobrien } 33090075Sobrien err2 = xfs_trans_commit(args.trans, 33190075Sobrien XFS_TRANS_RELEASE_LOG_RES, 33290075Sobrien NULL); 33390075Sobrien xfs_iunlock(dp, XFS_ILOCK_EXCL); 33490075Sobrien 33590075Sobrien /* 336169689Skan * Hit the inode change time. 33790075Sobrien */ 33890075Sobrien if (!error && (flags & ATTR_KERNOTIME) == 0) { 33990075Sobrien xfs_ichgtime(dp, XFS_ICHGTIME_CHG); 34090075Sobrien } 34190075Sobrien return(error == 0 ? err2 : error); 342169689Skan } 34390075Sobrien 34490075Sobrien /* 34590075Sobrien * It won't fit in the shortform, transform to a leaf block. 34690075Sobrien * GROT: another possible req'mt for a double-split btree op. 34790075Sobrien */ 348169689Skan XFS_BMAP_INIT(args.flist, args.firstblock); 34990075Sobrien error = xfs_attr_shortform_to_leaf(&args); 35090075Sobrien if (!error) { 35190075Sobrien error = xfs_bmap_finish(&args.trans, args.flist, 35290075Sobrien *args.firstblock, &committed); 35390075Sobrien } 354169689Skan if (error) { 35590075Sobrien ASSERT(committed); 35690075Sobrien args.trans = NULL; 35790075Sobrien xfs_bmap_cancel(&flist); 35890075Sobrien goto out; 35990075Sobrien } 360169689Skan 36190075Sobrien /* 36290075Sobrien * bmap_finish() may have committed the last trans and started 36390075Sobrien * a new one. We need the inode to be in all transactions. 36490075Sobrien */ 36590075Sobrien if (committed) { 366169689Skan xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); 36790075Sobrien xfs_trans_ihold(args.trans, dp); 36890075Sobrien } 36990075Sobrien 37090075Sobrien /* 37190075Sobrien * Commit the leaf transformation. We'll need another (linked) 372169689Skan * transaction to add the new attribute to the leaf. 37390075Sobrien */ 37490075Sobrien if ((error = xfs_attr_rolltrans(&args.trans, dp))) 37590075Sobrien goto out; 37690075Sobrien 37790075Sobrien } 378169689Skan 37990075Sobrien if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { 38090075Sobrien error = xfs_attr_leaf_addname(&args); 38190075Sobrien } else { 38290075Sobrien error = xfs_attr_node_addname(&args); 38390075Sobrien } 384169689Skan if (error) { 38590075Sobrien goto out; 38690075Sobrien } 38790075Sobrien 38890075Sobrien /* 38990075Sobrien * If this is a synchronous mount, make sure that the 390169689Skan * transaction goes to disk before returning to the user. 39190075Sobrien */ 39290075Sobrien if (mp->m_flags & XFS_MOUNT_WSYNC) { 39390075Sobrien xfs_trans_set_sync(args.trans); 39490075Sobrien } 39590075Sobrien 396169689Skan /* 39790075Sobrien * Commit the last in the sequence of transactions. 39890075Sobrien */ 39990075Sobrien xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); 40090075Sobrien error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES, 40190075Sobrien NULL); 402169689Skan xfs_iunlock(dp, XFS_ILOCK_EXCL); 40390075Sobrien 40490075Sobrien /* 40590075Sobrien * Hit the inode change time. 40690075Sobrien */ 40790075Sobrien if (!error && (flags & ATTR_KERNOTIME) == 0) { 40890075Sobrien xfs_ichgtime(dp, XFS_ICHGTIME_CHG); 40990075Sobrien } 41090075Sobrien 411169689Skan return(error); 41290075Sobrien 41390075Sobrienout: 41490075Sobrien if (args.trans) 41590075Sobrien xfs_trans_cancel(args.trans, 41690075Sobrien XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); 417169689Skan xfs_iunlock(dp, XFS_ILOCK_EXCL); 41890075Sobrien return(error); 41990075Sobrien} 42090075Sobrien 42190075Sobrienint 42290075Sobrienxfs_attr_set(bhv_desc_t *bdp, const char *name, char *value, int valuelen, int flags, 423169689Skan struct cred *cred) 42490075Sobrien{ 42590075Sobrien xfs_inode_t *dp; 42690075Sobrien int namelen; 42790075Sobrien 42890075Sobrien namelen = strlen(name); 429169689Skan if (namelen >= MAXNAMELEN) 43090075Sobrien return EFAULT; /* match IRIX behaviour */ 43190075Sobrien 43290075Sobrien XFS_STATS_INC(xs_attr_set); 43390075Sobrien 43490075Sobrien dp = XFS_BHVTOI(bdp); 435169689Skan if (XFS_FORCED_SHUTDOWN(dp->i_mount)) 43690075Sobrien return (EIO); 43790075Sobrien 43890075Sobrien return xfs_attr_set_int(dp, name, namelen, value, valuelen, flags); 43990075Sobrien} 44090075Sobrien 441169689Skan/* 44290075Sobrien * Generic handler routine to remove a name from an attribute list. 44390075Sobrien * Transitions attribute list from Btree to shortform as necessary. 44490075Sobrien */ 44590075SobrienSTATIC int 44690075Sobrienxfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags) 447169689Skan{ 44890075Sobrien xfs_da_args_t args; 44990075Sobrien xfs_fsblock_t firstblock; 45090075Sobrien xfs_bmap_free_t flist; 45190075Sobrien int error; 45290075Sobrien xfs_mount_t *mp = dp->i_mount; 453169689Skan 45490075Sobrien /* 45590075Sobrien * Fill in the arg structure for this request. 45690075Sobrien */ 45790075Sobrien memset((char *)&args, 0, sizeof(args)); 45890075Sobrien args.name = name; 459169689Skan args.namelen = namelen; 46090075Sobrien args.flags = flags; 46190075Sobrien args.hashval = xfs_da_hashname(args.name, args.namelen); 46290075Sobrien args.dp = dp; 46390075Sobrien args.firstblock = &firstblock; 46490075Sobrien args.flist = &flist; 465169689Skan args.total = 0; 46690075Sobrien args.whichfork = XFS_ATTR_FORK; 46790075Sobrien 46890075Sobrien /* 46990075Sobrien * Attach the dquots to the inode. 47090075Sobrien */ 471169689Skan if ((error = XFS_QM_DQATTACH(mp, dp, 0))) 47290075Sobrien return (error); 47390075Sobrien 47490075Sobrien /* 47590075Sobrien * Start our first transaction of the day. 47690075Sobrien * 477169689Skan * All future transactions during this code must be "chained" off 47890075Sobrien * this one via the trans_dup() call. All transactions will contain 47990075Sobrien * the inode, and the inode will always be marked with trans_ihold(). 48090075Sobrien * Since the inode will be locked in all transactions, we must log 48190075Sobrien * the inode in every transaction to let it float upward through 48290075Sobrien * the log. 48390075Sobrien */ 48490075Sobrien args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM); 485169689Skan 48690075Sobrien /* 48790075Sobrien * Root fork attributes can use reserved data blocks for this 48890075Sobrien * operation if necessary 48990075Sobrien */ 49090075Sobrien 491169689Skan if (flags & ATTR_ROOT) 492122180Skan args.trans->t_flags |= XFS_TRANS_RESERVE; 493122180Skan 494122180Skan if ((error = xfs_trans_reserve(args.trans, 495122180Skan XFS_ATTRRM_SPACE_RES(mp), 496122180Skan XFS_ATTRRM_LOG_RES(mp), 497117395Skan 0, XFS_TRANS_PERM_LOG_RES, 498169689Skan XFS_ATTRRM_LOG_COUNT))) { 499169689Skan xfs_trans_cancel(args.trans, 0); 500169689Skan return(error); 501169689Skan } 502169689Skan 503169689Skan xfs_ilock(dp, XFS_ILOCK_EXCL); 504169689Skan /* 505169689Skan * No need to make quota reservations here. We expect to release some 506169689Skan * blocks not allocate in the common case. 507169689Skan */ 508169689Skan xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); 509169689Skan xfs_trans_ihold(args.trans, dp); 510117395Skan 511117395Skan /* 512117395Skan * Decide on what work routines to call based on the inode size. 513117395Skan */ 514117395Skan if (XFS_IFORK_Q(dp) == 0 || 515117395Skan (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 51690075Sobrien dp->i_d.di_anextents == 0)) { 51790075Sobrien error = XFS_ERROR(ENOATTR); 518169689Skan goto out; 51990075Sobrien } 52090075Sobrien if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { 52190075Sobrien ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); 52290075Sobrien error = xfs_attr_shortform_remove(&args); 52390075Sobrien if (error) { 524169689Skan goto out; 525122180Skan } 526122180Skan } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { 527122180Skan error = xfs_attr_leaf_removename(&args); 528122180Skan } else { 529122180Skan error = xfs_attr_node_removename(&args); 53090075Sobrien } 531169689Skan if (error) { 53290075Sobrien goto out; 53390075Sobrien } 53490075Sobrien 53590075Sobrien /* 53690075Sobrien * If this is a synchronous mount, make sure that the 537169689Skan * transaction goes to disk before returning to the user. 538122180Skan */ 539122180Skan if (mp->m_flags & XFS_MOUNT_WSYNC) { 540122180Skan xfs_trans_set_sync(args.trans); 541122180Skan } 542122180Skan 543117395Skan /* 544117395Skan * Commit the last in the sequence of transactions. 545169689Skan */ 546169689Skan xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); 547169689Skan error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES, 548169689Skan NULL); 549169689Skan xfs_iunlock(dp, XFS_ILOCK_EXCL); 550169689Skan 551169689Skan /* 552169689Skan * Hit the inode change time. 553169689Skan */ 554169689Skan if (!error && (flags & ATTR_KERNOTIME) == 0) { 555117395Skan xfs_ichgtime(dp, XFS_ICHGTIME_CHG); 556117395Skan } 557117395Skan 558117395Skan return(error); 559117395Skan 560117395Skanout: 56190075Sobrien if (args.trans) 56290075Sobrien xfs_trans_cancel(args.trans, 563169689Skan XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); 56490075Sobrien xfs_iunlock(dp, XFS_ILOCK_EXCL); 56590075Sobrien return(error); 56690075Sobrien} 56790075Sobrien 56890075Sobrienint 569169689Skanxfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred) 570122180Skan{ 571122180Skan xfs_inode_t *dp; 572122180Skan int namelen; 573122180Skan 574122180Skan namelen = strlen(name); 57590075Sobrien if (namelen >= MAXNAMELEN) 576169689Skan return EFAULT; /* match IRIX behaviour */ 57790075Sobrien 57890075Sobrien XFS_STATS_INC(xs_attr_remove); 57990075Sobrien 58090075Sobrien dp = XFS_BHVTOI(bdp); 58190075Sobrien if (XFS_FORCED_SHUTDOWN(dp->i_mount)) 582169689Skan return (EIO); 583122180Skan 584122180Skan xfs_ilock(dp, XFS_ILOCK_SHARED); 585122180Skan if (XFS_IFORK_Q(dp) == 0 || 586122180Skan (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 587122180Skan dp->i_d.di_anextents == 0)) { 588117395Skan xfs_iunlock(dp, XFS_ILOCK_SHARED); 589117395Skan return(XFS_ERROR(ENOATTR)); 590169689Skan } 591169689Skan xfs_iunlock(dp, XFS_ILOCK_SHARED); 592169689Skan 593169689Skan return xfs_attr_remove_int(dp, name, namelen, flags); 594169689Skan} 595169689Skan 596169689Skan/* 597169689Skan * Generate a list of extended attribute names and optionally 598169689Skan * also value lengths. Positive return value follows the XFS 599169689Skan * convention of being an error, zero or negative return code 600117395Skan * is the length of the buffer returned (negated), indicating 601117395Skan * success. 602117395Skan */ 603117395Skanint 604117395Skanxfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags, 605117395Skan attrlist_cursor_kern_t *cursor, struct cred *cred) 60690075Sobrien{ 60790075Sobrien xfs_attr_list_context_t context; 608169689Skan xfs_inode_t *dp; 60990075Sobrien int error; 61090075Sobrien 61190075Sobrien XFS_STATS_INC(xs_attr_list); 61290075Sobrien 61390075Sobrien /* 614169689Skan * Validate the cursor. 615122180Skan */ 616122180Skan if (cursor->pad1 || cursor->pad2) 617122180Skan return(XFS_ERROR(EINVAL)); 618122180Skan if ((cursor->initted == 0) && 619122180Skan (cursor->hashval || cursor->blkno || cursor->offset)) 62090075Sobrien return(XFS_ERROR(EINVAL)); 621169689Skan 62290075Sobrien /* 62390075Sobrien * Check for a properly aligned buffer. 62490075Sobrien */ 62590075Sobrien if (((long)buffer) & (sizeof(int)-1)) 62690075Sobrien return(XFS_ERROR(EFAULT)); 62790075Sobrien if (flags & ATTR_KERNOVAL) 62890075Sobrien bufsize = 0; 62990075Sobrien 63090075Sobrien /* 631169689Skan * Initialize the output buffer. 63290075Sobrien */ 63390075Sobrien context.dp = dp = XFS_BHVTOI(bdp); 63490075Sobrien context.cursor = cursor; 63590075Sobrien context.count = 0; 63690075Sobrien context.dupcnt = 0; 63790075Sobrien context.resynch = 1; 638169689Skan context.flags = flags; 63990075Sobrien if (!(flags & ATTR_KERNAMELS)) { 64090075Sobrien context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ 64190075Sobrien context.firstu = context.bufsize; 64290075Sobrien context.alist = (attrlist_t *)buffer; 64390075Sobrien context.alist->al_count = 0; 64490075Sobrien context.alist->al_more = 0; 64590075Sobrien context.alist->al_offset[0] = context.bufsize; 64690075Sobrien } 647169689Skan else { 64890075Sobrien context.bufsize = bufsize; 64990075Sobrien context.firstu = context.bufsize; 65090075Sobrien context.alist = (attrlist_t *)buffer; 65190075Sobrien } 65290075Sobrien 65390075Sobrien if (XFS_FORCED_SHUTDOWN(dp->i_mount)) 654169689Skan return (EIO); 655169689Skan 65690075Sobrien xfs_ilock(dp, XFS_ILOCK_SHARED); 65790075Sobrien /* 658169689Skan * Decide on what work routines to call based on the inode size. 65990075Sobrien */ 66090075Sobrien xfs_attr_trace_l_c("syscall start", &context); 66190075Sobrien if (XFS_IFORK_Q(dp) == 0 || 66290075Sobrien (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 66390075Sobrien dp->i_d.di_anextents == 0)) { 66490075Sobrien error = 0; 66590075Sobrien } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { 66690075Sobrien error = xfs_attr_shortform_list(&context); 667169689Skan } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { 66890075Sobrien error = xfs_attr_leaf_list(&context); 66990075Sobrien } else { 67090075Sobrien error = xfs_attr_node_list(&context); 67190075Sobrien } 67290075Sobrien xfs_iunlock(dp, XFS_ILOCK_SHARED); 67390075Sobrien xfs_attr_trace_l_c("syscall end", &context); 67490075Sobrien 675169689Skan if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) { 67690075Sobrien ASSERT(error >= 0); 67790075Sobrien } 67890075Sobrien else { /* must return negated buffer size or the error */ 67990075Sobrien if (context.count < 0) 68090075Sobrien error = XFS_ERROR(ERANGE); 68190075Sobrien else 68290075Sobrien error = -context.count; 68390075Sobrien } 684169689Skan 68590075Sobrien return(error); 68690075Sobrien} 687169689Skan 68890075Sobrienint /* error */ 68990075Sobrienxfs_attr_inactive(xfs_inode_t *dp) 69090075Sobrien{ 69190075Sobrien xfs_trans_t *trans; 692169689Skan xfs_mount_t *mp; 69390075Sobrien int error; 69490075Sobrien 695169689Skan mp = dp->i_mount; 69690075Sobrien ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); 69790075Sobrien 69890075Sobrien xfs_ilock(dp, XFS_ILOCK_SHARED); 69990075Sobrien if ((XFS_IFORK_Q(dp) == 0) || 70090075Sobrien (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || 70190075Sobrien (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 702169689Skan dp->i_d.di_anextents == 0)) { 70390075Sobrien xfs_iunlock(dp, XFS_ILOCK_SHARED); 70490075Sobrien return(0); 70590075Sobrien } 70690075Sobrien xfs_iunlock(dp, XFS_ILOCK_SHARED); 70790075Sobrien 70890075Sobrien /* 709117395Skan * Start our first transaction of the day. 71090075Sobrien * 71190075Sobrien * All future transactions during this code must be "chained" off 71290075Sobrien * this one via the trans_dup() call. All transactions will contain 713169689Skan * the inode, and the inode will always be marked with trans_ihold(). 71490075Sobrien * Since the inode will be locked in all transactions, we must log 71590075Sobrien * the inode in every transaction to let it float upward through 71690075Sobrien * the log. 717169689Skan */ 71890075Sobrien trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL); 71990075Sobrien if ((error = xfs_trans_reserve(trans, 0, XFS_ATTRINVAL_LOG_RES(mp), 0, 72090075Sobrien XFS_TRANS_PERM_LOG_RES, 72190075Sobrien XFS_ATTRINVAL_LOG_COUNT))) { 722169689Skan xfs_trans_cancel(trans, 0); 72390075Sobrien return(error); 72490075Sobrien } 72590075Sobrien xfs_ilock(dp, XFS_ILOCK_EXCL); 72690075Sobrien 72790075Sobrien /* 72890075Sobrien * No need to make quota reservations here. We expect to release some 72990075Sobrien * blocks, not allocate, in the common case. 73090075Sobrien */ 73190075Sobrien xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL); 73290075Sobrien xfs_trans_ihold(trans, dp); 73390075Sobrien 734169689Skan /* 73590075Sobrien * Decide on what work routines to call based on the inode size. 73690075Sobrien */ 73790075Sobrien if ((XFS_IFORK_Q(dp) == 0) || 73890075Sobrien (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || 73990075Sobrien (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 74090075Sobrien dp->i_d.di_anextents == 0)) { 741169689Skan error = 0; 74290075Sobrien goto out; 74390075Sobrien } 74490075Sobrien error = xfs_attr_root_inactive(&trans, dp); 74590075Sobrien if (error) 74690075Sobrien goto out; 74790075Sobrien /* 74890075Sobrien * signal synchronous inactive transactions unless this 749169689Skan * is a synchronous mount filesystem in which case we 750117395Skan * know that we're here because we've been called out of 75190075Sobrien * xfs_inactive which means that the last reference is gone 75290075Sobrien * and the unlink transaction has already hit the disk so 75390075Sobrien * async inactive transactions are safe. 75490075Sobrien */ 75590075Sobrien if ((error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK, 756169689Skan (!(mp->m_flags & XFS_MOUNT_WSYNC) 75790075Sobrien ? 1 : 0)))) 75890075Sobrien goto out; 75990075Sobrien 76090075Sobrien /* 76190075Sobrien * Commit the last in the sequence of transactions. 76290075Sobrien */ 763169689Skan xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); 76490075Sobrien error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES, 76590075Sobrien NULL); 76690075Sobrien xfs_iunlock(dp, XFS_ILOCK_EXCL); 76790075Sobrien 76890075Sobrien return(error); 76990075Sobrien 770169689Skanout: 77190075Sobrien xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); 77290075Sobrien xfs_iunlock(dp, XFS_ILOCK_EXCL); 77390075Sobrien return(error); 77490075Sobrien} 77590075Sobrien 77690075Sobrien 77790075Sobrien 778169689Skan/*======================================================================== 779117395Skan * External routines when attribute list is inside the inode 78090075Sobrien *========================================================================*/ 78190075Sobrien 78290075Sobrien/* 78390075Sobrien * Add a name to the shortform attribute list structure 78490075Sobrien * This is the external routine. 785169689Skan */ 78690075SobrienSTATIC int 78790075Sobrienxfs_attr_shortform_addname(xfs_da_args_t *args) 78890075Sobrien{ 78990075Sobrien int newsize, forkoff, retval; 79090075Sobrien 79190075Sobrien retval = xfs_attr_shortform_lookup(args); 792169689Skan if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { 79390075Sobrien return(retval); 79490075Sobrien } else if (retval == EEXIST) { 79590075Sobrien if (args->flags & ATTR_CREATE) 79690075Sobrien return(retval); 79790075Sobrien retval = xfs_attr_shortform_remove(args); 79890075Sobrien ASSERT(retval == 0); 799169689Skan } 80090075Sobrien 80190075Sobrien if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX || 80290075Sobrien args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX) 80390075Sobrien return(XFS_ERROR(ENOSPC)); 80490075Sobrien 80590075Sobrien newsize = XFS_ATTR_SF_TOTSIZE(args->dp); 806169689Skan newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); 80790075Sobrien 80890075Sobrien forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize); 80990075Sobrien if (!forkoff) 81090075Sobrien return(XFS_ERROR(ENOSPC)); 81190075Sobrien 812169689Skan xfs_attr_shortform_add(args, forkoff); 81390075Sobrien return(0); 81490075Sobrien} 81590075Sobrien 81690075Sobrien 81790075Sobrien/*======================================================================== 818169689Skan * External routines when attribute list is one block 81990075Sobrien *========================================================================*/ 82090075Sobrien 82190075Sobrien/* 82290075Sobrien * Add a name to the leaf attribute list structure 82390075Sobrien * 824169689Skan * This leaf block cannot have a "remote" value, we only call this routine 82590075Sobrien * if bmap_one_block() says there is only one block (ie: no remote blks). 82690075Sobrien */ 82790075Sobrienint 82890075Sobrienxfs_attr_leaf_addname(xfs_da_args_t *args) 82990075Sobrien{ 83090075Sobrien xfs_inode_t *dp; 831169689Skan xfs_dabuf_t *bp; 83290075Sobrien int retval, error, committed, forkoff; 83390075Sobrien 83490075Sobrien /* 83590075Sobrien * Read the (only) block in the attribute list in. 83690075Sobrien */ 83790075Sobrien dp = args->dp; 838169689Skan args->blkno = 0; 83990075Sobrien error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, 84090075Sobrien XFS_ATTR_FORK); 84190075Sobrien if (error) 84290075Sobrien return(error); 84390075Sobrien ASSERT(bp != NULL); 844169689Skan 84590075Sobrien /* 84690075Sobrien * Look up the given attribute in the leaf block. Figure out if 84790075Sobrien * the given flags produce an error or call for an atomic rename. 84890075Sobrien */ 84990075Sobrien retval = xfs_attr_leaf_lookup_int(bp, args); 850169689Skan if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { 85190075Sobrien xfs_da_brelse(args->trans, bp); 85290075Sobrien return(retval); 85390075Sobrien } else if (retval == EEXIST) { 85490075Sobrien if (args->flags & ATTR_CREATE) { /* pure create op */ 85590075Sobrien xfs_da_brelse(args->trans, bp); 856169689Skan return(retval); 85790075Sobrien } 85890075Sobrien args->rename = 1; /* an atomic rename */ 85990075Sobrien args->blkno2 = args->blkno; /* set 2nd entry info*/ 86090075Sobrien args->index2 = args->index; 86190075Sobrien args->rmtblkno2 = args->rmtblkno; 862169689Skan args->rmtblkcnt2 = args->rmtblkcnt; 863169689Skan } 864169689Skan 865169689Skan /* 866169689Skan * Add the attribute to the leaf block, transitioning to a Btree 867169689Skan * if required. 868169689Skan */ 869169689Skan retval = xfs_attr_leaf_add(bp, args); 870169689Skan xfs_da_buf_done(bp); 871169689Skan if (retval == ENOSPC) { 872169689Skan /* 873169689Skan * Promote the attribute list to the Btree format, then 874169689Skan * Commit that transaction so that the node_addname() call 875169689Skan * can manage its own transactions. 876169689Skan */ 877169689Skan XFS_BMAP_INIT(args->flist, args->firstblock); 878169689Skan error = xfs_attr_leaf_to_node(args); 879169689Skan if (!error) { 880169689Skan error = xfs_bmap_finish(&args->trans, args->flist, 881169689Skan *args->firstblock, &committed); 88290075Sobrien } 883169689Skan if (error) { 884117395Skan ASSERT(committed); 88590075Sobrien args->trans = NULL; 886169689Skan xfs_bmap_cancel(args->flist); 88790075Sobrien return(error); 88890075Sobrien } 88990075Sobrien 890169689Skan /* 891117395Skan * bmap_finish() may have committed the last trans and started 89290075Sobrien * a new one. We need the inode to be in all transactions. 893169689Skan */ 89490075Sobrien if (committed) { 89590075Sobrien xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 896169689Skan xfs_trans_ihold(args->trans, dp); 897117395Skan } 89890075Sobrien 89990075Sobrien /* 90090075Sobrien * Commit the current trans (including the inode) and start 90190075Sobrien * a new one. 90290075Sobrien */ 903169689Skan if ((error = xfs_attr_rolltrans(&args->trans, dp))) 904117395Skan return (error); 90590075Sobrien 906169689Skan /* 90790075Sobrien * Fob the whole rest of the problem off on the Btree code. 90890075Sobrien */ 90990075Sobrien error = xfs_attr_node_addname(args); 910169689Skan return(error); 911117395Skan } 91290075Sobrien 91390075Sobrien /* 91490075Sobrien * Commit the transaction that added the attr name so that 91590075Sobrien * later routines can manage their own transactions. 91690075Sobrien */ 917169689Skan if ((error = xfs_attr_rolltrans(&args->trans, dp))) 918117395Skan return (error); 91990075Sobrien 920169689Skan /* 92190075Sobrien * If there was an out-of-line value, allocate the blocks we 92290075Sobrien * identified for its storage and copy the value. This is done 92390075Sobrien * after we create the attribute so that we don't overflow the 924169689Skan * maximum size of a transaction and/or hit a deadlock. 925169689Skan */ 926169689Skan if (args->rmtblkno > 0) { 92790075Sobrien error = xfs_attr_rmtval_set(args); 928169689Skan if (error) 92990075Sobrien return(error); 93090075Sobrien } 931169689Skan 932169689Skan /* 933169689Skan * If this is an atomic rename operation, we must "flip" the 93490075Sobrien * incomplete flags on the "new" and "old" attribute/value pairs 935169689Skan * so that one disappears and one appears atomically. Then we 93690075Sobrien * must remove the "old" attribute/value pair. 93790075Sobrien */ 938169689Skan if (args->rename) { 939169689Skan /* 940169689Skan * In a separate transaction, set the incomplete flag on the 94190075Sobrien * "old" attr and clear the incomplete flag on the "new" attr. 942169689Skan */ 94390075Sobrien error = xfs_attr_leaf_flipflags(args); 94490075Sobrien if (error) 945169689Skan return(error); 946169689Skan 94790075Sobrien /* 948169689Skan * Dismantle the "old" attribute/value pair by removing 94990075Sobrien * a "remote" value (if it exists). 95090075Sobrien */ 951169689Skan args->index = args->index2; 952169689Skan args->blkno = args->blkno2; 953169689Skan args->rmtblkno = args->rmtblkno2; 95490075Sobrien args->rmtblkcnt = args->rmtblkcnt2; 955169689Skan if (args->rmtblkno) { 95690075Sobrien error = xfs_attr_rmtval_remove(args); 95790075Sobrien if (error) 958169689Skan return(error); 959169689Skan } 960169689Skan 96190075Sobrien /* 962169689Skan * Read in the block containing the "old" attr, then 96390075Sobrien * remove the "old" attr from that block (neat, huh!) 96490075Sobrien */ 96590075Sobrien error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, 966169689Skan &bp, XFS_ATTR_FORK); 96790075Sobrien if (error) 96890075Sobrien return(error); 96990075Sobrien ASSERT(bp != NULL); 97090075Sobrien (void)xfs_attr_leaf_remove(bp, args); 971169689Skan 97290075Sobrien /* 97390075Sobrien * If the result is small enough, shrink it all into the inode. 974169689Skan */ 97590075Sobrien if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { 97690075Sobrien XFS_BMAP_INIT(args->flist, args->firstblock); 97790075Sobrien error = xfs_attr_leaf_to_shortform(bp, args, forkoff); 97890075Sobrien /* bp is gone due to xfs_da_shrink_inode */ 97990075Sobrien if (!error) { 980117395Skan error = xfs_bmap_finish(&args->trans, 981169689Skan args->flist, 98290075Sobrien *args->firstblock, 98390075Sobrien &committed); 98490075Sobrien } 98590075Sobrien if (error) { 986169689Skan ASSERT(committed); 98790075Sobrien args->trans = NULL; 98890075Sobrien xfs_bmap_cancel(args->flist); 98990075Sobrien return(error); 990169689Skan } 99190075Sobrien 99290075Sobrien /* 99390075Sobrien * bmap_finish() may have committed the last trans 99490075Sobrien * and started a new one. We need the inode to be 99590075Sobrien * in all transactions. 99690075Sobrien */ 99790075Sobrien if (committed) { 998169689Skan xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 999169689Skan xfs_trans_ihold(args->trans, dp); 100090075Sobrien } 1001169689Skan } else 100290075Sobrien xfs_da_buf_done(bp); 1003122180Skan 1004169689Skan /* 1005169689Skan * Commit the remove and start the next trans in series. 1006122180Skan */ 1007122180Skan error = xfs_attr_rolltrans(&args->trans, dp); 1008122180Skan 100990075Sobrien } else if (args->rmtblkno > 0) { 1010169689Skan /* 1011122180Skan * Added a "remote" value, just clear the incomplete flag. 101290075Sobrien */ 101390075Sobrien error = xfs_attr_leaf_clearflag(args); 101490075Sobrien } 101590075Sobrien return(error); 101690075Sobrien} 1017169689Skan 1018169689Skan/* 101990075Sobrien * Remove a name from the leaf attribute list structure 1020169689Skan * 102190075Sobrien * This leaf block cannot have a "remote" value, we only call this routine 1022122180Skan * if bmap_one_block() says there is only one block (ie: no remote blks). 1023169689Skan */ 1024169689SkanSTATIC int 1025122180Skanxfs_attr_leaf_removename(xfs_da_args_t *args) 1026122180Skan{ 1027122180Skan xfs_inode_t *dp; 102890075Sobrien xfs_dabuf_t *bp; 102990075Sobrien int error, committed, forkoff; 1030169689Skan 1031122180Skan /* 103290075Sobrien * Remove the attribute. 103390075Sobrien */ 103490075Sobrien dp = args->dp; 1035169689Skan args->blkno = 0; 103690075Sobrien error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, 103790075Sobrien XFS_ATTR_FORK); 103890075Sobrien if (error) { 103990075Sobrien return(error); 104090075Sobrien } 1041169689Skan 1042122180Skan ASSERT(bp != NULL); 1043122180Skan error = xfs_attr_leaf_lookup_int(bp, args); 1044122180Skan if (error == ENOATTR) { 1045122180Skan xfs_da_brelse(args->trans, bp); 1046122180Skan return(error); 104790075Sobrien } 1048169689Skan 104990075Sobrien (void)xfs_attr_leaf_remove(bp, args); 105090075Sobrien 105190075Sobrien /* 105290075Sobrien * If the result is small enough, shrink it all into the inode. 105390075Sobrien */ 1054169689Skan if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { 1055122180Skan XFS_BMAP_INIT(args->flist, args->firstblock); 1056122180Skan error = xfs_attr_leaf_to_shortform(bp, args, forkoff); 1057122180Skan /* bp is gone due to xfs_da_shrink_inode */ 1058122180Skan if (!error) { 1059122180Skan error = xfs_bmap_finish(&args->trans, args->flist, 106090075Sobrien *args->firstblock, &committed); 1061169689Skan } 106290075Sobrien if (error) { 106390075Sobrien ASSERT(committed); 106490075Sobrien args->trans = NULL; 106590075Sobrien xfs_bmap_cancel(args->flist); 106690075Sobrien return(error); 1067169689Skan } 1068122180Skan 1069122180Skan /* 1070122180Skan * bmap_finish() may have committed the last trans and started 1071122180Skan * a new one. We need the inode to be in all transactions. 1072122180Skan */ 107390075Sobrien if (committed) { 1074169689Skan xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 107590075Sobrien xfs_trans_ihold(args->trans, dp); 107690075Sobrien } 107790075Sobrien } else 107890075Sobrien xfs_da_buf_done(bp); 107990075Sobrien return(0); 1080169689Skan} 1081122180Skan 1082122180Skan/* 1083122180Skan * Look up a name in a leaf attribute list structure. 1084122180Skan * 1085122180Skan * This leaf block cannot have a "remote" value, we only call this routine 108690075Sobrien * if bmap_one_block() says there is only one block (ie: no remote blks). 1087169689Skan */ 108890075SobrienSTATIC int 108990075Sobrienxfs_attr_leaf_get(xfs_da_args_t *args) 109090075Sobrien{ 109190075Sobrien xfs_dabuf_t *bp; 109290075Sobrien int error; 1093169689Skan 1094122180Skan args->blkno = 0; 1095122180Skan error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, 1096122180Skan XFS_ATTR_FORK); 1097122180Skan if (error) 1098122180Skan return(error); 109990075Sobrien ASSERT(bp != NULL); 110090075Sobrien 1101169689Skan error = xfs_attr_leaf_lookup_int(bp, args); 110290075Sobrien if (error != EEXIST) { 110390075Sobrien xfs_da_brelse(args->trans, bp); 110490075Sobrien return(error); 110590075Sobrien } 110690075Sobrien error = xfs_attr_leaf_getvalue(bp, args); 1107169689Skan xfs_da_brelse(args->trans, bp); 1108122180Skan if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) { 1109122180Skan error = xfs_attr_rmtval_get(args); 1110122180Skan } 1111122180Skan return(error); 1112122180Skan} 111390075Sobrien 111490075Sobrien/* 111590075Sobrien * Copy out attribute entries for attr_list(), for leaf attribute lists. 1116169689Skan */ 111790075SobrienSTATIC int 111890075Sobrienxfs_attr_leaf_list(xfs_attr_list_context_t *context) 111990075Sobrien{ 112090075Sobrien xfs_attr_leafblock_t *leaf; 1121122180Skan int error; 1122169689Skan xfs_dabuf_t *bp; 1123122180Skan 1124122180Skan context->cursor->blkno = 0; 1125122180Skan error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK); 1126122180Skan if (error) 112790075Sobrien return(error); 112890075Sobrien ASSERT(bp != NULL); 112990075Sobrien leaf = bp->data; 1130122180Skan if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) { 113190075Sobrien XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW, 113290075Sobrien context->dp->i_mount, leaf); 113390075Sobrien xfs_da_brelse(NULL, bp); 113490075Sobrien return(XFS_ERROR(EFSCORRUPTED)); 113590075Sobrien } 1136169689Skan 113790075Sobrien (void)xfs_attr_leaf_list_int(bp, context); 113890075Sobrien xfs_da_brelse(NULL, bp); 113990075Sobrien return(0); 114090075Sobrien} 114190075Sobrien 1142169689Skan 1143122180Skan/*======================================================================== 1144122180Skan * External routines when attribute list size > XFS_LBSIZE(mp). 1145122180Skan *========================================================================*/ 1146122180Skan 1147122180Skan/* 114890075Sobrien * Add a name to a Btree-format attribute list. 1149169689Skan * 115090075Sobrien * This will involve walking down the Btree, and may involve splitting 115190075Sobrien * leaf nodes and even splitting intermediate nodes up to and including 115290075Sobrien * the root node (a special case of an intermediate node). 115390075Sobrien * 115490075Sobrien * "Remote" attribute values confuse the issue and atomic rename operations 1155169689Skan * add a whole extra layer of confusion on top of that. 1156122180Skan */ 1157122180SkanSTATIC int 1158122180Skanxfs_attr_node_addname(xfs_da_args_t *args) 1159122180Skan{ 1160122180Skan xfs_da_state_t *state; 116190075Sobrien xfs_da_state_blk_t *blk; 1162169689Skan xfs_inode_t *dp; 116390075Sobrien xfs_mount_t *mp; 116490075Sobrien int committed, retval, error; 116590075Sobrien 116690075Sobrien /* 116790075Sobrien * Fill in bucket of arguments/results/context to carry around. 1168169689Skan */ 1169122180Skan dp = args->dp; 1170122180Skan mp = dp->i_mount; 1171122180Skanrestart: 1172122180Skan state = xfs_da_state_alloc(); 1173122180Skan state->args = args; 117490075Sobrien state->mp = mp; 117590075Sobrien state->blocksize = state->mp->m_sb.sb_blocksize; 117690075Sobrien state->node_ents = state->mp->m_attr_node_ents; 1177169689Skan 117890075Sobrien /* 117990075Sobrien * Search to see if name already exists, and get back a pointer 118090075Sobrien * to where it should go. 118190075Sobrien */ 118290075Sobrien error = xfs_da_node_lookup_int(state, &retval); 1183169689Skan if (error) 1184122180Skan goto out; 1185122180Skan blk = &state->path.blk[ state->path.active-1 ]; 1186122180Skan ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); 1187122180Skan if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { 1188122180Skan goto out; 118990075Sobrien } else if (retval == EEXIST) { 119090075Sobrien if (args->flags & ATTR_CREATE) 119190075Sobrien goto out; 1192169689Skan args->rename = 1; /* atomic rename op */ 119390075Sobrien args->blkno2 = args->blkno; /* set 2nd entry info*/ 119490075Sobrien args->index2 = args->index; 119590075Sobrien args->rmtblkno2 = args->rmtblkno; 119690075Sobrien args->rmtblkcnt2 = args->rmtblkcnt; 119790075Sobrien args->rmtblkno = 0; 119890075Sobrien args->rmtblkcnt = 0; 119990075Sobrien } 120090075Sobrien 120190075Sobrien retval = xfs_attr_leaf_add(blk->bp, state->args); 120290075Sobrien if (retval == ENOSPC) { 1203169689Skan if (state->path.active == 1) { 120490075Sobrien /* 120590075Sobrien * Its really a single leaf node, but it had 1206117395Skan * out-of-line values so it looked like it *might* 120790075Sobrien * have been a b-tree. 120890075Sobrien */ 120990075Sobrien xfs_da_state_free(state); 1210169689Skan XFS_BMAP_INIT(args->flist, args->firstblock); 121190075Sobrien error = xfs_attr_leaf_to_node(args); 121290075Sobrien if (!error) { 121390075Sobrien error = xfs_bmap_finish(&args->trans, 121490075Sobrien args->flist, 121590075Sobrien *args->firstblock, 1216132718Skan &committed); 121790075Sobrien } 1218169689Skan if (error) { 121990075Sobrien ASSERT(committed); 122090075Sobrien args->trans = NULL; 122190075Sobrien xfs_bmap_cancel(args->flist); 122290075Sobrien goto out; 122390075Sobrien } 122490075Sobrien 122590075Sobrien /* 122690075Sobrien * bmap_finish() may have committed the last trans 1227169689Skan * and started a new one. We need the inode to be 122890075Sobrien * in all transactions. 122990075Sobrien */ 123090075Sobrien if (committed) { 123190075Sobrien xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 123290075Sobrien xfs_trans_ihold(args->trans, dp); 123390075Sobrien } 123490075Sobrien 123590075Sobrien /* 123690075Sobrien * Commit the node conversion and start the next 1237169689Skan * trans in the chain. 1238169689Skan */ 1239169689Skan if ((error = xfs_attr_rolltrans(&args->trans, dp))) 1240169689Skan goto out; 1241169689Skan 1242169689Skan goto restart; 1243169689Skan } 1244169689Skan 124590075Sobrien /* 124690075Sobrien * Split as many Btree elements as required. 1247122180Skan * This code tracks the new and old attr's location 1248219639Smm * in the index/blkno/rmtblkno/rmtblkcnt fields and 1249122180Skan * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields. 1250219639Smm */ 1251117395Skan XFS_BMAP_INIT(args->flist, args->firstblock); 1252117395Skan error = xfs_da_split(state); 125390075Sobrien if (!error) { 1254 error = xfs_bmap_finish(&args->trans, args->flist, 1255 *args->firstblock, &committed); 1256 } 1257 if (error) { 1258 ASSERT(committed); 1259 args->trans = NULL; 1260 xfs_bmap_cancel(args->flist); 1261 goto out; 1262 } 1263 1264 /* 1265 * bmap_finish() may have committed the last trans and started 1266 * a new one. We need the inode to be in all transactions. 1267 */ 1268 if (committed) { 1269 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 1270 xfs_trans_ihold(args->trans, dp); 1271 } 1272 } else { 1273 /* 1274 * Addition succeeded, update Btree hashvals. 1275 */ 1276 xfs_da_fixhashpath(state, &state->path); 1277 } 1278 1279 /* 1280 * Kill the state structure, we're done with it and need to 1281 * allow the buffers to come back later. 1282 */ 1283 xfs_da_state_free(state); 1284 state = NULL; 1285 1286 /* 1287 * Commit the leaf addition or btree split and start the next 1288 * trans in the chain. 1289 */ 1290 if ((error = xfs_attr_rolltrans(&args->trans, dp))) 1291 goto out; 1292 1293 /* 1294 * If there was an out-of-line value, allocate the blocks we 1295 * identified for its storage and copy the value. This is done 1296 * after we create the attribute so that we don't overflow the 1297 * maximum size of a transaction and/or hit a deadlock. 1298 */ 1299 if (args->rmtblkno > 0) { 1300 error = xfs_attr_rmtval_set(args); 1301 if (error) 1302 return(error); 1303 } 1304 1305 /* 1306 * If this is an atomic rename operation, we must "flip" the 1307 * incomplete flags on the "new" and "old" attribute/value pairs 1308 * so that one disappears and one appears atomically. Then we 1309 * must remove the "old" attribute/value pair. 1310 */ 1311 if (args->rename) { 1312 /* 1313 * In a separate transaction, set the incomplete flag on the 1314 * "old" attr and clear the incomplete flag on the "new" attr. 1315 */ 1316 error = xfs_attr_leaf_flipflags(args); 1317 if (error) 1318 goto out; 1319 1320 /* 1321 * Dismantle the "old" attribute/value pair by removing 1322 * a "remote" value (if it exists). 1323 */ 1324 args->index = args->index2; 1325 args->blkno = args->blkno2; 1326 args->rmtblkno = args->rmtblkno2; 1327 args->rmtblkcnt = args->rmtblkcnt2; 1328 if (args->rmtblkno) { 1329 error = xfs_attr_rmtval_remove(args); 1330 if (error) 1331 return(error); 1332 } 1333 1334 /* 1335 * Re-find the "old" attribute entry after any split ops. 1336 * The INCOMPLETE flag means that we will find the "old" 1337 * attr, not the "new" one. 1338 */ 1339 args->flags |= XFS_ATTR_INCOMPLETE; 1340 state = xfs_da_state_alloc(); 1341 state->args = args; 1342 state->mp = mp; 1343 state->blocksize = state->mp->m_sb.sb_blocksize; 1344 state->node_ents = state->mp->m_attr_node_ents; 1345 state->inleaf = 0; 1346 error = xfs_da_node_lookup_int(state, &retval); 1347 if (error) 1348 goto out; 1349 1350 /* 1351 * Remove the name and update the hashvals in the tree. 1352 */ 1353 blk = &state->path.blk[ state->path.active-1 ]; 1354 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); 1355 error = xfs_attr_leaf_remove(blk->bp, args); 1356 xfs_da_fixhashpath(state, &state->path); 1357 1358 /* 1359 * Check to see if the tree needs to be collapsed. 1360 */ 1361 if (retval && (state->path.active > 1)) { 1362 XFS_BMAP_INIT(args->flist, args->firstblock); 1363 error = xfs_da_join(state); 1364 if (!error) { 1365 error = xfs_bmap_finish(&args->trans, 1366 args->flist, 1367 *args->firstblock, 1368 &committed); 1369 } 1370 if (error) { 1371 ASSERT(committed); 1372 args->trans = NULL; 1373 xfs_bmap_cancel(args->flist); 1374 goto out; 1375 } 1376 1377 /* 1378 * bmap_finish() may have committed the last trans 1379 * and started a new one. We need the inode to be 1380 * in all transactions. 1381 */ 1382 if (committed) { 1383 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 1384 xfs_trans_ihold(args->trans, dp); 1385 } 1386 } 1387 1388 /* 1389 * Commit and start the next trans in the chain. 1390 */ 1391 if ((error = xfs_attr_rolltrans(&args->trans, dp))) 1392 goto out; 1393 1394 } else if (args->rmtblkno > 0) { 1395 /* 1396 * Added a "remote" value, just clear the incomplete flag. 1397 */ 1398 error = xfs_attr_leaf_clearflag(args); 1399 if (error) 1400 goto out; 1401 } 1402 retval = error = 0; 1403 1404out: 1405 if (state) 1406 xfs_da_state_free(state); 1407 if (error) 1408 return(error); 1409 return(retval); 1410} 1411 1412/* 1413 * Remove a name from a B-tree attribute list. 1414 * 1415 * This will involve walking down the Btree, and may involve joining 1416 * leaf nodes and even joining intermediate nodes up to and including 1417 * the root node (a special case of an intermediate node). 1418 */ 1419STATIC int 1420xfs_attr_node_removename(xfs_da_args_t *args) 1421{ 1422 xfs_da_state_t *state; 1423 xfs_da_state_blk_t *blk; 1424 xfs_inode_t *dp; 1425 xfs_dabuf_t *bp; 1426 int retval, error, committed, forkoff; 1427 1428 /* 1429 * Tie a string around our finger to remind us where we are. 1430 */ 1431 dp = args->dp; 1432 state = xfs_da_state_alloc(); 1433 state->args = args; 1434 state->mp = dp->i_mount; 1435 state->blocksize = state->mp->m_sb.sb_blocksize; 1436 state->node_ents = state->mp->m_attr_node_ents; 1437 1438 /* 1439 * Search to see if name exists, and get back a pointer to it. 1440 */ 1441 error = xfs_da_node_lookup_int(state, &retval); 1442 if (error || (retval != EEXIST)) { 1443 if (error == 0) 1444 error = retval; 1445 goto out; 1446 } 1447 1448 /* 1449 * If there is an out-of-line value, de-allocate the blocks. 1450 * This is done before we remove the attribute so that we don't 1451 * overflow the maximum size of a transaction and/or hit a deadlock. 1452 */ 1453 blk = &state->path.blk[ state->path.active-1 ]; 1454 ASSERT(blk->bp != NULL); 1455 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); 1456 if (args->rmtblkno > 0) { 1457 /* 1458 * Fill in disk block numbers in the state structure 1459 * so that we can get the buffers back after we commit 1460 * several transactions in the following calls. 1461 */ 1462 error = xfs_attr_fillstate(state); 1463 if (error) 1464 goto out; 1465 1466 /* 1467 * Mark the attribute as INCOMPLETE, then bunmapi() the 1468 * remote value. 1469 */ 1470 error = xfs_attr_leaf_setflag(args); 1471 if (error) 1472 goto out; 1473 error = xfs_attr_rmtval_remove(args); 1474 if (error) 1475 goto out; 1476 1477 /* 1478 * Refill the state structure with buffers, the prior calls 1479 * released our buffers. 1480 */ 1481 error = xfs_attr_refillstate(state); 1482 if (error) 1483 goto out; 1484 } 1485 1486 /* 1487 * Remove the name and update the hashvals in the tree. 1488 */ 1489 blk = &state->path.blk[ state->path.active-1 ]; 1490 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); 1491 retval = xfs_attr_leaf_remove(blk->bp, args); 1492 xfs_da_fixhashpath(state, &state->path); 1493 1494 /* 1495 * Check to see if the tree needs to be collapsed. 1496 */ 1497 if (retval && (state->path.active > 1)) { 1498 XFS_BMAP_INIT(args->flist, args->firstblock); 1499 error = xfs_da_join(state); 1500 if (!error) { 1501 error = xfs_bmap_finish(&args->trans, args->flist, 1502 *args->firstblock, &committed); 1503 } 1504 if (error) { 1505 ASSERT(committed); 1506 args->trans = NULL; 1507 xfs_bmap_cancel(args->flist); 1508 goto out; 1509 } 1510 1511 /* 1512 * bmap_finish() may have committed the last trans and started 1513 * a new one. We need the inode to be in all transactions. 1514 */ 1515 if (committed) { 1516 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 1517 xfs_trans_ihold(args->trans, dp); 1518 } 1519 1520 /* 1521 * Commit the Btree join operation and start a new trans. 1522 */ 1523 if ((error = xfs_attr_rolltrans(&args->trans, dp))) 1524 goto out; 1525 } 1526 1527 /* 1528 * If the result is small enough, push it all into the inode. 1529 */ 1530 if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { 1531 /* 1532 * Have to get rid of the copy of this dabuf in the state. 1533 */ 1534 ASSERT(state->path.active == 1); 1535 ASSERT(state->path.blk[0].bp); 1536 xfs_da_buf_done(state->path.blk[0].bp); 1537 state->path.blk[0].bp = NULL; 1538 1539 error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, 1540 XFS_ATTR_FORK); 1541 if (error) 1542 goto out; 1543 ASSERT(be16_to_cpu(((xfs_attr_leafblock_t *) 1544 bp->data)->hdr.info.magic) 1545 == XFS_ATTR_LEAF_MAGIC); 1546 1547 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { 1548 XFS_BMAP_INIT(args->flist, args->firstblock); 1549 error = xfs_attr_leaf_to_shortform(bp, args, forkoff); 1550 /* bp is gone due to xfs_da_shrink_inode */ 1551 if (!error) { 1552 error = xfs_bmap_finish(&args->trans, 1553 args->flist, 1554 *args->firstblock, 1555 &committed); 1556 } 1557 if (error) { 1558 ASSERT(committed); 1559 args->trans = NULL; 1560 xfs_bmap_cancel(args->flist); 1561 goto out; 1562 } 1563 1564 /* 1565 * bmap_finish() may have committed the last trans 1566 * and started a new one. We need the inode to be 1567 * in all transactions. 1568 */ 1569 if (committed) { 1570 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 1571 xfs_trans_ihold(args->trans, dp); 1572 } 1573 } else 1574 xfs_da_brelse(args->trans, bp); 1575 } 1576 error = 0; 1577 1578out: 1579 xfs_da_state_free(state); 1580 return(error); 1581} 1582 1583/* 1584 * Fill in the disk block numbers in the state structure for the buffers 1585 * that are attached to the state structure. 1586 * This is done so that we can quickly reattach ourselves to those buffers 1587 * after some set of transaction commits have released these buffers. 1588 */ 1589STATIC int 1590xfs_attr_fillstate(xfs_da_state_t *state) 1591{ 1592 xfs_da_state_path_t *path; 1593 xfs_da_state_blk_t *blk; 1594 int level; 1595 1596 /* 1597 * Roll down the "path" in the state structure, storing the on-disk 1598 * block number for those buffers in the "path". 1599 */ 1600 path = &state->path; 1601 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); 1602 for (blk = path->blk, level = 0; level < path->active; blk++, level++) { 1603 if (blk->bp) { 1604 blk->disk_blkno = xfs_da_blkno(blk->bp); 1605 xfs_da_buf_done(blk->bp); 1606 blk->bp = NULL; 1607 } else { 1608 blk->disk_blkno = 0; 1609 } 1610 } 1611 1612 /* 1613 * Roll down the "altpath" in the state structure, storing the on-disk 1614 * block number for those buffers in the "altpath". 1615 */ 1616 path = &state->altpath; 1617 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); 1618 for (blk = path->blk, level = 0; level < path->active; blk++, level++) { 1619 if (blk->bp) { 1620 blk->disk_blkno = xfs_da_blkno(blk->bp); 1621 xfs_da_buf_done(blk->bp); 1622 blk->bp = NULL; 1623 } else { 1624 blk->disk_blkno = 0; 1625 } 1626 } 1627 1628 return(0); 1629} 1630 1631/* 1632 * Reattach the buffers to the state structure based on the disk block 1633 * numbers stored in the state structure. 1634 * This is done after some set of transaction commits have released those 1635 * buffers from our grip. 1636 */ 1637STATIC int 1638xfs_attr_refillstate(xfs_da_state_t *state) 1639{ 1640 xfs_da_state_path_t *path; 1641 xfs_da_state_blk_t *blk; 1642 int level, error; 1643 1644 /* 1645 * Roll down the "path" in the state structure, storing the on-disk 1646 * block number for those buffers in the "path". 1647 */ 1648 path = &state->path; 1649 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); 1650 for (blk = path->blk, level = 0; level < path->active; blk++, level++) { 1651 if (blk->disk_blkno) { 1652 error = xfs_da_read_buf(state->args->trans, 1653 state->args->dp, 1654 blk->blkno, blk->disk_blkno, 1655 &blk->bp, XFS_ATTR_FORK); 1656 if (error) 1657 return(error); 1658 } else { 1659 blk->bp = NULL; 1660 } 1661 } 1662 1663 /* 1664 * Roll down the "altpath" in the state structure, storing the on-disk 1665 * block number for those buffers in the "altpath". 1666 */ 1667 path = &state->altpath; 1668 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); 1669 for (blk = path->blk, level = 0; level < path->active; blk++, level++) { 1670 if (blk->disk_blkno) { 1671 error = xfs_da_read_buf(state->args->trans, 1672 state->args->dp, 1673 blk->blkno, blk->disk_blkno, 1674 &blk->bp, XFS_ATTR_FORK); 1675 if (error) 1676 return(error); 1677 } else { 1678 blk->bp = NULL; 1679 } 1680 } 1681 1682 return(0); 1683} 1684 1685/* 1686 * Look up a filename in a node attribute list. 1687 * 1688 * This routine gets called for any attribute fork that has more than one 1689 * block, ie: both true Btree attr lists and for single-leaf-blocks with 1690 * "remote" values taking up more blocks. 1691 */ 1692STATIC int 1693xfs_attr_node_get(xfs_da_args_t *args) 1694{ 1695 xfs_da_state_t *state; 1696 xfs_da_state_blk_t *blk; 1697 int error, retval; 1698 int i; 1699 1700 state = xfs_da_state_alloc(); 1701 state->args = args; 1702 state->mp = args->dp->i_mount; 1703 state->blocksize = state->mp->m_sb.sb_blocksize; 1704 state->node_ents = state->mp->m_attr_node_ents; 1705 1706 /* 1707 * Search to see if name exists, and get back a pointer to it. 1708 */ 1709 error = xfs_da_node_lookup_int(state, &retval); 1710 if (error) { 1711 retval = error; 1712 } else if (retval == EEXIST) { 1713 blk = &state->path.blk[ state->path.active-1 ]; 1714 ASSERT(blk->bp != NULL); 1715 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); 1716 1717 /* 1718 * Get the value, local or "remote" 1719 */ 1720 retval = xfs_attr_leaf_getvalue(blk->bp, args); 1721 if (!retval && (args->rmtblkno > 0) 1722 && !(args->flags & ATTR_KERNOVAL)) { 1723 retval = xfs_attr_rmtval_get(args); 1724 } 1725 } 1726 1727 /* 1728 * If not in a transaction, we have to release all the buffers. 1729 */ 1730 for (i = 0; i < state->path.active; i++) { 1731 xfs_da_brelse(args->trans, state->path.blk[i].bp); 1732 state->path.blk[i].bp = NULL; 1733 } 1734 1735 xfs_da_state_free(state); 1736 return(retval); 1737} 1738 1739STATIC int /* error */ 1740xfs_attr_node_list(xfs_attr_list_context_t *context) 1741{ 1742 attrlist_cursor_kern_t *cursor; 1743 xfs_attr_leafblock_t *leaf; 1744 xfs_da_intnode_t *node; 1745 xfs_da_node_entry_t *btree; 1746 int error, i; 1747 xfs_dabuf_t *bp; 1748 1749 cursor = context->cursor; 1750 cursor->initted = 1; 1751 1752 /* 1753 * Do all sorts of validation on the passed-in cursor structure. 1754 * If anything is amiss, ignore the cursor and look up the hashval 1755 * starting from the btree root. 1756 */ 1757 bp = NULL; 1758 if (cursor->blkno > 0) { 1759 error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, 1760 &bp, XFS_ATTR_FORK); 1761 if ((error != 0) && (error != EFSCORRUPTED)) 1762 return(error); 1763 if (bp) { 1764 node = bp->data; 1765 switch (be16_to_cpu(node->hdr.info.magic)) { 1766 case XFS_DA_NODE_MAGIC: 1767 xfs_attr_trace_l_cn("wrong blk", context, node); 1768 xfs_da_brelse(NULL, bp); 1769 bp = NULL; 1770 break; 1771 case XFS_ATTR_LEAF_MAGIC: 1772 leaf = bp->data; 1773 if (cursor->hashval > be32_to_cpu(leaf->entries[ 1774 be16_to_cpu(leaf->hdr.count)-1].hashval)) { 1775 xfs_attr_trace_l_cl("wrong blk", 1776 context, leaf); 1777 xfs_da_brelse(NULL, bp); 1778 bp = NULL; 1779 } else if (cursor->hashval <= 1780 be32_to_cpu(leaf->entries[0].hashval)) { 1781 xfs_attr_trace_l_cl("maybe wrong blk", 1782 context, leaf); 1783 xfs_da_brelse(NULL, bp); 1784 bp = NULL; 1785 } 1786 break; 1787 default: 1788 xfs_attr_trace_l_c("wrong blk - ??", context); 1789 xfs_da_brelse(NULL, bp); 1790 bp = NULL; 1791 } 1792 } 1793 } 1794 1795 /* 1796 * We did not find what we expected given the cursor's contents, 1797 * so we start from the top and work down based on the hash value. 1798 * Note that start of node block is same as start of leaf block. 1799 */ 1800 if (bp == NULL) { 1801 cursor->blkno = 0; 1802 for (;;) { 1803 error = xfs_da_read_buf(NULL, context->dp, 1804 cursor->blkno, -1, &bp, 1805 XFS_ATTR_FORK); 1806 if (error) 1807 return(error); 1808 if (unlikely(bp == NULL)) { 1809 XFS_ERROR_REPORT("xfs_attr_node_list(2)", 1810 XFS_ERRLEVEL_LOW, 1811 context->dp->i_mount); 1812 return(XFS_ERROR(EFSCORRUPTED)); 1813 } 1814 node = bp->data; 1815 if (be16_to_cpu(node->hdr.info.magic) 1816 == XFS_ATTR_LEAF_MAGIC) 1817 break; 1818 if (unlikely(be16_to_cpu(node->hdr.info.magic) 1819 != XFS_DA_NODE_MAGIC)) { 1820 XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)", 1821 XFS_ERRLEVEL_LOW, 1822 context->dp->i_mount, 1823 node); 1824 xfs_da_brelse(NULL, bp); 1825 return(XFS_ERROR(EFSCORRUPTED)); 1826 } 1827 btree = node->btree; 1828 for (i = 0; i < be16_to_cpu(node->hdr.count); 1829 btree++, i++) { 1830 if (cursor->hashval 1831 <= be32_to_cpu(btree->hashval)) { 1832 cursor->blkno = be32_to_cpu(btree->before); 1833 xfs_attr_trace_l_cb("descending", 1834 context, btree); 1835 break; 1836 } 1837 } 1838 if (i == be16_to_cpu(node->hdr.count)) { 1839 xfs_da_brelse(NULL, bp); 1840 return(0); 1841 } 1842 xfs_da_brelse(NULL, bp); 1843 } 1844 } 1845 ASSERT(bp != NULL); 1846 1847 /* 1848 * Roll upward through the blocks, processing each leaf block in 1849 * order. As long as there is space in the result buffer, keep 1850 * adding the information. 1851 */ 1852 for (;;) { 1853 leaf = bp->data; 1854 if (unlikely(be16_to_cpu(leaf->hdr.info.magic) 1855 != XFS_ATTR_LEAF_MAGIC)) { 1856 XFS_CORRUPTION_ERROR("xfs_attr_node_list(4)", 1857 XFS_ERRLEVEL_LOW, 1858 context->dp->i_mount, leaf); 1859 xfs_da_brelse(NULL, bp); 1860 return(XFS_ERROR(EFSCORRUPTED)); 1861 } 1862 error = xfs_attr_leaf_list_int(bp, context); 1863 if (error || !leaf->hdr.info.forw) 1864 break; /* not really an error, buffer full or EOF */ 1865 cursor->blkno = be32_to_cpu(leaf->hdr.info.forw); 1866 xfs_da_brelse(NULL, bp); 1867 error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, 1868 &bp, XFS_ATTR_FORK); 1869 if (error) 1870 return(error); 1871 if (unlikely((bp == NULL))) { 1872 XFS_ERROR_REPORT("xfs_attr_node_list(5)", 1873 XFS_ERRLEVEL_LOW, 1874 context->dp->i_mount); 1875 return(XFS_ERROR(EFSCORRUPTED)); 1876 } 1877 } 1878 xfs_da_brelse(NULL, bp); 1879 return(0); 1880} 1881 1882 1883/*======================================================================== 1884 * External routines for manipulating out-of-line attribute values. 1885 *========================================================================*/ 1886 1887/* 1888 * Read the value associated with an attribute from the out-of-line buffer 1889 * that we stored it in. 1890 */ 1891STATIC int 1892xfs_attr_rmtval_get(xfs_da_args_t *args) 1893{ 1894 xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; 1895 xfs_mount_t *mp; 1896 xfs_daddr_t dblkno; 1897 xfs_caddr_t dst; 1898 xfs_buf_t *bp; 1899 int nmap, error, tmp, valuelen, blkcnt, i; 1900 xfs_dablk_t lblkno; 1901 1902 ASSERT(!(args->flags & ATTR_KERNOVAL)); 1903 1904 mp = args->dp->i_mount; 1905 dst = args->value; 1906 valuelen = args->valuelen; 1907 lblkno = args->rmtblkno; 1908 while (valuelen > 0) { 1909 nmap = ATTR_RMTVALUE_MAPSIZE; 1910 error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno, 1911 args->rmtblkcnt, 1912 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, 1913 NULL, 0, map, &nmap, NULL, NULL); 1914 if (error) 1915 return(error); 1916 ASSERT(nmap >= 1); 1917 1918 for (i = 0; (i < nmap) && (valuelen > 0); i++) { 1919 ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && 1920 (map[i].br_startblock != HOLESTARTBLOCK)); 1921 dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); 1922 blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); 1923 error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno, 1924 blkcnt, XFS_BUF_LOCK, &bp); 1925 if (error) 1926 return(error); 1927 1928 tmp = (valuelen < XFS_BUF_SIZE(bp)) 1929 ? valuelen : XFS_BUF_SIZE(bp); 1930 xfs_biomove(bp, 0, tmp, dst, XFS_B_READ); 1931 xfs_buf_relse(bp); 1932 dst += tmp; 1933 valuelen -= tmp; 1934 1935 lblkno += map[i].br_blockcount; 1936 } 1937 } 1938 ASSERT(valuelen == 0); 1939 return(0); 1940} 1941 1942/* 1943 * Write the value associated with an attribute into the out-of-line buffer 1944 * that we have defined for it. 1945 */ 1946STATIC int 1947xfs_attr_rmtval_set(xfs_da_args_t *args) 1948{ 1949 xfs_mount_t *mp; 1950 xfs_fileoff_t lfileoff; 1951 xfs_inode_t *dp; 1952 xfs_bmbt_irec_t map; 1953 xfs_daddr_t dblkno; 1954 xfs_caddr_t src; 1955 xfs_buf_t *bp; 1956 xfs_dablk_t lblkno; 1957 int blkcnt, valuelen, nmap, error, tmp, committed; 1958 1959 dp = args->dp; 1960 mp = dp->i_mount; 1961 src = args->value; 1962 1963 /* 1964 * Find a "hole" in the attribute address space large enough for 1965 * us to drop the new attribute's value into. 1966 */ 1967 blkcnt = XFS_B_TO_FSB(mp, args->valuelen); 1968 lfileoff = 0; 1969 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, 1970 XFS_ATTR_FORK); 1971 if (error) { 1972 return(error); 1973 } 1974 args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; 1975 args->rmtblkcnt = blkcnt; 1976 1977 /* 1978 * Roll through the "value", allocating blocks on disk as required. 1979 */ 1980 while (blkcnt > 0) { 1981 /* 1982 * Allocate a single extent, up to the size of the value. 1983 */ 1984 XFS_BMAP_INIT(args->flist, args->firstblock); 1985 nmap = 1; 1986 error = xfs_bmapi(args->trans, dp, (xfs_fileoff_t)lblkno, 1987 blkcnt, 1988 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA | 1989 XFS_BMAPI_WRITE, 1990 args->firstblock, args->total, &map, &nmap, 1991 args->flist, NULL); 1992 if (!error) { 1993 error = xfs_bmap_finish(&args->trans, args->flist, 1994 *args->firstblock, &committed); 1995 } 1996 if (error) { 1997 ASSERT(committed); 1998 args->trans = NULL; 1999 xfs_bmap_cancel(args->flist); 2000 return(error); 2001 } 2002 2003 /* 2004 * bmap_finish() may have committed the last trans and started 2005 * a new one. We need the inode to be in all transactions. 2006 */ 2007 if (committed) { 2008 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 2009 xfs_trans_ihold(args->trans, dp); 2010 } 2011 2012 ASSERT(nmap == 1); 2013 ASSERT((map.br_startblock != DELAYSTARTBLOCK) && 2014 (map.br_startblock != HOLESTARTBLOCK)); 2015 lblkno += map.br_blockcount; 2016 blkcnt -= map.br_blockcount; 2017 2018 /* 2019 * Start the next trans in the chain. 2020 */ 2021 if ((error = xfs_attr_rolltrans(&args->trans, dp))) 2022 return (error); 2023 } 2024 2025 /* 2026 * Roll through the "value", copying the attribute value to the 2027 * already-allocated blocks. Blocks are written synchronously 2028 * so that we can know they are all on disk before we turn off 2029 * the INCOMPLETE flag. 2030 */ 2031 lblkno = args->rmtblkno; 2032 valuelen = args->valuelen; 2033 while (valuelen > 0) { 2034 /* 2035 * Try to remember where we decided to put the value. 2036 */ 2037 XFS_BMAP_INIT(args->flist, args->firstblock); 2038 nmap = 1; 2039 error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno, 2040 args->rmtblkcnt, 2041 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, 2042 args->firstblock, 0, &map, &nmap, 2043 NULL, NULL); 2044 if (error) { 2045 return(error); 2046 } 2047 ASSERT(nmap == 1); 2048 ASSERT((map.br_startblock != DELAYSTARTBLOCK) && 2049 (map.br_startblock != HOLESTARTBLOCK)); 2050 2051 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 2052 blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 2053 2054 bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno, 2055 blkcnt, XFS_BUF_LOCK); 2056 ASSERT(bp); 2057 ASSERT(!XFS_BUF_GETERROR(bp)); 2058 2059 tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen : 2060 XFS_BUF_SIZE(bp); 2061 xfs_biomove(bp, 0, tmp, src, XFS_B_WRITE); 2062 if (tmp < XFS_BUF_SIZE(bp)) 2063 xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp); 2064 if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */ 2065 return (error); 2066 } 2067 src += tmp; 2068 valuelen -= tmp; 2069 2070 lblkno += map.br_blockcount; 2071 } 2072 ASSERT(valuelen == 0); 2073 return(0); 2074} 2075 2076/* 2077 * Remove the value associated with an attribute by deleting the 2078 * out-of-line buffer that it is stored on. 2079 */ 2080STATIC int 2081xfs_attr_rmtval_remove(xfs_da_args_t *args) 2082{ 2083 xfs_mount_t *mp; 2084 xfs_bmbt_irec_t map; 2085 xfs_buf_t *bp; 2086 xfs_daddr_t dblkno; 2087 xfs_dablk_t lblkno; 2088 int valuelen, blkcnt, nmap, error, done, committed; 2089 2090 mp = args->dp->i_mount; 2091 2092 /* 2093 * Roll through the "value", invalidating the attribute value's 2094 * blocks. 2095 */ 2096 lblkno = args->rmtblkno; 2097 valuelen = args->rmtblkcnt; 2098 while (valuelen > 0) { 2099 /* 2100 * Try to remember where we decided to put the value. 2101 */ 2102 XFS_BMAP_INIT(args->flist, args->firstblock); 2103 nmap = 1; 2104 error = xfs_bmapi(NULL, args->dp, (xfs_fileoff_t)lblkno, 2105 args->rmtblkcnt, 2106 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, 2107 args->firstblock, 0, &map, &nmap, 2108 args->flist, NULL); 2109 if (error) { 2110 return(error); 2111 } 2112 ASSERT(nmap == 1); 2113 ASSERT((map.br_startblock != DELAYSTARTBLOCK) && 2114 (map.br_startblock != HOLESTARTBLOCK)); 2115 2116 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 2117 blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 2118 2119 /* 2120 * If the "remote" value is in the cache, remove it. 2121 */ 2122 bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, 2123 XFS_INCORE_TRYLOCK); 2124 if (bp) { 2125 XFS_BUF_STALE(bp); 2126 XFS_BUF_UNDELAYWRITE(bp); 2127 xfs_buf_relse(bp); 2128 bp = NULL; 2129 } 2130 2131 valuelen -= map.br_blockcount; 2132 2133 lblkno += map.br_blockcount; 2134 } 2135 2136 /* 2137 * Keep de-allocating extents until the remote-value region is gone. 2138 */ 2139 lblkno = args->rmtblkno; 2140 blkcnt = args->rmtblkcnt; 2141 done = 0; 2142 while (!done) { 2143 XFS_BMAP_INIT(args->flist, args->firstblock); 2144 error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, 2145 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, 2146 1, args->firstblock, args->flist, 2147 NULL, &done); 2148 if (!error) { 2149 error = xfs_bmap_finish(&args->trans, args->flist, 2150 *args->firstblock, &committed); 2151 } 2152 if (error) { 2153 ASSERT(committed); 2154 args->trans = NULL; 2155 xfs_bmap_cancel(args->flist); 2156 return(error); 2157 } 2158 2159 /* 2160 * bmap_finish() may have committed the last trans and started 2161 * a new one. We need the inode to be in all transactions. 2162 */ 2163 if (committed) { 2164 xfs_trans_ijoin(args->trans, args->dp, XFS_ILOCK_EXCL); 2165 xfs_trans_ihold(args->trans, args->dp); 2166 } 2167 2168 /* 2169 * Close out trans and start the next one in the chain. 2170 */ 2171 if ((error = xfs_attr_rolltrans(&args->trans, args->dp))) 2172 return (error); 2173 } 2174 return(0); 2175} 2176 2177#if defined(XFS_ATTR_TRACE) 2178/* 2179 * Add a trace buffer entry for an attr_list context structure. 2180 */ 2181void 2182xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context) 2183{ 2184 xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, 2185 (__psunsigned_t)context->dp, 2186 (__psunsigned_t)context->cursor->hashval, 2187 (__psunsigned_t)context->cursor->blkno, 2188 (__psunsigned_t)context->cursor->offset, 2189 (__psunsigned_t)context->alist, 2190 (__psunsigned_t)context->bufsize, 2191 (__psunsigned_t)context->count, 2192 (__psunsigned_t)context->firstu, 2193 (__psunsigned_t) 2194 ((context->count > 0) && 2195 !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) 2196 ? (ATTR_ENTRY(context->alist, 2197 context->count-1)->a_valuelen) 2198 : 0, 2199 (__psunsigned_t)context->dupcnt, 2200 (__psunsigned_t)context->flags, 2201 (__psunsigned_t)NULL, 2202 (__psunsigned_t)NULL, 2203 (__psunsigned_t)NULL); 2204} 2205 2206/* 2207 * Add a trace buffer entry for a context structure and a Btree node. 2208 */ 2209void 2210xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, 2211 struct xfs_da_intnode *node) 2212{ 2213 xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, 2214 (__psunsigned_t)context->dp, 2215 (__psunsigned_t)context->cursor->hashval, 2216 (__psunsigned_t)context->cursor->blkno, 2217 (__psunsigned_t)context->cursor->offset, 2218 (__psunsigned_t)context->alist, 2219 (__psunsigned_t)context->bufsize, 2220 (__psunsigned_t)context->count, 2221 (__psunsigned_t)context->firstu, 2222 (__psunsigned_t) 2223 ((context->count > 0) && 2224 !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) 2225 ? (ATTR_ENTRY(context->alist, 2226 context->count-1)->a_valuelen) 2227 : 0, 2228 (__psunsigned_t)context->dupcnt, 2229 (__psunsigned_t)context->flags, 2230 (__psunsigned_t)be16_to_cpu(node->hdr.count), 2231 (__psunsigned_t)be32_to_cpu(node->btree[0].hashval), 2232 (__psunsigned_t)be32_to_cpu(node->btree[ 2233 be16_to_cpu(node->hdr.count)-1].hashval)); 2234} 2235 2236/* 2237 * Add a trace buffer entry for a context structure and a Btree element. 2238 */ 2239void 2240xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, 2241 struct xfs_da_node_entry *btree) 2242{ 2243 xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, 2244 (__psunsigned_t)context->dp, 2245 (__psunsigned_t)context->cursor->hashval, 2246 (__psunsigned_t)context->cursor->blkno, 2247 (__psunsigned_t)context->cursor->offset, 2248 (__psunsigned_t)context->alist, 2249 (__psunsigned_t)context->bufsize, 2250 (__psunsigned_t)context->count, 2251 (__psunsigned_t)context->firstu, 2252 (__psunsigned_t) 2253 ((context->count > 0) && 2254 !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) 2255 ? (ATTR_ENTRY(context->alist, 2256 context->count-1)->a_valuelen) 2257 : 0, 2258 (__psunsigned_t)context->dupcnt, 2259 (__psunsigned_t)context->flags, 2260 (__psunsigned_t)be32_to_cpu(btree->hashval), 2261 (__psunsigned_t)be32_to_cpu(btree->before), 2262 (__psunsigned_t)NULL); 2263} 2264 2265/* 2266 * Add a trace buffer entry for a context structure and a leaf block. 2267 */ 2268void 2269xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, 2270 struct xfs_attr_leafblock *leaf) 2271{ 2272 xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, 2273 (__psunsigned_t)context->dp, 2274 (__psunsigned_t)context->cursor->hashval, 2275 (__psunsigned_t)context->cursor->blkno, 2276 (__psunsigned_t)context->cursor->offset, 2277 (__psunsigned_t)context->alist, 2278 (__psunsigned_t)context->bufsize, 2279 (__psunsigned_t)context->count, 2280 (__psunsigned_t)context->firstu, 2281 (__psunsigned_t) 2282 ((context->count > 0) && 2283 !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) 2284 ? (ATTR_ENTRY(context->alist, 2285 context->count-1)->a_valuelen) 2286 : 0, 2287 (__psunsigned_t)context->dupcnt, 2288 (__psunsigned_t)context->flags, 2289 (__psunsigned_t)be16_to_cpu(leaf->hdr.count), 2290 (__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval), 2291 (__psunsigned_t)be32_to_cpu(leaf->entries[ 2292 be16_to_cpu(leaf->hdr.count)-1].hashval)); 2293} 2294 2295/* 2296 * Add a trace buffer entry for the arguments given to the routine, 2297 * generic form. 2298 */ 2299void 2300xfs_attr_trace_enter(int type, char *where, 2301 __psunsigned_t a2, __psunsigned_t a3, 2302 __psunsigned_t a4, __psunsigned_t a5, 2303 __psunsigned_t a6, __psunsigned_t a7, 2304 __psunsigned_t a8, __psunsigned_t a9, 2305 __psunsigned_t a10, __psunsigned_t a11, 2306 __psunsigned_t a12, __psunsigned_t a13, 2307 __psunsigned_t a14, __psunsigned_t a15) 2308{ 2309 ASSERT(xfs_attr_trace_buf); 2310 ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type), 2311 (void *)where, 2312 (void *)a2, (void *)a3, (void *)a4, 2313 (void *)a5, (void *)a6, (void *)a7, 2314 (void *)a8, (void *)a9, (void *)a10, 2315 (void *)a11, (void *)a12, (void *)a13, 2316 (void *)a14, (void *)a15); 2317} 2318#endif /* XFS_ATTR_TRACE */ 2319 2320 2321/*======================================================================== 2322 * System (pseudo) namespace attribute interface routines. 2323 *========================================================================*/ 2324 2325STATIC int 2326posix_acl_access_set( 2327 xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags) 2328{ 2329 return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS); 2330} 2331 2332STATIC int 2333posix_acl_access_remove( 2334 struct xfs_vnode *vp, char *name, int xflags) 2335{ 2336 return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); 2337} 2338 2339STATIC int 2340posix_acl_access_get( 2341 xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags) 2342{ 2343 return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS); 2344} 2345 2346STATIC int 2347posix_acl_access_exists( 2348 xfs_vnode_t *vp) 2349{ 2350 return xfs_acl_vhasacl_access(vp); 2351} 2352 2353STATIC int 2354posix_acl_default_set( 2355 xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags) 2356{ 2357 return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT); 2358} 2359 2360STATIC int 2361posix_acl_default_get( 2362 xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags) 2363{ 2364 return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT); 2365} 2366 2367STATIC int 2368posix_acl_default_remove( 2369 struct xfs_vnode *vp, char *name, int xflags) 2370{ 2371 return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT); 2372} 2373 2374STATIC int 2375posix_acl_default_exists( 2376 xfs_vnode_t *vp) 2377{ 2378 return xfs_acl_vhasacl_default(vp); 2379} 2380 2381STATIC struct attrnames posix_acl_access = { 2382 .attr_name = "posix_acl_access", 2383 .attr_namelen = sizeof("posix_acl_access") - 1, 2384 .attr_get = posix_acl_access_get, 2385 .attr_set = posix_acl_access_set, 2386 .attr_remove = posix_acl_access_remove, 2387 .attr_exists = posix_acl_access_exists, 2388}; 2389 2390STATIC struct attrnames posix_acl_default = { 2391 .attr_name = "posix_acl_default", 2392 .attr_namelen = sizeof("posix_acl_default") - 1, 2393 .attr_get = posix_acl_default_get, 2394 .attr_set = posix_acl_default_set, 2395 .attr_remove = posix_acl_default_remove, 2396 .attr_exists = posix_acl_default_exists, 2397}; 2398 2399STATIC struct attrnames *attr_system_names[] = 2400 { &posix_acl_access, &posix_acl_default }; 2401 2402 2403/*======================================================================== 2404 * Namespace-prefix-style attribute name interface routines. 2405 *========================================================================*/ 2406 2407STATIC int 2408attr_generic_set( 2409 struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags) 2410{ 2411 int error; 2412 2413 XVOP_ATTR_SET(vp, name, data, size, xflags, NULL, error); 2414 return -error; 2415} 2416 2417STATIC int 2418attr_generic_get( 2419 struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags) 2420{ 2421 int error, asize = size; 2422 2423 XVOP_ATTR_GET(vp, name, data, &asize, xflags, NULL, error); 2424 if (!error) 2425 return asize; 2426 return -error; 2427} 2428 2429STATIC int 2430attr_generic_remove( 2431 struct xfs_vnode *vp, char *name, int xflags) 2432{ 2433 int error; 2434 2435 XVOP_ATTR_REMOVE(vp, name, xflags, NULL, error); 2436 return -error; 2437} 2438 2439STATIC int 2440attr_generic_listadd( 2441 attrnames_t *prefix, 2442 attrnames_t *namesp, 2443 void *data, 2444 size_t size, 2445 ssize_t *result) 2446{ 2447 char *p = (char *)data + *result; 2448 2449 *result += prefix->attr_namelen; 2450 *result += namesp->attr_namelen + 1; 2451 if (!size) 2452 return 0; 2453 if (*result > size) 2454 return -ERANGE; 2455 strcpy(p, prefix->attr_name); 2456 p += prefix->attr_namelen; 2457 strcpy(p, namesp->attr_name); 2458 p += namesp->attr_namelen + 1; 2459 return 0; 2460} 2461 2462STATIC int 2463attr_system_list( 2464 struct xfs_vnode *vp, 2465 void *data, 2466 size_t size, 2467 ssize_t *result) 2468{ 2469 attrnames_t *namesp; 2470 int i, error = 0; 2471 2472 for (i = 0; i < ATTR_SYSCOUNT; i++) { 2473 namesp = attr_system_names[i]; 2474 if (!namesp->attr_exists || !namesp->attr_exists(vp)) 2475 continue; 2476 error = attr_generic_listadd(&attr_system, namesp, 2477 data, size, result); 2478 if (error) 2479 break; 2480 } 2481 return error; 2482} 2483 2484int 2485attr_generic_list( 2486 struct xfs_vnode *vp, void *data, size_t size, int xflags, ssize_t *result) 2487{ 2488 attrlist_cursor_kern_t cursor = { 0 }; 2489 int error; 2490 2491 XVOP_ATTR_LIST(vp, data, size, xflags, &cursor, NULL, error); 2492 if (error > 0) 2493 return -error; 2494 *result = -error; 2495 return attr_system_list(vp, data, size, result); 2496} 2497 2498attrnames_t * 2499attr_lookup_namespace( 2500 char *name, 2501 struct attrnames **names, 2502 int nnames) 2503{ 2504 int i; 2505 2506 for (i = 0; i < nnames; i++) 2507 if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen)) 2508 return names[i]; 2509 return NULL; 2510} 2511 2512/* 2513 * Some checks to prevent people abusing EAs to get over quota: 2514 * - Don't allow modifying user EAs on devices/symlinks; 2515 * - Don't allow modifying user EAs if sticky bit set; 2516 */ 2517STATIC int 2518attr_user_capable( 2519 struct xfs_vnode *vp, 2520 cred_t *cred) 2521{ 2522#ifdef XXXKAN 2523 struct inode *inode = vn_to_inode(vp); 2524 2525 if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) 2526 return -EPERM; 2527 if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) && 2528 !capable(CAP_SYS_ADMIN)) 2529 return -EPERM; 2530 if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && 2531 (current_fsuid(cred) != inode->i_uid) && !capable(CAP_FOWNER)) 2532 return -EPERM; 2533#endif 2534 return 0; 2535} 2536 2537STATIC int 2538attr_trusted_capable( 2539 struct xfs_vnode *vp, 2540 cred_t *cred) 2541{ 2542#ifdef XXXKAN 2543 struct inode *inode = vn_to_inode(vp); 2544 2545 if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) 2546 return -EPERM; 2547 if (!capable(CAP_SYS_ADMIN)) 2548 return -EPERM; 2549#endif 2550 return 0; 2551} 2552 2553STATIC int 2554attr_secure_capable( 2555 struct xfs_vnode *vp, 2556 cred_t *cred) 2557{ 2558 return -ENOSECURITY; 2559} 2560 2561STATIC int 2562attr_system_set( 2563 struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags) 2564{ 2565 attrnames_t *namesp; 2566 int error; 2567 2568 if (xflags & ATTR_CREATE) 2569 return -EINVAL; 2570 2571 namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); 2572 if (!namesp) 2573 return -EOPNOTSUPP; 2574 error = namesp->attr_set(vp, name, data, size, xflags); 2575#ifdef XXXKAN 2576 if (!error) 2577 error = vn_revalidate(vp); 2578#endif 2579 return error; 2580} 2581 2582STATIC int 2583attr_system_get( 2584 struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags) 2585{ 2586 attrnames_t *namesp; 2587 2588 namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); 2589 if (!namesp) 2590 return -EOPNOTSUPP; 2591 return namesp->attr_get(vp, name, data, size, xflags); 2592} 2593 2594STATIC int 2595attr_system_remove( 2596 struct xfs_vnode *vp, char *name, int xflags) 2597{ 2598 attrnames_t *namesp; 2599 2600 namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); 2601 if (!namesp) 2602 return -EOPNOTSUPP; 2603 return namesp->attr_remove(vp, name, xflags); 2604} 2605 2606struct attrnames attr_system = { 2607 .attr_name = "system.", 2608 .attr_namelen = sizeof("system.") - 1, 2609 .attr_flag = ATTR_SYSTEM, 2610 .attr_get = attr_system_get, 2611 .attr_set = attr_system_set, 2612 .attr_remove = attr_system_remove, 2613 .attr_capable = (attrcapable_t)fs_noerr, 2614}; 2615 2616struct attrnames attr_trusted = { 2617 .attr_name = "trusted.", 2618 .attr_namelen = sizeof("trusted.") - 1, 2619 .attr_flag = ATTR_ROOT, 2620 .attr_get = attr_generic_get, 2621 .attr_set = attr_generic_set, 2622 .attr_remove = attr_generic_remove, 2623 .attr_capable = attr_trusted_capable, 2624}; 2625 2626struct attrnames attr_secure = { 2627 .attr_name = "security.", 2628 .attr_namelen = sizeof("security.") - 1, 2629 .attr_flag = ATTR_SECURE, 2630 .attr_get = attr_generic_get, 2631 .attr_set = attr_generic_set, 2632 .attr_remove = attr_generic_remove, 2633 .attr_capable = attr_secure_capable, 2634}; 2635 2636struct attrnames attr_user = { 2637 .attr_name = "user.", 2638 .attr_namelen = sizeof("user.") - 1, 2639 .attr_get = attr_generic_get, 2640 .attr_set = attr_generic_set, 2641 .attr_remove = attr_generic_remove, 2642 .attr_capable = attr_user_capable, 2643}; 2644 2645struct attrnames *attr_namespaces[] = 2646 { &attr_system, &attr_trusted, &attr_secure, &attr_user }; 2647