1594 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.4 * All Rights Reserved.5 */6#include "xfs.h"7#include "xfs_fs.h"8#include "xfs_shared.h"9#include "xfs_format.h"10#include "xfs_log_format.h"11#include "xfs_trans_resv.h"12#include "xfs_mount.h"13#include "xfs_defer.h"14#include "xfs_da_format.h"15#include "xfs_da_btree.h"16#include "xfs_attr_sf.h"17#include "xfs_inode.h"18#include "xfs_trans.h"19#include "xfs_bmap.h"20#include "xfs_bmap_btree.h"21#include "xfs_attr.h"22#include "xfs_attr_leaf.h"23#include "xfs_attr_remote.h"24#include "xfs_quota.h"25#include "xfs_trans_space.h"26#include "xfs_trace.h"27#include "xfs_attr_item.h"28#include "xfs_xattr.h"29#include "xfs_parent.h"30 31struct kmem_cache *xfs_attr_intent_cache;32 33/*34 * xfs_attr.c35 *36 * Provide the external interfaces to manage attribute lists.37 */38 39/*========================================================================40 * Function prototypes for the kernel.41 *========================================================================*/42 43/*44 * Internal routines when attribute list fits inside the inode.45 */46STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);47 48/*49 * Internal routines when attribute list is one block.50 */51STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);52STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);53STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);54 55/*56 * Internal routines when attribute list is more than one block.57 */58STATIC int xfs_attr_node_get(xfs_da_args_t *args);59STATIC void xfs_attr_restore_rmt_blk(struct xfs_da_args *args);60static int xfs_attr_node_try_addname(struct xfs_attr_intent *attr);61STATIC int xfs_attr_node_addname_find_attr(struct xfs_attr_intent *attr);62STATIC int xfs_attr_node_remove_attr(struct xfs_attr_intent *attr);63STATIC int xfs_attr_node_lookup(struct xfs_da_args *args,64 struct xfs_da_state *state);65 66int67xfs_inode_hasattr(68 struct xfs_inode *ip)69{70 if (!xfs_inode_has_attr_fork(ip))71 return 0;72 if (ip->i_af.if_format == XFS_DINODE_FMT_EXTENTS &&73 ip->i_af.if_nextents == 0)74 return 0;75 return 1;76}77 78/*79 * Returns true if the there is exactly only block in the attr fork, in which80 * case the attribute fork consists of a single leaf block entry.81 */82bool83xfs_attr_is_leaf(84 struct xfs_inode *ip)85{86 struct xfs_ifork *ifp = &ip->i_af;87 struct xfs_iext_cursor icur;88 struct xfs_bmbt_irec imap;89 90 ASSERT(!xfs_need_iread_extents(ifp));91 92 if (ifp->if_nextents != 1 || ifp->if_format != XFS_DINODE_FMT_EXTENTS)93 return false;94 95 xfs_iext_first(ifp, &icur);96 xfs_iext_get_extent(ifp, &icur, &imap);97 return imap.br_startoff == 0 && imap.br_blockcount == 1;98}99 100/*101 * XXX (dchinner): name path state saving and refilling is an optimisation to102 * avoid needing to look up name entries after rolling transactions removing103 * remote xattr blocks between the name entry lookup and name entry removal.104 * This optimisation got sidelined when combining the set and remove state105 * machines, but the code has been left in place because it is worthwhile to106 * restore the optimisation once the combined state machine paths have settled.107 *108 * This comment is a public service announcement to remind Future Dave that he109 * still needs to restore this code to working order.110 */111#if 0112/*113 * Fill in the disk block numbers in the state structure for the buffers114 * that are attached to the state structure.115 * This is done so that we can quickly reattach ourselves to those buffers116 * after some set of transaction commits have released these buffers.117 */118static int119xfs_attr_fillstate(xfs_da_state_t *state)120{121 xfs_da_state_path_t *path;122 xfs_da_state_blk_t *blk;123 int level;124 125 trace_xfs_attr_fillstate(state->args);126 127 /*128 * Roll down the "path" in the state structure, storing the on-disk129 * block number for those buffers in the "path".130 */131 path = &state->path;132 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));133 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {134 if (blk->bp) {135 blk->disk_blkno = xfs_buf_daddr(blk->bp);136 blk->bp = NULL;137 } else {138 blk->disk_blkno = 0;139 }140 }141 142 /*143 * Roll down the "altpath" in the state structure, storing the on-disk144 * block number for those buffers in the "altpath".145 */146 path = &state->altpath;147 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));148 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {149 if (blk->bp) {150 blk->disk_blkno = xfs_buf_daddr(blk->bp);151 blk->bp = NULL;152 } else {153 blk->disk_blkno = 0;154 }155 }156 157 return 0;158}159 160/*161 * Reattach the buffers to the state structure based on the disk block162 * numbers stored in the state structure.163 * This is done after some set of transaction commits have released those164 * buffers from our grip.165 */166static int167xfs_attr_refillstate(xfs_da_state_t *state)168{169 xfs_da_state_path_t *path;170 xfs_da_state_blk_t *blk;171 int level, error;172 173 trace_xfs_attr_refillstate(state->args);174 175 /*176 * Roll down the "path" in the state structure, storing the on-disk177 * block number for those buffers in the "path".178 */179 path = &state->path;180 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));181 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {182 if (blk->disk_blkno) {183 error = xfs_da3_node_read_mapped(state->args->trans,184 state->args->dp, blk->disk_blkno,185 &blk->bp, XFS_ATTR_FORK);186 if (error)187 return error;188 } else {189 blk->bp = NULL;190 }191 }192 193 /*194 * Roll down the "altpath" in the state structure, storing the on-disk195 * block number for those buffers in the "altpath".196 */197 path = &state->altpath;198 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));199 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {200 if (blk->disk_blkno) {201 error = xfs_da3_node_read_mapped(state->args->trans,202 state->args->dp, blk->disk_blkno,203 &blk->bp, XFS_ATTR_FORK);204 if (error)205 return error;206 } else {207 blk->bp = NULL;208 }209 }210 211 return 0;212}213#else214static int xfs_attr_fillstate(xfs_da_state_t *state) { return 0; }215#endif216 217/*========================================================================218 * Overall external interface routines.219 *========================================================================*/220 221/*222 * Retrieve an extended attribute and its value. Must have ilock.223 * Returns 0 on successful retrieval, otherwise an error.224 */225int226xfs_attr_get_ilocked(227 struct xfs_da_args *args)228{229 int error;230 231 xfs_assert_ilocked(args->dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);232 233 if (!xfs_inode_hasattr(args->dp))234 return -ENOATTR;235 236 /*237 * The incore attr fork iext tree must be loaded for xfs_attr_is_leaf238 * to work correctly.239 */240 error = xfs_iread_extents(args->trans, args->dp, XFS_ATTR_FORK);241 if (error)242 return error;243 244 if (args->dp->i_af.if_format == XFS_DINODE_FMT_LOCAL)245 return xfs_attr_shortform_getvalue(args);246 if (xfs_attr_is_leaf(args->dp))247 return xfs_attr_leaf_get(args);248 return xfs_attr_node_get(args);249}250 251/*252 * Retrieve an extended attribute by name, and its value if requested.253 *254 * If args->valuelen is zero, then the caller does not want the value, just an255 * indication whether the attribute exists and the size of the value if it256 * exists. The size is returned in args.valuelen.257 *258 * If args->value is NULL but args->valuelen is non-zero, allocate the buffer259 * for the value after existence of the attribute has been determined. The260 * caller always has to free args->value if it is set, no matter if this261 * function was successful or not.262 *263 * If the attribute is found, but exceeds the size limit set by the caller in264 * args->valuelen, return -ERANGE with the size of the attribute that was found265 * in args->valuelen.266 */267int268xfs_attr_get(269 struct xfs_da_args *args)270{271 uint lock_mode;272 int error;273 274 XFS_STATS_INC(args->dp->i_mount, xs_attr_get);275 276 if (xfs_is_shutdown(args->dp->i_mount))277 return -EIO;278 279 if (!args->owner)280 args->owner = args->dp->i_ino;281 args->geo = args->dp->i_mount->m_attr_geo;282 args->whichfork = XFS_ATTR_FORK;283 xfs_attr_sethash(args);284 285 /* Entirely possible to look up a name which doesn't exist */286 args->op_flags = XFS_DA_OP_OKNOENT;287 288 lock_mode = xfs_ilock_attr_map_shared(args->dp);289 error = xfs_attr_get_ilocked(args);290 xfs_iunlock(args->dp, lock_mode);291 292 return error;293}294 295/*296 * Calculate how many blocks we need for the new attribute,297 */298int299xfs_attr_calc_size(300 struct xfs_da_args *args,301 int *local)302{303 struct xfs_mount *mp = args->dp->i_mount;304 int size;305 int nblks;306 307 /*308 * Determine space new attribute will use, and if it would be309 * "local" or "remote" (note: local != inline).310 */311 size = xfs_attr_leaf_newentsize(args, local);312 nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);313 if (*local) {314 if (size > (args->geo->blksize / 2)) {315 /* Double split possible */316 nblks *= 2;317 }318 } else {319 /*320 * Out of line attribute, cannot double split, but321 * make room for the attribute value itself.322 */323 uint dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen);324 nblks += dblocks;325 nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);326 }327 328 return nblks;329}330 331/* Initialize transaction reservation for an xattr set/replace/upsert */332inline struct xfs_trans_res333xfs_attr_set_resv(334 const struct xfs_da_args *args)335{336 struct xfs_mount *mp = args->dp->i_mount;337 struct xfs_trans_res ret = {338 .tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +339 M_RES(mp)->tr_attrsetrt.tr_logres * args->total,340 .tr_logcount = XFS_ATTRSET_LOG_COUNT,341 .tr_logflags = XFS_TRANS_PERM_LOG_RES,342 };343 344 return ret;345}346 347/*348 * Add an attr to a shortform fork. If there is no space,349 * xfs_attr_shortform_addname() will convert to leaf format and return -ENOSPC.350 * to use.351 */352STATIC int353xfs_attr_try_sf_addname(354 struct xfs_inode *dp,355 struct xfs_da_args *args)356{357 358 int error;359 360 /*361 * Build initial attribute list (if required).362 */363 if (dp->i_af.if_format == XFS_DINODE_FMT_EXTENTS)364 xfs_attr_shortform_create(args);365 366 error = xfs_attr_shortform_addname(args);367 if (error == -ENOSPC)368 return error;369 370 /*371 * Commit the shortform mods, and we're done.372 * NOTE: this is also the error path (EEXIST, etc).373 */374 if (!error)375 xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);376 377 if (xfs_has_wsync(dp->i_mount))378 xfs_trans_set_sync(args->trans);379 380 return error;381}382 383static int384xfs_attr_sf_addname(385 struct xfs_attr_intent *attr)386{387 struct xfs_da_args *args = attr->xattri_da_args;388 struct xfs_inode *dp = args->dp;389 int error = 0;390 391 error = xfs_attr_try_sf_addname(dp, args);392 if (error != -ENOSPC) {393 ASSERT(!error || error == -EEXIST);394 attr->xattri_dela_state = XFS_DAS_DONE;395 goto out;396 }397 398 /*399 * It won't fit in the shortform, transform to a leaf block. GROT:400 * another possible req'mt for a double-split btree op.401 */402 error = xfs_attr_shortform_to_leaf(args);403 if (error)404 return error;405 406 attr->xattri_dela_state = XFS_DAS_LEAF_ADD;407out:408 trace_xfs_attr_sf_addname_return(attr->xattri_dela_state, args->dp);409 return error;410}411 412/* Compute the hash value for a user/root/secure extended attribute */413xfs_dahash_t414xfs_attr_hashname(415 const uint8_t *name,416 int namelen)417{418 return xfs_da_hashname(name, namelen);419}420 421/* Compute the hash value for any extended attribute from any namespace. */422xfs_dahash_t423xfs_attr_hashval(424 struct xfs_mount *mp,425 unsigned int attr_flags,426 const uint8_t *name,427 int namelen,428 const void *value,429 int valuelen)430{431 ASSERT(xfs_attr_check_namespace(attr_flags));432 433 if (attr_flags & XFS_ATTR_PARENT)434 return xfs_parent_hashattr(mp, name, namelen, value, valuelen);435 436 return xfs_attr_hashname(name, namelen);437}438 439/* Save the current remote block info and clear the current pointers. */440static void441xfs_attr_save_rmt_blk(442 struct xfs_da_args *args)443{444 args->blkno2 = args->blkno;445 args->index2 = args->index;446 args->rmtblkno2 = args->rmtblkno;447 args->rmtblkcnt2 = args->rmtblkcnt;448 args->rmtvaluelen2 = args->rmtvaluelen;449 args->rmtblkno = 0;450 args->rmtblkcnt = 0;451 args->rmtvaluelen = 0;452}453 454/* Set stored info about a remote block */455static void456xfs_attr_restore_rmt_blk(457 struct xfs_da_args *args)458{459 args->blkno = args->blkno2;460 args->index = args->index2;461 args->rmtblkno = args->rmtblkno2;462 args->rmtblkcnt = args->rmtblkcnt2;463 args->rmtvaluelen = args->rmtvaluelen2;464}465 466/*467 * PPTR_REPLACE operations require the caller to set the old and new names and468 * values explicitly. Update the canonical fields to the new name and value469 * here now that the removal phase has finished.470 */471static void472xfs_attr_update_pptr_replace_args(473 struct xfs_da_args *args)474{475 ASSERT(args->new_namelen > 0);476 args->name = args->new_name;477 args->namelen = args->new_namelen;478 args->value = args->new_value;479 args->valuelen = args->new_valuelen;480 xfs_attr_sethash(args);481}482 483/*484 * Handle the state change on completion of a multi-state attr operation.485 *486 * If the XFS_DA_OP_REPLACE flag is set, this means the operation was the first487 * modification in a attr replace operation and we still have to do the second488 * state, indicated by @replace_state.489 *490 * We consume the XFS_DA_OP_REPLACE flag so that when we are called again on491 * completion of the second half of the attr replace operation we correctly492 * signal that it is done.493 */494static enum xfs_delattr_state495xfs_attr_complete_op(496 struct xfs_attr_intent *attr,497 enum xfs_delattr_state replace_state)498{499 struct xfs_da_args *args = attr->xattri_da_args;500 501 if (!(args->op_flags & XFS_DA_OP_REPLACE))502 replace_state = XFS_DAS_DONE;503 else if (xfs_attr_intent_op(attr) == XFS_ATTRI_OP_FLAGS_PPTR_REPLACE)504 xfs_attr_update_pptr_replace_args(args);505 506 args->op_flags &= ~XFS_DA_OP_REPLACE;507 args->attr_filter &= ~XFS_ATTR_INCOMPLETE;508 return replace_state;509}510 511/*512 * Try to add an attribute to an inode in leaf form.513 */514static int515xfs_attr_leaf_addname(516 struct xfs_attr_intent *attr)517{518 struct xfs_da_args *args = attr->xattri_da_args;519 struct xfs_buf *bp;520 int error;521 522 ASSERT(xfs_attr_is_leaf(args->dp));523 524 error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);525 if (error)526 return error;527 528 /*529 * Look up the xattr name to set the insertion point for the new xattr.530 */531 error = xfs_attr3_leaf_lookup_int(bp, args);532 switch (error) {533 case -ENOATTR:534 if (args->op_flags & XFS_DA_OP_REPLACE)535 goto out_brelse;536 break;537 case -EEXIST:538 if (!(args->op_flags & XFS_DA_OP_REPLACE))539 goto out_brelse;540 541 trace_xfs_attr_leaf_replace(args);542 /*543 * Save the existing remote attr state so that the current544 * values reflect the state of the new attribute we are about to545 * add, not the attribute we just found and will remove later.546 */547 xfs_attr_save_rmt_blk(args);548 break;549 case 0:550 break;551 default:552 goto out_brelse;553 }554 555 /*556 * We need to commit and roll if we need to allocate remote xattr blocks557 * or perform more xattr manipulations. Otherwise there is nothing more558 * to do and we can return success.559 */560 if (!xfs_attr3_leaf_add(bp, args)) {561 error = xfs_attr3_leaf_to_node(args);562 if (error)563 return error;564 565 attr->xattri_dela_state = XFS_DAS_NODE_ADD;566 } else if (args->rmtblkno) {567 attr->xattri_dela_state = XFS_DAS_LEAF_SET_RMT;568 } else {569 attr->xattri_dela_state =570 xfs_attr_complete_op(attr, XFS_DAS_LEAF_REPLACE);571 }572 573 trace_xfs_attr_leaf_addname_return(attr->xattri_dela_state, args->dp);574 return 0;575 576out_brelse:577 xfs_trans_brelse(args->trans, bp);578 return error;579}580 581/*582 * Add an entry to a node format attr tree.583 *584 * Note that we might still have a leaf here - xfs_attr_is_leaf() cannot tell585 * the difference between leaf + remote attr blocks and a node format tree,586 * so we may still end up having to convert from leaf to node format here.587 */588static int589xfs_attr_node_addname(590 struct xfs_attr_intent *attr)591{592 struct xfs_da_args *args = attr->xattri_da_args;593 int error;594 595 error = xfs_attr_node_addname_find_attr(attr);596 if (error)597 return error;598 599 error = xfs_attr_node_try_addname(attr);600 if (error == 1) {601 error = xfs_attr3_leaf_to_node(args);602 if (error)603 return error;604 /*605 * No state change, we really are in node form now606 * but we need the transaction rolled to continue.607 */608 goto out;609 }610 if (error)611 return error;612 613 if (args->rmtblkno)614 attr->xattri_dela_state = XFS_DAS_NODE_SET_RMT;615 else616 attr->xattri_dela_state = xfs_attr_complete_op(attr,617 XFS_DAS_NODE_REPLACE);618out:619 trace_xfs_attr_node_addname_return(attr->xattri_dela_state, args->dp);620 return error;621}622 623static int624xfs_attr_rmtval_alloc(625 struct xfs_attr_intent *attr)626{627 struct xfs_da_args *args = attr->xattri_da_args;628 int error = 0;629 630 /*631 * If there was an out-of-line value, allocate the blocks we632 * identified for its storage and copy the value. This is done633 * after we create the attribute so that we don't overflow the634 * maximum size of a transaction and/or hit a deadlock.635 */636 if (attr->xattri_blkcnt > 0) {637 error = xfs_attr_rmtval_set_blk(attr);638 if (error)639 return error;640 /* Roll the transaction only if there is more to allocate. */641 if (attr->xattri_blkcnt > 0)642 goto out;643 }644 645 error = xfs_attr_rmtval_set_value(args);646 if (error)647 return error;648 649 attr->xattri_dela_state = xfs_attr_complete_op(attr,650 ++attr->xattri_dela_state);651 /*652 * If we are not doing a rename, we've finished the operation but still653 * have to clear the incomplete flag protecting the new attr from654 * exposing partially initialised state if we crash during creation.655 */656 if (attr->xattri_dela_state == XFS_DAS_DONE)657 error = xfs_attr3_leaf_clearflag(args);658out:659 trace_xfs_attr_rmtval_alloc(attr->xattri_dela_state, args->dp);660 return error;661}662 663/*664 * Mark an attribute entry INCOMPLETE and save pointers to the relevant buffers665 * for later deletion of the entry.666 */667static int668xfs_attr_leaf_mark_incomplete(669 struct xfs_da_args *args,670 struct xfs_da_state *state)671{672 int error;673 674 /*675 * Fill in disk block numbers in the state structure676 * so that we can get the buffers back after we commit677 * several transactions in the following calls.678 */679 error = xfs_attr_fillstate(state);680 if (error)681 return error;682 683 /*684 * Mark the attribute as INCOMPLETE685 */686 return xfs_attr3_leaf_setflag(args);687}688 689/* Ensure the da state of an xattr deferred work item is ready to go. */690static inline void691xfs_attr_item_init_da_state(692 struct xfs_attr_intent *attr)693{694 struct xfs_da_args *args = attr->xattri_da_args;695 696 if (!attr->xattri_da_state)697 attr->xattri_da_state = xfs_da_state_alloc(args);698 else699 xfs_da_state_reset(attr->xattri_da_state, args);700}701 702/*703 * Initial setup for xfs_attr_node_removename. Make sure the attr is there and704 * the blocks are valid. Attr keys with remote blocks will be marked705 * incomplete.706 */707static708int xfs_attr_node_removename_setup(709 struct xfs_attr_intent *attr)710{711 struct xfs_da_args *args = attr->xattri_da_args;712 struct xfs_da_state *state;713 int error;714 715 xfs_attr_item_init_da_state(attr);716 error = xfs_attr_node_lookup(args, attr->xattri_da_state);717 if (error != -EEXIST)718 goto out;719 error = 0;720 721 state = attr->xattri_da_state;722 ASSERT(state->path.blk[state->path.active - 1].bp != NULL);723 ASSERT(state->path.blk[state->path.active - 1].magic ==724 XFS_ATTR_LEAF_MAGIC);725 726 error = xfs_attr_leaf_mark_incomplete(args, state);727 if (error)728 goto out;729 if (args->rmtblkno > 0)730 error = xfs_attr_rmtval_invalidate(args);731out:732 if (error) {733 xfs_da_state_free(attr->xattri_da_state);734 attr->xattri_da_state = NULL;735 }736 737 return error;738}739 740/*741 * Remove the original attr we have just replaced. This is dependent on the742 * original lookup and insert placing the old attr in args->blkno/args->index743 * and the new attr in args->blkno2/args->index2.744 */745static int746xfs_attr_leaf_remove_attr(747 struct xfs_attr_intent *attr)748{749 struct xfs_da_args *args = attr->xattri_da_args;750 struct xfs_inode *dp = args->dp;751 struct xfs_buf *bp = NULL;752 int forkoff;753 int error;754 755 error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,756 args->blkno, &bp);757 if (error)758 return error;759 760 xfs_attr3_leaf_remove(bp, args);761 762 forkoff = xfs_attr_shortform_allfit(bp, dp);763 if (forkoff)764 error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);765 /* bp is gone due to xfs_da_shrink_inode */766 767 return error;768}769 770/*771 * Shrink an attribute from leaf to shortform. Used by the node format remove772 * path when the node format collapses to a single block and so we have to check773 * if it can be collapsed further.774 */775static int776xfs_attr_leaf_shrink(777 struct xfs_da_args *args)778{779 struct xfs_inode *dp = args->dp;780 struct xfs_buf *bp;781 int forkoff;782 int error;783 784 if (!xfs_attr_is_leaf(dp))785 return 0;786 787 error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);788 if (error)789 return error;790 791 forkoff = xfs_attr_shortform_allfit(bp, dp);792 if (forkoff) {793 error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);794 /* bp is gone due to xfs_da_shrink_inode */795 } else {796 xfs_trans_brelse(args->trans, bp);797 }798 799 return error;800}801 802/*803 * Run the attribute operation specified in @attr.804 *805 * This routine is meant to function as a delayed operation and will set the806 * state to XFS_DAS_DONE when the operation is complete. Calling functions will807 * need to handle this, and recall the function until either an error or808 * XFS_DAS_DONE is detected.809 */810int811xfs_attr_set_iter(812 struct xfs_attr_intent *attr)813{814 struct xfs_da_args *args = attr->xattri_da_args;815 int error = 0;816 817 /* State machine switch */818next_state:819 switch (attr->xattri_dela_state) {820 case XFS_DAS_UNINIT:821 ASSERT(0);822 return -EFSCORRUPTED;823 case XFS_DAS_SF_ADD:824 return xfs_attr_sf_addname(attr);825 case XFS_DAS_LEAF_ADD:826 return xfs_attr_leaf_addname(attr);827 case XFS_DAS_NODE_ADD:828 return xfs_attr_node_addname(attr);829 830 case XFS_DAS_SF_REMOVE:831 error = xfs_attr_sf_removename(args);832 attr->xattri_dela_state = xfs_attr_complete_op(attr,833 xfs_attr_init_add_state(args));834 break;835 case XFS_DAS_LEAF_REMOVE:836 error = xfs_attr_leaf_removename(args);837 attr->xattri_dela_state = xfs_attr_complete_op(attr,838 xfs_attr_init_add_state(args));839 break;840 case XFS_DAS_NODE_REMOVE:841 error = xfs_attr_node_removename_setup(attr);842 if (error == -ENOATTR &&843 (args->op_flags & XFS_DA_OP_RECOVERY)) {844 attr->xattri_dela_state = xfs_attr_complete_op(attr,845 xfs_attr_init_add_state(args));846 error = 0;847 break;848 }849 if (error)850 return error;851 attr->xattri_dela_state = XFS_DAS_NODE_REMOVE_RMT;852 if (args->rmtblkno == 0)853 attr->xattri_dela_state++;854 break;855 856 case XFS_DAS_LEAF_SET_RMT:857 case XFS_DAS_NODE_SET_RMT:858 error = xfs_attr_rmtval_find_space(attr);859 if (error)860 return error;861 attr->xattri_dela_state++;862 fallthrough;863 864 case XFS_DAS_LEAF_ALLOC_RMT:865 case XFS_DAS_NODE_ALLOC_RMT:866 error = xfs_attr_rmtval_alloc(attr);867 if (error)868 return error;869 if (attr->xattri_dela_state == XFS_DAS_DONE)870 break;871 goto next_state;872 873 case XFS_DAS_LEAF_REPLACE:874 case XFS_DAS_NODE_REPLACE:875 /*876 * We must "flip" the incomplete flags on the "new" and "old"877 * attribute/value pairs so that one disappears and one appears878 * atomically.879 */880 error = xfs_attr3_leaf_flipflags(args);881 if (error)882 return error;883 /*884 * We must commit the flag value change now to make it atomic885 * and then we can start the next trans in series at REMOVE_OLD.886 */887 attr->xattri_dela_state++;888 break;889 890 case XFS_DAS_LEAF_REMOVE_OLD:891 case XFS_DAS_NODE_REMOVE_OLD:892 /*893 * If we have a remote attr, start the process of removing it894 * by invalidating any cached buffers.895 *896 * If we don't have a remote attr, we skip the remote block897 * removal state altogether with a second state increment.898 */899 xfs_attr_restore_rmt_blk(args);900 if (args->rmtblkno) {901 error = xfs_attr_rmtval_invalidate(args);902 if (error)903 return error;904 } else {905 attr->xattri_dela_state++;906 }907 908 attr->xattri_dela_state++;909 goto next_state;910 911 case XFS_DAS_LEAF_REMOVE_RMT:912 case XFS_DAS_NODE_REMOVE_RMT:913 error = xfs_attr_rmtval_remove(attr);914 if (error == -EAGAIN) {915 error = 0;916 break;917 }918 if (error)919 return error;920 921 /*922 * We've finished removing the remote attr blocks, so commit the923 * transaction and move on to removing the attr name from the924 * leaf/node block. Removing the attr might require a full925 * transaction reservation for btree block freeing, so we926 * can't do that in the same transaction where we removed the927 * remote attr blocks.928 */929 attr->xattri_dela_state++;930 break;931 932 case XFS_DAS_LEAF_REMOVE_ATTR:933 error = xfs_attr_leaf_remove_attr(attr);934 attr->xattri_dela_state = xfs_attr_complete_op(attr,935 xfs_attr_init_add_state(args));936 break;937 938 case XFS_DAS_NODE_REMOVE_ATTR:939 error = xfs_attr_node_remove_attr(attr);940 if (!error)941 error = xfs_attr_leaf_shrink(args);942 attr->xattri_dela_state = xfs_attr_complete_op(attr,943 xfs_attr_init_add_state(args));944 break;945 default:946 ASSERT(0);947 break;948 }949 950 trace_xfs_attr_set_iter_return(attr->xattri_dela_state, args->dp);951 return error;952}953 954 955/*956 * Return EEXIST if attr is found, or ENOATTR if not957 */958static int959xfs_attr_lookup(960 struct xfs_da_args *args)961{962 struct xfs_inode *dp = args->dp;963 struct xfs_buf *bp = NULL;964 struct xfs_da_state *state;965 int error;966 967 if (!xfs_inode_hasattr(dp))968 return -ENOATTR;969 970 if (dp->i_af.if_format == XFS_DINODE_FMT_LOCAL) {971 if (xfs_attr_sf_findname(args))972 return -EEXIST;973 return -ENOATTR;974 }975 976 /* Prerequisite for xfs_attr_is_leaf */977 error = xfs_iread_extents(args->trans, args->dp, XFS_ATTR_FORK);978 if (error)979 return error;980 981 if (xfs_attr_is_leaf(dp)) {982 error = xfs_attr_leaf_hasname(args, &bp);983 984 if (bp)985 xfs_trans_brelse(args->trans, bp);986 987 return error;988 }989 990 state = xfs_da_state_alloc(args);991 error = xfs_attr_node_lookup(args, state);992 xfs_da_state_free(state);993 return error;994}995 996int997xfs_attr_add_fork(998 struct xfs_inode *ip, /* incore inode pointer */999 int size, /* space new attribute needs */1000 int rsvd) /* xact may use reserved blks */1001{1002 struct xfs_mount *mp = ip->i_mount;1003 struct xfs_trans *tp; /* transaction pointer */1004 unsigned int blks; /* space reservation */1005 int error; /* error return value */1006 1007 ASSERT(!XFS_NOT_DQATTACHED(mp, ip));1008 1009 blks = XFS_ADDAFORK_SPACE_RES(mp);1010 1011 error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_addafork, blks, 0,1012 rsvd, &tp);1013 if (error)1014 return error;1015 1016 if (xfs_inode_has_attr_fork(ip))1017 goto trans_cancel;1018 1019 error = xfs_bmap_add_attrfork(tp, ip, size, rsvd);1020 if (error)1021 goto trans_cancel;1022 1023 error = xfs_trans_commit(tp);1024 xfs_iunlock(ip, XFS_ILOCK_EXCL);1025 return error;1026 1027trans_cancel:1028 xfs_trans_cancel(tp);1029 xfs_iunlock(ip, XFS_ILOCK_EXCL);1030 return error;1031}1032 1033/*1034 * Make a change to the xattr structure.1035 *1036 * The caller must have initialized @args, attached dquots, and must not hold1037 * any ILOCKs. Reserved data blocks may be used if @rsvd is set.1038 *1039 * Returns -EEXIST for XFS_ATTRUPDATE_CREATE if the name already exists.1040 * Returns -ENOATTR for XFS_ATTRUPDATE_REMOVE if the name does not exist.1041 * Returns 0 on success, or a negative errno if something else went wrong.1042 */1043int1044xfs_attr_set(1045 struct xfs_da_args *args,1046 enum xfs_attr_update op,1047 bool rsvd)1048{1049 struct xfs_inode *dp = args->dp;1050 struct xfs_mount *mp = dp->i_mount;1051 struct xfs_trans_res tres;1052 int error, local;1053 int rmt_blks = 0;1054 unsigned int total = 0;1055 1056 ASSERT(!args->trans);1057 1058 switch (op) {1059 case XFS_ATTRUPDATE_UPSERT:1060 case XFS_ATTRUPDATE_CREATE:1061 case XFS_ATTRUPDATE_REPLACE:1062 XFS_STATS_INC(mp, xs_attr_set);1063 args->total = xfs_attr_calc_size(args, &local);1064 1065 /*1066 * If the inode doesn't have an attribute fork, add one.1067 * (inode must not be locked when we call this routine)1068 */1069 if (xfs_inode_has_attr_fork(dp) == 0) {1070 int sf_size = sizeof(struct xfs_attr_sf_hdr) +1071 xfs_attr_sf_entsize_byname(args->namelen,1072 args->valuelen);1073 1074 error = xfs_attr_add_fork(dp, sf_size, rsvd);1075 if (error)1076 return error;1077 }1078 1079 if (!local)1080 rmt_blks = xfs_attr3_rmt_blocks(mp, args->valuelen);1081 1082 tres = xfs_attr_set_resv(args);1083 total = args->total;1084 break;1085 case XFS_ATTRUPDATE_REMOVE:1086 XFS_STATS_INC(mp, xs_attr_remove);1087 rmt_blks = xfs_attr3_max_rmt_blocks(mp);1088 tres = M_RES(mp)->tr_attrrm;1089 total = XFS_ATTRRM_SPACE_RES(mp);1090 break;1091 }1092 1093 /*1094 * Root fork attributes can use reserved data blocks for this1095 * operation if necessary1096 */1097 error = xfs_trans_alloc_inode(dp, &tres, total, 0, rsvd, &args->trans);1098 if (error)1099 return error;1100 1101 if (op != XFS_ATTRUPDATE_REMOVE || xfs_inode_hasattr(dp)) {1102 error = xfs_iext_count_extend(args->trans, dp, XFS_ATTR_FORK,1103 XFS_IEXT_ATTR_MANIP_CNT(rmt_blks));1104 if (error)1105 goto out_trans_cancel;1106 }1107 1108 error = xfs_attr_lookup(args);1109 switch (error) {1110 case -EEXIST:1111 if (op == XFS_ATTRUPDATE_REMOVE) {1112 /* if no value, we are performing a remove operation */1113 xfs_attr_defer_add(args, XFS_ATTR_DEFER_REMOVE);1114 break;1115 }1116 1117 /* Pure create fails if the attr already exists */1118 if (op == XFS_ATTRUPDATE_CREATE)1119 goto out_trans_cancel;1120 xfs_attr_defer_add(args, XFS_ATTR_DEFER_REPLACE);1121 break;1122 case -ENOATTR:1123 /* Can't remove what isn't there. */1124 if (op == XFS_ATTRUPDATE_REMOVE)1125 goto out_trans_cancel;1126 1127 /* Pure replace fails if no existing attr to replace. */1128 if (op == XFS_ATTRUPDATE_REPLACE)1129 goto out_trans_cancel;1130 xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET);1131 break;1132 default:1133 goto out_trans_cancel;1134 }1135 1136 /*1137 * If this is a synchronous mount, make sure that the1138 * transaction goes to disk before returning to the user.1139 */1140 if (xfs_has_wsync(mp))1141 xfs_trans_set_sync(args->trans);1142 1143 xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);1144 1145 /*1146 * Commit the last in the sequence of transactions.1147 */1148 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);1149 error = xfs_trans_commit(args->trans);1150out_unlock:1151 xfs_iunlock(dp, XFS_ILOCK_EXCL);1152 args->trans = NULL;1153 return error;1154 1155out_trans_cancel:1156 if (args->trans)1157 xfs_trans_cancel(args->trans);1158 goto out_unlock;1159}1160 1161/*========================================================================1162 * External routines when attribute list is inside the inode1163 *========================================================================*/1164 1165int xfs_attr_sf_totsize(struct xfs_inode *dp)1166{1167 struct xfs_attr_sf_hdr *sf = dp->i_af.if_data;1168 1169 return be16_to_cpu(sf->totsize);1170}1171 1172/*1173 * Add a name to the shortform attribute list structure1174 * This is the external routine.1175 */1176static int1177xfs_attr_shortform_addname(1178 struct xfs_da_args *args)1179{1180 int newsize, forkoff;1181 1182 trace_xfs_attr_sf_addname(args);1183 1184 if (xfs_attr_sf_findname(args)) {1185 int error;1186 1187 ASSERT(args->op_flags & XFS_DA_OP_REPLACE);1188 1189 error = xfs_attr_sf_removename(args);1190 if (error)1191 return error;1192 1193 /*1194 * Since we have removed the old attr, clear XFS_DA_OP_REPLACE1195 * so that the new attr doesn't fit in shortform format, the1196 * leaf format add routine won't trip over the attr not being1197 * around.1198 */1199 args->op_flags &= ~XFS_DA_OP_REPLACE;1200 } else {1201 ASSERT(!(args->op_flags & XFS_DA_OP_REPLACE));1202 }1203 1204 if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||1205 args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)1206 return -ENOSPC;1207 1208 newsize = xfs_attr_sf_totsize(args->dp);1209 newsize += xfs_attr_sf_entsize_byname(args->namelen, args->valuelen);1210 1211 forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);1212 if (!forkoff)1213 return -ENOSPC;1214 1215 xfs_attr_shortform_add(args, forkoff);1216 return 0;1217}1218 1219 1220/*========================================================================1221 * External routines when attribute list is one block1222 *========================================================================*/1223 1224/*1225 * Return EEXIST if attr is found, or ENOATTR if not1226 */1227STATIC int1228xfs_attr_leaf_hasname(1229 struct xfs_da_args *args,1230 struct xfs_buf **bp)1231{1232 int error = 0;1233 1234 error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, bp);1235 if (error)1236 return error;1237 1238 error = xfs_attr3_leaf_lookup_int(*bp, args);1239 if (error != -ENOATTR && error != -EEXIST)1240 xfs_trans_brelse(args->trans, *bp);1241 1242 return error;1243}1244 1245/*1246 * Remove a name from the leaf attribute list structure1247 *1248 * This leaf block cannot have a "remote" value, we only call this routine1249 * if bmap_one_block() says there is only one block (ie: no remote blks).1250 */1251STATIC int1252xfs_attr_leaf_removename(1253 struct xfs_da_args *args)1254{1255 struct xfs_inode *dp;1256 struct xfs_buf *bp;1257 int error, forkoff;1258 1259 trace_xfs_attr_leaf_removename(args);1260 1261 /*1262 * Remove the attribute.1263 */1264 dp = args->dp;1265 1266 error = xfs_attr_leaf_hasname(args, &bp);1267 if (error == -ENOATTR) {1268 xfs_trans_brelse(args->trans, bp);1269 if (args->op_flags & XFS_DA_OP_RECOVERY)1270 return 0;1271 return error;1272 } else if (error != -EEXIST)1273 return error;1274 1275 xfs_attr3_leaf_remove(bp, args);1276 1277 /*1278 * If the result is small enough, shrink it all into the inode.1279 */1280 forkoff = xfs_attr_shortform_allfit(bp, dp);1281 if (forkoff)1282 return xfs_attr3_leaf_to_shortform(bp, args, forkoff);1283 /* bp is gone due to xfs_da_shrink_inode */1284 1285 return 0;1286}1287 1288/*1289 * Look up a name in a leaf attribute list structure.1290 *1291 * This leaf block cannot have a "remote" value, we only call this routine1292 * if bmap_one_block() says there is only one block (ie: no remote blks).1293 *1294 * Returns 0 on successful retrieval, otherwise an error.1295 */1296STATIC int1297xfs_attr_leaf_get(xfs_da_args_t *args)1298{1299 struct xfs_buf *bp;1300 int error;1301 1302 trace_xfs_attr_leaf_get(args);1303 1304 error = xfs_attr_leaf_hasname(args, &bp);1305 1306 if (error == -ENOATTR) {1307 xfs_trans_brelse(args->trans, bp);1308 return error;1309 } else if (error != -EEXIST)1310 return error;1311 1312 1313 error = xfs_attr3_leaf_getvalue(bp, args);1314 xfs_trans_brelse(args->trans, bp);1315 return error;1316}1317 1318/* Return EEXIST if attr is found, or ENOATTR if not. */1319STATIC int1320xfs_attr_node_lookup(1321 struct xfs_da_args *args,1322 struct xfs_da_state *state)1323{1324 int retval, error;1325 1326 /*1327 * Search to see if name exists, and get back a pointer to it.1328 */1329 error = xfs_da3_node_lookup_int(state, &retval);1330 if (error)1331 return error;1332 1333 return retval;1334}1335 1336/*========================================================================1337 * External routines when attribute list size > geo->blksize1338 *========================================================================*/1339 1340STATIC int1341xfs_attr_node_addname_find_attr(1342 struct xfs_attr_intent *attr)1343{1344 struct xfs_da_args *args = attr->xattri_da_args;1345 int error;1346 1347 /*1348 * Search to see if name already exists, and get back a pointer1349 * to where it should go.1350 */1351 xfs_attr_item_init_da_state(attr);1352 error = xfs_attr_node_lookup(args, attr->xattri_da_state);1353 switch (error) {1354 case -ENOATTR:1355 if (args->op_flags & XFS_DA_OP_REPLACE)1356 goto error;1357 break;1358 case -EEXIST:1359 if (!(args->op_flags & XFS_DA_OP_REPLACE))1360 goto error;1361 1362 1363 trace_xfs_attr_node_replace(args);1364 /*1365 * Save the existing remote attr state so that the current1366 * values reflect the state of the new attribute we are about to1367 * add, not the attribute we just found and will remove later.1368 */1369 xfs_attr_save_rmt_blk(args);1370 break;1371 case 0:1372 break;1373 default:1374 goto error;1375 }1376 1377 return 0;1378error:1379 if (attr->xattri_da_state) {1380 xfs_da_state_free(attr->xattri_da_state);1381 attr->xattri_da_state = NULL;1382 }1383 return error;1384}1385 1386/*1387 * Add a name to a Btree-format attribute list.1388 *1389 * This will involve walking down the Btree, and may involve splitting leaf1390 * nodes and even splitting intermediate nodes up to and including the root1391 * node (a special case of an intermediate node).1392 *1393 * If the tree was still in single leaf format and needs to converted to1394 * real node format return 1 and let the caller handle that.1395 */1396static int1397xfs_attr_node_try_addname(1398 struct xfs_attr_intent *attr)1399{1400 struct xfs_da_state *state = attr->xattri_da_state;1401 struct xfs_da_state_blk *blk;1402 int error = 0;1403 1404 trace_xfs_attr_node_addname(state->args);1405 1406 blk = &state->path.blk[state->path.active-1];1407 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);1408 1409 if (!xfs_attr3_leaf_add(blk->bp, state->args)) {1410 if (state->path.active == 1) {1411 /*1412 * Its really a single leaf node, but it had1413 * out-of-line values so it looked like it *might*1414 * have been a b-tree. Let the caller deal with this.1415 */1416 error = 1;1417 goto out;1418 }1419 1420 /*1421 * Split as many Btree elements as required.1422 * This code tracks the new and old attr's location1423 * in the index/blkno/rmtblkno/rmtblkcnt fields and1424 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.1425 */1426 error = xfs_da3_split(state);1427 if (error)1428 goto out;1429 } else {1430 /*1431 * Addition succeeded, update Btree hashvals.1432 */1433 xfs_da3_fixhashpath(state, &state->path);1434 }1435 1436out:1437 xfs_da_state_free(state);1438 attr->xattri_da_state = NULL;1439 return error;1440}1441 1442static int1443xfs_attr_node_removename(1444 struct xfs_da_args *args,1445 struct xfs_da_state *state)1446{1447 struct xfs_da_state_blk *blk;1448 int retval;1449 1450 /*1451 * Remove the name and update the hashvals in the tree.1452 */1453 blk = &state->path.blk[state->path.active-1];1454 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);1455 retval = xfs_attr3_leaf_remove(blk->bp, args);1456 xfs_da3_fixhashpath(state, &state->path);1457 1458 return retval;1459}1460 1461static int1462xfs_attr_node_remove_attr(1463 struct xfs_attr_intent *attr)1464{1465 struct xfs_da_args *args = attr->xattri_da_args;1466 struct xfs_da_state *state = xfs_da_state_alloc(args);1467 int retval = 0;1468 int error = 0;1469 1470 /*1471 * The attr we are removing has already been marked incomplete, so1472 * we need to set the filter appropriately to re-find the "old"1473 * attribute entry after any split ops.1474 */1475 args->attr_filter |= XFS_ATTR_INCOMPLETE;1476 error = xfs_da3_node_lookup_int(state, &retval);1477 if (error)1478 goto out;1479 1480 error = xfs_attr_node_removename(args, state);1481 1482 /*1483 * Check to see if the tree needs to be collapsed.1484 */1485 if (retval && (state->path.active > 1)) {1486 error = xfs_da3_join(state);1487 if (error)1488 goto out;1489 }1490 retval = error = 0;1491 1492out:1493 xfs_da_state_free(state);1494 if (error)1495 return error;1496 return retval;1497}1498 1499/*1500 * Retrieve the attribute data from a node attribute list.1501 *1502 * This routine gets called for any attribute fork that has more than one1503 * block, ie: both true Btree attr lists and for single-leaf-blocks with1504 * "remote" values taking up more blocks.1505 *1506 * Returns 0 on successful retrieval, otherwise an error.1507 */1508STATIC int1509xfs_attr_node_get(1510 struct xfs_da_args *args)1511{1512 struct xfs_da_state *state;1513 struct xfs_da_state_blk *blk;1514 int i;1515 int error;1516 1517 trace_xfs_attr_node_get(args);1518 1519 /*1520 * Search to see if name exists, and get back a pointer to it.1521 */1522 state = xfs_da_state_alloc(args);1523 error = xfs_attr_node_lookup(args, state);1524 if (error != -EEXIST)1525 goto out_release;1526 1527 /*1528 * Get the value, local or "remote"1529 */1530 blk = &state->path.blk[state->path.active - 1];1531 error = xfs_attr3_leaf_getvalue(blk->bp, args);1532 1533 /*1534 * If not in a transaction, we have to release all the buffers.1535 */1536out_release:1537 for (i = 0; i < state->path.active; i++) {1538 xfs_trans_brelse(args->trans, state->path.blk[i].bp);1539 state->path.blk[i].bp = NULL;1540 }1541 1542 xfs_da_state_free(state);1543 return error;1544}1545 1546/* Enforce that there is at most one namespace bit per attr. */1547inline bool xfs_attr_check_namespace(unsigned int attr_flags)1548{1549 return hweight32(attr_flags & XFS_ATTR_NSP_ONDISK_MASK) < 2;1550}1551 1552/* Returns true if the attribute entry name is valid. */1553bool1554xfs_attr_namecheck(1555 unsigned int attr_flags,1556 const void *name,1557 size_t length)1558{1559 /* Only one namespace bit allowed. */1560 if (!xfs_attr_check_namespace(attr_flags))1561 return false;1562 1563 /*1564 * MAXNAMELEN includes the trailing null, but (name/length) leave it1565 * out, so use >= for the length check.1566 */1567 if (length >= MAXNAMELEN)1568 return false;1569 1570 /* Parent pointers have their own validation. */1571 if (attr_flags & XFS_ATTR_PARENT)1572 return xfs_parent_namecheck(attr_flags, name, length);1573 1574 /* There shouldn't be any nulls here */1575 return !memchr(name, 0, length);1576}1577 1578int __init1579xfs_attr_intent_init_cache(void)1580{1581 xfs_attr_intent_cache = kmem_cache_create("xfs_attr_intent",1582 sizeof(struct xfs_attr_intent),1583 0, 0, NULL);1584 1585 return xfs_attr_intent_cache != NULL ? 0 : -ENOMEM;1586}1587 1588void1589xfs_attr_intent_destroy_cache(void)1590{1591 kmem_cache_destroy(xfs_attr_intent_cache);1592 xfs_attr_intent_cache = NULL;1593}1594