1153323Srodrigc/* 2159451Srodrigc * Copyright (c) 2000-2005 Silicon Graphics, Inc. 3159451Srodrigc * All Rights Reserved. 4153323Srodrigc * 5159451Srodrigc * This program is free software; you can redistribute it and/or 6159451Srodrigc * modify it under the terms of the GNU General Public License as 7153323Srodrigc * published by the Free Software Foundation. 8153323Srodrigc * 9159451Srodrigc * This program is distributed in the hope that it would be useful, 10159451Srodrigc * but WITHOUT ANY WARRANTY; without even the implied warranty of 11159451Srodrigc * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12159451Srodrigc * GNU General Public License for more details. 13153323Srodrigc * 14159451Srodrigc * You should have received a copy of the GNU General Public License 15159451Srodrigc * along with this program; if not, write the Free Software Foundation, 16159451Srodrigc * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17153323Srodrigc */ 18153323Srodrigc 19159451Srodrigc//#include <linux/capability.h> 20159451Srodrigc 21153323Srodrigc#include "xfs.h" 22159451Srodrigc#include "xfs_fs.h" 23153323Srodrigc#include "xfs_types.h" 24159451Srodrigc#include "xfs_bit.h" 25159451Srodrigc#include "xfs_log.h" 26153323Srodrigc#include "xfs_inum.h" 27153323Srodrigc#include "xfs_trans.h" 28153323Srodrigc#include "xfs_sb.h" 29153323Srodrigc#include "xfs_ag.h" 30153323Srodrigc#include "xfs_dir.h" 31153323Srodrigc#include "xfs_dir2.h" 32153323Srodrigc#include "xfs_dmapi.h" 33153323Srodrigc#include "xfs_mount.h" 34159451Srodrigc#include "xfs_da_btree.h" 35159451Srodrigc#include "xfs_bmap_btree.h" 36153323Srodrigc#include "xfs_alloc_btree.h" 37153323Srodrigc#include "xfs_ialloc_btree.h" 38153323Srodrigc#include "xfs_dir_sf.h" 39153323Srodrigc#include "xfs_dir2_sf.h" 40159451Srodrigc#include "xfs_attr_sf.h" 41153323Srodrigc#include "xfs_dinode.h" 42159451Srodrigc#include "xfs_inode.h" 43159451Srodrigc#include "xfs_alloc.h" 44159451Srodrigc#include "xfs_btree.h" 45153323Srodrigc#include "xfs_inode_item.h" 46153323Srodrigc#include "xfs_bmap.h" 47153323Srodrigc#include "xfs_attr.h" 48153323Srodrigc#include "xfs_attr_leaf.h" 49153323Srodrigc#include "xfs_error.h" 50153323Srodrigc#include "xfs_quota.h" 51153323Srodrigc#include "xfs_trans_space.h" 52153323Srodrigc#include "xfs_acl.h" 53159451Srodrigc#include "xfs_rw.h" 54153323Srodrigc 55153323Srodrigc/* 56153323Srodrigc * xfs_attr.c 57153323Srodrigc * 58153323Srodrigc * Provide the external interfaces to manage attribute lists. 59153323Srodrigc */ 60153323Srodrigc 61159451Srodrigc#define ATTR_SYSCOUNT 2 62159451SrodrigcSTATIC struct attrnames posix_acl_access; 63159451SrodrigcSTATIC struct attrnames posix_acl_default; 64159451SrodrigcSTATIC struct attrnames *attr_system_names[ATTR_SYSCOUNT]; 65159451Srodrigc 66153323Srodrigc/*======================================================================== 67153323Srodrigc * Function prototypes for the kernel. 68153323Srodrigc *========================================================================*/ 69153323Srodrigc 70153323Srodrigc/* 71153323Srodrigc * Internal routines when attribute list fits inside the inode. 72153323Srodrigc */ 73153323SrodrigcSTATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); 74153323Srodrigc 75153323Srodrigc/* 76153323Srodrigc * Internal routines when attribute list is one block. 77153323Srodrigc */ 78159451SrodrigcSTATIC int xfs_attr_leaf_get(xfs_da_args_t *args); 79153323SrodrigcSTATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); 80153323SrodrigcSTATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); 81153323SrodrigcSTATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context); 82153323Srodrigc 83153323Srodrigc/* 84153323Srodrigc * Internal routines when attribute list is more than one block. 85153323Srodrigc */ 86159451SrodrigcSTATIC int xfs_attr_node_get(xfs_da_args_t *args); 87153323SrodrigcSTATIC int xfs_attr_node_addname(xfs_da_args_t *args); 88153323SrodrigcSTATIC int xfs_attr_node_removename(xfs_da_args_t *args); 89153323SrodrigcSTATIC int xfs_attr_node_list(xfs_attr_list_context_t *context); 90153323SrodrigcSTATIC int xfs_attr_fillstate(xfs_da_state_t *state); 91153323SrodrigcSTATIC int xfs_attr_refillstate(xfs_da_state_t *state); 92153323Srodrigc 93153323Srodrigc/* 94153323Srodrigc * Routines to manipulate out-of-line attribute values. 95153323Srodrigc */ 96153323SrodrigcSTATIC int xfs_attr_rmtval_get(xfs_da_args_t *args); 97153323SrodrigcSTATIC int xfs_attr_rmtval_set(xfs_da_args_t *args); 98153323SrodrigcSTATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); 99153323Srodrigc 100153323Srodrigc#define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ 101153323Srodrigc 102153323Srodrigc#if defined(XFS_ATTR_TRACE) 103153323Srodrigcktrace_t *xfs_attr_trace_buf; 104153323Srodrigc#endif 105153323Srodrigc 106153323Srodrigc 107153323Srodrigc/*======================================================================== 108153323Srodrigc * Overall external interface routines. 109153323Srodrigc *========================================================================*/ 110153323Srodrigc 111159451Srodrigcint 112159451Srodrigcxfs_attr_fetch(xfs_inode_t *ip, const char *name, int namelen, 113159451Srodrigc char *value, int *valuelenp, int flags, struct cred *cred) 114153323Srodrigc{ 115153323Srodrigc xfs_da_args_t args; 116153323Srodrigc int error; 117153323Srodrigc 118153323Srodrigc if ((XFS_IFORK_Q(ip) == 0) || 119153323Srodrigc (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 120153323Srodrigc ip->i_d.di_anextents == 0)) 121153323Srodrigc return(ENOATTR); 122153323Srodrigc 123153323Srodrigc /* 124153323Srodrigc * Fill in the arg structure for this request. 125153323Srodrigc */ 126153323Srodrigc memset((char *)&args, 0, sizeof(args)); 127153323Srodrigc args.name = name; 128153323Srodrigc args.namelen = namelen; 129153323Srodrigc args.value = value; 130153323Srodrigc args.valuelen = *valuelenp; 131153323Srodrigc args.flags = flags; 132153323Srodrigc args.hashval = xfs_da_hashname(args.name, args.namelen); 133153323Srodrigc args.dp = ip; 134153323Srodrigc args.whichfork = XFS_ATTR_FORK; 135153323Srodrigc 136153323Srodrigc /* 137153323Srodrigc * Decide on what work routines to call based on the inode size. 138153323Srodrigc */ 139153323Srodrigc if (XFS_IFORK_Q(ip) == 0 || 140153323Srodrigc (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 141153323Srodrigc ip->i_d.di_anextents == 0)) { 142153323Srodrigc error = XFS_ERROR(ENOATTR); 143153323Srodrigc } else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { 144153323Srodrigc error = xfs_attr_shortform_getvalue(&args); 145153323Srodrigc } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) { 146153323Srodrigc error = xfs_attr_leaf_get(&args); 147153323Srodrigc } else { 148153323Srodrigc error = xfs_attr_node_get(&args); 149153323Srodrigc } 150153323Srodrigc 151153323Srodrigc /* 152153323Srodrigc * Return the number of bytes in the value to the caller. 153153323Srodrigc */ 154153323Srodrigc *valuelenp = args.valuelen; 155153323Srodrigc 156153323Srodrigc if (error == EEXIST) 157153323Srodrigc error = 0; 158153323Srodrigc return(error); 159153323Srodrigc} 160153323Srodrigc 161153323Srodrigcint 162153323Srodrigcxfs_attr_get(bhv_desc_t *bdp, const char *name, char *value, int *valuelenp, 163153323Srodrigc int flags, struct cred *cred) 164153323Srodrigc{ 165153323Srodrigc xfs_inode_t *ip = XFS_BHVTOI(bdp); 166159451Srodrigc int error, namelen; 167153323Srodrigc 168159451Srodrigc XFS_STATS_INC(xs_attr_get); 169159451Srodrigc 170153323Srodrigc if (!name) 171153323Srodrigc return(EINVAL); 172159451Srodrigc namelen = strlen(name); 173159451Srodrigc if (namelen >= MAXNAMELEN) 174159451Srodrigc return(EFAULT); /* match IRIX behaviour */ 175159451Srodrigc 176159451Srodrigc if (XFS_FORCED_SHUTDOWN(ip->i_mount)) 177159451Srodrigc return(EIO); 178159451Srodrigc 179159451Srodrigc xfs_ilock(ip, XFS_ILOCK_SHARED); 180159451Srodrigc error = xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, cred); 181159451Srodrigc xfs_iunlock(ip, XFS_ILOCK_SHARED); 182159451Srodrigc return(error); 183153323Srodrigc} 184153323Srodrigc 185159451SrodrigcSTATIC int 186159451Srodrigcxfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, 187159451Srodrigc char *value, int valuelen, int flags) 188153323Srodrigc{ 189153323Srodrigc xfs_da_args_t args; 190153323Srodrigc xfs_fsblock_t firstblock; 191153323Srodrigc xfs_bmap_free_t flist; 192153323Srodrigc int error, err2, committed; 193153323Srodrigc int local, size; 194153323Srodrigc uint nblks; 195159451Srodrigc xfs_mount_t *mp = dp->i_mount; 196153323Srodrigc int rsvd = (flags & ATTR_ROOT) != 0; 197153323Srodrigc 198153323Srodrigc /* 199153323Srodrigc * Attach the dquots to the inode. 200153323Srodrigc */ 201153323Srodrigc if ((error = XFS_QM_DQATTACH(mp, dp, 0))) 202153323Srodrigc return (error); 203153323Srodrigc 204153323Srodrigc /* 205159451Srodrigc * Determine space new attribute will use, and if it would be 206159451Srodrigc * "local" or "remote" (note: local != inline). 207159451Srodrigc */ 208159451Srodrigc size = xfs_attr_leaf_newentsize(namelen, valuelen, 209159451Srodrigc mp->m_sb.sb_blocksize, &local); 210159451Srodrigc 211159451Srodrigc /* 212153323Srodrigc * If the inode doesn't have an attribute fork, add one. 213153323Srodrigc * (inode must not be locked when we call this routine) 214153323Srodrigc */ 215153323Srodrigc if (XFS_IFORK_Q(dp) == 0) { 216159451Srodrigc if ((error = xfs_bmap_add_attrfork(dp, size, rsvd))) 217153323Srodrigc return(error); 218153323Srodrigc } 219153323Srodrigc 220153323Srodrigc /* 221153323Srodrigc * Fill in the arg structure for this request. 222153323Srodrigc */ 223153323Srodrigc memset((char *)&args, 0, sizeof(args)); 224153323Srodrigc args.name = name; 225153323Srodrigc args.namelen = namelen; 226153323Srodrigc args.value = value; 227153323Srodrigc args.valuelen = valuelen; 228153323Srodrigc args.flags = flags; 229153323Srodrigc args.hashval = xfs_da_hashname(args.name, args.namelen); 230153323Srodrigc args.dp = dp; 231153323Srodrigc args.firstblock = &firstblock; 232153323Srodrigc args.flist = &flist; 233153323Srodrigc args.whichfork = XFS_ATTR_FORK; 234159451Srodrigc args.addname = 1; 235153323Srodrigc args.oknoent = 1; 236153323Srodrigc 237153323Srodrigc nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); 238153323Srodrigc if (local) { 239153323Srodrigc if (size > (mp->m_sb.sb_blocksize >> 1)) { 240153323Srodrigc /* Double split possible */ 241153323Srodrigc nblks <<= 1; 242153323Srodrigc } 243153323Srodrigc } else { 244153323Srodrigc uint dblocks = XFS_B_TO_FSB(mp, valuelen); 245153323Srodrigc /* Out of line attribute, cannot double split, but make 246153323Srodrigc * room for the attribute value itself. 247153323Srodrigc */ 248153323Srodrigc nblks += dblocks; 249153323Srodrigc nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); 250153323Srodrigc } 251153323Srodrigc 252153323Srodrigc /* Size is now blocks for attribute data */ 253153323Srodrigc args.total = nblks; 254153323Srodrigc 255153323Srodrigc /* 256153323Srodrigc * Start our first transaction of the day. 257153323Srodrigc * 258153323Srodrigc * All future transactions during this code must be "chained" off 259153323Srodrigc * this one via the trans_dup() call. All transactions will contain 260153323Srodrigc * the inode, and the inode will always be marked with trans_ihold(). 261153323Srodrigc * Since the inode will be locked in all transactions, we must log 262153323Srodrigc * the inode in every transaction to let it float upward through 263153323Srodrigc * the log. 264153323Srodrigc */ 265153323Srodrigc args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET); 266153323Srodrigc 267153323Srodrigc /* 268153323Srodrigc * Root fork attributes can use reserved data blocks for this 269153323Srodrigc * operation if necessary 270153323Srodrigc */ 271153323Srodrigc 272153323Srodrigc if (rsvd) 273153323Srodrigc args.trans->t_flags |= XFS_TRANS_RESERVE; 274153323Srodrigc 275153323Srodrigc if ((error = xfs_trans_reserve(args.trans, (uint) nblks, 276153323Srodrigc XFS_ATTRSET_LOG_RES(mp, nblks), 277153323Srodrigc 0, XFS_TRANS_PERM_LOG_RES, 278153323Srodrigc XFS_ATTRSET_LOG_COUNT))) { 279153323Srodrigc xfs_trans_cancel(args.trans, 0); 280153323Srodrigc return(error); 281153323Srodrigc } 282153323Srodrigc xfs_ilock(dp, XFS_ILOCK_EXCL); 283153323Srodrigc 284153323Srodrigc error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0, 285153323Srodrigc rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : 286153323Srodrigc XFS_QMOPT_RES_REGBLKS); 287153323Srodrigc if (error) { 288153323Srodrigc xfs_iunlock(dp, XFS_ILOCK_EXCL); 289153323Srodrigc xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); 290153323Srodrigc return (error); 291153323Srodrigc } 292153323Srodrigc 293153323Srodrigc xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); 294153323Srodrigc xfs_trans_ihold(args.trans, dp); 295153323Srodrigc 296153323Srodrigc /* 297159451Srodrigc * If the attribute list is non-existent or a shortform list, 298153323Srodrigc * upgrade it to a single-leaf-block attribute list. 299153323Srodrigc */ 300153323Srodrigc if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || 301153323Srodrigc ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) && 302153323Srodrigc (dp->i_d.di_anextents == 0))) { 303153323Srodrigc 304153323Srodrigc /* 305153323Srodrigc * Build initial attribute list (if required). 306153323Srodrigc */ 307153323Srodrigc if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) 308159451Srodrigc xfs_attr_shortform_create(&args); 309153323Srodrigc 310153323Srodrigc /* 311153323Srodrigc * Try to add the attr to the attribute list in 312153323Srodrigc * the inode. 313153323Srodrigc */ 314153323Srodrigc error = xfs_attr_shortform_addname(&args); 315153323Srodrigc if (error != ENOSPC) { 316153323Srodrigc /* 317153323Srodrigc * Commit the shortform mods, and we're done. 318153323Srodrigc * NOTE: this is also the error path (EEXIST, etc). 319153323Srodrigc */ 320153323Srodrigc ASSERT(args.trans != NULL); 321153323Srodrigc 322153323Srodrigc /* 323153323Srodrigc * If this is a synchronous mount, make sure that 324153323Srodrigc * the transaction goes to disk before returning 325153323Srodrigc * to the user. 326153323Srodrigc */ 327153323Srodrigc if (mp->m_flags & XFS_MOUNT_WSYNC) { 328153323Srodrigc xfs_trans_set_sync(args.trans); 329153323Srodrigc } 330153323Srodrigc err2 = xfs_trans_commit(args.trans, 331153323Srodrigc XFS_TRANS_RELEASE_LOG_RES, 332153323Srodrigc NULL); 333153323Srodrigc xfs_iunlock(dp, XFS_ILOCK_EXCL); 334153323Srodrigc 335153323Srodrigc /* 336153323Srodrigc * Hit the inode change time. 337153323Srodrigc */ 338153323Srodrigc if (!error && (flags & ATTR_KERNOTIME) == 0) { 339153323Srodrigc xfs_ichgtime(dp, XFS_ICHGTIME_CHG); 340153323Srodrigc } 341153323Srodrigc return(error == 0 ? err2 : error); 342153323Srodrigc } 343153323Srodrigc 344153323Srodrigc /* 345153323Srodrigc * It won't fit in the shortform, transform to a leaf block. 346153323Srodrigc * GROT: another possible req'mt for a double-split btree op. 347153323Srodrigc */ 348153323Srodrigc XFS_BMAP_INIT(args.flist, args.firstblock); 349153323Srodrigc error = xfs_attr_shortform_to_leaf(&args); 350153323Srodrigc if (!error) { 351153323Srodrigc error = xfs_bmap_finish(&args.trans, args.flist, 352153323Srodrigc *args.firstblock, &committed); 353153323Srodrigc } 354153323Srodrigc if (error) { 355153323Srodrigc ASSERT(committed); 356153323Srodrigc args.trans = NULL; 357153323Srodrigc xfs_bmap_cancel(&flist); 358153323Srodrigc goto out; 359153323Srodrigc } 360153323Srodrigc 361153323Srodrigc /* 362153323Srodrigc * bmap_finish() may have committed the last trans and started 363153323Srodrigc * a new one. We need the inode to be in all transactions. 364153323Srodrigc */ 365153323Srodrigc if (committed) { 366153323Srodrigc xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); 367153323Srodrigc xfs_trans_ihold(args.trans, dp); 368153323Srodrigc } 369153323Srodrigc 370153323Srodrigc /* 371153323Srodrigc * Commit the leaf transformation. We'll need another (linked) 372153323Srodrigc * transaction to add the new attribute to the leaf. 373153323Srodrigc */ 374153323Srodrigc if ((error = xfs_attr_rolltrans(&args.trans, dp))) 375153323Srodrigc goto out; 376153323Srodrigc 377153323Srodrigc } 378153323Srodrigc 379153323Srodrigc if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { 380153323Srodrigc error = xfs_attr_leaf_addname(&args); 381153323Srodrigc } else { 382153323Srodrigc error = xfs_attr_node_addname(&args); 383153323Srodrigc } 384153323Srodrigc if (error) { 385153323Srodrigc goto out; 386153323Srodrigc } 387153323Srodrigc 388153323Srodrigc /* 389153323Srodrigc * If this is a synchronous mount, make sure that the 390153323Srodrigc * transaction goes to disk before returning to the user. 391153323Srodrigc */ 392153323Srodrigc if (mp->m_flags & XFS_MOUNT_WSYNC) { 393153323Srodrigc xfs_trans_set_sync(args.trans); 394153323Srodrigc } 395153323Srodrigc 396153323Srodrigc /* 397153323Srodrigc * Commit the last in the sequence of transactions. 398153323Srodrigc */ 399153323Srodrigc xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); 400153323Srodrigc error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES, 401153323Srodrigc NULL); 402153323Srodrigc xfs_iunlock(dp, XFS_ILOCK_EXCL); 403153323Srodrigc 404153323Srodrigc /* 405153323Srodrigc * Hit the inode change time. 406153323Srodrigc */ 407153323Srodrigc if (!error && (flags & ATTR_KERNOTIME) == 0) { 408153323Srodrigc xfs_ichgtime(dp, XFS_ICHGTIME_CHG); 409153323Srodrigc } 410153323Srodrigc 411153323Srodrigc return(error); 412153323Srodrigc 413153323Srodrigcout: 414153323Srodrigc if (args.trans) 415153323Srodrigc xfs_trans_cancel(args.trans, 416153323Srodrigc XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); 417153323Srodrigc xfs_iunlock(dp, XFS_ILOCK_EXCL); 418153323Srodrigc return(error); 419153323Srodrigc} 420153323Srodrigc 421159451Srodrigcint 422159451Srodrigcxfs_attr_set(bhv_desc_t *bdp, const char *name, char *value, int valuelen, int flags, 423159451Srodrigc struct cred *cred) 424153323Srodrigc{ 425159451Srodrigc xfs_inode_t *dp; 426159451Srodrigc int namelen; 427153323Srodrigc 428153323Srodrigc namelen = strlen(name); 429159451Srodrigc if (namelen >= MAXNAMELEN) 430159451Srodrigc return EFAULT; /* match IRIX behaviour */ 431153323Srodrigc 432159451Srodrigc XFS_STATS_INC(xs_attr_set); 433153323Srodrigc 434153323Srodrigc dp = XFS_BHVTOI(bdp); 435159451Srodrigc if (XFS_FORCED_SHUTDOWN(dp->i_mount)) 436153323Srodrigc return (EIO); 437153323Srodrigc 438159451Srodrigc return xfs_attr_set_int(dp, name, namelen, value, valuelen, flags); 439159451Srodrigc} 440153323Srodrigc 441159451Srodrigc/* 442159451Srodrigc * Generic handler routine to remove a name from an attribute list. 443159451Srodrigc * Transitions attribute list from Btree to shortform as necessary. 444159451Srodrigc */ 445159451SrodrigcSTATIC int 446159451Srodrigcxfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags) 447159451Srodrigc{ 448159451Srodrigc xfs_da_args_t args; 449159451Srodrigc xfs_fsblock_t firstblock; 450159451Srodrigc xfs_bmap_free_t flist; 451159451Srodrigc int error; 452159451Srodrigc xfs_mount_t *mp = dp->i_mount; 453159451Srodrigc 454153323Srodrigc /* 455153323Srodrigc * Fill in the arg structure for this request. 456153323Srodrigc */ 457153323Srodrigc memset((char *)&args, 0, sizeof(args)); 458153323Srodrigc args.name = name; 459153323Srodrigc args.namelen = namelen; 460153323Srodrigc args.flags = flags; 461153323Srodrigc args.hashval = xfs_da_hashname(args.name, args.namelen); 462153323Srodrigc args.dp = dp; 463153323Srodrigc args.firstblock = &firstblock; 464153323Srodrigc args.flist = &flist; 465153323Srodrigc args.total = 0; 466153323Srodrigc args.whichfork = XFS_ATTR_FORK; 467153323Srodrigc 468153323Srodrigc /* 469153323Srodrigc * Attach the dquots to the inode. 470153323Srodrigc */ 471153323Srodrigc if ((error = XFS_QM_DQATTACH(mp, dp, 0))) 472153323Srodrigc return (error); 473153323Srodrigc 474153323Srodrigc /* 475153323Srodrigc * Start our first transaction of the day. 476153323Srodrigc * 477153323Srodrigc * All future transactions during this code must be "chained" off 478153323Srodrigc * this one via the trans_dup() call. All transactions will contain 479153323Srodrigc * the inode, and the inode will always be marked with trans_ihold(). 480153323Srodrigc * Since the inode will be locked in all transactions, we must log 481153323Srodrigc * the inode in every transaction to let it float upward through 482153323Srodrigc * the log. 483153323Srodrigc */ 484153323Srodrigc args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM); 485153323Srodrigc 486153323Srodrigc /* 487153323Srodrigc * Root fork attributes can use reserved data blocks for this 488153323Srodrigc * operation if necessary 489153323Srodrigc */ 490153323Srodrigc 491153323Srodrigc if (flags & ATTR_ROOT) 492153323Srodrigc args.trans->t_flags |= XFS_TRANS_RESERVE; 493153323Srodrigc 494153323Srodrigc if ((error = xfs_trans_reserve(args.trans, 495153323Srodrigc XFS_ATTRRM_SPACE_RES(mp), 496153323Srodrigc XFS_ATTRRM_LOG_RES(mp), 497153323Srodrigc 0, XFS_TRANS_PERM_LOG_RES, 498153323Srodrigc XFS_ATTRRM_LOG_COUNT))) { 499153323Srodrigc xfs_trans_cancel(args.trans, 0); 500153323Srodrigc return(error); 501153323Srodrigc } 502153323Srodrigc 503153323Srodrigc xfs_ilock(dp, XFS_ILOCK_EXCL); 504153323Srodrigc /* 505153323Srodrigc * No need to make quota reservations here. We expect to release some 506153323Srodrigc * blocks not allocate in the common case. 507153323Srodrigc */ 508153323Srodrigc xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); 509153323Srodrigc xfs_trans_ihold(args.trans, dp); 510153323Srodrigc 511153323Srodrigc /* 512153323Srodrigc * Decide on what work routines to call based on the inode size. 513153323Srodrigc */ 514153323Srodrigc if (XFS_IFORK_Q(dp) == 0 || 515153323Srodrigc (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 516153323Srodrigc dp->i_d.di_anextents == 0)) { 517153323Srodrigc error = XFS_ERROR(ENOATTR); 518153323Srodrigc goto out; 519153323Srodrigc } 520153323Srodrigc if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { 521153323Srodrigc ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); 522153323Srodrigc error = xfs_attr_shortform_remove(&args); 523153323Srodrigc if (error) { 524153323Srodrigc goto out; 525153323Srodrigc } 526153323Srodrigc } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { 527153323Srodrigc error = xfs_attr_leaf_removename(&args); 528153323Srodrigc } else { 529153323Srodrigc error = xfs_attr_node_removename(&args); 530153323Srodrigc } 531153323Srodrigc if (error) { 532153323Srodrigc goto out; 533153323Srodrigc } 534153323Srodrigc 535153323Srodrigc /* 536153323Srodrigc * If this is a synchronous mount, make sure that the 537153323Srodrigc * transaction goes to disk before returning to the user. 538153323Srodrigc */ 539153323Srodrigc if (mp->m_flags & XFS_MOUNT_WSYNC) { 540153323Srodrigc xfs_trans_set_sync(args.trans); 541153323Srodrigc } 542153323Srodrigc 543153323Srodrigc /* 544153323Srodrigc * Commit the last in the sequence of transactions. 545153323Srodrigc */ 546153323Srodrigc xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); 547153323Srodrigc error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES, 548153323Srodrigc NULL); 549153323Srodrigc xfs_iunlock(dp, XFS_ILOCK_EXCL); 550153323Srodrigc 551153323Srodrigc /* 552153323Srodrigc * Hit the inode change time. 553153323Srodrigc */ 554153323Srodrigc if (!error && (flags & ATTR_KERNOTIME) == 0) { 555153323Srodrigc xfs_ichgtime(dp, XFS_ICHGTIME_CHG); 556153323Srodrigc } 557153323Srodrigc 558153323Srodrigc return(error); 559153323Srodrigc 560153323Srodrigcout: 561153323Srodrigc if (args.trans) 562153323Srodrigc xfs_trans_cancel(args.trans, 563153323Srodrigc XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); 564153323Srodrigc xfs_iunlock(dp, XFS_ILOCK_EXCL); 565153323Srodrigc return(error); 566153323Srodrigc} 567153323Srodrigc 568159451Srodrigcint 569159451Srodrigcxfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred) 570159451Srodrigc{ 571159451Srodrigc xfs_inode_t *dp; 572159451Srodrigc int namelen; 573159451Srodrigc 574159451Srodrigc namelen = strlen(name); 575159451Srodrigc if (namelen >= MAXNAMELEN) 576159451Srodrigc return EFAULT; /* match IRIX behaviour */ 577159451Srodrigc 578159451Srodrigc XFS_STATS_INC(xs_attr_remove); 579159451Srodrigc 580159451Srodrigc dp = XFS_BHVTOI(bdp); 581159451Srodrigc if (XFS_FORCED_SHUTDOWN(dp->i_mount)) 582159451Srodrigc return (EIO); 583159451Srodrigc 584159451Srodrigc xfs_ilock(dp, XFS_ILOCK_SHARED); 585159451Srodrigc if (XFS_IFORK_Q(dp) == 0 || 586159451Srodrigc (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 587159451Srodrigc dp->i_d.di_anextents == 0)) { 588159451Srodrigc xfs_iunlock(dp, XFS_ILOCK_SHARED); 589159451Srodrigc return(XFS_ERROR(ENOATTR)); 590159451Srodrigc } 591159451Srodrigc xfs_iunlock(dp, XFS_ILOCK_SHARED); 592159451Srodrigc 593159451Srodrigc return xfs_attr_remove_int(dp, name, namelen, flags); 594159451Srodrigc} 595159451Srodrigc 596153323Srodrigc/* 597153323Srodrigc * Generate a list of extended attribute names and optionally 598153323Srodrigc * also value lengths. Positive return value follows the XFS 599153323Srodrigc * convention of being an error, zero or negative return code 600153323Srodrigc * is the length of the buffer returned (negated), indicating 601153323Srodrigc * success. 602153323Srodrigc */ 603153323Srodrigcint 604153323Srodrigcxfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags, 605153323Srodrigc attrlist_cursor_kern_t *cursor, struct cred *cred) 606153323Srodrigc{ 607153323Srodrigc xfs_attr_list_context_t context; 608153323Srodrigc xfs_inode_t *dp; 609153323Srodrigc int error; 610153323Srodrigc 611153323Srodrigc XFS_STATS_INC(xs_attr_list); 612153323Srodrigc 613153323Srodrigc /* 614153323Srodrigc * Validate the cursor. 615153323Srodrigc */ 616153323Srodrigc if (cursor->pad1 || cursor->pad2) 617153323Srodrigc return(XFS_ERROR(EINVAL)); 618153323Srodrigc if ((cursor->initted == 0) && 619153323Srodrigc (cursor->hashval || cursor->blkno || cursor->offset)) 620153323Srodrigc return(XFS_ERROR(EINVAL)); 621153323Srodrigc 622153323Srodrigc /* 623153323Srodrigc * Check for a properly aligned buffer. 624153323Srodrigc */ 625153323Srodrigc if (((long)buffer) & (sizeof(int)-1)) 626153323Srodrigc return(XFS_ERROR(EFAULT)); 627153323Srodrigc if (flags & ATTR_KERNOVAL) 628153323Srodrigc bufsize = 0; 629153323Srodrigc 630153323Srodrigc /* 631153323Srodrigc * Initialize the output buffer. 632153323Srodrigc */ 633153323Srodrigc context.dp = dp = XFS_BHVTOI(bdp); 634153323Srodrigc context.cursor = cursor; 635153323Srodrigc context.count = 0; 636153323Srodrigc context.dupcnt = 0; 637153323Srodrigc context.resynch = 1; 638153323Srodrigc context.flags = flags; 639153323Srodrigc if (!(flags & ATTR_KERNAMELS)) { 640153323Srodrigc context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ 641153323Srodrigc context.firstu = context.bufsize; 642153323Srodrigc context.alist = (attrlist_t *)buffer; 643153323Srodrigc context.alist->al_count = 0; 644153323Srodrigc context.alist->al_more = 0; 645153323Srodrigc context.alist->al_offset[0] = context.bufsize; 646153323Srodrigc } 647153323Srodrigc else { 648153323Srodrigc context.bufsize = bufsize; 649153323Srodrigc context.firstu = context.bufsize; 650153323Srodrigc context.alist = (attrlist_t *)buffer; 651153323Srodrigc } 652153323Srodrigc 653153323Srodrigc if (XFS_FORCED_SHUTDOWN(dp->i_mount)) 654153323Srodrigc return (EIO); 655159451Srodrigc 656153323Srodrigc xfs_ilock(dp, XFS_ILOCK_SHARED); 657153323Srodrigc /* 658153323Srodrigc * Decide on what work routines to call based on the inode size. 659153323Srodrigc */ 660153323Srodrigc xfs_attr_trace_l_c("syscall start", &context); 661153323Srodrigc if (XFS_IFORK_Q(dp) == 0 || 662153323Srodrigc (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 663153323Srodrigc dp->i_d.di_anextents == 0)) { 664153323Srodrigc error = 0; 665153323Srodrigc } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { 666153323Srodrigc error = xfs_attr_shortform_list(&context); 667153323Srodrigc } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { 668153323Srodrigc error = xfs_attr_leaf_list(&context); 669153323Srodrigc } else { 670153323Srodrigc error = xfs_attr_node_list(&context); 671153323Srodrigc } 672153323Srodrigc xfs_iunlock(dp, XFS_ILOCK_SHARED); 673153323Srodrigc xfs_attr_trace_l_c("syscall end", &context); 674153323Srodrigc 675153323Srodrigc if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) { 676153323Srodrigc ASSERT(error >= 0); 677153323Srodrigc } 678153323Srodrigc else { /* must return negated buffer size or the error */ 679153323Srodrigc if (context.count < 0) 680153323Srodrigc error = XFS_ERROR(ERANGE); 681153323Srodrigc else 682153323Srodrigc error = -context.count; 683153323Srodrigc } 684153323Srodrigc 685153323Srodrigc return(error); 686153323Srodrigc} 687153323Srodrigc 688153323Srodrigcint /* error */ 689153323Srodrigcxfs_attr_inactive(xfs_inode_t *dp) 690153323Srodrigc{ 691153323Srodrigc xfs_trans_t *trans; 692153323Srodrigc xfs_mount_t *mp; 693153323Srodrigc int error; 694153323Srodrigc 695153323Srodrigc mp = dp->i_mount; 696153323Srodrigc ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); 697153323Srodrigc 698159451Srodrigc xfs_ilock(dp, XFS_ILOCK_SHARED); 699153323Srodrigc if ((XFS_IFORK_Q(dp) == 0) || 700153323Srodrigc (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || 701153323Srodrigc (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 702153323Srodrigc dp->i_d.di_anextents == 0)) { 703159451Srodrigc xfs_iunlock(dp, XFS_ILOCK_SHARED); 704153323Srodrigc return(0); 705153323Srodrigc } 706159451Srodrigc xfs_iunlock(dp, XFS_ILOCK_SHARED); 707153323Srodrigc 708153323Srodrigc /* 709153323Srodrigc * Start our first transaction of the day. 710153323Srodrigc * 711153323Srodrigc * All future transactions during this code must be "chained" off 712153323Srodrigc * this one via the trans_dup() call. All transactions will contain 713153323Srodrigc * the inode, and the inode will always be marked with trans_ihold(). 714153323Srodrigc * Since the inode will be locked in all transactions, we must log 715153323Srodrigc * the inode in every transaction to let it float upward through 716153323Srodrigc * the log. 717153323Srodrigc */ 718153323Srodrigc trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL); 719153323Srodrigc if ((error = xfs_trans_reserve(trans, 0, XFS_ATTRINVAL_LOG_RES(mp), 0, 720153323Srodrigc XFS_TRANS_PERM_LOG_RES, 721153323Srodrigc XFS_ATTRINVAL_LOG_COUNT))) { 722153323Srodrigc xfs_trans_cancel(trans, 0); 723153323Srodrigc return(error); 724153323Srodrigc } 725153323Srodrigc xfs_ilock(dp, XFS_ILOCK_EXCL); 726153323Srodrigc 727153323Srodrigc /* 728153323Srodrigc * No need to make quota reservations here. We expect to release some 729153323Srodrigc * blocks, not allocate, in the common case. 730153323Srodrigc */ 731153323Srodrigc xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL); 732153323Srodrigc xfs_trans_ihold(trans, dp); 733153323Srodrigc 734153323Srodrigc /* 735153323Srodrigc * Decide on what work routines to call based on the inode size. 736153323Srodrigc */ 737153323Srodrigc if ((XFS_IFORK_Q(dp) == 0) || 738153323Srodrigc (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || 739153323Srodrigc (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && 740153323Srodrigc dp->i_d.di_anextents == 0)) { 741153323Srodrigc error = 0; 742153323Srodrigc goto out; 743153323Srodrigc } 744153323Srodrigc error = xfs_attr_root_inactive(&trans, dp); 745153323Srodrigc if (error) 746153323Srodrigc goto out; 747153323Srodrigc /* 748153323Srodrigc * signal synchronous inactive transactions unless this 749153323Srodrigc * is a synchronous mount filesystem in which case we 750153323Srodrigc * know that we're here because we've been called out of 751153323Srodrigc * xfs_inactive which means that the last reference is gone 752153323Srodrigc * and the unlink transaction has already hit the disk so 753153323Srodrigc * async inactive transactions are safe. 754153323Srodrigc */ 755153323Srodrigc if ((error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK, 756153323Srodrigc (!(mp->m_flags & XFS_MOUNT_WSYNC) 757153323Srodrigc ? 1 : 0)))) 758153323Srodrigc goto out; 759153323Srodrigc 760153323Srodrigc /* 761153323Srodrigc * Commit the last in the sequence of transactions. 762153323Srodrigc */ 763153323Srodrigc xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); 764153323Srodrigc error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES, 765153323Srodrigc NULL); 766153323Srodrigc xfs_iunlock(dp, XFS_ILOCK_EXCL); 767153323Srodrigc 768153323Srodrigc return(error); 769153323Srodrigc 770153323Srodrigcout: 771153323Srodrigc xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); 772153323Srodrigc xfs_iunlock(dp, XFS_ILOCK_EXCL); 773153323Srodrigc return(error); 774153323Srodrigc} 775153323Srodrigc 776153323Srodrigc 777153323Srodrigc 778153323Srodrigc/*======================================================================== 779153323Srodrigc * External routines when attribute list is inside the inode 780153323Srodrigc *========================================================================*/ 781153323Srodrigc 782153323Srodrigc/* 783153323Srodrigc * Add a name to the shortform attribute list structure 784153323Srodrigc * This is the external routine. 785153323Srodrigc */ 786153323SrodrigcSTATIC int 787153323Srodrigcxfs_attr_shortform_addname(xfs_da_args_t *args) 788153323Srodrigc{ 789159451Srodrigc int newsize, forkoff, retval; 790153323Srodrigc 791153323Srodrigc retval = xfs_attr_shortform_lookup(args); 792153323Srodrigc if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { 793153323Srodrigc return(retval); 794153323Srodrigc } else if (retval == EEXIST) { 795153323Srodrigc if (args->flags & ATTR_CREATE) 796153323Srodrigc return(retval); 797153323Srodrigc retval = xfs_attr_shortform_remove(args); 798153323Srodrigc ASSERT(retval == 0); 799153323Srodrigc } 800153323Srodrigc 801159451Srodrigc if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX || 802159451Srodrigc args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX) 803159451Srodrigc return(XFS_ERROR(ENOSPC)); 804159451Srodrigc 805153323Srodrigc newsize = XFS_ATTR_SF_TOTSIZE(args->dp); 806153323Srodrigc newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); 807159451Srodrigc 808159451Srodrigc forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize); 809159451Srodrigc if (!forkoff) 810153323Srodrigc return(XFS_ERROR(ENOSPC)); 811159451Srodrigc 812159451Srodrigc xfs_attr_shortform_add(args, forkoff); 813153323Srodrigc return(0); 814153323Srodrigc} 815153323Srodrigc 816153323Srodrigc 817153323Srodrigc/*======================================================================== 818153323Srodrigc * External routines when attribute list is one block 819153323Srodrigc *========================================================================*/ 820153323Srodrigc 821153323Srodrigc/* 822153323Srodrigc * Add a name to the leaf attribute list structure 823153323Srodrigc * 824153323Srodrigc * This leaf block cannot have a "remote" value, we only call this routine 825153323Srodrigc * if bmap_one_block() says there is only one block (ie: no remote blks). 826153323Srodrigc */ 827153323Srodrigcint 828153323Srodrigcxfs_attr_leaf_addname(xfs_da_args_t *args) 829153323Srodrigc{ 830153323Srodrigc xfs_inode_t *dp; 831153323Srodrigc xfs_dabuf_t *bp; 832159451Srodrigc int retval, error, committed, forkoff; 833153323Srodrigc 834153323Srodrigc /* 835153323Srodrigc * Read the (only) block in the attribute list in. 836153323Srodrigc */ 837153323Srodrigc dp = args->dp; 838153323Srodrigc args->blkno = 0; 839153323Srodrigc error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, 840153323Srodrigc XFS_ATTR_FORK); 841153323Srodrigc if (error) 842153323Srodrigc return(error); 843153323Srodrigc ASSERT(bp != NULL); 844153323Srodrigc 845153323Srodrigc /* 846153323Srodrigc * Look up the given attribute in the leaf block. Figure out if 847153323Srodrigc * the given flags produce an error or call for an atomic rename. 848153323Srodrigc */ 849153323Srodrigc retval = xfs_attr_leaf_lookup_int(bp, args); 850153323Srodrigc if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { 851153323Srodrigc xfs_da_brelse(args->trans, bp); 852153323Srodrigc return(retval); 853153323Srodrigc } else if (retval == EEXIST) { 854153323Srodrigc if (args->flags & ATTR_CREATE) { /* pure create op */ 855153323Srodrigc xfs_da_brelse(args->trans, bp); 856153323Srodrigc return(retval); 857153323Srodrigc } 858153323Srodrigc args->rename = 1; /* an atomic rename */ 859153323Srodrigc args->blkno2 = args->blkno; /* set 2nd entry info*/ 860153323Srodrigc args->index2 = args->index; 861153323Srodrigc args->rmtblkno2 = args->rmtblkno; 862153323Srodrigc args->rmtblkcnt2 = args->rmtblkcnt; 863153323Srodrigc } 864153323Srodrigc 865153323Srodrigc /* 866153323Srodrigc * Add the attribute to the leaf block, transitioning to a Btree 867153323Srodrigc * if required. 868153323Srodrigc */ 869153323Srodrigc retval = xfs_attr_leaf_add(bp, args); 870153323Srodrigc xfs_da_buf_done(bp); 871153323Srodrigc if (retval == ENOSPC) { 872153323Srodrigc /* 873153323Srodrigc * Promote the attribute list to the Btree format, then 874153323Srodrigc * Commit that transaction so that the node_addname() call 875153323Srodrigc * can manage its own transactions. 876153323Srodrigc */ 877153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 878153323Srodrigc error = xfs_attr_leaf_to_node(args); 879153323Srodrigc if (!error) { 880153323Srodrigc error = xfs_bmap_finish(&args->trans, args->flist, 881153323Srodrigc *args->firstblock, &committed); 882153323Srodrigc } 883153323Srodrigc if (error) { 884153323Srodrigc ASSERT(committed); 885153323Srodrigc args->trans = NULL; 886153323Srodrigc xfs_bmap_cancel(args->flist); 887153323Srodrigc return(error); 888153323Srodrigc } 889153323Srodrigc 890153323Srodrigc /* 891153323Srodrigc * bmap_finish() may have committed the last trans and started 892153323Srodrigc * a new one. We need the inode to be in all transactions. 893153323Srodrigc */ 894153323Srodrigc if (committed) { 895153323Srodrigc xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 896153323Srodrigc xfs_trans_ihold(args->trans, dp); 897153323Srodrigc } 898153323Srodrigc 899153323Srodrigc /* 900153323Srodrigc * Commit the current trans (including the inode) and start 901153323Srodrigc * a new one. 902153323Srodrigc */ 903153323Srodrigc if ((error = xfs_attr_rolltrans(&args->trans, dp))) 904153323Srodrigc return (error); 905153323Srodrigc 906153323Srodrigc /* 907153323Srodrigc * Fob the whole rest of the problem off on the Btree code. 908153323Srodrigc */ 909153323Srodrigc error = xfs_attr_node_addname(args); 910153323Srodrigc return(error); 911153323Srodrigc } 912153323Srodrigc 913153323Srodrigc /* 914153323Srodrigc * Commit the transaction that added the attr name so that 915153323Srodrigc * later routines can manage their own transactions. 916153323Srodrigc */ 917153323Srodrigc if ((error = xfs_attr_rolltrans(&args->trans, dp))) 918153323Srodrigc return (error); 919153323Srodrigc 920153323Srodrigc /* 921153323Srodrigc * If there was an out-of-line value, allocate the blocks we 922153323Srodrigc * identified for its storage and copy the value. This is done 923153323Srodrigc * after we create the attribute so that we don't overflow the 924153323Srodrigc * maximum size of a transaction and/or hit a deadlock. 925153323Srodrigc */ 926153323Srodrigc if (args->rmtblkno > 0) { 927153323Srodrigc error = xfs_attr_rmtval_set(args); 928153323Srodrigc if (error) 929153323Srodrigc return(error); 930153323Srodrigc } 931153323Srodrigc 932153323Srodrigc /* 933153323Srodrigc * If this is an atomic rename operation, we must "flip" the 934153323Srodrigc * incomplete flags on the "new" and "old" attribute/value pairs 935153323Srodrigc * so that one disappears and one appears atomically. Then we 936153323Srodrigc * must remove the "old" attribute/value pair. 937153323Srodrigc */ 938153323Srodrigc if (args->rename) { 939153323Srodrigc /* 940153323Srodrigc * In a separate transaction, set the incomplete flag on the 941153323Srodrigc * "old" attr and clear the incomplete flag on the "new" attr. 942153323Srodrigc */ 943153323Srodrigc error = xfs_attr_leaf_flipflags(args); 944153323Srodrigc if (error) 945153323Srodrigc return(error); 946153323Srodrigc 947153323Srodrigc /* 948153323Srodrigc * Dismantle the "old" attribute/value pair by removing 949153323Srodrigc * a "remote" value (if it exists). 950153323Srodrigc */ 951153323Srodrigc args->index = args->index2; 952153323Srodrigc args->blkno = args->blkno2; 953153323Srodrigc args->rmtblkno = args->rmtblkno2; 954153323Srodrigc args->rmtblkcnt = args->rmtblkcnt2; 955153323Srodrigc if (args->rmtblkno) { 956153323Srodrigc error = xfs_attr_rmtval_remove(args); 957153323Srodrigc if (error) 958153323Srodrigc return(error); 959153323Srodrigc } 960153323Srodrigc 961153323Srodrigc /* 962153323Srodrigc * Read in the block containing the "old" attr, then 963153323Srodrigc * remove the "old" attr from that block (neat, huh!) 964153323Srodrigc */ 965153323Srodrigc error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, 966153323Srodrigc &bp, XFS_ATTR_FORK); 967153323Srodrigc if (error) 968153323Srodrigc return(error); 969153323Srodrigc ASSERT(bp != NULL); 970153323Srodrigc (void)xfs_attr_leaf_remove(bp, args); 971153323Srodrigc 972153323Srodrigc /* 973153323Srodrigc * If the result is small enough, shrink it all into the inode. 974153323Srodrigc */ 975159451Srodrigc if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { 976153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 977159451Srodrigc error = xfs_attr_leaf_to_shortform(bp, args, forkoff); 978153323Srodrigc /* bp is gone due to xfs_da_shrink_inode */ 979153323Srodrigc if (!error) { 980153323Srodrigc error = xfs_bmap_finish(&args->trans, 981153323Srodrigc args->flist, 982153323Srodrigc *args->firstblock, 983153323Srodrigc &committed); 984153323Srodrigc } 985153323Srodrigc if (error) { 986153323Srodrigc ASSERT(committed); 987153323Srodrigc args->trans = NULL; 988153323Srodrigc xfs_bmap_cancel(args->flist); 989153323Srodrigc return(error); 990153323Srodrigc } 991153323Srodrigc 992153323Srodrigc /* 993153323Srodrigc * bmap_finish() may have committed the last trans 994153323Srodrigc * and started a new one. We need the inode to be 995153323Srodrigc * in all transactions. 996153323Srodrigc */ 997153323Srodrigc if (committed) { 998153323Srodrigc xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 999153323Srodrigc xfs_trans_ihold(args->trans, dp); 1000153323Srodrigc } 1001153323Srodrigc } else 1002153323Srodrigc xfs_da_buf_done(bp); 1003153323Srodrigc 1004153323Srodrigc /* 1005153323Srodrigc * Commit the remove and start the next trans in series. 1006153323Srodrigc */ 1007153323Srodrigc error = xfs_attr_rolltrans(&args->trans, dp); 1008153323Srodrigc 1009153323Srodrigc } else if (args->rmtblkno > 0) { 1010153323Srodrigc /* 1011153323Srodrigc * Added a "remote" value, just clear the incomplete flag. 1012153323Srodrigc */ 1013153323Srodrigc error = xfs_attr_leaf_clearflag(args); 1014153323Srodrigc } 1015153323Srodrigc return(error); 1016153323Srodrigc} 1017153323Srodrigc 1018153323Srodrigc/* 1019153323Srodrigc * Remove a name from the leaf attribute list structure 1020153323Srodrigc * 1021153323Srodrigc * This leaf block cannot have a "remote" value, we only call this routine 1022153323Srodrigc * if bmap_one_block() says there is only one block (ie: no remote blks). 1023153323Srodrigc */ 1024153323SrodrigcSTATIC int 1025153323Srodrigcxfs_attr_leaf_removename(xfs_da_args_t *args) 1026153323Srodrigc{ 1027153323Srodrigc xfs_inode_t *dp; 1028153323Srodrigc xfs_dabuf_t *bp; 1029159451Srodrigc int error, committed, forkoff; 1030153323Srodrigc 1031153323Srodrigc /* 1032153323Srodrigc * Remove the attribute. 1033153323Srodrigc */ 1034153323Srodrigc dp = args->dp; 1035153323Srodrigc args->blkno = 0; 1036153323Srodrigc error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, 1037153323Srodrigc XFS_ATTR_FORK); 1038153323Srodrigc if (error) { 1039153323Srodrigc return(error); 1040153323Srodrigc } 1041153323Srodrigc 1042153323Srodrigc ASSERT(bp != NULL); 1043153323Srodrigc error = xfs_attr_leaf_lookup_int(bp, args); 1044153323Srodrigc if (error == ENOATTR) { 1045153323Srodrigc xfs_da_brelse(args->trans, bp); 1046153323Srodrigc return(error); 1047153323Srodrigc } 1048153323Srodrigc 1049153323Srodrigc (void)xfs_attr_leaf_remove(bp, args); 1050153323Srodrigc 1051153323Srodrigc /* 1052153323Srodrigc * If the result is small enough, shrink it all into the inode. 1053153323Srodrigc */ 1054159451Srodrigc if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { 1055153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 1056159451Srodrigc error = xfs_attr_leaf_to_shortform(bp, args, forkoff); 1057153323Srodrigc /* bp is gone due to xfs_da_shrink_inode */ 1058153323Srodrigc if (!error) { 1059153323Srodrigc error = xfs_bmap_finish(&args->trans, args->flist, 1060153323Srodrigc *args->firstblock, &committed); 1061153323Srodrigc } 1062153323Srodrigc if (error) { 1063153323Srodrigc ASSERT(committed); 1064153323Srodrigc args->trans = NULL; 1065153323Srodrigc xfs_bmap_cancel(args->flist); 1066153323Srodrigc return(error); 1067153323Srodrigc } 1068153323Srodrigc 1069153323Srodrigc /* 1070153323Srodrigc * bmap_finish() may have committed the last trans and started 1071153323Srodrigc * a new one. We need the inode to be in all transactions. 1072153323Srodrigc */ 1073153323Srodrigc if (committed) { 1074153323Srodrigc xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 1075153323Srodrigc xfs_trans_ihold(args->trans, dp); 1076153323Srodrigc } 1077153323Srodrigc } else 1078153323Srodrigc xfs_da_buf_done(bp); 1079153323Srodrigc return(0); 1080153323Srodrigc} 1081153323Srodrigc 1082153323Srodrigc/* 1083153323Srodrigc * Look up a name in a leaf attribute list structure. 1084153323Srodrigc * 1085153323Srodrigc * This leaf block cannot have a "remote" value, we only call this routine 1086153323Srodrigc * if bmap_one_block() says there is only one block (ie: no remote blks). 1087153323Srodrigc */ 1088159451SrodrigcSTATIC int 1089153323Srodrigcxfs_attr_leaf_get(xfs_da_args_t *args) 1090153323Srodrigc{ 1091153323Srodrigc xfs_dabuf_t *bp; 1092153323Srodrigc int error; 1093153323Srodrigc 1094153323Srodrigc args->blkno = 0; 1095153323Srodrigc error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, 1096153323Srodrigc XFS_ATTR_FORK); 1097153323Srodrigc if (error) 1098153323Srodrigc return(error); 1099153323Srodrigc ASSERT(bp != NULL); 1100153323Srodrigc 1101153323Srodrigc error = xfs_attr_leaf_lookup_int(bp, args); 1102153323Srodrigc if (error != EEXIST) { 1103153323Srodrigc xfs_da_brelse(args->trans, bp); 1104153323Srodrigc return(error); 1105153323Srodrigc } 1106153323Srodrigc error = xfs_attr_leaf_getvalue(bp, args); 1107153323Srodrigc xfs_da_brelse(args->trans, bp); 1108153323Srodrigc if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) { 1109153323Srodrigc error = xfs_attr_rmtval_get(args); 1110153323Srodrigc } 1111153323Srodrigc return(error); 1112153323Srodrigc} 1113153323Srodrigc 1114153323Srodrigc/* 1115153323Srodrigc * Copy out attribute entries for attr_list(), for leaf attribute lists. 1116153323Srodrigc */ 1117153323SrodrigcSTATIC int 1118153323Srodrigcxfs_attr_leaf_list(xfs_attr_list_context_t *context) 1119153323Srodrigc{ 1120153323Srodrigc xfs_attr_leafblock_t *leaf; 1121153323Srodrigc int error; 1122153323Srodrigc xfs_dabuf_t *bp; 1123153323Srodrigc 1124153323Srodrigc context->cursor->blkno = 0; 1125153323Srodrigc error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK); 1126153323Srodrigc if (error) 1127153323Srodrigc return(error); 1128153323Srodrigc ASSERT(bp != NULL); 1129153323Srodrigc leaf = bp->data; 1130159451Srodrigc if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) { 1131153323Srodrigc XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW, 1132153323Srodrigc context->dp->i_mount, leaf); 1133153323Srodrigc xfs_da_brelse(NULL, bp); 1134153323Srodrigc return(XFS_ERROR(EFSCORRUPTED)); 1135153323Srodrigc } 1136153323Srodrigc 1137153323Srodrigc (void)xfs_attr_leaf_list_int(bp, context); 1138153323Srodrigc xfs_da_brelse(NULL, bp); 1139153323Srodrigc return(0); 1140153323Srodrigc} 1141153323Srodrigc 1142153323Srodrigc 1143153323Srodrigc/*======================================================================== 1144153323Srodrigc * External routines when attribute list size > XFS_LBSIZE(mp). 1145153323Srodrigc *========================================================================*/ 1146153323Srodrigc 1147153323Srodrigc/* 1148153323Srodrigc * Add a name to a Btree-format attribute list. 1149153323Srodrigc * 1150153323Srodrigc * This will involve walking down the Btree, and may involve splitting 1151153323Srodrigc * leaf nodes and even splitting intermediate nodes up to and including 1152153323Srodrigc * the root node (a special case of an intermediate node). 1153153323Srodrigc * 1154153323Srodrigc * "Remote" attribute values confuse the issue and atomic rename operations 1155153323Srodrigc * add a whole extra layer of confusion on top of that. 1156153323Srodrigc */ 1157153323SrodrigcSTATIC int 1158153323Srodrigcxfs_attr_node_addname(xfs_da_args_t *args) 1159153323Srodrigc{ 1160153323Srodrigc xfs_da_state_t *state; 1161153323Srodrigc xfs_da_state_blk_t *blk; 1162153323Srodrigc xfs_inode_t *dp; 1163153323Srodrigc xfs_mount_t *mp; 1164153323Srodrigc int committed, retval, error; 1165153323Srodrigc 1166153323Srodrigc /* 1167153323Srodrigc * Fill in bucket of arguments/results/context to carry around. 1168153323Srodrigc */ 1169153323Srodrigc dp = args->dp; 1170153323Srodrigc mp = dp->i_mount; 1171153323Srodrigcrestart: 1172153323Srodrigc state = xfs_da_state_alloc(); 1173153323Srodrigc state->args = args; 1174153323Srodrigc state->mp = mp; 1175153323Srodrigc state->blocksize = state->mp->m_sb.sb_blocksize; 1176153323Srodrigc state->node_ents = state->mp->m_attr_node_ents; 1177153323Srodrigc 1178153323Srodrigc /* 1179153323Srodrigc * Search to see if name already exists, and get back a pointer 1180153323Srodrigc * to where it should go. 1181153323Srodrigc */ 1182153323Srodrigc error = xfs_da_node_lookup_int(state, &retval); 1183153323Srodrigc if (error) 1184153323Srodrigc goto out; 1185153323Srodrigc blk = &state->path.blk[ state->path.active-1 ]; 1186153323Srodrigc ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); 1187153323Srodrigc if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { 1188153323Srodrigc goto out; 1189153323Srodrigc } else if (retval == EEXIST) { 1190153323Srodrigc if (args->flags & ATTR_CREATE) 1191153323Srodrigc goto out; 1192153323Srodrigc args->rename = 1; /* atomic rename op */ 1193153323Srodrigc args->blkno2 = args->blkno; /* set 2nd entry info*/ 1194153323Srodrigc args->index2 = args->index; 1195153323Srodrigc args->rmtblkno2 = args->rmtblkno; 1196153323Srodrigc args->rmtblkcnt2 = args->rmtblkcnt; 1197153323Srodrigc args->rmtblkno = 0; 1198153323Srodrigc args->rmtblkcnt = 0; 1199153323Srodrigc } 1200153323Srodrigc 1201153323Srodrigc retval = xfs_attr_leaf_add(blk->bp, state->args); 1202153323Srodrigc if (retval == ENOSPC) { 1203153323Srodrigc if (state->path.active == 1) { 1204153323Srodrigc /* 1205153323Srodrigc * Its really a single leaf node, but it had 1206153323Srodrigc * out-of-line values so it looked like it *might* 1207153323Srodrigc * have been a b-tree. 1208153323Srodrigc */ 1209153323Srodrigc xfs_da_state_free(state); 1210153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 1211153323Srodrigc error = xfs_attr_leaf_to_node(args); 1212153323Srodrigc if (!error) { 1213153323Srodrigc error = xfs_bmap_finish(&args->trans, 1214153323Srodrigc args->flist, 1215153323Srodrigc *args->firstblock, 1216153323Srodrigc &committed); 1217153323Srodrigc } 1218153323Srodrigc if (error) { 1219153323Srodrigc ASSERT(committed); 1220153323Srodrigc args->trans = NULL; 1221153323Srodrigc xfs_bmap_cancel(args->flist); 1222153323Srodrigc goto out; 1223153323Srodrigc } 1224153323Srodrigc 1225153323Srodrigc /* 1226153323Srodrigc * bmap_finish() may have committed the last trans 1227153323Srodrigc * and started a new one. We need the inode to be 1228153323Srodrigc * in all transactions. 1229153323Srodrigc */ 1230153323Srodrigc if (committed) { 1231153323Srodrigc xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 1232153323Srodrigc xfs_trans_ihold(args->trans, dp); 1233153323Srodrigc } 1234153323Srodrigc 1235153323Srodrigc /* 1236153323Srodrigc * Commit the node conversion and start the next 1237153323Srodrigc * trans in the chain. 1238153323Srodrigc */ 1239153323Srodrigc if ((error = xfs_attr_rolltrans(&args->trans, dp))) 1240153323Srodrigc goto out; 1241153323Srodrigc 1242153323Srodrigc goto restart; 1243153323Srodrigc } 1244153323Srodrigc 1245153323Srodrigc /* 1246153323Srodrigc * Split as many Btree elements as required. 1247153323Srodrigc * This code tracks the new and old attr's location 1248153323Srodrigc * in the index/blkno/rmtblkno/rmtblkcnt fields and 1249153323Srodrigc * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields. 1250153323Srodrigc */ 1251153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 1252153323Srodrigc error = xfs_da_split(state); 1253153323Srodrigc if (!error) { 1254153323Srodrigc error = xfs_bmap_finish(&args->trans, args->flist, 1255153323Srodrigc *args->firstblock, &committed); 1256153323Srodrigc } 1257153323Srodrigc if (error) { 1258153323Srodrigc ASSERT(committed); 1259153323Srodrigc args->trans = NULL; 1260153323Srodrigc xfs_bmap_cancel(args->flist); 1261153323Srodrigc goto out; 1262153323Srodrigc } 1263153323Srodrigc 1264153323Srodrigc /* 1265153323Srodrigc * bmap_finish() may have committed the last trans and started 1266153323Srodrigc * a new one. We need the inode to be in all transactions. 1267153323Srodrigc */ 1268153323Srodrigc if (committed) { 1269153323Srodrigc xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 1270153323Srodrigc xfs_trans_ihold(args->trans, dp); 1271153323Srodrigc } 1272153323Srodrigc } else { 1273153323Srodrigc /* 1274153323Srodrigc * Addition succeeded, update Btree hashvals. 1275153323Srodrigc */ 1276153323Srodrigc xfs_da_fixhashpath(state, &state->path); 1277153323Srodrigc } 1278153323Srodrigc 1279153323Srodrigc /* 1280153323Srodrigc * Kill the state structure, we're done with it and need to 1281153323Srodrigc * allow the buffers to come back later. 1282153323Srodrigc */ 1283153323Srodrigc xfs_da_state_free(state); 1284153323Srodrigc state = NULL; 1285153323Srodrigc 1286153323Srodrigc /* 1287153323Srodrigc * Commit the leaf addition or btree split and start the next 1288153323Srodrigc * trans in the chain. 1289153323Srodrigc */ 1290153323Srodrigc if ((error = xfs_attr_rolltrans(&args->trans, dp))) 1291153323Srodrigc goto out; 1292153323Srodrigc 1293153323Srodrigc /* 1294153323Srodrigc * If there was an out-of-line value, allocate the blocks we 1295153323Srodrigc * identified for its storage and copy the value. This is done 1296153323Srodrigc * after we create the attribute so that we don't overflow the 1297153323Srodrigc * maximum size of a transaction and/or hit a deadlock. 1298153323Srodrigc */ 1299153323Srodrigc if (args->rmtblkno > 0) { 1300153323Srodrigc error = xfs_attr_rmtval_set(args); 1301153323Srodrigc if (error) 1302153323Srodrigc return(error); 1303153323Srodrigc } 1304153323Srodrigc 1305153323Srodrigc /* 1306153323Srodrigc * If this is an atomic rename operation, we must "flip" the 1307153323Srodrigc * incomplete flags on the "new" and "old" attribute/value pairs 1308153323Srodrigc * so that one disappears and one appears atomically. Then we 1309153323Srodrigc * must remove the "old" attribute/value pair. 1310153323Srodrigc */ 1311153323Srodrigc if (args->rename) { 1312153323Srodrigc /* 1313153323Srodrigc * In a separate transaction, set the incomplete flag on the 1314153323Srodrigc * "old" attr and clear the incomplete flag on the "new" attr. 1315153323Srodrigc */ 1316153323Srodrigc error = xfs_attr_leaf_flipflags(args); 1317153323Srodrigc if (error) 1318153323Srodrigc goto out; 1319153323Srodrigc 1320153323Srodrigc /* 1321153323Srodrigc * Dismantle the "old" attribute/value pair by removing 1322153323Srodrigc * a "remote" value (if it exists). 1323153323Srodrigc */ 1324153323Srodrigc args->index = args->index2; 1325153323Srodrigc args->blkno = args->blkno2; 1326153323Srodrigc args->rmtblkno = args->rmtblkno2; 1327153323Srodrigc args->rmtblkcnt = args->rmtblkcnt2; 1328153323Srodrigc if (args->rmtblkno) { 1329153323Srodrigc error = xfs_attr_rmtval_remove(args); 1330153323Srodrigc if (error) 1331153323Srodrigc return(error); 1332153323Srodrigc } 1333153323Srodrigc 1334153323Srodrigc /* 1335153323Srodrigc * Re-find the "old" attribute entry after any split ops. 1336153323Srodrigc * The INCOMPLETE flag means that we will find the "old" 1337153323Srodrigc * attr, not the "new" one. 1338153323Srodrigc */ 1339153323Srodrigc args->flags |= XFS_ATTR_INCOMPLETE; 1340153323Srodrigc state = xfs_da_state_alloc(); 1341153323Srodrigc state->args = args; 1342153323Srodrigc state->mp = mp; 1343153323Srodrigc state->blocksize = state->mp->m_sb.sb_blocksize; 1344153323Srodrigc state->node_ents = state->mp->m_attr_node_ents; 1345153323Srodrigc state->inleaf = 0; 1346153323Srodrigc error = xfs_da_node_lookup_int(state, &retval); 1347153323Srodrigc if (error) 1348153323Srodrigc goto out; 1349153323Srodrigc 1350153323Srodrigc /* 1351153323Srodrigc * Remove the name and update the hashvals in the tree. 1352153323Srodrigc */ 1353153323Srodrigc blk = &state->path.blk[ state->path.active-1 ]; 1354153323Srodrigc ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); 1355153323Srodrigc error = xfs_attr_leaf_remove(blk->bp, args); 1356153323Srodrigc xfs_da_fixhashpath(state, &state->path); 1357153323Srodrigc 1358153323Srodrigc /* 1359153323Srodrigc * Check to see if the tree needs to be collapsed. 1360153323Srodrigc */ 1361153323Srodrigc if (retval && (state->path.active > 1)) { 1362153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 1363153323Srodrigc error = xfs_da_join(state); 1364153323Srodrigc if (!error) { 1365153323Srodrigc error = xfs_bmap_finish(&args->trans, 1366153323Srodrigc args->flist, 1367153323Srodrigc *args->firstblock, 1368153323Srodrigc &committed); 1369153323Srodrigc } 1370153323Srodrigc if (error) { 1371153323Srodrigc ASSERT(committed); 1372153323Srodrigc args->trans = NULL; 1373153323Srodrigc xfs_bmap_cancel(args->flist); 1374153323Srodrigc goto out; 1375153323Srodrigc } 1376153323Srodrigc 1377153323Srodrigc /* 1378153323Srodrigc * bmap_finish() may have committed the last trans 1379153323Srodrigc * and started a new one. We need the inode to be 1380153323Srodrigc * in all transactions. 1381153323Srodrigc */ 1382153323Srodrigc if (committed) { 1383153323Srodrigc xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 1384153323Srodrigc xfs_trans_ihold(args->trans, dp); 1385153323Srodrigc } 1386153323Srodrigc } 1387153323Srodrigc 1388153323Srodrigc /* 1389153323Srodrigc * Commit and start the next trans in the chain. 1390153323Srodrigc */ 1391153323Srodrigc if ((error = xfs_attr_rolltrans(&args->trans, dp))) 1392153323Srodrigc goto out; 1393153323Srodrigc 1394153323Srodrigc } else if (args->rmtblkno > 0) { 1395153323Srodrigc /* 1396153323Srodrigc * Added a "remote" value, just clear the incomplete flag. 1397153323Srodrigc */ 1398153323Srodrigc error = xfs_attr_leaf_clearflag(args); 1399153323Srodrigc if (error) 1400153323Srodrigc goto out; 1401153323Srodrigc } 1402153323Srodrigc retval = error = 0; 1403153323Srodrigc 1404153323Srodrigcout: 1405153323Srodrigc if (state) 1406153323Srodrigc xfs_da_state_free(state); 1407153323Srodrigc if (error) 1408153323Srodrigc return(error); 1409153323Srodrigc return(retval); 1410153323Srodrigc} 1411153323Srodrigc 1412153323Srodrigc/* 1413153323Srodrigc * Remove a name from a B-tree attribute list. 1414153323Srodrigc * 1415153323Srodrigc * This will involve walking down the Btree, and may involve joining 1416153323Srodrigc * leaf nodes and even joining intermediate nodes up to and including 1417153323Srodrigc * the root node (a special case of an intermediate node). 1418153323Srodrigc */ 1419153323SrodrigcSTATIC int 1420153323Srodrigcxfs_attr_node_removename(xfs_da_args_t *args) 1421153323Srodrigc{ 1422153323Srodrigc xfs_da_state_t *state; 1423153323Srodrigc xfs_da_state_blk_t *blk; 1424153323Srodrigc xfs_inode_t *dp; 1425153323Srodrigc xfs_dabuf_t *bp; 1426159451Srodrigc int retval, error, committed, forkoff; 1427153323Srodrigc 1428153323Srodrigc /* 1429153323Srodrigc * Tie a string around our finger to remind us where we are. 1430153323Srodrigc */ 1431153323Srodrigc dp = args->dp; 1432153323Srodrigc state = xfs_da_state_alloc(); 1433153323Srodrigc state->args = args; 1434153323Srodrigc state->mp = dp->i_mount; 1435153323Srodrigc state->blocksize = state->mp->m_sb.sb_blocksize; 1436153323Srodrigc state->node_ents = state->mp->m_attr_node_ents; 1437153323Srodrigc 1438153323Srodrigc /* 1439153323Srodrigc * Search to see if name exists, and get back a pointer to it. 1440153323Srodrigc */ 1441153323Srodrigc error = xfs_da_node_lookup_int(state, &retval); 1442153323Srodrigc if (error || (retval != EEXIST)) { 1443153323Srodrigc if (error == 0) 1444153323Srodrigc error = retval; 1445153323Srodrigc goto out; 1446153323Srodrigc } 1447153323Srodrigc 1448153323Srodrigc /* 1449153323Srodrigc * If there is an out-of-line value, de-allocate the blocks. 1450153323Srodrigc * This is done before we remove the attribute so that we don't 1451153323Srodrigc * overflow the maximum size of a transaction and/or hit a deadlock. 1452153323Srodrigc */ 1453153323Srodrigc blk = &state->path.blk[ state->path.active-1 ]; 1454153323Srodrigc ASSERT(blk->bp != NULL); 1455153323Srodrigc ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); 1456153323Srodrigc if (args->rmtblkno > 0) { 1457153323Srodrigc /* 1458153323Srodrigc * Fill in disk block numbers in the state structure 1459153323Srodrigc * so that we can get the buffers back after we commit 1460153323Srodrigc * several transactions in the following calls. 1461153323Srodrigc */ 1462153323Srodrigc error = xfs_attr_fillstate(state); 1463153323Srodrigc if (error) 1464153323Srodrigc goto out; 1465153323Srodrigc 1466153323Srodrigc /* 1467153323Srodrigc * Mark the attribute as INCOMPLETE, then bunmapi() the 1468153323Srodrigc * remote value. 1469153323Srodrigc */ 1470153323Srodrigc error = xfs_attr_leaf_setflag(args); 1471153323Srodrigc if (error) 1472153323Srodrigc goto out; 1473153323Srodrigc error = xfs_attr_rmtval_remove(args); 1474153323Srodrigc if (error) 1475153323Srodrigc goto out; 1476153323Srodrigc 1477153323Srodrigc /* 1478153323Srodrigc * Refill the state structure with buffers, the prior calls 1479153323Srodrigc * released our buffers. 1480153323Srodrigc */ 1481153323Srodrigc error = xfs_attr_refillstate(state); 1482153323Srodrigc if (error) 1483153323Srodrigc goto out; 1484153323Srodrigc } 1485153323Srodrigc 1486153323Srodrigc /* 1487153323Srodrigc * Remove the name and update the hashvals in the tree. 1488153323Srodrigc */ 1489153323Srodrigc blk = &state->path.blk[ state->path.active-1 ]; 1490153323Srodrigc ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); 1491153323Srodrigc retval = xfs_attr_leaf_remove(blk->bp, args); 1492153323Srodrigc xfs_da_fixhashpath(state, &state->path); 1493153323Srodrigc 1494153323Srodrigc /* 1495153323Srodrigc * Check to see if the tree needs to be collapsed. 1496153323Srodrigc */ 1497153323Srodrigc if (retval && (state->path.active > 1)) { 1498153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 1499153323Srodrigc error = xfs_da_join(state); 1500153323Srodrigc if (!error) { 1501153323Srodrigc error = xfs_bmap_finish(&args->trans, args->flist, 1502153323Srodrigc *args->firstblock, &committed); 1503153323Srodrigc } 1504153323Srodrigc if (error) { 1505153323Srodrigc ASSERT(committed); 1506153323Srodrigc args->trans = NULL; 1507153323Srodrigc xfs_bmap_cancel(args->flist); 1508153323Srodrigc goto out; 1509153323Srodrigc } 1510153323Srodrigc 1511153323Srodrigc /* 1512153323Srodrigc * bmap_finish() may have committed the last trans and started 1513153323Srodrigc * a new one. We need the inode to be in all transactions. 1514153323Srodrigc */ 1515153323Srodrigc if (committed) { 1516153323Srodrigc xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 1517153323Srodrigc xfs_trans_ihold(args->trans, dp); 1518153323Srodrigc } 1519153323Srodrigc 1520153323Srodrigc /* 1521153323Srodrigc * Commit the Btree join operation and start a new trans. 1522153323Srodrigc */ 1523153323Srodrigc if ((error = xfs_attr_rolltrans(&args->trans, dp))) 1524153323Srodrigc goto out; 1525153323Srodrigc } 1526153323Srodrigc 1527153323Srodrigc /* 1528153323Srodrigc * If the result is small enough, push it all into the inode. 1529153323Srodrigc */ 1530153323Srodrigc if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { 1531153323Srodrigc /* 1532153323Srodrigc * Have to get rid of the copy of this dabuf in the state. 1533153323Srodrigc */ 1534153323Srodrigc ASSERT(state->path.active == 1); 1535153323Srodrigc ASSERT(state->path.blk[0].bp); 1536153323Srodrigc xfs_da_buf_done(state->path.blk[0].bp); 1537153323Srodrigc state->path.blk[0].bp = NULL; 1538153323Srodrigc 1539153323Srodrigc error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, 1540153323Srodrigc XFS_ATTR_FORK); 1541153323Srodrigc if (error) 1542153323Srodrigc goto out; 1543159451Srodrigc ASSERT(be16_to_cpu(((xfs_attr_leafblock_t *) 1544159451Srodrigc bp->data)->hdr.info.magic) 1545153323Srodrigc == XFS_ATTR_LEAF_MAGIC); 1546153323Srodrigc 1547159451Srodrigc if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { 1548153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 1549159451Srodrigc error = xfs_attr_leaf_to_shortform(bp, args, forkoff); 1550153323Srodrigc /* bp is gone due to xfs_da_shrink_inode */ 1551153323Srodrigc if (!error) { 1552153323Srodrigc error = xfs_bmap_finish(&args->trans, 1553153323Srodrigc args->flist, 1554153323Srodrigc *args->firstblock, 1555153323Srodrigc &committed); 1556153323Srodrigc } 1557153323Srodrigc if (error) { 1558153323Srodrigc ASSERT(committed); 1559153323Srodrigc args->trans = NULL; 1560153323Srodrigc xfs_bmap_cancel(args->flist); 1561153323Srodrigc goto out; 1562153323Srodrigc } 1563153323Srodrigc 1564153323Srodrigc /* 1565153323Srodrigc * bmap_finish() may have committed the last trans 1566153323Srodrigc * and started a new one. We need the inode to be 1567153323Srodrigc * in all transactions. 1568153323Srodrigc */ 1569153323Srodrigc if (committed) { 1570153323Srodrigc xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 1571153323Srodrigc xfs_trans_ihold(args->trans, dp); 1572153323Srodrigc } 1573153323Srodrigc } else 1574153323Srodrigc xfs_da_brelse(args->trans, bp); 1575153323Srodrigc } 1576153323Srodrigc error = 0; 1577153323Srodrigc 1578153323Srodrigcout: 1579153323Srodrigc xfs_da_state_free(state); 1580153323Srodrigc return(error); 1581153323Srodrigc} 1582153323Srodrigc 1583153323Srodrigc/* 1584153323Srodrigc * Fill in the disk block numbers in the state structure for the buffers 1585153323Srodrigc * that are attached to the state structure. 1586153323Srodrigc * This is done so that we can quickly reattach ourselves to those buffers 1587159451Srodrigc * after some set of transaction commits have released these buffers. 1588153323Srodrigc */ 1589153323SrodrigcSTATIC int 1590153323Srodrigcxfs_attr_fillstate(xfs_da_state_t *state) 1591153323Srodrigc{ 1592153323Srodrigc xfs_da_state_path_t *path; 1593153323Srodrigc xfs_da_state_blk_t *blk; 1594153323Srodrigc int level; 1595153323Srodrigc 1596153323Srodrigc /* 1597153323Srodrigc * Roll down the "path" in the state structure, storing the on-disk 1598153323Srodrigc * block number for those buffers in the "path". 1599153323Srodrigc */ 1600153323Srodrigc path = &state->path; 1601153323Srodrigc ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); 1602153323Srodrigc for (blk = path->blk, level = 0; level < path->active; blk++, level++) { 1603153323Srodrigc if (blk->bp) { 1604153323Srodrigc blk->disk_blkno = xfs_da_blkno(blk->bp); 1605153323Srodrigc xfs_da_buf_done(blk->bp); 1606153323Srodrigc blk->bp = NULL; 1607153323Srodrigc } else { 1608153323Srodrigc blk->disk_blkno = 0; 1609153323Srodrigc } 1610153323Srodrigc } 1611153323Srodrigc 1612153323Srodrigc /* 1613153323Srodrigc * Roll down the "altpath" in the state structure, storing the on-disk 1614153323Srodrigc * block number for those buffers in the "altpath". 1615153323Srodrigc */ 1616153323Srodrigc path = &state->altpath; 1617153323Srodrigc ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); 1618153323Srodrigc for (blk = path->blk, level = 0; level < path->active; blk++, level++) { 1619153323Srodrigc if (blk->bp) { 1620153323Srodrigc blk->disk_blkno = xfs_da_blkno(blk->bp); 1621153323Srodrigc xfs_da_buf_done(blk->bp); 1622153323Srodrigc blk->bp = NULL; 1623153323Srodrigc } else { 1624153323Srodrigc blk->disk_blkno = 0; 1625153323Srodrigc } 1626153323Srodrigc } 1627153323Srodrigc 1628153323Srodrigc return(0); 1629153323Srodrigc} 1630153323Srodrigc 1631153323Srodrigc/* 1632153323Srodrigc * Reattach the buffers to the state structure based on the disk block 1633153323Srodrigc * numbers stored in the state structure. 1634159451Srodrigc * This is done after some set of transaction commits have released those 1635153323Srodrigc * buffers from our grip. 1636153323Srodrigc */ 1637153323SrodrigcSTATIC int 1638153323Srodrigcxfs_attr_refillstate(xfs_da_state_t *state) 1639153323Srodrigc{ 1640153323Srodrigc xfs_da_state_path_t *path; 1641153323Srodrigc xfs_da_state_blk_t *blk; 1642153323Srodrigc int level, error; 1643153323Srodrigc 1644153323Srodrigc /* 1645153323Srodrigc * Roll down the "path" in the state structure, storing the on-disk 1646153323Srodrigc * block number for those buffers in the "path". 1647153323Srodrigc */ 1648153323Srodrigc path = &state->path; 1649153323Srodrigc ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); 1650153323Srodrigc for (blk = path->blk, level = 0; level < path->active; blk++, level++) { 1651153323Srodrigc if (blk->disk_blkno) { 1652153323Srodrigc error = xfs_da_read_buf(state->args->trans, 1653153323Srodrigc state->args->dp, 1654153323Srodrigc blk->blkno, blk->disk_blkno, 1655153323Srodrigc &blk->bp, XFS_ATTR_FORK); 1656153323Srodrigc if (error) 1657153323Srodrigc return(error); 1658153323Srodrigc } else { 1659153323Srodrigc blk->bp = NULL; 1660153323Srodrigc } 1661153323Srodrigc } 1662153323Srodrigc 1663153323Srodrigc /* 1664153323Srodrigc * Roll down the "altpath" in the state structure, storing the on-disk 1665153323Srodrigc * block number for those buffers in the "altpath". 1666153323Srodrigc */ 1667153323Srodrigc path = &state->altpath; 1668153323Srodrigc ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); 1669153323Srodrigc for (blk = path->blk, level = 0; level < path->active; blk++, level++) { 1670153323Srodrigc if (blk->disk_blkno) { 1671153323Srodrigc error = xfs_da_read_buf(state->args->trans, 1672153323Srodrigc state->args->dp, 1673153323Srodrigc blk->blkno, blk->disk_blkno, 1674153323Srodrigc &blk->bp, XFS_ATTR_FORK); 1675153323Srodrigc if (error) 1676153323Srodrigc return(error); 1677153323Srodrigc } else { 1678153323Srodrigc blk->bp = NULL; 1679153323Srodrigc } 1680153323Srodrigc } 1681153323Srodrigc 1682153323Srodrigc return(0); 1683153323Srodrigc} 1684153323Srodrigc 1685153323Srodrigc/* 1686153323Srodrigc * Look up a filename in a node attribute list. 1687153323Srodrigc * 1688153323Srodrigc * This routine gets called for any attribute fork that has more than one 1689153323Srodrigc * block, ie: both true Btree attr lists and for single-leaf-blocks with 1690153323Srodrigc * "remote" values taking up more blocks. 1691153323Srodrigc */ 1692159451SrodrigcSTATIC int 1693153323Srodrigcxfs_attr_node_get(xfs_da_args_t *args) 1694153323Srodrigc{ 1695153323Srodrigc xfs_da_state_t *state; 1696153323Srodrigc xfs_da_state_blk_t *blk; 1697153323Srodrigc int error, retval; 1698153323Srodrigc int i; 1699153323Srodrigc 1700153323Srodrigc state = xfs_da_state_alloc(); 1701153323Srodrigc state->args = args; 1702153323Srodrigc state->mp = args->dp->i_mount; 1703153323Srodrigc state->blocksize = state->mp->m_sb.sb_blocksize; 1704153323Srodrigc state->node_ents = state->mp->m_attr_node_ents; 1705153323Srodrigc 1706153323Srodrigc /* 1707153323Srodrigc * Search to see if name exists, and get back a pointer to it. 1708153323Srodrigc */ 1709153323Srodrigc error = xfs_da_node_lookup_int(state, &retval); 1710153323Srodrigc if (error) { 1711153323Srodrigc retval = error; 1712153323Srodrigc } else if (retval == EEXIST) { 1713153323Srodrigc blk = &state->path.blk[ state->path.active-1 ]; 1714153323Srodrigc ASSERT(blk->bp != NULL); 1715153323Srodrigc ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); 1716153323Srodrigc 1717153323Srodrigc /* 1718153323Srodrigc * Get the value, local or "remote" 1719153323Srodrigc */ 1720153323Srodrigc retval = xfs_attr_leaf_getvalue(blk->bp, args); 1721153323Srodrigc if (!retval && (args->rmtblkno > 0) 1722153323Srodrigc && !(args->flags & ATTR_KERNOVAL)) { 1723153323Srodrigc retval = xfs_attr_rmtval_get(args); 1724153323Srodrigc } 1725153323Srodrigc } 1726153323Srodrigc 1727153323Srodrigc /* 1728153323Srodrigc * If not in a transaction, we have to release all the buffers. 1729153323Srodrigc */ 1730153323Srodrigc for (i = 0; i < state->path.active; i++) { 1731153323Srodrigc xfs_da_brelse(args->trans, state->path.blk[i].bp); 1732153323Srodrigc state->path.blk[i].bp = NULL; 1733153323Srodrigc } 1734153323Srodrigc 1735153323Srodrigc xfs_da_state_free(state); 1736153323Srodrigc return(retval); 1737153323Srodrigc} 1738153323Srodrigc 1739153323SrodrigcSTATIC int /* error */ 1740153323Srodrigcxfs_attr_node_list(xfs_attr_list_context_t *context) 1741153323Srodrigc{ 1742153323Srodrigc attrlist_cursor_kern_t *cursor; 1743153323Srodrigc xfs_attr_leafblock_t *leaf; 1744153323Srodrigc xfs_da_intnode_t *node; 1745153323Srodrigc xfs_da_node_entry_t *btree; 1746153323Srodrigc int error, i; 1747153323Srodrigc xfs_dabuf_t *bp; 1748153323Srodrigc 1749153323Srodrigc cursor = context->cursor; 1750153323Srodrigc cursor->initted = 1; 1751153323Srodrigc 1752153323Srodrigc /* 1753153323Srodrigc * Do all sorts of validation on the passed-in cursor structure. 1754153323Srodrigc * If anything is amiss, ignore the cursor and look up the hashval 1755153323Srodrigc * starting from the btree root. 1756153323Srodrigc */ 1757153323Srodrigc bp = NULL; 1758153323Srodrigc if (cursor->blkno > 0) { 1759153323Srodrigc error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, 1760153323Srodrigc &bp, XFS_ATTR_FORK); 1761153323Srodrigc if ((error != 0) && (error != EFSCORRUPTED)) 1762153323Srodrigc return(error); 1763153323Srodrigc if (bp) { 1764153323Srodrigc node = bp->data; 1765159451Srodrigc switch (be16_to_cpu(node->hdr.info.magic)) { 1766153323Srodrigc case XFS_DA_NODE_MAGIC: 1767153323Srodrigc xfs_attr_trace_l_cn("wrong blk", context, node); 1768153323Srodrigc xfs_da_brelse(NULL, bp); 1769153323Srodrigc bp = NULL; 1770153323Srodrigc break; 1771153323Srodrigc case XFS_ATTR_LEAF_MAGIC: 1772153323Srodrigc leaf = bp->data; 1773159451Srodrigc if (cursor->hashval > be32_to_cpu(leaf->entries[ 1774159451Srodrigc be16_to_cpu(leaf->hdr.count)-1].hashval)) { 1775153323Srodrigc xfs_attr_trace_l_cl("wrong blk", 1776153323Srodrigc context, leaf); 1777153323Srodrigc xfs_da_brelse(NULL, bp); 1778153323Srodrigc bp = NULL; 1779153323Srodrigc } else if (cursor->hashval <= 1780159451Srodrigc be32_to_cpu(leaf->entries[0].hashval)) { 1781153323Srodrigc xfs_attr_trace_l_cl("maybe wrong blk", 1782153323Srodrigc context, leaf); 1783153323Srodrigc xfs_da_brelse(NULL, bp); 1784153323Srodrigc bp = NULL; 1785153323Srodrigc } 1786153323Srodrigc break; 1787153323Srodrigc default: 1788153323Srodrigc xfs_attr_trace_l_c("wrong blk - ??", context); 1789153323Srodrigc xfs_da_brelse(NULL, bp); 1790153323Srodrigc bp = NULL; 1791153323Srodrigc } 1792153323Srodrigc } 1793153323Srodrigc } 1794153323Srodrigc 1795153323Srodrigc /* 1796153323Srodrigc * We did not find what we expected given the cursor's contents, 1797153323Srodrigc * so we start from the top and work down based on the hash value. 1798153323Srodrigc * Note that start of node block is same as start of leaf block. 1799153323Srodrigc */ 1800153323Srodrigc if (bp == NULL) { 1801153323Srodrigc cursor->blkno = 0; 1802153323Srodrigc for (;;) { 1803153323Srodrigc error = xfs_da_read_buf(NULL, context->dp, 1804153323Srodrigc cursor->blkno, -1, &bp, 1805153323Srodrigc XFS_ATTR_FORK); 1806153323Srodrigc if (error) 1807153323Srodrigc return(error); 1808153323Srodrigc if (unlikely(bp == NULL)) { 1809153323Srodrigc XFS_ERROR_REPORT("xfs_attr_node_list(2)", 1810153323Srodrigc XFS_ERRLEVEL_LOW, 1811153323Srodrigc context->dp->i_mount); 1812153323Srodrigc return(XFS_ERROR(EFSCORRUPTED)); 1813153323Srodrigc } 1814153323Srodrigc node = bp->data; 1815159451Srodrigc if (be16_to_cpu(node->hdr.info.magic) 1816153323Srodrigc == XFS_ATTR_LEAF_MAGIC) 1817153323Srodrigc break; 1818159451Srodrigc if (unlikely(be16_to_cpu(node->hdr.info.magic) 1819153323Srodrigc != XFS_DA_NODE_MAGIC)) { 1820153323Srodrigc XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)", 1821153323Srodrigc XFS_ERRLEVEL_LOW, 1822153323Srodrigc context->dp->i_mount, 1823153323Srodrigc node); 1824153323Srodrigc xfs_da_brelse(NULL, bp); 1825153323Srodrigc return(XFS_ERROR(EFSCORRUPTED)); 1826153323Srodrigc } 1827153323Srodrigc btree = node->btree; 1828159451Srodrigc for (i = 0; i < be16_to_cpu(node->hdr.count); 1829153323Srodrigc btree++, i++) { 1830153323Srodrigc if (cursor->hashval 1831159451Srodrigc <= be32_to_cpu(btree->hashval)) { 1832159451Srodrigc cursor->blkno = be32_to_cpu(btree->before); 1833153323Srodrigc xfs_attr_trace_l_cb("descending", 1834153323Srodrigc context, btree); 1835153323Srodrigc break; 1836153323Srodrigc } 1837153323Srodrigc } 1838159451Srodrigc if (i == be16_to_cpu(node->hdr.count)) { 1839153323Srodrigc xfs_da_brelse(NULL, bp); 1840153323Srodrigc return(0); 1841153323Srodrigc } 1842153323Srodrigc xfs_da_brelse(NULL, bp); 1843153323Srodrigc } 1844153323Srodrigc } 1845153323Srodrigc ASSERT(bp != NULL); 1846153323Srodrigc 1847153323Srodrigc /* 1848153323Srodrigc * Roll upward through the blocks, processing each leaf block in 1849153323Srodrigc * order. As long as there is space in the result buffer, keep 1850153323Srodrigc * adding the information. 1851153323Srodrigc */ 1852153323Srodrigc for (;;) { 1853153323Srodrigc leaf = bp->data; 1854159451Srodrigc if (unlikely(be16_to_cpu(leaf->hdr.info.magic) 1855153323Srodrigc != XFS_ATTR_LEAF_MAGIC)) { 1856153323Srodrigc XFS_CORRUPTION_ERROR("xfs_attr_node_list(4)", 1857153323Srodrigc XFS_ERRLEVEL_LOW, 1858153323Srodrigc context->dp->i_mount, leaf); 1859153323Srodrigc xfs_da_brelse(NULL, bp); 1860153323Srodrigc return(XFS_ERROR(EFSCORRUPTED)); 1861153323Srodrigc } 1862153323Srodrigc error = xfs_attr_leaf_list_int(bp, context); 1863159451Srodrigc if (error || !leaf->hdr.info.forw) 1864153323Srodrigc break; /* not really an error, buffer full or EOF */ 1865159451Srodrigc cursor->blkno = be32_to_cpu(leaf->hdr.info.forw); 1866153323Srodrigc xfs_da_brelse(NULL, bp); 1867153323Srodrigc error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, 1868153323Srodrigc &bp, XFS_ATTR_FORK); 1869153323Srodrigc if (error) 1870153323Srodrigc return(error); 1871153323Srodrigc if (unlikely((bp == NULL))) { 1872153323Srodrigc XFS_ERROR_REPORT("xfs_attr_node_list(5)", 1873153323Srodrigc XFS_ERRLEVEL_LOW, 1874153323Srodrigc context->dp->i_mount); 1875153323Srodrigc return(XFS_ERROR(EFSCORRUPTED)); 1876153323Srodrigc } 1877153323Srodrigc } 1878153323Srodrigc xfs_da_brelse(NULL, bp); 1879153323Srodrigc return(0); 1880153323Srodrigc} 1881153323Srodrigc 1882153323Srodrigc 1883153323Srodrigc/*======================================================================== 1884153323Srodrigc * External routines for manipulating out-of-line attribute values. 1885153323Srodrigc *========================================================================*/ 1886153323Srodrigc 1887153323Srodrigc/* 1888153323Srodrigc * Read the value associated with an attribute from the out-of-line buffer 1889153323Srodrigc * that we stored it in. 1890153323Srodrigc */ 1891153323SrodrigcSTATIC int 1892153323Srodrigcxfs_attr_rmtval_get(xfs_da_args_t *args) 1893153323Srodrigc{ 1894153323Srodrigc xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; 1895153323Srodrigc xfs_mount_t *mp; 1896153323Srodrigc xfs_daddr_t dblkno; 1897153323Srodrigc xfs_caddr_t dst; 1898153323Srodrigc xfs_buf_t *bp; 1899153323Srodrigc int nmap, error, tmp, valuelen, blkcnt, i; 1900153323Srodrigc xfs_dablk_t lblkno; 1901153323Srodrigc 1902153323Srodrigc ASSERT(!(args->flags & ATTR_KERNOVAL)); 1903153323Srodrigc 1904153323Srodrigc mp = args->dp->i_mount; 1905153323Srodrigc dst = args->value; 1906153323Srodrigc valuelen = args->valuelen; 1907153323Srodrigc lblkno = args->rmtblkno; 1908153323Srodrigc while (valuelen > 0) { 1909153323Srodrigc nmap = ATTR_RMTVALUE_MAPSIZE; 1910153323Srodrigc error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno, 1911153323Srodrigc args->rmtblkcnt, 1912153323Srodrigc XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, 1913159451Srodrigc NULL, 0, map, &nmap, NULL, NULL); 1914153323Srodrigc if (error) 1915153323Srodrigc return(error); 1916153323Srodrigc ASSERT(nmap >= 1); 1917153323Srodrigc 1918153323Srodrigc for (i = 0; (i < nmap) && (valuelen > 0); i++) { 1919153323Srodrigc ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && 1920153323Srodrigc (map[i].br_startblock != HOLESTARTBLOCK)); 1921153323Srodrigc dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); 1922153323Srodrigc blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); 1923153323Srodrigc error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno, 1924153323Srodrigc blkcnt, XFS_BUF_LOCK, &bp); 1925153323Srodrigc if (error) 1926153323Srodrigc return(error); 1927153323Srodrigc 1928153323Srodrigc tmp = (valuelen < XFS_BUF_SIZE(bp)) 1929153323Srodrigc ? valuelen : XFS_BUF_SIZE(bp); 1930153323Srodrigc xfs_biomove(bp, 0, tmp, dst, XFS_B_READ); 1931153323Srodrigc xfs_buf_relse(bp); 1932153323Srodrigc dst += tmp; 1933153323Srodrigc valuelen -= tmp; 1934153323Srodrigc 1935153323Srodrigc lblkno += map[i].br_blockcount; 1936153323Srodrigc } 1937153323Srodrigc } 1938153323Srodrigc ASSERT(valuelen == 0); 1939153323Srodrigc return(0); 1940153323Srodrigc} 1941153323Srodrigc 1942153323Srodrigc/* 1943153323Srodrigc * Write the value associated with an attribute into the out-of-line buffer 1944153323Srodrigc * that we have defined for it. 1945153323Srodrigc */ 1946153323SrodrigcSTATIC int 1947153323Srodrigcxfs_attr_rmtval_set(xfs_da_args_t *args) 1948153323Srodrigc{ 1949153323Srodrigc xfs_mount_t *mp; 1950153323Srodrigc xfs_fileoff_t lfileoff; 1951153323Srodrigc xfs_inode_t *dp; 1952153323Srodrigc xfs_bmbt_irec_t map; 1953153323Srodrigc xfs_daddr_t dblkno; 1954153323Srodrigc xfs_caddr_t src; 1955153323Srodrigc xfs_buf_t *bp; 1956153323Srodrigc xfs_dablk_t lblkno; 1957153323Srodrigc int blkcnt, valuelen, nmap, error, tmp, committed; 1958153323Srodrigc 1959153323Srodrigc dp = args->dp; 1960153323Srodrigc mp = dp->i_mount; 1961153323Srodrigc src = args->value; 1962153323Srodrigc 1963153323Srodrigc /* 1964153323Srodrigc * Find a "hole" in the attribute address space large enough for 1965153323Srodrigc * us to drop the new attribute's value into. 1966153323Srodrigc */ 1967153323Srodrigc blkcnt = XFS_B_TO_FSB(mp, args->valuelen); 1968153323Srodrigc lfileoff = 0; 1969153323Srodrigc error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, 1970153323Srodrigc XFS_ATTR_FORK); 1971153323Srodrigc if (error) { 1972153323Srodrigc return(error); 1973153323Srodrigc } 1974153323Srodrigc args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; 1975153323Srodrigc args->rmtblkcnt = blkcnt; 1976153323Srodrigc 1977153323Srodrigc /* 1978153323Srodrigc * Roll through the "value", allocating blocks on disk as required. 1979153323Srodrigc */ 1980153323Srodrigc while (blkcnt > 0) { 1981153323Srodrigc /* 1982153323Srodrigc * Allocate a single extent, up to the size of the value. 1983153323Srodrigc */ 1984153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 1985153323Srodrigc nmap = 1; 1986153323Srodrigc error = xfs_bmapi(args->trans, dp, (xfs_fileoff_t)lblkno, 1987153323Srodrigc blkcnt, 1988153323Srodrigc XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA | 1989153323Srodrigc XFS_BMAPI_WRITE, 1990153323Srodrigc args->firstblock, args->total, &map, &nmap, 1991159451Srodrigc args->flist, NULL); 1992153323Srodrigc if (!error) { 1993153323Srodrigc error = xfs_bmap_finish(&args->trans, args->flist, 1994153323Srodrigc *args->firstblock, &committed); 1995153323Srodrigc } 1996153323Srodrigc if (error) { 1997153323Srodrigc ASSERT(committed); 1998153323Srodrigc args->trans = NULL; 1999153323Srodrigc xfs_bmap_cancel(args->flist); 2000153323Srodrigc return(error); 2001153323Srodrigc } 2002153323Srodrigc 2003153323Srodrigc /* 2004153323Srodrigc * bmap_finish() may have committed the last trans and started 2005153323Srodrigc * a new one. We need the inode to be in all transactions. 2006153323Srodrigc */ 2007153323Srodrigc if (committed) { 2008153323Srodrigc xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); 2009153323Srodrigc xfs_trans_ihold(args->trans, dp); 2010153323Srodrigc } 2011153323Srodrigc 2012153323Srodrigc ASSERT(nmap == 1); 2013153323Srodrigc ASSERT((map.br_startblock != DELAYSTARTBLOCK) && 2014153323Srodrigc (map.br_startblock != HOLESTARTBLOCK)); 2015153323Srodrigc lblkno += map.br_blockcount; 2016153323Srodrigc blkcnt -= map.br_blockcount; 2017153323Srodrigc 2018153323Srodrigc /* 2019153323Srodrigc * Start the next trans in the chain. 2020153323Srodrigc */ 2021153323Srodrigc if ((error = xfs_attr_rolltrans(&args->trans, dp))) 2022153323Srodrigc return (error); 2023153323Srodrigc } 2024153323Srodrigc 2025153323Srodrigc /* 2026153323Srodrigc * Roll through the "value", copying the attribute value to the 2027153323Srodrigc * already-allocated blocks. Blocks are written synchronously 2028153323Srodrigc * so that we can know they are all on disk before we turn off 2029153323Srodrigc * the INCOMPLETE flag. 2030153323Srodrigc */ 2031153323Srodrigc lblkno = args->rmtblkno; 2032153323Srodrigc valuelen = args->valuelen; 2033153323Srodrigc while (valuelen > 0) { 2034153323Srodrigc /* 2035153323Srodrigc * Try to remember where we decided to put the value. 2036153323Srodrigc */ 2037153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 2038153323Srodrigc nmap = 1; 2039153323Srodrigc error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno, 2040153323Srodrigc args->rmtblkcnt, 2041153323Srodrigc XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, 2042159451Srodrigc args->firstblock, 0, &map, &nmap, 2043159451Srodrigc NULL, NULL); 2044153323Srodrigc if (error) { 2045153323Srodrigc return(error); 2046153323Srodrigc } 2047153323Srodrigc ASSERT(nmap == 1); 2048153323Srodrigc ASSERT((map.br_startblock != DELAYSTARTBLOCK) && 2049153323Srodrigc (map.br_startblock != HOLESTARTBLOCK)); 2050153323Srodrigc 2051153323Srodrigc dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 2052153323Srodrigc blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 2053153323Srodrigc 2054153323Srodrigc bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno, 2055153323Srodrigc blkcnt, XFS_BUF_LOCK); 2056153323Srodrigc ASSERT(bp); 2057153323Srodrigc ASSERT(!XFS_BUF_GETERROR(bp)); 2058153323Srodrigc 2059153323Srodrigc tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen : 2060153323Srodrigc XFS_BUF_SIZE(bp); 2061153323Srodrigc xfs_biomove(bp, 0, tmp, src, XFS_B_WRITE); 2062153323Srodrigc if (tmp < XFS_BUF_SIZE(bp)) 2063153323Srodrigc xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp); 2064153323Srodrigc if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */ 2065153323Srodrigc return (error); 2066153323Srodrigc } 2067153323Srodrigc src += tmp; 2068153323Srodrigc valuelen -= tmp; 2069153323Srodrigc 2070153323Srodrigc lblkno += map.br_blockcount; 2071153323Srodrigc } 2072153323Srodrigc ASSERT(valuelen == 0); 2073153323Srodrigc return(0); 2074153323Srodrigc} 2075153323Srodrigc 2076153323Srodrigc/* 2077153323Srodrigc * Remove the value associated with an attribute by deleting the 2078153323Srodrigc * out-of-line buffer that it is stored on. 2079153323Srodrigc */ 2080153323SrodrigcSTATIC int 2081153323Srodrigcxfs_attr_rmtval_remove(xfs_da_args_t *args) 2082153323Srodrigc{ 2083153323Srodrigc xfs_mount_t *mp; 2084153323Srodrigc xfs_bmbt_irec_t map; 2085153323Srodrigc xfs_buf_t *bp; 2086153323Srodrigc xfs_daddr_t dblkno; 2087153323Srodrigc xfs_dablk_t lblkno; 2088153323Srodrigc int valuelen, blkcnt, nmap, error, done, committed; 2089153323Srodrigc 2090153323Srodrigc mp = args->dp->i_mount; 2091153323Srodrigc 2092153323Srodrigc /* 2093153323Srodrigc * Roll through the "value", invalidating the attribute value's 2094153323Srodrigc * blocks. 2095153323Srodrigc */ 2096153323Srodrigc lblkno = args->rmtblkno; 2097153323Srodrigc valuelen = args->rmtblkcnt; 2098153323Srodrigc while (valuelen > 0) { 2099153323Srodrigc /* 2100153323Srodrigc * Try to remember where we decided to put the value. 2101153323Srodrigc */ 2102153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 2103153323Srodrigc nmap = 1; 2104153323Srodrigc error = xfs_bmapi(NULL, args->dp, (xfs_fileoff_t)lblkno, 2105153323Srodrigc args->rmtblkcnt, 2106153323Srodrigc XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, 2107153323Srodrigc args->firstblock, 0, &map, &nmap, 2108159451Srodrigc args->flist, NULL); 2109153323Srodrigc if (error) { 2110153323Srodrigc return(error); 2111153323Srodrigc } 2112153323Srodrigc ASSERT(nmap == 1); 2113153323Srodrigc ASSERT((map.br_startblock != DELAYSTARTBLOCK) && 2114153323Srodrigc (map.br_startblock != HOLESTARTBLOCK)); 2115153323Srodrigc 2116153323Srodrigc dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), 2117153323Srodrigc blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); 2118153323Srodrigc 2119153323Srodrigc /* 2120153323Srodrigc * If the "remote" value is in the cache, remove it. 2121153323Srodrigc */ 2122159451Srodrigc bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, 2123159451Srodrigc XFS_INCORE_TRYLOCK); 2124153323Srodrigc if (bp) { 2125153323Srodrigc XFS_BUF_STALE(bp); 2126153323Srodrigc XFS_BUF_UNDELAYWRITE(bp); 2127153323Srodrigc xfs_buf_relse(bp); 2128153323Srodrigc bp = NULL; 2129153323Srodrigc } 2130153323Srodrigc 2131153323Srodrigc valuelen -= map.br_blockcount; 2132153323Srodrigc 2133153323Srodrigc lblkno += map.br_blockcount; 2134153323Srodrigc } 2135153323Srodrigc 2136153323Srodrigc /* 2137153323Srodrigc * Keep de-allocating extents until the remote-value region is gone. 2138153323Srodrigc */ 2139153323Srodrigc lblkno = args->rmtblkno; 2140153323Srodrigc blkcnt = args->rmtblkcnt; 2141153323Srodrigc done = 0; 2142153323Srodrigc while (!done) { 2143153323Srodrigc XFS_BMAP_INIT(args->flist, args->firstblock); 2144153323Srodrigc error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, 2145153323Srodrigc XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, 2146159451Srodrigc 1, args->firstblock, args->flist, 2147159451Srodrigc NULL, &done); 2148153323Srodrigc if (!error) { 2149153323Srodrigc error = xfs_bmap_finish(&args->trans, args->flist, 2150153323Srodrigc *args->firstblock, &committed); 2151153323Srodrigc } 2152153323Srodrigc if (error) { 2153153323Srodrigc ASSERT(committed); 2154153323Srodrigc args->trans = NULL; 2155153323Srodrigc xfs_bmap_cancel(args->flist); 2156153323Srodrigc return(error); 2157153323Srodrigc } 2158153323Srodrigc 2159153323Srodrigc /* 2160153323Srodrigc * bmap_finish() may have committed the last trans and started 2161153323Srodrigc * a new one. We need the inode to be in all transactions. 2162153323Srodrigc */ 2163153323Srodrigc if (committed) { 2164153323Srodrigc xfs_trans_ijoin(args->trans, args->dp, XFS_ILOCK_EXCL); 2165153323Srodrigc xfs_trans_ihold(args->trans, args->dp); 2166153323Srodrigc } 2167153323Srodrigc 2168153323Srodrigc /* 2169153323Srodrigc * Close out trans and start the next one in the chain. 2170153323Srodrigc */ 2171153323Srodrigc if ((error = xfs_attr_rolltrans(&args->trans, args->dp))) 2172153323Srodrigc return (error); 2173153323Srodrigc } 2174153323Srodrigc return(0); 2175153323Srodrigc} 2176153323Srodrigc 2177153323Srodrigc#if defined(XFS_ATTR_TRACE) 2178153323Srodrigc/* 2179153323Srodrigc * Add a trace buffer entry for an attr_list context structure. 2180153323Srodrigc */ 2181153323Srodrigcvoid 2182153323Srodrigcxfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context) 2183153323Srodrigc{ 2184153323Srodrigc xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, 2185153323Srodrigc (__psunsigned_t)context->dp, 2186153323Srodrigc (__psunsigned_t)context->cursor->hashval, 2187153323Srodrigc (__psunsigned_t)context->cursor->blkno, 2188153323Srodrigc (__psunsigned_t)context->cursor->offset, 2189153323Srodrigc (__psunsigned_t)context->alist, 2190153323Srodrigc (__psunsigned_t)context->bufsize, 2191153323Srodrigc (__psunsigned_t)context->count, 2192153323Srodrigc (__psunsigned_t)context->firstu, 2193153323Srodrigc (__psunsigned_t) 2194153323Srodrigc ((context->count > 0) && 2195153323Srodrigc !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) 2196153323Srodrigc ? (ATTR_ENTRY(context->alist, 2197153323Srodrigc context->count-1)->a_valuelen) 2198153323Srodrigc : 0, 2199153323Srodrigc (__psunsigned_t)context->dupcnt, 2200153323Srodrigc (__psunsigned_t)context->flags, 2201153323Srodrigc (__psunsigned_t)NULL, 2202153323Srodrigc (__psunsigned_t)NULL, 2203153323Srodrigc (__psunsigned_t)NULL); 2204153323Srodrigc} 2205153323Srodrigc 2206153323Srodrigc/* 2207153323Srodrigc * Add a trace buffer entry for a context structure and a Btree node. 2208153323Srodrigc */ 2209153323Srodrigcvoid 2210153323Srodrigcxfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, 2211153323Srodrigc struct xfs_da_intnode *node) 2212153323Srodrigc{ 2213153323Srodrigc xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, 2214153323Srodrigc (__psunsigned_t)context->dp, 2215153323Srodrigc (__psunsigned_t)context->cursor->hashval, 2216153323Srodrigc (__psunsigned_t)context->cursor->blkno, 2217153323Srodrigc (__psunsigned_t)context->cursor->offset, 2218153323Srodrigc (__psunsigned_t)context->alist, 2219153323Srodrigc (__psunsigned_t)context->bufsize, 2220153323Srodrigc (__psunsigned_t)context->count, 2221153323Srodrigc (__psunsigned_t)context->firstu, 2222153323Srodrigc (__psunsigned_t) 2223153323Srodrigc ((context->count > 0) && 2224153323Srodrigc !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) 2225153323Srodrigc ? (ATTR_ENTRY(context->alist, 2226153323Srodrigc context->count-1)->a_valuelen) 2227153323Srodrigc : 0, 2228153323Srodrigc (__psunsigned_t)context->dupcnt, 2229153323Srodrigc (__psunsigned_t)context->flags, 2230159451Srodrigc (__psunsigned_t)be16_to_cpu(node->hdr.count), 2231159451Srodrigc (__psunsigned_t)be32_to_cpu(node->btree[0].hashval), 2232159451Srodrigc (__psunsigned_t)be32_to_cpu(node->btree[ 2233159451Srodrigc be16_to_cpu(node->hdr.count)-1].hashval)); 2234153323Srodrigc} 2235153323Srodrigc 2236153323Srodrigc/* 2237153323Srodrigc * Add a trace buffer entry for a context structure and a Btree element. 2238153323Srodrigc */ 2239153323Srodrigcvoid 2240153323Srodrigcxfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, 2241153323Srodrigc struct xfs_da_node_entry *btree) 2242153323Srodrigc{ 2243153323Srodrigc xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, 2244153323Srodrigc (__psunsigned_t)context->dp, 2245153323Srodrigc (__psunsigned_t)context->cursor->hashval, 2246153323Srodrigc (__psunsigned_t)context->cursor->blkno, 2247153323Srodrigc (__psunsigned_t)context->cursor->offset, 2248153323Srodrigc (__psunsigned_t)context->alist, 2249153323Srodrigc (__psunsigned_t)context->bufsize, 2250153323Srodrigc (__psunsigned_t)context->count, 2251153323Srodrigc (__psunsigned_t)context->firstu, 2252153323Srodrigc (__psunsigned_t) 2253153323Srodrigc ((context->count > 0) && 2254153323Srodrigc !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) 2255153323Srodrigc ? (ATTR_ENTRY(context->alist, 2256153323Srodrigc context->count-1)->a_valuelen) 2257153323Srodrigc : 0, 2258153323Srodrigc (__psunsigned_t)context->dupcnt, 2259153323Srodrigc (__psunsigned_t)context->flags, 2260159451Srodrigc (__psunsigned_t)be32_to_cpu(btree->hashval), 2261159451Srodrigc (__psunsigned_t)be32_to_cpu(btree->before), 2262153323Srodrigc (__psunsigned_t)NULL); 2263153323Srodrigc} 2264153323Srodrigc 2265153323Srodrigc/* 2266153323Srodrigc * Add a trace buffer entry for a context structure and a leaf block. 2267153323Srodrigc */ 2268153323Srodrigcvoid 2269153323Srodrigcxfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, 2270153323Srodrigc struct xfs_attr_leafblock *leaf) 2271153323Srodrigc{ 2272153323Srodrigc xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, 2273153323Srodrigc (__psunsigned_t)context->dp, 2274153323Srodrigc (__psunsigned_t)context->cursor->hashval, 2275153323Srodrigc (__psunsigned_t)context->cursor->blkno, 2276153323Srodrigc (__psunsigned_t)context->cursor->offset, 2277153323Srodrigc (__psunsigned_t)context->alist, 2278153323Srodrigc (__psunsigned_t)context->bufsize, 2279153323Srodrigc (__psunsigned_t)context->count, 2280153323Srodrigc (__psunsigned_t)context->firstu, 2281153323Srodrigc (__psunsigned_t) 2282153323Srodrigc ((context->count > 0) && 2283153323Srodrigc !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) 2284153323Srodrigc ? (ATTR_ENTRY(context->alist, 2285153323Srodrigc context->count-1)->a_valuelen) 2286153323Srodrigc : 0, 2287153323Srodrigc (__psunsigned_t)context->dupcnt, 2288153323Srodrigc (__psunsigned_t)context->flags, 2289159451Srodrigc (__psunsigned_t)be16_to_cpu(leaf->hdr.count), 2290159451Srodrigc (__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval), 2291159451Srodrigc (__psunsigned_t)be32_to_cpu(leaf->entries[ 2292159451Srodrigc be16_to_cpu(leaf->hdr.count)-1].hashval)); 2293153323Srodrigc} 2294153323Srodrigc 2295153323Srodrigc/* 2296153323Srodrigc * Add a trace buffer entry for the arguments given to the routine, 2297153323Srodrigc * generic form. 2298153323Srodrigc */ 2299153323Srodrigcvoid 2300153323Srodrigcxfs_attr_trace_enter(int type, char *where, 2301153323Srodrigc __psunsigned_t a2, __psunsigned_t a3, 2302153323Srodrigc __psunsigned_t a4, __psunsigned_t a5, 2303153323Srodrigc __psunsigned_t a6, __psunsigned_t a7, 2304153323Srodrigc __psunsigned_t a8, __psunsigned_t a9, 2305153323Srodrigc __psunsigned_t a10, __psunsigned_t a11, 2306153323Srodrigc __psunsigned_t a12, __psunsigned_t a13, 2307153323Srodrigc __psunsigned_t a14, __psunsigned_t a15) 2308153323Srodrigc{ 2309153323Srodrigc ASSERT(xfs_attr_trace_buf); 2310153323Srodrigc ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type), 2311153323Srodrigc (void *)where, 2312153323Srodrigc (void *)a2, (void *)a3, (void *)a4, 2313153323Srodrigc (void *)a5, (void *)a6, (void *)a7, 2314153323Srodrigc (void *)a8, (void *)a9, (void *)a10, 2315153323Srodrigc (void *)a11, (void *)a12, (void *)a13, 2316153323Srodrigc (void *)a14, (void *)a15); 2317153323Srodrigc} 2318153323Srodrigc#endif /* XFS_ATTR_TRACE */ 2319153323Srodrigc 2320153323Srodrigc 2321153323Srodrigc/*======================================================================== 2322153323Srodrigc * System (pseudo) namespace attribute interface routines. 2323153323Srodrigc *========================================================================*/ 2324153323Srodrigc 2325153323SrodrigcSTATIC int 2326153323Srodrigcposix_acl_access_set( 2327153323Srodrigc xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags) 2328153323Srodrigc{ 2329153323Srodrigc return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS); 2330153323Srodrigc} 2331153323Srodrigc 2332153323SrodrigcSTATIC int 2333153323Srodrigcposix_acl_access_remove( 2334153323Srodrigc struct xfs_vnode *vp, char *name, int xflags) 2335153323Srodrigc{ 2336153323Srodrigc return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); 2337153323Srodrigc} 2338153323Srodrigc 2339153323SrodrigcSTATIC int 2340153323Srodrigcposix_acl_access_get( 2341153323Srodrigc xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags) 2342153323Srodrigc{ 2343153323Srodrigc return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS); 2344153323Srodrigc} 2345153323Srodrigc 2346153323SrodrigcSTATIC int 2347153323Srodrigcposix_acl_access_exists( 2348153323Srodrigc xfs_vnode_t *vp) 2349153323Srodrigc{ 2350153323Srodrigc return xfs_acl_vhasacl_access(vp); 2351153323Srodrigc} 2352153323Srodrigc 2353153323SrodrigcSTATIC int 2354153323Srodrigcposix_acl_default_set( 2355153323Srodrigc xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags) 2356153323Srodrigc{ 2357153323Srodrigc return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT); 2358153323Srodrigc} 2359153323Srodrigc 2360153323SrodrigcSTATIC int 2361153323Srodrigcposix_acl_default_get( 2362153323Srodrigc xfs_vnode_t *vp, char *name, void *data, size_t size, int xflags) 2363153323Srodrigc{ 2364153323Srodrigc return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT); 2365153323Srodrigc} 2366153323Srodrigc 2367153323SrodrigcSTATIC int 2368153323Srodrigcposix_acl_default_remove( 2369153323Srodrigc struct xfs_vnode *vp, char *name, int xflags) 2370153323Srodrigc{ 2371153323Srodrigc return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT); 2372153323Srodrigc} 2373153323Srodrigc 2374153323SrodrigcSTATIC int 2375153323Srodrigcposix_acl_default_exists( 2376153323Srodrigc xfs_vnode_t *vp) 2377153323Srodrigc{ 2378153323Srodrigc return xfs_acl_vhasacl_default(vp); 2379153323Srodrigc} 2380153323Srodrigc 2381159451SrodrigcSTATIC struct attrnames posix_acl_access = { 2382153323Srodrigc .attr_name = "posix_acl_access", 2383153323Srodrigc .attr_namelen = sizeof("posix_acl_access") - 1, 2384153323Srodrigc .attr_get = posix_acl_access_get, 2385153323Srodrigc .attr_set = posix_acl_access_set, 2386153323Srodrigc .attr_remove = posix_acl_access_remove, 2387153323Srodrigc .attr_exists = posix_acl_access_exists, 2388153323Srodrigc}; 2389153323Srodrigc 2390159451SrodrigcSTATIC struct attrnames posix_acl_default = { 2391153323Srodrigc .attr_name = "posix_acl_default", 2392153323Srodrigc .attr_namelen = sizeof("posix_acl_default") - 1, 2393153323Srodrigc .attr_get = posix_acl_default_get, 2394153323Srodrigc .attr_set = posix_acl_default_set, 2395153323Srodrigc .attr_remove = posix_acl_default_remove, 2396153323Srodrigc .attr_exists = posix_acl_default_exists, 2397153323Srodrigc}; 2398153323Srodrigc 2399159451SrodrigcSTATIC struct attrnames *attr_system_names[] = 2400153323Srodrigc { &posix_acl_access, &posix_acl_default }; 2401153323Srodrigc 2402153323Srodrigc 2403153323Srodrigc/*======================================================================== 2404153323Srodrigc * Namespace-prefix-style attribute name interface routines. 2405153323Srodrigc *========================================================================*/ 2406153323Srodrigc 2407153323SrodrigcSTATIC int 2408153323Srodrigcattr_generic_set( 2409153323Srodrigc struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags) 2410153323Srodrigc{ 2411153323Srodrigc int error; 2412153323Srodrigc 2413153323Srodrigc XVOP_ATTR_SET(vp, name, data, size, xflags, NULL, error); 2414153323Srodrigc return -error; 2415153323Srodrigc} 2416153323Srodrigc 2417153323SrodrigcSTATIC int 2418153323Srodrigcattr_generic_get( 2419153323Srodrigc struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags) 2420153323Srodrigc{ 2421153323Srodrigc int error, asize = size; 2422153323Srodrigc 2423153323Srodrigc XVOP_ATTR_GET(vp, name, data, &asize, xflags, NULL, error); 2424153323Srodrigc if (!error) 2425153323Srodrigc return asize; 2426153323Srodrigc return -error; 2427153323Srodrigc} 2428153323Srodrigc 2429153323SrodrigcSTATIC int 2430153323Srodrigcattr_generic_remove( 2431153323Srodrigc struct xfs_vnode *vp, char *name, int xflags) 2432153323Srodrigc{ 2433153323Srodrigc int error; 2434153323Srodrigc 2435153323Srodrigc XVOP_ATTR_REMOVE(vp, name, xflags, NULL, error); 2436153323Srodrigc return -error; 2437153323Srodrigc} 2438153323Srodrigc 2439153323SrodrigcSTATIC int 2440153323Srodrigcattr_generic_listadd( 2441153323Srodrigc attrnames_t *prefix, 2442153323Srodrigc attrnames_t *namesp, 2443153323Srodrigc void *data, 2444153323Srodrigc size_t size, 2445153323Srodrigc ssize_t *result) 2446153323Srodrigc{ 2447153323Srodrigc char *p = (char *)data + *result; 2448153323Srodrigc 2449153323Srodrigc *result += prefix->attr_namelen; 2450153323Srodrigc *result += namesp->attr_namelen + 1; 2451153323Srodrigc if (!size) 2452153323Srodrigc return 0; 2453153323Srodrigc if (*result > size) 2454153323Srodrigc return -ERANGE; 2455153323Srodrigc strcpy(p, prefix->attr_name); 2456153323Srodrigc p += prefix->attr_namelen; 2457153323Srodrigc strcpy(p, namesp->attr_name); 2458153323Srodrigc p += namesp->attr_namelen + 1; 2459153323Srodrigc return 0; 2460153323Srodrigc} 2461153323Srodrigc 2462153323SrodrigcSTATIC int 2463153323Srodrigcattr_system_list( 2464153323Srodrigc struct xfs_vnode *vp, 2465153323Srodrigc void *data, 2466153323Srodrigc size_t size, 2467153323Srodrigc ssize_t *result) 2468153323Srodrigc{ 2469153323Srodrigc attrnames_t *namesp; 2470153323Srodrigc int i, error = 0; 2471153323Srodrigc 2472153323Srodrigc for (i = 0; i < ATTR_SYSCOUNT; i++) { 2473153323Srodrigc namesp = attr_system_names[i]; 2474153323Srodrigc if (!namesp->attr_exists || !namesp->attr_exists(vp)) 2475153323Srodrigc continue; 2476153323Srodrigc error = attr_generic_listadd(&attr_system, namesp, 2477153323Srodrigc data, size, result); 2478153323Srodrigc if (error) 2479153323Srodrigc break; 2480153323Srodrigc } 2481153323Srodrigc return error; 2482153323Srodrigc} 2483153323Srodrigc 2484153323Srodrigcint 2485153323Srodrigcattr_generic_list( 2486153323Srodrigc struct xfs_vnode *vp, void *data, size_t size, int xflags, ssize_t *result) 2487153323Srodrigc{ 2488153323Srodrigc attrlist_cursor_kern_t cursor = { 0 }; 2489153323Srodrigc int error; 2490153323Srodrigc 2491153323Srodrigc XVOP_ATTR_LIST(vp, data, size, xflags, &cursor, NULL, error); 2492153323Srodrigc if (error > 0) 2493153323Srodrigc return -error; 2494153323Srodrigc *result = -error; 2495153323Srodrigc return attr_system_list(vp, data, size, result); 2496153323Srodrigc} 2497153323Srodrigc 2498153323Srodrigcattrnames_t * 2499153323Srodrigcattr_lookup_namespace( 2500153323Srodrigc char *name, 2501153323Srodrigc struct attrnames **names, 2502153323Srodrigc int nnames) 2503153323Srodrigc{ 2504153323Srodrigc int i; 2505153323Srodrigc 2506153323Srodrigc for (i = 0; i < nnames; i++) 2507153323Srodrigc if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen)) 2508153323Srodrigc return names[i]; 2509153323Srodrigc return NULL; 2510153323Srodrigc} 2511153323Srodrigc 2512153323Srodrigc/* 2513153323Srodrigc * Some checks to prevent people abusing EAs to get over quota: 2514153323Srodrigc * - Don't allow modifying user EAs on devices/symlinks; 2515153323Srodrigc * - Don't allow modifying user EAs if sticky bit set; 2516153323Srodrigc */ 2517153323SrodrigcSTATIC int 2518153323Srodrigcattr_user_capable( 2519153323Srodrigc struct xfs_vnode *vp, 2520153323Srodrigc cred_t *cred) 2521153323Srodrigc{ 2522159147Simp#ifdef XXXKAN 2523159451Srodrigc struct inode *inode = vn_to_inode(vp); 2524153323Srodrigc 2525153323Srodrigc if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) 2526153323Srodrigc return -EPERM; 2527153323Srodrigc if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) && 2528153323Srodrigc !capable(CAP_SYS_ADMIN)) 2529153323Srodrigc return -EPERM; 2530153323Srodrigc if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && 2531153323Srodrigc (current_fsuid(cred) != inode->i_uid) && !capable(CAP_FOWNER)) 2532153323Srodrigc return -EPERM; 2533153323Srodrigc#endif 2534153323Srodrigc return 0; 2535153323Srodrigc} 2536153323Srodrigc 2537153323SrodrigcSTATIC int 2538153323Srodrigcattr_trusted_capable( 2539153323Srodrigc struct xfs_vnode *vp, 2540153323Srodrigc cred_t *cred) 2541153323Srodrigc{ 2542159147Simp#ifdef XXXKAN 2543159451Srodrigc struct inode *inode = vn_to_inode(vp); 2544153323Srodrigc 2545153323Srodrigc if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) 2546153323Srodrigc return -EPERM; 2547153323Srodrigc if (!capable(CAP_SYS_ADMIN)) 2548153323Srodrigc return -EPERM; 2549153323Srodrigc#endif 2550153323Srodrigc return 0; 2551153323Srodrigc} 2552153323Srodrigc 2553153323SrodrigcSTATIC int 2554153323Srodrigcattr_secure_capable( 2555153323Srodrigc struct xfs_vnode *vp, 2556153323Srodrigc cred_t *cred) 2557153323Srodrigc{ 2558153323Srodrigc return -ENOSECURITY; 2559153323Srodrigc} 2560153323Srodrigc 2561153323SrodrigcSTATIC int 2562153323Srodrigcattr_system_set( 2563153323Srodrigc struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags) 2564153323Srodrigc{ 2565153323Srodrigc attrnames_t *namesp; 2566153323Srodrigc int error; 2567153323Srodrigc 2568153323Srodrigc if (xflags & ATTR_CREATE) 2569153323Srodrigc return -EINVAL; 2570153323Srodrigc 2571153323Srodrigc namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); 2572153323Srodrigc if (!namesp) 2573153323Srodrigc return -EOPNOTSUPP; 2574153323Srodrigc error = namesp->attr_set(vp, name, data, size, xflags); 2575159147Simp#ifdef XXXKAN 2576153323Srodrigc if (!error) 2577153323Srodrigc error = vn_revalidate(vp); 2578153323Srodrigc#endif 2579153323Srodrigc return error; 2580153323Srodrigc} 2581153323Srodrigc 2582153323SrodrigcSTATIC int 2583153323Srodrigcattr_system_get( 2584153323Srodrigc struct xfs_vnode *vp, char *name, void *data, size_t size, int xflags) 2585153323Srodrigc{ 2586153323Srodrigc attrnames_t *namesp; 2587153323Srodrigc 2588153323Srodrigc namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); 2589153323Srodrigc if (!namesp) 2590153323Srodrigc return -EOPNOTSUPP; 2591153323Srodrigc return namesp->attr_get(vp, name, data, size, xflags); 2592153323Srodrigc} 2593153323Srodrigc 2594153323SrodrigcSTATIC int 2595153323Srodrigcattr_system_remove( 2596153323Srodrigc struct xfs_vnode *vp, char *name, int xflags) 2597153323Srodrigc{ 2598153323Srodrigc attrnames_t *namesp; 2599153323Srodrigc 2600153323Srodrigc namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); 2601153323Srodrigc if (!namesp) 2602153323Srodrigc return -EOPNOTSUPP; 2603153323Srodrigc return namesp->attr_remove(vp, name, xflags); 2604153323Srodrigc} 2605153323Srodrigc 2606153323Srodrigcstruct attrnames attr_system = { 2607153323Srodrigc .attr_name = "system.", 2608153323Srodrigc .attr_namelen = sizeof("system.") - 1, 2609153323Srodrigc .attr_flag = ATTR_SYSTEM, 2610153323Srodrigc .attr_get = attr_system_get, 2611153323Srodrigc .attr_set = attr_system_set, 2612153323Srodrigc .attr_remove = attr_system_remove, 2613153323Srodrigc .attr_capable = (attrcapable_t)fs_noerr, 2614153323Srodrigc}; 2615153323Srodrigc 2616153323Srodrigcstruct attrnames attr_trusted = { 2617153323Srodrigc .attr_name = "trusted.", 2618153323Srodrigc .attr_namelen = sizeof("trusted.") - 1, 2619153323Srodrigc .attr_flag = ATTR_ROOT, 2620153323Srodrigc .attr_get = attr_generic_get, 2621153323Srodrigc .attr_set = attr_generic_set, 2622153323Srodrigc .attr_remove = attr_generic_remove, 2623153323Srodrigc .attr_capable = attr_trusted_capable, 2624153323Srodrigc}; 2625153323Srodrigc 2626153323Srodrigcstruct attrnames attr_secure = { 2627153323Srodrigc .attr_name = "security.", 2628153323Srodrigc .attr_namelen = sizeof("security.") - 1, 2629153323Srodrigc .attr_flag = ATTR_SECURE, 2630153323Srodrigc .attr_get = attr_generic_get, 2631153323Srodrigc .attr_set = attr_generic_set, 2632153323Srodrigc .attr_remove = attr_generic_remove, 2633153323Srodrigc .attr_capable = attr_secure_capable, 2634153323Srodrigc}; 2635153323Srodrigc 2636153323Srodrigcstruct attrnames attr_user = { 2637153323Srodrigc .attr_name = "user.", 2638153323Srodrigc .attr_namelen = sizeof("user.") - 1, 2639153323Srodrigc .attr_get = attr_generic_get, 2640153323Srodrigc .attr_set = attr_generic_set, 2641153323Srodrigc .attr_remove = attr_generic_remove, 2642153323Srodrigc .attr_capable = attr_user_capable, 2643153323Srodrigc}; 2644153323Srodrigc 2645153323Srodrigcstruct attrnames *attr_namespaces[] = 2646153323Srodrigc { &attr_system, &attr_trusted, &attr_secure, &attr_user }; 2647