10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0
230f712c9SDave Chinner /*
330f712c9SDave Chinner * Copyright (c) 2000-2005 Silicon Graphics, Inc.
430f712c9SDave Chinner * All Rights Reserved.
530f712c9SDave Chinner */
630f712c9SDave Chinner #include "xfs.h"
730f712c9SDave Chinner #include "xfs_fs.h"
830f712c9SDave Chinner #include "xfs_shared.h"
930f712c9SDave Chinner #include "xfs_format.h"
1030f712c9SDave Chinner #include "xfs_log_format.h"
1130f712c9SDave Chinner #include "xfs_trans_resv.h"
1230f712c9SDave Chinner #include "xfs_mount.h"
133ab78df2SDarrick J. Wong #include "xfs_defer.h"
1430f712c9SDave Chinner #include "xfs_da_format.h"
1530f712c9SDave Chinner #include "xfs_da_btree.h"
1630f712c9SDave Chinner #include "xfs_attr_sf.h"
1730f712c9SDave Chinner #include "xfs_inode.h"
1830f712c9SDave Chinner #include "xfs_trans.h"
1930f712c9SDave Chinner #include "xfs_bmap.h"
2030f712c9SDave Chinner #include "xfs_bmap_btree.h"
2130f712c9SDave Chinner #include "xfs_attr.h"
2230f712c9SDave Chinner #include "xfs_attr_leaf.h"
2330f712c9SDave Chinner #include "xfs_attr_remote.h"
2430f712c9SDave Chinner #include "xfs_quota.h"
2530f712c9SDave Chinner #include "xfs_trans_space.h"
2630f712c9SDave Chinner #include "xfs_trace.h"
27fd920008SAllison Henderson #include "xfs_attr_item.h"
28d9c61ccbSDarrick J. Wong #include "xfs_xattr.h"
29fd920008SAllison Henderson
30e2c78949SDarrick J. Wong struct kmem_cache *xfs_attr_intent_cache;
3130f712c9SDave Chinner
3230f712c9SDave Chinner /*
3330f712c9SDave Chinner * xfs_attr.c
3430f712c9SDave Chinner *
3530f712c9SDave Chinner * Provide the external interfaces to manage attribute lists.
3630f712c9SDave Chinner */
3730f712c9SDave Chinner
3830f712c9SDave Chinner /*========================================================================
3930f712c9SDave Chinner * Function prototypes for the kernel.
4030f712c9SDave Chinner *========================================================================*/
4130f712c9SDave Chinner
4230f712c9SDave Chinner /*
4330f712c9SDave Chinner * Internal routines when attribute list fits inside the inode.
4430f712c9SDave Chinner */
4530f712c9SDave Chinner STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
4630f712c9SDave Chinner
4730f712c9SDave Chinner /*
4830f712c9SDave Chinner * Internal routines when attribute list is one block.
4930f712c9SDave Chinner */
5030f712c9SDave Chinner STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
5130f712c9SDave Chinner STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
5207120f1aSAllison Collins STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
5330f712c9SDave Chinner
5430f712c9SDave Chinner /*
5530f712c9SDave Chinner * Internal routines when attribute list is more than one block.
5630f712c9SDave Chinner */
5730f712c9SDave Chinner STATIC int xfs_attr_node_get(xfs_da_args_t *args);
585d954cc0SAllison Henderson STATIC void xfs_attr_restore_rmt_blk(struct xfs_da_args *args);
59e3c5de22SDarrick J. Wong static int xfs_attr_node_try_addname(struct xfs_attr_intent *attr);
60e3c5de22SDarrick J. Wong STATIC int xfs_attr_node_addname_find_attr(struct xfs_attr_intent *attr);
61e3c5de22SDarrick J. Wong STATIC int xfs_attr_node_remove_attr(struct xfs_attr_intent *attr);
624d0cdd2bSDarrick J. Wong STATIC int xfs_attr_node_lookup(struct xfs_da_args *args,
634d0cdd2bSDarrick J. Wong struct xfs_da_state *state);
6430f712c9SDave Chinner
6530f712c9SDave Chinner int
xfs_inode_hasattr(struct xfs_inode * ip)6630f712c9SDave Chinner xfs_inode_hasattr(
6730f712c9SDave Chinner struct xfs_inode *ip)
6830f712c9SDave Chinner {
69932b42c6SDarrick J. Wong if (!xfs_inode_has_attr_fork(ip))
70fdaf1bb3SDave Chinner return 0;
712ed5b09bSDarrick J. Wong if (ip->i_af.if_format == XFS_DINODE_FMT_EXTENTS &&
722ed5b09bSDarrick J. Wong ip->i_af.if_nextents == 0)
7330f712c9SDave Chinner return 0;
7430f712c9SDave Chinner return 1;
7530f712c9SDave Chinner }
7630f712c9SDave Chinner
772ac131dfSChristoph Hellwig /*
782ac131dfSChristoph Hellwig * Returns true if the there is exactly only block in the attr fork, in which
792ac131dfSChristoph Hellwig * case the attribute fork consists of a single leaf block entry.
802ac131dfSChristoph Hellwig */
812ac131dfSChristoph Hellwig bool
xfs_attr_is_leaf(struct xfs_inode * ip)822ac131dfSChristoph Hellwig xfs_attr_is_leaf(
832ac131dfSChristoph Hellwig struct xfs_inode *ip)
842ac131dfSChristoph Hellwig {
852ed5b09bSDarrick J. Wong struct xfs_ifork *ifp = &ip->i_af;
862ac131dfSChristoph Hellwig struct xfs_iext_cursor icur;
872ac131dfSChristoph Hellwig struct xfs_bmbt_irec imap;
882ac131dfSChristoph Hellwig
892ac131dfSChristoph Hellwig if (ifp->if_nextents != 1 || ifp->if_format != XFS_DINODE_FMT_EXTENTS)
902ac131dfSChristoph Hellwig return false;
912ac131dfSChristoph Hellwig
922ac131dfSChristoph Hellwig xfs_iext_first(ifp, &icur);
932ac131dfSChristoph Hellwig xfs_iext_get_extent(ifp, &icur, &imap);
942ac131dfSChristoph Hellwig return imap.br_startoff == 0 && imap.br_blockcount == 1;
952ac131dfSChristoph Hellwig }
962ac131dfSChristoph Hellwig
9759782a23SDave Chinner /*
9859782a23SDave Chinner * XXX (dchinner): name path state saving and refilling is an optimisation to
9959782a23SDave Chinner * avoid needing to look up name entries after rolling transactions removing
10059782a23SDave Chinner * remote xattr blocks between the name entry lookup and name entry removal.
10159782a23SDave Chinner * This optimisation got sidelined when combining the set and remove state
10259782a23SDave Chinner * machines, but the code has been left in place because it is worthwhile to
10359782a23SDave Chinner * restore the optimisation once the combined state machine paths have settled.
10459782a23SDave Chinner *
10559782a23SDave Chinner * This comment is a public service announcement to remind Future Dave that he
10659782a23SDave Chinner * still needs to restore this code to working order.
10759782a23SDave Chinner */
10859782a23SDave Chinner #if 0
10959782a23SDave Chinner /*
11059782a23SDave Chinner * Fill in the disk block numbers in the state structure for the buffers
11159782a23SDave Chinner * that are attached to the state structure.
11259782a23SDave Chinner * This is done so that we can quickly reattach ourselves to those buffers
11359782a23SDave Chinner * after some set of transaction commits have released these buffers.
11459782a23SDave Chinner */
11559782a23SDave Chinner static int
11659782a23SDave Chinner xfs_attr_fillstate(xfs_da_state_t *state)
11759782a23SDave Chinner {
11859782a23SDave Chinner xfs_da_state_path_t *path;
11959782a23SDave Chinner xfs_da_state_blk_t *blk;
12059782a23SDave Chinner int level;
12159782a23SDave Chinner
12259782a23SDave Chinner trace_xfs_attr_fillstate(state->args);
12359782a23SDave Chinner
12459782a23SDave Chinner /*
12559782a23SDave Chinner * Roll down the "path" in the state structure, storing the on-disk
12659782a23SDave Chinner * block number for those buffers in the "path".
12759782a23SDave Chinner */
12859782a23SDave Chinner path = &state->path;
12959782a23SDave Chinner ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
13059782a23SDave Chinner for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
13159782a23SDave Chinner if (blk->bp) {
13259782a23SDave Chinner blk->disk_blkno = xfs_buf_daddr(blk->bp);
13359782a23SDave Chinner blk->bp = NULL;
13459782a23SDave Chinner } else {
13559782a23SDave Chinner blk->disk_blkno = 0;
13659782a23SDave Chinner }
13759782a23SDave Chinner }
13859782a23SDave Chinner
13959782a23SDave Chinner /*
14059782a23SDave Chinner * Roll down the "altpath" in the state structure, storing the on-disk
14159782a23SDave Chinner * block number for those buffers in the "altpath".
14259782a23SDave Chinner */
14359782a23SDave Chinner path = &state->altpath;
14459782a23SDave Chinner ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
14559782a23SDave Chinner for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
14659782a23SDave Chinner if (blk->bp) {
14759782a23SDave Chinner blk->disk_blkno = xfs_buf_daddr(blk->bp);
14859782a23SDave Chinner blk->bp = NULL;
14959782a23SDave Chinner } else {
15059782a23SDave Chinner blk->disk_blkno = 0;
15159782a23SDave Chinner }
15259782a23SDave Chinner }
15359782a23SDave Chinner
15459782a23SDave Chinner return 0;
15559782a23SDave Chinner }
15659782a23SDave Chinner
15759782a23SDave Chinner /*
15859782a23SDave Chinner * Reattach the buffers to the state structure based on the disk block
15959782a23SDave Chinner * numbers stored in the state structure.
16059782a23SDave Chinner * This is done after some set of transaction commits have released those
16159782a23SDave Chinner * buffers from our grip.
16259782a23SDave Chinner */
16359782a23SDave Chinner static int
16459782a23SDave Chinner xfs_attr_refillstate(xfs_da_state_t *state)
16559782a23SDave Chinner {
16659782a23SDave Chinner xfs_da_state_path_t *path;
16759782a23SDave Chinner xfs_da_state_blk_t *blk;
16859782a23SDave Chinner int level, error;
16959782a23SDave Chinner
17059782a23SDave Chinner trace_xfs_attr_refillstate(state->args);
17159782a23SDave Chinner
17259782a23SDave Chinner /*
17359782a23SDave Chinner * Roll down the "path" in the state structure, storing the on-disk
17459782a23SDave Chinner * block number for those buffers in the "path".
17559782a23SDave Chinner */
17659782a23SDave Chinner path = &state->path;
17759782a23SDave Chinner ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
17859782a23SDave Chinner for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
17959782a23SDave Chinner if (blk->disk_blkno) {
18059782a23SDave Chinner error = xfs_da3_node_read_mapped(state->args->trans,
18159782a23SDave Chinner state->args->dp, blk->disk_blkno,
18259782a23SDave Chinner &blk->bp, XFS_ATTR_FORK);
18359782a23SDave Chinner if (error)
18459782a23SDave Chinner return error;
18559782a23SDave Chinner } else {
18659782a23SDave Chinner blk->bp = NULL;
18759782a23SDave Chinner }
18859782a23SDave Chinner }
18959782a23SDave Chinner
19059782a23SDave Chinner /*
19159782a23SDave Chinner * Roll down the "altpath" in the state structure, storing the on-disk
19259782a23SDave Chinner * block number for those buffers in the "altpath".
19359782a23SDave Chinner */
19459782a23SDave Chinner path = &state->altpath;
19559782a23SDave Chinner ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
19659782a23SDave Chinner for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
19759782a23SDave Chinner if (blk->disk_blkno) {
19859782a23SDave Chinner error = xfs_da3_node_read_mapped(state->args->trans,
19959782a23SDave Chinner state->args->dp, blk->disk_blkno,
20059782a23SDave Chinner &blk->bp, XFS_ATTR_FORK);
20159782a23SDave Chinner if (error)
20259782a23SDave Chinner return error;
20359782a23SDave Chinner } else {
20459782a23SDave Chinner blk->bp = NULL;
20559782a23SDave Chinner }
20659782a23SDave Chinner }
20759782a23SDave Chinner
20859782a23SDave Chinner return 0;
20959782a23SDave Chinner }
21059782a23SDave Chinner #else
xfs_attr_fillstate(xfs_da_state_t * state)21159782a23SDave Chinner static int xfs_attr_fillstate(xfs_da_state_t *state) { return 0; }
21259782a23SDave Chinner #endif
21359782a23SDave Chinner
21430f712c9SDave Chinner /*========================================================================
21530f712c9SDave Chinner * Overall external interface routines.
21630f712c9SDave Chinner *========================================================================*/
21730f712c9SDave Chinner
218728bcaa3SDave Chinner /*
219728bcaa3SDave Chinner * Retrieve an extended attribute and its value. Must have ilock.
220728bcaa3SDave Chinner * Returns 0 on successful retrieval, otherwise an error.
221728bcaa3SDave Chinner */
222ad017f65SDarrick J. Wong int
xfs_attr_get_ilocked(struct xfs_da_args * args)223ad017f65SDarrick J. Wong xfs_attr_get_ilocked(
224ad017f65SDarrick J. Wong struct xfs_da_args *args)
225ad017f65SDarrick J. Wong {
226c36f533fSChristoph Hellwig ASSERT(xfs_isilocked(args->dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
227cf69f824SChristoph Hellwig
228c36f533fSChristoph Hellwig if (!xfs_inode_hasattr(args->dp))
229ad017f65SDarrick J. Wong return -ENOATTR;
230c36f533fSChristoph Hellwig
2312ed5b09bSDarrick J. Wong if (args->dp->i_af.if_format == XFS_DINODE_FMT_LOCAL)
232ad017f65SDarrick J. Wong return xfs_attr_shortform_getvalue(args);
2332ac131dfSChristoph Hellwig if (xfs_attr_is_leaf(args->dp))
234ad017f65SDarrick J. Wong return xfs_attr_leaf_get(args);
235ad017f65SDarrick J. Wong return xfs_attr_node_get(args);
236ad017f65SDarrick J. Wong }
237ad017f65SDarrick J. Wong
238ddbca70cSDave Chinner /*
239ddbca70cSDave Chinner * Retrieve an extended attribute by name, and its value if requested.
240ddbca70cSDave Chinner *
241e513e25cSChristoph Hellwig * If args->valuelen is zero, then the caller does not want the value, just an
242e513e25cSChristoph Hellwig * indication whether the attribute exists and the size of the value if it
243e513e25cSChristoph Hellwig * exists. The size is returned in args.valuelen.
244ddbca70cSDave Chinner *
245d49db18bSChristoph Hellwig * If args->value is NULL but args->valuelen is non-zero, allocate the buffer
246d49db18bSChristoph Hellwig * for the value after existence of the attribute has been determined. The
247d49db18bSChristoph Hellwig * caller always has to free args->value if it is set, no matter if this
248d49db18bSChristoph Hellwig * function was successful or not.
249d49db18bSChristoph Hellwig *
250ddbca70cSDave Chinner * If the attribute is found, but exceeds the size limit set by the caller in
251e5171d7eSChristoph Hellwig * args->valuelen, return -ERANGE with the size of the attribute that was found
252e5171d7eSChristoph Hellwig * in args->valuelen.
253ddbca70cSDave Chinner */
25430f712c9SDave Chinner int
xfs_attr_get(struct xfs_da_args * args)25530f712c9SDave Chinner xfs_attr_get(
256e5171d7eSChristoph Hellwig struct xfs_da_args *args)
25730f712c9SDave Chinner {
25830f712c9SDave Chinner uint lock_mode;
25930f712c9SDave Chinner int error;
26030f712c9SDave Chinner
261e5171d7eSChristoph Hellwig XFS_STATS_INC(args->dp->i_mount, xs_attr_get);
26230f712c9SDave Chinner
26375c8c50fSDave Chinner if (xfs_is_shutdown(args->dp->i_mount))
2642451337dSDave Chinner return -EIO;
26530f712c9SDave Chinner
266e5171d7eSChristoph Hellwig args->geo = args->dp->i_mount->m_attr_geo;
267e5171d7eSChristoph Hellwig args->whichfork = XFS_ATTR_FORK;
268e5171d7eSChristoph Hellwig args->hashval = xfs_da_hashname(args->name, args->namelen);
26930f712c9SDave Chinner
270c400ee3eSEric Sandeen /* Entirely possible to look up a name which doesn't exist */
271e5171d7eSChristoph Hellwig args->op_flags = XFS_DA_OP_OKNOENT;
27230f712c9SDave Chinner
273e5171d7eSChristoph Hellwig lock_mode = xfs_ilock_attr_map_shared(args->dp);
274c36f533fSChristoph Hellwig error = xfs_attr_get_ilocked(args);
275e5171d7eSChristoph Hellwig xfs_iunlock(args->dp, lock_mode);
276ddbca70cSDave Chinner
277728bcaa3SDave Chinner return error;
27830f712c9SDave Chinner }
27930f712c9SDave Chinner
28030f712c9SDave Chinner /*
28130f712c9SDave Chinner * Calculate how many blocks we need for the new attribute,
28230f712c9SDave Chinner */
283fd920008SAllison Henderson int
xfs_attr_calc_size(struct xfs_da_args * args,int * local)28430f712c9SDave Chinner xfs_attr_calc_size(
28530f712c9SDave Chinner struct xfs_da_args *args,
28630f712c9SDave Chinner int *local)
28730f712c9SDave Chinner {
28830f712c9SDave Chinner struct xfs_mount *mp = args->dp->i_mount;
28930f712c9SDave Chinner int size;
29030f712c9SDave Chinner int nblks;
29130f712c9SDave Chinner
29230f712c9SDave Chinner /*
29330f712c9SDave Chinner * Determine space new attribute will use, and if it would be
29430f712c9SDave Chinner * "local" or "remote" (note: local != inline).
29530f712c9SDave Chinner */
29630f712c9SDave Chinner size = xfs_attr_leaf_newentsize(args, local);
29730f712c9SDave Chinner nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
29830f712c9SDave Chinner if (*local) {
29930f712c9SDave Chinner if (size > (args->geo->blksize / 2)) {
30030f712c9SDave Chinner /* Double split possible */
30130f712c9SDave Chinner nblks *= 2;
30230f712c9SDave Chinner }
30330f712c9SDave Chinner } else {
30430f712c9SDave Chinner /*
30530f712c9SDave Chinner * Out of line attribute, cannot double split, but
30630f712c9SDave Chinner * make room for the attribute value itself.
30730f712c9SDave Chinner */
30830f712c9SDave Chinner uint dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen);
30930f712c9SDave Chinner nblks += dblocks;
31030f712c9SDave Chinner nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
31130f712c9SDave Chinner }
31230f712c9SDave Chinner
31330f712c9SDave Chinner return nblks;
31430f712c9SDave Chinner }
31530f712c9SDave Chinner
316c3546cf5SAllison Henderson /* Initialize transaction reservation for attr operations */
317c3546cf5SAllison Henderson void
xfs_init_attr_trans(struct xfs_da_args * args,struct xfs_trans_res * tres,unsigned int * total)318c3546cf5SAllison Henderson xfs_init_attr_trans(
319c3546cf5SAllison Henderson struct xfs_da_args *args,
320c3546cf5SAllison Henderson struct xfs_trans_res *tres,
321c3546cf5SAllison Henderson unsigned int *total)
322c3546cf5SAllison Henderson {
323c3546cf5SAllison Henderson struct xfs_mount *mp = args->dp->i_mount;
324c3546cf5SAllison Henderson
325c3546cf5SAllison Henderson if (args->value) {
326c3546cf5SAllison Henderson tres->tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
327c3546cf5SAllison Henderson M_RES(mp)->tr_attrsetrt.tr_logres *
328c3546cf5SAllison Henderson args->total;
329c3546cf5SAllison Henderson tres->tr_logcount = XFS_ATTRSET_LOG_COUNT;
330c3546cf5SAllison Henderson tres->tr_logflags = XFS_TRANS_PERM_LOG_RES;
331c3546cf5SAllison Henderson *total = args->total;
332c3546cf5SAllison Henderson } else {
333c3546cf5SAllison Henderson *tres = M_RES(mp)->tr_attrrm;
334c3546cf5SAllison Henderson *total = XFS_ATTRRM_SPACE_RES(mp);
335c3546cf5SAllison Henderson }
336c3546cf5SAllison Henderson }
337c3546cf5SAllison Henderson
338e0c41089SDave Chinner /*
339e0c41089SDave Chinner * Add an attr to a shortform fork. If there is no space,
340e0c41089SDave Chinner * xfs_attr_shortform_addname() will convert to leaf format and return -ENOSPC.
341e0c41089SDave Chinner * to use.
342e0c41089SDave Chinner */
3434c74a56bSAllison Henderson STATIC int
xfs_attr_try_sf_addname(struct xfs_inode * dp,struct xfs_da_args * args)3444c74a56bSAllison Henderson xfs_attr_try_sf_addname(
3454c74a56bSAllison Henderson struct xfs_inode *dp,
3464c74a56bSAllison Henderson struct xfs_da_args *args)
3474c74a56bSAllison Henderson {
3484c74a56bSAllison Henderson
3496cc5b5f8SAllison Collins int error;
3506cc5b5f8SAllison Collins
3516cc5b5f8SAllison Collins /*
3526cc5b5f8SAllison Collins * Build initial attribute list (if required).
3536cc5b5f8SAllison Collins */
3542ed5b09bSDarrick J. Wong if (dp->i_af.if_format == XFS_DINODE_FMT_EXTENTS)
3556cc5b5f8SAllison Collins xfs_attr_shortform_create(args);
3564c74a56bSAllison Henderson
3574c74a56bSAllison Henderson error = xfs_attr_shortform_addname(args);
3584c74a56bSAllison Henderson if (error == -ENOSPC)
3594c74a56bSAllison Henderson return error;
3604c74a56bSAllison Henderson
3614c74a56bSAllison Henderson /*
3624c74a56bSAllison Henderson * Commit the shortform mods, and we're done.
3634c74a56bSAllison Henderson * NOTE: this is also the error path (EEXIST, etc).
3644c74a56bSAllison Henderson */
3651d733019SChristoph Hellwig if (!error && !(args->op_flags & XFS_DA_OP_NOTIME))
3664c74a56bSAllison Henderson xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
3674c74a56bSAllison Henderson
3680560f31aSDave Chinner if (xfs_has_wsync(dp->i_mount))
3694c74a56bSAllison Henderson xfs_trans_set_sync(args->trans);
3704c74a56bSAllison Henderson
3716cc5b5f8SAllison Collins return error;
3724c74a56bSAllison Henderson }
3734c74a56bSAllison Henderson
374e0c41089SDave Chinner static int
xfs_attr_sf_addname(struct xfs_attr_intent * attr)375816c8e39SAllison Henderson xfs_attr_sf_addname(
376e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr)
3778f502a40SAllison Henderson {
378d68c51e9SAllison Henderson struct xfs_da_args *args = attr->xattri_da_args;
379db1a28ccSAllison Collins struct xfs_inode *dp = args->dp;
3808f502a40SAllison Henderson int error = 0;
3812f3cd809SAllison Henderson
3822f3cd809SAllison Henderson error = xfs_attr_try_sf_addname(dp, args);
383e0c41089SDave Chinner if (error != -ENOSPC) {
384e0c41089SDave Chinner ASSERT(!error || error == -EEXIST);
385e0c41089SDave Chinner attr->xattri_dela_state = XFS_DAS_DONE;
386e0c41089SDave Chinner goto out;
387e0c41089SDave Chinner }
3886286514bSAllison Henderson
3892f3cd809SAllison Henderson /*
390db1a28ccSAllison Collins * It won't fit in the shortform, transform to a leaf block. GROT:
391db1a28ccSAllison Collins * another possible req'mt for a double-split btree op.
3922f3cd809SAllison Henderson */
393e53bcffaSDarrick J. Wong error = xfs_attr_shortform_to_leaf(args);
3942f3cd809SAllison Henderson if (error)
3952f3cd809SAllison Henderson return error;
3962f3cd809SAllison Henderson
397e0c41089SDave Chinner attr->xattri_dela_state = XFS_DAS_LEAF_ADD;
398e0c41089SDave Chinner out:
399e0c41089SDave Chinner trace_xfs_attr_sf_addname_return(attr->xattri_dela_state, args->dp);
400e0c41089SDave Chinner return error;
401db1a28ccSAllison Collins }
402db1a28ccSAllison Collins
4033d58507dSChristoph Hellwig /* Save the current remote block info and clear the current pointers. */
4043d58507dSChristoph Hellwig static void
xfs_attr_save_rmt_blk(struct xfs_da_args * args)4053d58507dSChristoph Hellwig xfs_attr_save_rmt_blk(
4063d58507dSChristoph Hellwig struct xfs_da_args *args)
4073d58507dSChristoph Hellwig {
4083d58507dSChristoph Hellwig args->blkno2 = args->blkno;
4093d58507dSChristoph Hellwig args->index2 = args->index;
4103d58507dSChristoph Hellwig args->rmtblkno2 = args->rmtblkno;
4113d58507dSChristoph Hellwig args->rmtblkcnt2 = args->rmtblkcnt;
4123d58507dSChristoph Hellwig args->rmtvaluelen2 = args->rmtvaluelen;
4133d58507dSChristoph Hellwig args->rmtblkno = 0;
4143d58507dSChristoph Hellwig args->rmtblkcnt = 0;
4153d58507dSChristoph Hellwig args->rmtvaluelen = 0;
4163d58507dSChristoph Hellwig }
4173d58507dSChristoph Hellwig
4183d58507dSChristoph Hellwig /* Set stored info about a remote block */
4193d58507dSChristoph Hellwig static void
xfs_attr_restore_rmt_blk(struct xfs_da_args * args)4203d58507dSChristoph Hellwig xfs_attr_restore_rmt_blk(
4213d58507dSChristoph Hellwig struct xfs_da_args *args)
4223d58507dSChristoph Hellwig {
4233d58507dSChristoph Hellwig args->blkno = args->blkno2;
4243d58507dSChristoph Hellwig args->index = args->index2;
4253d58507dSChristoph Hellwig args->rmtblkno = args->rmtblkno2;
4263d58507dSChristoph Hellwig args->rmtblkcnt = args->rmtblkcnt2;
4273d58507dSChristoph Hellwig args->rmtvaluelen = args->rmtvaluelen2;
4283d58507dSChristoph Hellwig }
4293d58507dSChristoph Hellwig
430411b434aSDave Chinner /*
431fdaf1bb3SDave Chinner * Handle the state change on completion of a multi-state attr operation.
432fdaf1bb3SDave Chinner *
433fdaf1bb3SDave Chinner * If the XFS_DA_OP_REPLACE flag is set, this means the operation was the first
434fdaf1bb3SDave Chinner * modification in a attr replace operation and we still have to do the second
435fdaf1bb3SDave Chinner * state, indicated by @replace_state.
436fdaf1bb3SDave Chinner *
437fdaf1bb3SDave Chinner * We consume the XFS_DA_OP_REPLACE flag so that when we are called again on
438fdaf1bb3SDave Chinner * completion of the second half of the attr replace operation we correctly
439fdaf1bb3SDave Chinner * signal that it is done.
440411b434aSDave Chinner */
441fdaf1bb3SDave Chinner static enum xfs_delattr_state
xfs_attr_complete_op(struct xfs_attr_intent * attr,enum xfs_delattr_state replace_state)442fdaf1bb3SDave Chinner xfs_attr_complete_op(
443e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr,
444fdaf1bb3SDave Chinner enum xfs_delattr_state replace_state)
445411b434aSDave Chinner {
446411b434aSDave Chinner struct xfs_da_args *args = attr->xattri_da_args;
447fdaf1bb3SDave Chinner bool do_replace = args->op_flags & XFS_DA_OP_REPLACE;
448411b434aSDave Chinner
449fdaf1bb3SDave Chinner args->op_flags &= ~XFS_DA_OP_REPLACE;
450fdaf1bb3SDave Chinner args->attr_filter &= ~XFS_ATTR_INCOMPLETE;
4519efd8426SAndrey Albershteyn if (do_replace)
452fdaf1bb3SDave Chinner return replace_state;
4539efd8426SAndrey Albershteyn
454fdaf1bb3SDave Chinner return XFS_DAS_DONE;
455411b434aSDave Chinner }
456411b434aSDave Chinner
4573d58507dSChristoph Hellwig /*
4583d58507dSChristoph Hellwig * Try to add an attribute to an inode in leaf form.
4593d58507dSChristoph Hellwig */
460e0c41089SDave Chinner static int
xfs_attr_leaf_addname(struct xfs_attr_intent * attr)461cd1549d6SAllison Henderson xfs_attr_leaf_addname(
462e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr)
463cd1549d6SAllison Henderson {
464cd1549d6SAllison Henderson struct xfs_da_args *args = attr->xattri_da_args;
4653d58507dSChristoph Hellwig struct xfs_buf *bp;
466cd1549d6SAllison Henderson int error;
467cd1549d6SAllison Henderson
468e0c41089SDave Chinner ASSERT(xfs_attr_is_leaf(args->dp));
469e22b88deSDave Chinner
4703d58507dSChristoph Hellwig error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
471cd1549d6SAllison Henderson if (error)
472cd1549d6SAllison Henderson return error;
473cd1549d6SAllison Henderson
474cd1549d6SAllison Henderson /*
4753d58507dSChristoph Hellwig * Look up the xattr name to set the insertion point for the new xattr.
476cd1549d6SAllison Henderson */
4773d58507dSChristoph Hellwig error = xfs_attr3_leaf_lookup_int(bp, args);
4783d58507dSChristoph Hellwig switch (error) {
4793d58507dSChristoph Hellwig case -ENOATTR:
4803d58507dSChristoph Hellwig if (args->op_flags & XFS_DA_OP_REPLACE)
4813d58507dSChristoph Hellwig goto out_brelse;
4823d58507dSChristoph Hellwig break;
4833d58507dSChristoph Hellwig case -EEXIST:
4843d58507dSChristoph Hellwig if (!(args->op_flags & XFS_DA_OP_REPLACE))
4853d58507dSChristoph Hellwig goto out_brelse;
4863d58507dSChristoph Hellwig
4873d58507dSChristoph Hellwig trace_xfs_attr_leaf_replace(args);
4883d58507dSChristoph Hellwig /*
4893d58507dSChristoph Hellwig * Save the existing remote attr state so that the current
4903d58507dSChristoph Hellwig * values reflect the state of the new attribute we are about to
4913d58507dSChristoph Hellwig * add, not the attribute we just found and will remove later.
4923d58507dSChristoph Hellwig */
4933d58507dSChristoph Hellwig xfs_attr_save_rmt_blk(args);
4943d58507dSChristoph Hellwig break;
4953d58507dSChristoph Hellwig case 0:
4963d58507dSChristoph Hellwig break;
4973d58507dSChristoph Hellwig default:
4983d58507dSChristoph Hellwig goto out_brelse;
499cd1549d6SAllison Henderson }
500cd1549d6SAllison Henderson
501cd1549d6SAllison Henderson /*
502a4b8917bSDave Chinner * We need to commit and roll if we need to allocate remote xattr blocks
503a4b8917bSDave Chinner * or perform more xattr manipulations. Otherwise there is nothing more
504a4b8917bSDave Chinner * to do and we can return success.
505cd1549d6SAllison Henderson */
506702e1ac4SChristoph Hellwig if (!xfs_attr3_leaf_add(bp, args)) {
5073d58507dSChristoph Hellwig error = xfs_attr3_leaf_to_node(args);
5083d58507dSChristoph Hellwig if (error)
5093d58507dSChristoph Hellwig return error;
5103d58507dSChristoph Hellwig
5113d58507dSChristoph Hellwig attr->xattri_dela_state = XFS_DAS_NODE_ADD;
5123d58507dSChristoph Hellwig } else if (args->rmtblkno) {
5137d035336SDave Chinner attr->xattri_dela_state = XFS_DAS_LEAF_SET_RMT;
5143d58507dSChristoph Hellwig } else {
5153d58507dSChristoph Hellwig attr->xattri_dela_state =
5163d58507dSChristoph Hellwig xfs_attr_complete_op(attr, XFS_DAS_LEAF_REPLACE);
5173d58507dSChristoph Hellwig }
5183d58507dSChristoph Hellwig
519cd1549d6SAllison Henderson trace_xfs_attr_leaf_addname_return(attr->xattri_dela_state, args->dp);
520702e1ac4SChristoph Hellwig return 0;
5213d58507dSChristoph Hellwig
5223d58507dSChristoph Hellwig out_brelse:
5233d58507dSChristoph Hellwig xfs_trans_brelse(args->trans, bp);
5243d58507dSChristoph Hellwig return error;
525cd1549d6SAllison Henderson }
526cd1549d6SAllison Henderson
5274e3d96a5SDave Chinner /*
5284e3d96a5SDave Chinner * Add an entry to a node format attr tree.
5294e3d96a5SDave Chinner *
5304e3d96a5SDave Chinner * Note that we might still have a leaf here - xfs_attr_is_leaf() cannot tell
5314e3d96a5SDave Chinner * the difference between leaf + remote attr blocks and a node format tree,
5324e3d96a5SDave Chinner * so we may still end up having to convert from leaf to node format here.
5334e3d96a5SDave Chinner */
534e0c41089SDave Chinner static int
xfs_attr_node_addname(struct xfs_attr_intent * attr)535e0c41089SDave Chinner xfs_attr_node_addname(
536e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr)
537e0c41089SDave Chinner {
538e0c41089SDave Chinner struct xfs_da_args *args = attr->xattri_da_args;
539e0c41089SDave Chinner int error;
540e0c41089SDave Chinner
541e0c41089SDave Chinner error = xfs_attr_node_addname_find_attr(attr);
542e0c41089SDave Chinner if (error)
543e0c41089SDave Chinner return error;
544e0c41089SDave Chinner
545e0c41089SDave Chinner error = xfs_attr_node_try_addname(attr);
546*f37a5f0eSChristoph Hellwig if (error == 1) {
5474e3d96a5SDave Chinner error = xfs_attr3_leaf_to_node(args);
5484e3d96a5SDave Chinner if (error)
5494e3d96a5SDave Chinner return error;
5504e3d96a5SDave Chinner /*
5514e3d96a5SDave Chinner * No state change, we really are in node form now
5524e3d96a5SDave Chinner * but we need the transaction rolled to continue.
5534e3d96a5SDave Chinner */
5544e3d96a5SDave Chinner goto out;
5554e3d96a5SDave Chinner }
556e0c41089SDave Chinner if (error)
557e0c41089SDave Chinner return error;
558e0c41089SDave Chinner
5594e3d96a5SDave Chinner if (args->rmtblkno)
5607d035336SDave Chinner attr->xattri_dela_state = XFS_DAS_NODE_SET_RMT;
5614e3d96a5SDave Chinner else
562fdaf1bb3SDave Chinner attr->xattri_dela_state = xfs_attr_complete_op(attr,
563fdaf1bb3SDave Chinner XFS_DAS_NODE_REPLACE);
5644e3d96a5SDave Chinner out:
565e0c41089SDave Chinner trace_xfs_attr_node_addname_return(attr->xattri_dela_state, args->dp);
566e0c41089SDave Chinner return error;
567e0c41089SDave Chinner }
568e0c41089SDave Chinner
5697d035336SDave Chinner static int
xfs_attr_rmtval_alloc(struct xfs_attr_intent * attr)5707d035336SDave Chinner xfs_attr_rmtval_alloc(
571e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr)
5727d035336SDave Chinner {
5737d035336SDave Chinner struct xfs_da_args *args = attr->xattri_da_args;
5747d035336SDave Chinner int error = 0;
5757d035336SDave Chinner
5767d035336SDave Chinner /*
5777d035336SDave Chinner * If there was an out-of-line value, allocate the blocks we
5787d035336SDave Chinner * identified for its storage and copy the value. This is done
5797d035336SDave Chinner * after we create the attribute so that we don't overflow the
5807d035336SDave Chinner * maximum size of a transaction and/or hit a deadlock.
5817d035336SDave Chinner */
5827d035336SDave Chinner if (attr->xattri_blkcnt > 0) {
5837d035336SDave Chinner error = xfs_attr_rmtval_set_blk(attr);
5847d035336SDave Chinner if (error)
5857d035336SDave Chinner return error;
586411b434aSDave Chinner /* Roll the transaction only if there is more to allocate. */
5874e3d96a5SDave Chinner if (attr->xattri_blkcnt > 0)
5887d035336SDave Chinner goto out;
5897d035336SDave Chinner }
5907d035336SDave Chinner
5917d035336SDave Chinner error = xfs_attr_rmtval_set_value(args);
5927d035336SDave Chinner if (error)
5937d035336SDave Chinner return error;
5947d035336SDave Chinner
595fdaf1bb3SDave Chinner attr->xattri_dela_state = xfs_attr_complete_op(attr,
596fdaf1bb3SDave Chinner ++attr->xattri_dela_state);
597411b434aSDave Chinner /*
598fdaf1bb3SDave Chinner * If we are not doing a rename, we've finished the operation but still
599fdaf1bb3SDave Chinner * have to clear the incomplete flag protecting the new attr from
600fdaf1bb3SDave Chinner * exposing partially initialised state if we crash during creation.
601411b434aSDave Chinner */
602fdaf1bb3SDave Chinner if (attr->xattri_dela_state == XFS_DAS_DONE)
603fdaf1bb3SDave Chinner error = xfs_attr3_leaf_clearflag(args);
6047d035336SDave Chinner out:
6057d035336SDave Chinner trace_xfs_attr_rmtval_alloc(attr->xattri_dela_state, args->dp);
6067d035336SDave Chinner return error;
6077d035336SDave Chinner }
608e0c41089SDave Chinner
609db1a28ccSAllison Collins /*
610e5d5596aSDave Chinner * Mark an attribute entry INCOMPLETE and save pointers to the relevant buffers
611e5d5596aSDave Chinner * for later deletion of the entry.
612e5d5596aSDave Chinner */
613e5d5596aSDave Chinner static int
xfs_attr_leaf_mark_incomplete(struct xfs_da_args * args,struct xfs_da_state * state)614e5d5596aSDave Chinner xfs_attr_leaf_mark_incomplete(
615e5d5596aSDave Chinner struct xfs_da_args *args,
616e5d5596aSDave Chinner struct xfs_da_state *state)
617e5d5596aSDave Chinner {
618e5d5596aSDave Chinner int error;
619e5d5596aSDave Chinner
620e5d5596aSDave Chinner /*
621e5d5596aSDave Chinner * Fill in disk block numbers in the state structure
622e5d5596aSDave Chinner * so that we can get the buffers back after we commit
623e5d5596aSDave Chinner * several transactions in the following calls.
624e5d5596aSDave Chinner */
625e5d5596aSDave Chinner error = xfs_attr_fillstate(state);
626e5d5596aSDave Chinner if (error)
627e5d5596aSDave Chinner return error;
628e5d5596aSDave Chinner
629e5d5596aSDave Chinner /*
630e5d5596aSDave Chinner * Mark the attribute as INCOMPLETE
631e5d5596aSDave Chinner */
632e5d5596aSDave Chinner return xfs_attr3_leaf_setflag(args);
633e5d5596aSDave Chinner }
634e5d5596aSDave Chinner
6354d0cdd2bSDarrick J. Wong /* Ensure the da state of an xattr deferred work item is ready to go. */
6364d0cdd2bSDarrick J. Wong static inline void
xfs_attr_item_init_da_state(struct xfs_attr_intent * attr)6374d0cdd2bSDarrick J. Wong xfs_attr_item_init_da_state(
638e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr)
6394d0cdd2bSDarrick J. Wong {
6404d0cdd2bSDarrick J. Wong struct xfs_da_args *args = attr->xattri_da_args;
6414d0cdd2bSDarrick J. Wong
6424d0cdd2bSDarrick J. Wong if (!attr->xattri_da_state)
6434d0cdd2bSDarrick J. Wong attr->xattri_da_state = xfs_da_state_alloc(args);
6444d0cdd2bSDarrick J. Wong else
6454d0cdd2bSDarrick J. Wong xfs_da_state_reset(attr->xattri_da_state, args);
6464d0cdd2bSDarrick J. Wong }
6474d0cdd2bSDarrick J. Wong
648e5d5596aSDave Chinner /*
649e5d5596aSDave Chinner * Initial setup for xfs_attr_node_removename. Make sure the attr is there and
650e5d5596aSDave Chinner * the blocks are valid. Attr keys with remote blocks will be marked
651e5d5596aSDave Chinner * incomplete.
652e5d5596aSDave Chinner */
653e5d5596aSDave Chinner static
xfs_attr_node_removename_setup(struct xfs_attr_intent * attr)654e5d5596aSDave Chinner int xfs_attr_node_removename_setup(
655e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr)
656e5d5596aSDave Chinner {
657e5d5596aSDave Chinner struct xfs_da_args *args = attr->xattri_da_args;
658309001c2SDarrick J. Wong struct xfs_da_state *state;
659e5d5596aSDave Chinner int error;
660e5d5596aSDave Chinner
6614d0cdd2bSDarrick J. Wong xfs_attr_item_init_da_state(attr);
6624d0cdd2bSDarrick J. Wong error = xfs_attr_node_lookup(args, attr->xattri_da_state);
663e5d5596aSDave Chinner if (error != -EEXIST)
664e5d5596aSDave Chinner goto out;
665e5d5596aSDave Chinner error = 0;
666e5d5596aSDave Chinner
667309001c2SDarrick J. Wong state = attr->xattri_da_state;
668309001c2SDarrick J. Wong ASSERT(state->path.blk[state->path.active - 1].bp != NULL);
669309001c2SDarrick J. Wong ASSERT(state->path.blk[state->path.active - 1].magic ==
670e5d5596aSDave Chinner XFS_ATTR_LEAF_MAGIC);
671e5d5596aSDave Chinner
672309001c2SDarrick J. Wong error = xfs_attr_leaf_mark_incomplete(args, state);
673e5d5596aSDave Chinner if (error)
674e5d5596aSDave Chinner goto out;
6754b9879b1SDave Chinner if (args->rmtblkno > 0)
676e5d5596aSDave Chinner error = xfs_attr_rmtval_invalidate(args);
677e5d5596aSDave Chinner out:
678309001c2SDarrick J. Wong if (error) {
679309001c2SDarrick J. Wong xfs_da_state_free(attr->xattri_da_state);
680309001c2SDarrick J. Wong attr->xattri_da_state = NULL;
681309001c2SDarrick J. Wong }
682e5d5596aSDave Chinner
683e5d5596aSDave Chinner return error;
684e5d5596aSDave Chinner }
685e5d5596aSDave Chinner
686e5d5596aSDave Chinner /*
687b11fa61bSDave Chinner * Remove the original attr we have just replaced. This is dependent on the
688b11fa61bSDave Chinner * original lookup and insert placing the old attr in args->blkno/args->index
689b11fa61bSDave Chinner * and the new attr in args->blkno2/args->index2.
690b11fa61bSDave Chinner */
691b11fa61bSDave Chinner static int
xfs_attr_leaf_remove_attr(struct xfs_attr_intent * attr)692b11fa61bSDave Chinner xfs_attr_leaf_remove_attr(
693e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr)
694b11fa61bSDave Chinner {
695b11fa61bSDave Chinner struct xfs_da_args *args = attr->xattri_da_args;
696b11fa61bSDave Chinner struct xfs_inode *dp = args->dp;
697b11fa61bSDave Chinner struct xfs_buf *bp = NULL;
698b11fa61bSDave Chinner int forkoff;
699b11fa61bSDave Chinner int error;
700b11fa61bSDave Chinner
701b11fa61bSDave Chinner error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
702b11fa61bSDave Chinner &bp);
703b11fa61bSDave Chinner if (error)
704b11fa61bSDave Chinner return error;
705b11fa61bSDave Chinner
706b11fa61bSDave Chinner xfs_attr3_leaf_remove(bp, args);
707b11fa61bSDave Chinner
708b11fa61bSDave Chinner forkoff = xfs_attr_shortform_allfit(bp, dp);
709b11fa61bSDave Chinner if (forkoff)
710b11fa61bSDave Chinner error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
711b11fa61bSDave Chinner /* bp is gone due to xfs_da_shrink_inode */
712b11fa61bSDave Chinner
713b11fa61bSDave Chinner return error;
714b11fa61bSDave Chinner }
715b11fa61bSDave Chinner
716b11fa61bSDave Chinner /*
717b11fa61bSDave Chinner * Shrink an attribute from leaf to shortform. Used by the node format remove
718b11fa61bSDave Chinner * path when the node format collapses to a single block and so we have to check
719b11fa61bSDave Chinner * if it can be collapsed further.
720b11fa61bSDave Chinner */
721b11fa61bSDave Chinner static int
xfs_attr_leaf_shrink(struct xfs_da_args * args)722b11fa61bSDave Chinner xfs_attr_leaf_shrink(
72359782a23SDave Chinner struct xfs_da_args *args)
724b11fa61bSDave Chinner {
725b11fa61bSDave Chinner struct xfs_inode *dp = args->dp;
726b11fa61bSDave Chinner struct xfs_buf *bp;
72759782a23SDave Chinner int forkoff;
72859782a23SDave Chinner int error;
729b11fa61bSDave Chinner
730b11fa61bSDave Chinner if (!xfs_attr_is_leaf(dp))
731b11fa61bSDave Chinner return 0;
732b11fa61bSDave Chinner
733b11fa61bSDave Chinner error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
734b11fa61bSDave Chinner if (error)
735b11fa61bSDave Chinner return error;
736b11fa61bSDave Chinner
737b11fa61bSDave Chinner forkoff = xfs_attr_shortform_allfit(bp, dp);
738b11fa61bSDave Chinner if (forkoff) {
739b11fa61bSDave Chinner error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
740b11fa61bSDave Chinner /* bp is gone due to xfs_da_shrink_inode */
741b11fa61bSDave Chinner } else {
742b11fa61bSDave Chinner xfs_trans_brelse(args->trans, bp);
743b11fa61bSDave Chinner }
744b11fa61bSDave Chinner
745b11fa61bSDave Chinner return error;
746b11fa61bSDave Chinner }
747b11fa61bSDave Chinner
748b11fa61bSDave Chinner /*
7494e3d96a5SDave Chinner * Run the attribute operation specified in @attr.
7504e3d96a5SDave Chinner *
7514e3d96a5SDave Chinner * This routine is meant to function as a delayed operation and will set the
7524e3d96a5SDave Chinner * state to XFS_DAS_DONE when the operation is complete. Calling functions will
7534e3d96a5SDave Chinner * need to handle this, and recall the function until either an error or
7544e3d96a5SDave Chinner * XFS_DAS_DONE is detected.
755db1a28ccSAllison Collins */
756db1a28ccSAllison Collins int
xfs_attr_set_iter(struct xfs_attr_intent * attr)7578f502a40SAllison Henderson xfs_attr_set_iter(
758e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr)
759db1a28ccSAllison Collins {
760d68c51e9SAllison Henderson struct xfs_da_args *args = attr->xattri_da_args;
761b11fa61bSDave Chinner int error = 0;
762db1a28ccSAllison Collins
7638f502a40SAllison Henderson /* State machine switch */
764251b29c8SDave Chinner next_state:
765d68c51e9SAllison Henderson switch (attr->xattri_dela_state) {
7668f502a40SAllison Henderson case XFS_DAS_UNINIT:
767e0c41089SDave Chinner ASSERT(0);
768e0c41089SDave Chinner return -EFSCORRUPTED;
769e0c41089SDave Chinner case XFS_DAS_SF_ADD:
770d68c51e9SAllison Henderson return xfs_attr_sf_addname(attr);
771e0c41089SDave Chinner case XFS_DAS_LEAF_ADD:
772cd1549d6SAllison Henderson return xfs_attr_leaf_addname(attr);
773e0c41089SDave Chinner case XFS_DAS_NODE_ADD:
774e0c41089SDave Chinner return xfs_attr_node_addname(attr);
7757c93d4a8SAllison Collins
776e5d5596aSDave Chinner case XFS_DAS_SF_REMOVE:
777fdaf1bb3SDave Chinner error = xfs_attr_sf_removename(args);
778fdaf1bb3SDave Chinner attr->xattri_dela_state = xfs_attr_complete_op(attr,
779fdaf1bb3SDave Chinner xfs_attr_init_add_state(args));
780fdaf1bb3SDave Chinner break;
781e5d5596aSDave Chinner case XFS_DAS_LEAF_REMOVE:
782fdaf1bb3SDave Chinner error = xfs_attr_leaf_removename(args);
783fdaf1bb3SDave Chinner attr->xattri_dela_state = xfs_attr_complete_op(attr,
784fdaf1bb3SDave Chinner xfs_attr_init_add_state(args));
785fdaf1bb3SDave Chinner break;
786e5d5596aSDave Chinner case XFS_DAS_NODE_REMOVE:
787e5d5596aSDave Chinner error = xfs_attr_node_removename_setup(attr);
788fdaf1bb3SDave Chinner if (error == -ENOATTR &&
789fdaf1bb3SDave Chinner (args->op_flags & XFS_DA_OP_RECOVERY)) {
790fdaf1bb3SDave Chinner attr->xattri_dela_state = xfs_attr_complete_op(attr,
791fdaf1bb3SDave Chinner xfs_attr_init_add_state(args));
792fdaf1bb3SDave Chinner error = 0;
793fdaf1bb3SDave Chinner break;
794fdaf1bb3SDave Chinner }
795e5d5596aSDave Chinner if (error)
796e5d5596aSDave Chinner return error;
797e5d5596aSDave Chinner attr->xattri_dela_state = XFS_DAS_NODE_REMOVE_RMT;
798e5d5596aSDave Chinner if (args->rmtblkno == 0)
799e5d5596aSDave Chinner attr->xattri_dela_state++;
800e5d5596aSDave Chinner break;
801e5d5596aSDave Chinner
8027d035336SDave Chinner case XFS_DAS_LEAF_SET_RMT:
8037d035336SDave Chinner case XFS_DAS_NODE_SET_RMT:
804d68c51e9SAllison Henderson error = xfs_attr_rmtval_find_space(attr);
80583c6e707SAllison Henderson if (error)
80683c6e707SAllison Henderson return error;
807251b29c8SDave Chinner attr->xattri_dela_state++;
8082157d169SDave Chinner fallthrough;
8097d035336SDave Chinner
8102157d169SDave Chinner case XFS_DAS_LEAF_ALLOC_RMT:
811251b29c8SDave Chinner case XFS_DAS_NODE_ALLOC_RMT:
8127d035336SDave Chinner error = xfs_attr_rmtval_alloc(attr);
8138f502a40SAllison Henderson if (error)
8148f502a40SAllison Henderson return error;
8157d035336SDave Chinner if (attr->xattri_dela_state == XFS_DAS_DONE)
8167d035336SDave Chinner break;
817411b434aSDave Chinner goto next_state;
8188f502a40SAllison Henderson
8197d035336SDave Chinner case XFS_DAS_LEAF_REPLACE:
8207d035336SDave Chinner case XFS_DAS_NODE_REPLACE:
82183c6e707SAllison Henderson /*
822411b434aSDave Chinner * We must "flip" the incomplete flags on the "new" and "old"
823411b434aSDave Chinner * attribute/value pairs so that one disappears and one appears
8242e7ef218SDave Chinner * atomically.
82583c6e707SAllison Henderson */
82683c6e707SAllison Henderson error = xfs_attr3_leaf_flipflags(args);
82783c6e707SAllison Henderson if (error)
82883c6e707SAllison Henderson return error;
82983c6e707SAllison Henderson /*
8302e7ef218SDave Chinner * We must commit the flag value change now to make it atomic
8312e7ef218SDave Chinner * and then we can start the next trans in series at REMOVE_OLD.
83283c6e707SAllison Henderson */
833251b29c8SDave Chinner attr->xattri_dela_state++;
8347d035336SDave Chinner break;
835f38dc503SAllison Henderson
836411b434aSDave Chinner case XFS_DAS_LEAF_REMOVE_OLD:
837411b434aSDave Chinner case XFS_DAS_NODE_REMOVE_OLD:
83883c6e707SAllison Henderson /*
8392e7ef218SDave Chinner * If we have a remote attr, start the process of removing it
8402e7ef218SDave Chinner * by invalidating any cached buffers.
8412e7ef218SDave Chinner *
8422e7ef218SDave Chinner * If we don't have a remote attr, we skip the remote block
8432e7ef218SDave Chinner * removal state altogether with a second state increment.
84483c6e707SAllison Henderson */
84583c6e707SAllison Henderson xfs_attr_restore_rmt_blk(args);
8462e7ef218SDave Chinner if (args->rmtblkno) {
84783c6e707SAllison Henderson error = xfs_attr_rmtval_invalidate(args);
84883c6e707SAllison Henderson if (error)
84983c6e707SAllison Henderson return error;
8502e7ef218SDave Chinner } else {
8512e7ef218SDave Chinner attr->xattri_dela_state++;
8522e7ef218SDave Chinner }
85383c6e707SAllison Henderson
854251b29c8SDave Chinner attr->xattri_dela_state++;
8552e7ef218SDave Chinner goto next_state;
8562e7ef218SDave Chinner
8572e7ef218SDave Chinner case XFS_DAS_LEAF_REMOVE_RMT:
8582e7ef218SDave Chinner case XFS_DAS_NODE_REMOVE_RMT:
859d68c51e9SAllison Henderson error = xfs_attr_rmtval_remove(attr);
8604e3d96a5SDave Chinner if (error == -EAGAIN) {
8614e3d96a5SDave Chinner error = 0;
8622e7ef218SDave Chinner break;
8634e3d96a5SDave Chinner }
86483c6e707SAllison Henderson if (error)
86583c6e707SAllison Henderson return error;
8668f502a40SAllison Henderson
867251b29c8SDave Chinner /*
8682e7ef218SDave Chinner * We've finished removing the remote attr blocks, so commit the
8692e7ef218SDave Chinner * transaction and move on to removing the attr name from the
8702e7ef218SDave Chinner * leaf/node block. Removing the attr might require a full
8712e7ef218SDave Chinner * transaction reservation for btree block freeing, so we
8722e7ef218SDave Chinner * can't do that in the same transaction where we removed the
8732e7ef218SDave Chinner * remote attr blocks.
874251b29c8SDave Chinner */
875251b29c8SDave Chinner attr->xattri_dela_state++;
8762e7ef218SDave Chinner break;
877251b29c8SDave Chinner
878b11fa61bSDave Chinner case XFS_DAS_LEAF_REMOVE_ATTR:
879b11fa61bSDave Chinner error = xfs_attr_leaf_remove_attr(attr);
880fdaf1bb3SDave Chinner attr->xattri_dela_state = xfs_attr_complete_op(attr,
881fdaf1bb3SDave Chinner xfs_attr_init_add_state(args));
882b11fa61bSDave Chinner break;
88383c6e707SAllison Henderson
884b11fa61bSDave Chinner case XFS_DAS_NODE_REMOVE_ATTR:
885b11fa61bSDave Chinner error = xfs_attr_node_remove_attr(attr);
886b11fa61bSDave Chinner if (!error)
88759782a23SDave Chinner error = xfs_attr_leaf_shrink(args);
888fdaf1bb3SDave Chinner attr->xattri_dela_state = xfs_attr_complete_op(attr,
889fdaf1bb3SDave Chinner xfs_attr_init_add_state(args));
8908f502a40SAllison Henderson break;
8918f502a40SAllison Henderson default:
8924a4957c1SAllison Henderson ASSERT(0);
8938f502a40SAllison Henderson break;
8948f502a40SAllison Henderson }
8957d035336SDave Chinner
8967d035336SDave Chinner trace_xfs_attr_set_iter_return(attr->xattri_dela_state, args->dp);
8976ca5a4a1SAllison Henderson return error;
8982f3cd809SAllison Henderson }
8992f3cd809SAllison Henderson
9008f502a40SAllison Henderson
901068f985aSAllison Henderson /*
90207120f1aSAllison Collins * Return EEXIST if attr is found, or ENOATTR if not
90307120f1aSAllison Collins */
90451b495ebSDave Chinner static int
xfs_attr_lookup(struct xfs_da_args * args)90551b495ebSDave Chinner xfs_attr_lookup(
90607120f1aSAllison Collins struct xfs_da_args *args)
90707120f1aSAllison Collins {
90807120f1aSAllison Collins struct xfs_inode *dp = args->dp;
90907120f1aSAllison Collins struct xfs_buf *bp = NULL;
9104d0cdd2bSDarrick J. Wong struct xfs_da_state *state;
91107120f1aSAllison Collins int error;
91207120f1aSAllison Collins
91307120f1aSAllison Collins if (!xfs_inode_hasattr(dp))
91407120f1aSAllison Collins return -ENOATTR;
91507120f1aSAllison Collins
9162ed5b09bSDarrick J. Wong if (dp->i_af.if_format == XFS_DINODE_FMT_LOCAL)
91707120f1aSAllison Collins return xfs_attr_sf_findname(args, NULL, NULL);
91807120f1aSAllison Collins
9192ac131dfSChristoph Hellwig if (xfs_attr_is_leaf(dp)) {
92007120f1aSAllison Collins error = xfs_attr_leaf_hasname(args, &bp);
92107120f1aSAllison Collins
92207120f1aSAllison Collins if (bp)
92307120f1aSAllison Collins xfs_trans_brelse(args->trans, bp);
92407120f1aSAllison Collins
92507120f1aSAllison Collins return error;
92607120f1aSAllison Collins }
92707120f1aSAllison Collins
9284d0cdd2bSDarrick J. Wong state = xfs_da_state_alloc(args);
9294d0cdd2bSDarrick J. Wong error = xfs_attr_node_lookup(args, state);
9304d0cdd2bSDarrick J. Wong xfs_da_state_free(state);
9314d0cdd2bSDarrick J. Wong return error;
93207120f1aSAllison Collins }
93307120f1aSAllison Collins
934709c8632SDave Chinner static int
xfs_attr_intent_init(struct xfs_da_args * args,unsigned int op_flags,struct xfs_attr_intent ** attr)935e3c5de22SDarrick J. Wong xfs_attr_intent_init(
936709c8632SDave Chinner struct xfs_da_args *args,
937709c8632SDave Chinner unsigned int op_flags, /* op flag (set or remove) */
938e3c5de22SDarrick J. Wong struct xfs_attr_intent **attr) /* new xfs_attr_intent */
939709c8632SDave Chinner {
940709c8632SDave Chinner
941e3c5de22SDarrick J. Wong struct xfs_attr_intent *new;
942709c8632SDave Chinner
943e2c78949SDarrick J. Wong new = kmem_cache_zalloc(xfs_attr_intent_cache, GFP_NOFS | __GFP_NOFAIL);
944709c8632SDave Chinner new->xattri_op_flags = op_flags;
945709c8632SDave Chinner new->xattri_da_args = args;
946709c8632SDave Chinner
947709c8632SDave Chinner *attr = new;
948709c8632SDave Chinner return 0;
949709c8632SDave Chinner }
950709c8632SDave Chinner
951709c8632SDave Chinner /* Sets an attribute for an inode as a deferred operation */
952709c8632SDave Chinner static int
xfs_attr_defer_add(struct xfs_da_args * args)953709c8632SDave Chinner xfs_attr_defer_add(
954709c8632SDave Chinner struct xfs_da_args *args)
955709c8632SDave Chinner {
956e3c5de22SDarrick J. Wong struct xfs_attr_intent *new;
957709c8632SDave Chinner int error = 0;
958709c8632SDave Chinner
959e3c5de22SDarrick J. Wong error = xfs_attr_intent_init(args, XFS_ATTRI_OP_FLAGS_SET, &new);
960709c8632SDave Chinner if (error)
961709c8632SDave Chinner return error;
962709c8632SDave Chinner
963e0c41089SDave Chinner new->xattri_dela_state = xfs_attr_init_add_state(args);
964709c8632SDave Chinner xfs_defer_add(args->trans, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
965709c8632SDave Chinner trace_xfs_attr_defer_add(new->xattri_dela_state, args->dp);
966709c8632SDave Chinner
967709c8632SDave Chinner return 0;
968709c8632SDave Chinner }
969709c8632SDave Chinner
970709c8632SDave Chinner /* Sets an attribute for an inode as a deferred operation */
971709c8632SDave Chinner static int
xfs_attr_defer_replace(struct xfs_da_args * args)972709c8632SDave Chinner xfs_attr_defer_replace(
973709c8632SDave Chinner struct xfs_da_args *args)
974709c8632SDave Chinner {
975e3c5de22SDarrick J. Wong struct xfs_attr_intent *new;
976709c8632SDave Chinner int error = 0;
977709c8632SDave Chinner
978e3c5de22SDarrick J. Wong error = xfs_attr_intent_init(args, XFS_ATTRI_OP_FLAGS_REPLACE, &new);
979709c8632SDave Chinner if (error)
980709c8632SDave Chinner return error;
981709c8632SDave Chinner
982e0c41089SDave Chinner new->xattri_dela_state = xfs_attr_init_replace_state(args);
983709c8632SDave Chinner xfs_defer_add(args->trans, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
984709c8632SDave Chinner trace_xfs_attr_defer_replace(new->xattri_dela_state, args->dp);
985709c8632SDave Chinner
986709c8632SDave Chinner return 0;
987709c8632SDave Chinner }
988709c8632SDave Chinner
989709c8632SDave Chinner /* Removes an attribute for an inode as a deferred operation */
990709c8632SDave Chinner static int
xfs_attr_defer_remove(struct xfs_da_args * args)991709c8632SDave Chinner xfs_attr_defer_remove(
992709c8632SDave Chinner struct xfs_da_args *args)
993709c8632SDave Chinner {
994709c8632SDave Chinner
995e3c5de22SDarrick J. Wong struct xfs_attr_intent *new;
996709c8632SDave Chinner int error;
997709c8632SDave Chinner
998e3c5de22SDarrick J. Wong error = xfs_attr_intent_init(args, XFS_ATTRI_OP_FLAGS_REMOVE, &new);
999709c8632SDave Chinner if (error)
1000709c8632SDave Chinner return error;
1001709c8632SDave Chinner
10024b9879b1SDave Chinner new->xattri_dela_state = xfs_attr_init_remove_state(args);
1003709c8632SDave Chinner xfs_defer_add(args->trans, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
1004709c8632SDave Chinner trace_xfs_attr_defer_remove(new->xattri_dela_state, args->dp);
1005709c8632SDave Chinner
1006709c8632SDave Chinner return 0;
1007709c8632SDave Chinner }
1008709c8632SDave Chinner
100907120f1aSAllison Collins /*
1010a2544622SChristoph Hellwig * Note: If args->value is NULL the attribute will be removed, just like the
10110eb81a5fSChristoph Hellwig * Linux ->setattr API.
10120eb81a5fSChristoph Hellwig */
101330f712c9SDave Chinner int
xfs_attr_set(struct xfs_da_args * args)101430f712c9SDave Chinner xfs_attr_set(
1015a2544622SChristoph Hellwig struct xfs_da_args *args)
101630f712c9SDave Chinner {
1017a2544622SChristoph Hellwig struct xfs_inode *dp = args->dp;
101830f712c9SDave Chinner struct xfs_mount *mp = dp->i_mount;
101930f712c9SDave Chinner struct xfs_trans_res tres;
1020d5f0f49aSChristoph Hellwig bool rsvd = (args->attr_filter & XFS_ATTR_ROOT);
10214c74a56bSAllison Henderson int error, local;
10223a19bb14SChandan Babu R int rmt_blks = 0;
10230eb81a5fSChristoph Hellwig unsigned int total;
102430f712c9SDave Chinner
102575c8c50fSDave Chinner if (xfs_is_shutdown(dp->i_mount))
10262451337dSDave Chinner return -EIO;
102730f712c9SDave Chinner
10280eb81a5fSChristoph Hellwig error = xfs_qm_dqattach(dp);
10290eb81a5fSChristoph Hellwig if (error)
10300eb81a5fSChristoph Hellwig return error;
10310eb81a5fSChristoph Hellwig
1032a2544622SChristoph Hellwig args->geo = mp->m_attr_geo;
1033a2544622SChristoph Hellwig args->whichfork = XFS_ATTR_FORK;
1034a2544622SChristoph Hellwig args->hashval = xfs_da_hashname(args->name, args->namelen);
103530f712c9SDave Chinner
10360eb81a5fSChristoph Hellwig /*
10370eb81a5fSChristoph Hellwig * We have no control over the attribute names that userspace passes us
10380eb81a5fSChristoph Hellwig * to remove, so we have to allow the name lookup prior to attribute
1039f4288f01SDarrick J. Wong * removal to fail as well. Preserve the logged flag, since we need
1040f4288f01SDarrick J. Wong * to pass that through to the logging code.
10410eb81a5fSChristoph Hellwig */
1042f4288f01SDarrick J. Wong args->op_flags = XFS_DA_OP_OKNOENT |
1043f4288f01SDarrick J. Wong (args->op_flags & XFS_DA_OP_LOGGED);
10440eb81a5fSChristoph Hellwig
1045a2544622SChristoph Hellwig if (args->value) {
10460eb81a5fSChristoph Hellwig XFS_STATS_INC(mp, xs_attr_set);
1047a2544622SChristoph Hellwig args->total = xfs_attr_calc_size(args, &local);
104830f712c9SDave Chinner
104930f712c9SDave Chinner /*
105030f712c9SDave Chinner * If the inode doesn't have an attribute fork, add one.
105130f712c9SDave Chinner * (inode must not be locked when we call this routine)
105230f712c9SDave Chinner */
1053932b42c6SDarrick J. Wong if (xfs_inode_has_attr_fork(dp) == 0) {
10540eb81a5fSChristoph Hellwig int sf_size = sizeof(struct xfs_attr_sf_hdr) +
1055e01b7eedSCarlos Maiolino xfs_attr_sf_entsize_byname(args->namelen,
1056a2544622SChristoph Hellwig args->valuelen);
105730f712c9SDave Chinner
105830f712c9SDave Chinner error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
105930f712c9SDave Chinner if (error)
106030f712c9SDave Chinner return error;
106130f712c9SDave Chinner }
106230f712c9SDave Chinner
10633a19bb14SChandan Babu R if (!local)
10643a19bb14SChandan Babu R rmt_blks = xfs_attr3_rmt_blocks(mp, args->valuelen);
10650eb81a5fSChristoph Hellwig } else {
10660eb81a5fSChristoph Hellwig XFS_STATS_INC(mp, xs_attr_remove);
10673a19bb14SChandan Babu R rmt_blks = xfs_attr3_rmt_blocks(mp, XFS_XATTR_SIZE_MAX);
10680eb81a5fSChristoph Hellwig }
106930f712c9SDave Chinner
107030f712c9SDave Chinner /*
107130f712c9SDave Chinner * Root fork attributes can use reserved data blocks for this
107230f712c9SDave Chinner * operation if necessary
107330f712c9SDave Chinner */
1074c3546cf5SAllison Henderson xfs_init_attr_trans(args, &tres, &total);
10753de4eb10SDarrick J. Wong error = xfs_trans_alloc_inode(dp, &tres, total, 0, rsvd, &args->trans);
1076253f4911SChristoph Hellwig if (error)
1077efc2efebSDarrick J. Wong return error;
107830f712c9SDave Chinner
10793a19bb14SChandan Babu R if (args->value || xfs_inode_hasattr(dp)) {
10803a19bb14SChandan Babu R error = xfs_iext_count_may_overflow(dp, XFS_ATTR_FORK,
10813a19bb14SChandan Babu R XFS_IEXT_ATTR_MANIP_CNT(rmt_blks));
10824f86bb4bSChandan Babu R if (error == -EFBIG)
10834f86bb4bSChandan Babu R error = xfs_iext_count_upgrade(args->trans, dp,
10844f86bb4bSChandan Babu R XFS_IEXT_ATTR_MANIP_CNT(rmt_blks));
10853a19bb14SChandan Babu R if (error)
10863a19bb14SChandan Babu R goto out_trans_cancel;
10873a19bb14SChandan Babu R }
10883a19bb14SChandan Babu R
108951b495ebSDave Chinner error = xfs_attr_lookup(args);
1090709c8632SDave Chinner switch (error) {
1091709c8632SDave Chinner case -EEXIST:
1092709c8632SDave Chinner /* if no value, we are performing a remove operation */
1093709c8632SDave Chinner if (!args->value) {
1094709c8632SDave Chinner error = xfs_attr_defer_remove(args);
1095709c8632SDave Chinner break;
1096709c8632SDave Chinner }
1097709c8632SDave Chinner /* Pure create fails if the attr already exists */
1098709c8632SDave Chinner if (args->attr_flags & XATTR_CREATE)
1099deed9512SAllison Collins goto out_trans_cancel;
1100deed9512SAllison Collins
1101709c8632SDave Chinner error = xfs_attr_defer_replace(args);
1102709c8632SDave Chinner break;
1103709c8632SDave Chinner case -ENOATTR:
1104709c8632SDave Chinner /* Can't remove what isn't there. */
1105709c8632SDave Chinner if (!args->value)
1106710d707dSDarrick J. Wong goto out_trans_cancel;
1107f3f36c89SAllison Henderson
1108709c8632SDave Chinner /* Pure replace fails if no existing attr to replace. */
1109709c8632SDave Chinner if (args->attr_flags & XATTR_REPLACE)
1110deed9512SAllison Collins goto out_trans_cancel;
1111deed9512SAllison Collins
1112709c8632SDave Chinner error = xfs_attr_defer_add(args);
1113709c8632SDave Chinner break;
1114709c8632SDave Chinner default:
11150eb81a5fSChristoph Hellwig goto out_trans_cancel;
111630f712c9SDave Chinner }
1117709c8632SDave Chinner if (error)
1118709c8632SDave Chinner goto out_trans_cancel;
111930f712c9SDave Chinner
112030f712c9SDave Chinner /*
112130f712c9SDave Chinner * If this is a synchronous mount, make sure that the
112230f712c9SDave Chinner * transaction goes to disk before returning to the user.
112330f712c9SDave Chinner */
11240560f31aSDave Chinner if (xfs_has_wsync(mp))
1125a2544622SChristoph Hellwig xfs_trans_set_sync(args->trans);
112630f712c9SDave Chinner
11271d733019SChristoph Hellwig if (!(args->op_flags & XFS_DA_OP_NOTIME))
1128a2544622SChristoph Hellwig xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
112930f712c9SDave Chinner
113030f712c9SDave Chinner /*
113130f712c9SDave Chinner * Commit the last in the sequence of transactions.
113230f712c9SDave Chinner */
1133a2544622SChristoph Hellwig xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
1134a2544622SChristoph Hellwig error = xfs_trans_commit(args->trans);
11352f3cd809SAllison Henderson out_unlock:
113630f712c9SDave Chinner xfs_iunlock(dp, XFS_ILOCK_EXCL);
113730f712c9SDave Chinner return error;
113830f712c9SDave Chinner
11392f3cd809SAllison Henderson out_trans_cancel:
1140a2544622SChristoph Hellwig if (args->trans)
1141a2544622SChristoph Hellwig xfs_trans_cancel(args->trans);
11422f3cd809SAllison Henderson goto out_unlock;
114330f712c9SDave Chinner }
114430f712c9SDave Chinner
114530f712c9SDave Chinner /*========================================================================
114630f712c9SDave Chinner * External routines when attribute list is inside the inode
114730f712c9SDave Chinner *========================================================================*/
114830f712c9SDave Chinner
xfs_attr_sf_totsize(struct xfs_inode * dp)1149e01b7eedSCarlos Maiolino static inline int xfs_attr_sf_totsize(struct xfs_inode *dp)
1150e01b7eedSCarlos Maiolino {
1151e01b7eedSCarlos Maiolino struct xfs_attr_shortform *sf;
1152e01b7eedSCarlos Maiolino
11532ed5b09bSDarrick J. Wong sf = (struct xfs_attr_shortform *)dp->i_af.if_u1.if_data;
1154e01b7eedSCarlos Maiolino return be16_to_cpu(sf->hdr.totsize);
1155e01b7eedSCarlos Maiolino }
1156e01b7eedSCarlos Maiolino
115730f712c9SDave Chinner /*
115830f712c9SDave Chinner * Add a name to the shortform attribute list structure
115930f712c9SDave Chinner * This is the external routine.
116030f712c9SDave Chinner */
1161e7f358deSDave Chinner static int
xfs_attr_shortform_addname(struct xfs_da_args * args)1162e7f358deSDave Chinner xfs_attr_shortform_addname(
1163e7f358deSDave Chinner struct xfs_da_args *args)
116430f712c9SDave Chinner {
1165e7f358deSDave Chinner int newsize, forkoff;
1166e7f358deSDave Chinner int error;
116730f712c9SDave Chinner
116830f712c9SDave Chinner trace_xfs_attr_sf_addname(args);
116930f712c9SDave Chinner
1170e7f358deSDave Chinner error = xfs_attr_shortform_lookup(args);
1171e7f358deSDave Chinner switch (error) {
1172e7f358deSDave Chinner case -ENOATTR:
1173e7f358deSDave Chinner if (args->op_flags & XFS_DA_OP_REPLACE)
1174e7f358deSDave Chinner return error;
1175e7f358deSDave Chinner break;
1176e7f358deSDave Chinner case -EEXIST:
1177e7f358deSDave Chinner if (!(args->op_flags & XFS_DA_OP_REPLACE))
1178e7f358deSDave Chinner return error;
1179e7f358deSDave Chinner
1180e7f358deSDave Chinner error = xfs_attr_sf_removename(args);
1181e7f358deSDave Chinner if (error)
1182e7f358deSDave Chinner return error;
1183e7f358deSDave Chinner
11847b38460dSDarrick J. Wong /*
1185e7f358deSDave Chinner * Since we have removed the old attr, clear XFS_DA_OP_REPLACE
1186e7f358deSDave Chinner * so that the new attr doesn't fit in shortform format, the
1187e7f358deSDave Chinner * leaf format add routine won't trip over the attr not being
1188e7f358deSDave Chinner * around.
11897b38460dSDarrick J. Wong */
1190e7f358deSDave Chinner args->op_flags &= ~XFS_DA_OP_REPLACE;
1191e7f358deSDave Chinner break;
1192e7f358deSDave Chinner case 0:
1193e7f358deSDave Chinner break;
1194e7f358deSDave Chinner default:
1195e7f358deSDave Chinner return error;
119630f712c9SDave Chinner }
119730f712c9SDave Chinner
119830f712c9SDave Chinner if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
119930f712c9SDave Chinner args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
12002451337dSDave Chinner return -ENOSPC;
120130f712c9SDave Chinner
1202e01b7eedSCarlos Maiolino newsize = xfs_attr_sf_totsize(args->dp);
1203e01b7eedSCarlos Maiolino newsize += xfs_attr_sf_entsize_byname(args->namelen, args->valuelen);
120430f712c9SDave Chinner
120530f712c9SDave Chinner forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
120630f712c9SDave Chinner if (!forkoff)
12072451337dSDave Chinner return -ENOSPC;
120830f712c9SDave Chinner
120930f712c9SDave Chinner xfs_attr_shortform_add(args, forkoff);
121030f712c9SDave Chinner return 0;
121130f712c9SDave Chinner }
121230f712c9SDave Chinner
121330f712c9SDave Chinner
121430f712c9SDave Chinner /*========================================================================
121530f712c9SDave Chinner * External routines when attribute list is one block
121630f712c9SDave Chinner *========================================================================*/
121730f712c9SDave Chinner
121830f712c9SDave Chinner /*
121907120f1aSAllison Collins * Return EEXIST if attr is found, or ENOATTR if not
122007120f1aSAllison Collins */
122107120f1aSAllison Collins STATIC int
xfs_attr_leaf_hasname(struct xfs_da_args * args,struct xfs_buf ** bp)122207120f1aSAllison Collins xfs_attr_leaf_hasname(
122307120f1aSAllison Collins struct xfs_da_args *args,
122407120f1aSAllison Collins struct xfs_buf **bp)
122507120f1aSAllison Collins {
122607120f1aSAllison Collins int error = 0;
122707120f1aSAllison Collins
122807120f1aSAllison Collins error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp);
122907120f1aSAllison Collins if (error)
123007120f1aSAllison Collins return error;
123107120f1aSAllison Collins
123207120f1aSAllison Collins error = xfs_attr3_leaf_lookup_int(*bp, args);
123307120f1aSAllison Collins if (error != -ENOATTR && error != -EEXIST)
123407120f1aSAllison Collins xfs_trans_brelse(args->trans, *bp);
123507120f1aSAllison Collins
123607120f1aSAllison Collins return error;
123707120f1aSAllison Collins }
123807120f1aSAllison Collins
123907120f1aSAllison Collins /*
124030f712c9SDave Chinner * Remove a name from the leaf attribute list structure
124130f712c9SDave Chinner *
124230f712c9SDave Chinner * This leaf block cannot have a "remote" value, we only call this routine
124330f712c9SDave Chinner * if bmap_one_block() says there is only one block (ie: no remote blks).
124430f712c9SDave Chinner */
124530f712c9SDave Chinner STATIC int
xfs_attr_leaf_removename(struct xfs_da_args * args)124632a9b7c6SBrian Foster xfs_attr_leaf_removename(
124732a9b7c6SBrian Foster struct xfs_da_args *args)
124830f712c9SDave Chinner {
124932a9b7c6SBrian Foster struct xfs_inode *dp;
125030f712c9SDave Chinner struct xfs_buf *bp;
1251f6106efaSEric Sandeen int error, forkoff;
125230f712c9SDave Chinner
125330f712c9SDave Chinner trace_xfs_attr_leaf_removename(args);
125430f712c9SDave Chinner
125530f712c9SDave Chinner /*
125630f712c9SDave Chinner * Remove the attribute.
125730f712c9SDave Chinner */
125830f712c9SDave Chinner dp = args->dp;
125930f712c9SDave Chinner
126007120f1aSAllison Collins error = xfs_attr_leaf_hasname(args, &bp);
12612451337dSDave Chinner if (error == -ENOATTR) {
126230f712c9SDave Chinner xfs_trans_brelse(args->trans, bp);
1263fdaf1bb3SDave Chinner if (args->op_flags & XFS_DA_OP_RECOVERY)
1264fdaf1bb3SDave Chinner return 0;
126530f712c9SDave Chinner return error;
126607120f1aSAllison Collins } else if (error != -EEXIST)
126707120f1aSAllison Collins return error;
126830f712c9SDave Chinner
126930f712c9SDave Chinner xfs_attr3_leaf_remove(bp, args);
127030f712c9SDave Chinner
127130f712c9SDave Chinner /*
127230f712c9SDave Chinner * If the result is small enough, shrink it all into the inode.
127330f712c9SDave Chinner */
12740feaef17SAllison Collins forkoff = xfs_attr_shortform_allfit(bp, dp);
12750feaef17SAllison Collins if (forkoff)
12760feaef17SAllison Collins return xfs_attr3_leaf_to_shortform(bp, args, forkoff);
127730f712c9SDave Chinner /* bp is gone due to xfs_da_shrink_inode */
12780feaef17SAllison Collins
127930f712c9SDave Chinner return 0;
128030f712c9SDave Chinner }
128130f712c9SDave Chinner
128230f712c9SDave Chinner /*
128330f712c9SDave Chinner * Look up a name in a leaf attribute list structure.
128430f712c9SDave Chinner *
128530f712c9SDave Chinner * This leaf block cannot have a "remote" value, we only call this routine
128630f712c9SDave Chinner * if bmap_one_block() says there is only one block (ie: no remote blks).
1287728bcaa3SDave Chinner *
1288728bcaa3SDave Chinner * Returns 0 on successful retrieval, otherwise an error.
128930f712c9SDave Chinner */
129030f712c9SDave Chinner STATIC int
xfs_attr_leaf_get(xfs_da_args_t * args)129130f712c9SDave Chinner xfs_attr_leaf_get(xfs_da_args_t *args)
129230f712c9SDave Chinner {
129330f712c9SDave Chinner struct xfs_buf *bp;
129430f712c9SDave Chinner int error;
129530f712c9SDave Chinner
129630f712c9SDave Chinner trace_xfs_attr_leaf_get(args);
129730f712c9SDave Chinner
129807120f1aSAllison Collins error = xfs_attr_leaf_hasname(args, &bp);
129930f712c9SDave Chinner
130007120f1aSAllison Collins if (error == -ENOATTR) {
130130f712c9SDave Chinner xfs_trans_brelse(args->trans, bp);
130230f712c9SDave Chinner return error;
130307120f1aSAllison Collins } else if (error != -EEXIST)
130407120f1aSAllison Collins return error;
130507120f1aSAllison Collins
130607120f1aSAllison Collins
130730f712c9SDave Chinner error = xfs_attr3_leaf_getvalue(bp, args);
130830f712c9SDave Chinner xfs_trans_brelse(args->trans, bp);
130930f712c9SDave Chinner return error;
131030f712c9SDave Chinner }
131130f712c9SDave Chinner
13124d0cdd2bSDarrick J. Wong /* Return EEXIST if attr is found, or ENOATTR if not. */
131307120f1aSAllison Collins STATIC int
xfs_attr_node_lookup(struct xfs_da_args * args,struct xfs_da_state * state)13144d0cdd2bSDarrick J. Wong xfs_attr_node_lookup(
131507120f1aSAllison Collins struct xfs_da_args *args,
13164d0cdd2bSDarrick J. Wong struct xfs_da_state *state)
131707120f1aSAllison Collins {
131807120f1aSAllison Collins int retval, error;
131907120f1aSAllison Collins
132007120f1aSAllison Collins /*
132107120f1aSAllison Collins * Search to see if name exists, and get back a pointer to it.
132207120f1aSAllison Collins */
132307120f1aSAllison Collins error = xfs_da3_node_lookup_int(state, &retval);
1324a1de97feSYang Xu if (error)
13254d0cdd2bSDarrick J. Wong return error;
1326a1de97feSYang Xu
132707120f1aSAllison Collins return retval;
132807120f1aSAllison Collins }
132907120f1aSAllison Collins
133030f712c9SDave Chinner /*========================================================================
133130f712c9SDave Chinner * External routines when attribute list size > geo->blksize
133230f712c9SDave Chinner *========================================================================*/
133330f712c9SDave Chinner
133430f712c9SDave Chinner STATIC int
xfs_attr_node_addname_find_attr(struct xfs_attr_intent * attr)13356ca5a4a1SAllison Henderson xfs_attr_node_addname_find_attr(
1336e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr)
133730f712c9SDave Chinner {
1338d68c51e9SAllison Henderson struct xfs_da_args *args = attr->xattri_da_args;
1339e7f358deSDave Chinner int error;
134030f712c9SDave Chinner
134130f712c9SDave Chinner /*
134230f712c9SDave Chinner * Search to see if name already exists, and get back a pointer
134330f712c9SDave Chinner * to where it should go.
134430f712c9SDave Chinner */
13454d0cdd2bSDarrick J. Wong xfs_attr_item_init_da_state(attr);
13464d0cdd2bSDarrick J. Wong error = xfs_attr_node_lookup(args, attr->xattri_da_state);
1347e7f358deSDave Chinner switch (error) {
1348e7f358deSDave Chinner case -ENOATTR:
1349e7f358deSDave Chinner if (args->op_flags & XFS_DA_OP_REPLACE)
1350e7f358deSDave Chinner goto error;
1351e7f358deSDave Chinner break;
1352e7f358deSDave Chinner case -EEXIST:
1353e7f358deSDave Chinner if (!(args->op_flags & XFS_DA_OP_REPLACE))
1354a1de97feSYang Xu goto error;
135507120f1aSAllison Collins
135630f712c9SDave Chinner
135730f712c9SDave Chinner trace_xfs_attr_node_replace(args);
135830f712c9SDave Chinner /*
1359e7f358deSDave Chinner * Save the existing remote attr state so that the current
1360e7f358deSDave Chinner * values reflect the state of the new attribute we are about to
136130f712c9SDave Chinner * add, not the attribute we just found and will remove later.
136230f712c9SDave Chinner */
1363e7f358deSDave Chinner xfs_attr_save_rmt_blk(args);
1364e7f358deSDave Chinner break;
1365e7f358deSDave Chinner case 0:
1366e7f358deSDave Chinner break;
1367e7f358deSDave Chinner default:
1368e7f358deSDave Chinner goto error;
136930f712c9SDave Chinner }
137030f712c9SDave Chinner
13716ca5a4a1SAllison Henderson return 0;
13726ca5a4a1SAllison Henderson error:
1373309001c2SDarrick J. Wong if (attr->xattri_da_state) {
1374d68c51e9SAllison Henderson xfs_da_state_free(attr->xattri_da_state);
1375309001c2SDarrick J. Wong attr->xattri_da_state = NULL;
1376309001c2SDarrick J. Wong }
1377e7f358deSDave Chinner return error;
13786ca5a4a1SAllison Henderson }
13796ca5a4a1SAllison Henderson
13806ca5a4a1SAllison Henderson /*
13816ca5a4a1SAllison Henderson * Add a name to a Btree-format attribute list.
13826ca5a4a1SAllison Henderson *
1383*f37a5f0eSChristoph Hellwig * This will involve walking down the Btree, and may involve splitting leaf
1384*f37a5f0eSChristoph Hellwig * nodes and even splitting intermediate nodes up to and including the root
1385*f37a5f0eSChristoph Hellwig * node (a special case of an intermediate node).
1386*f37a5f0eSChristoph Hellwig *
1387*f37a5f0eSChristoph Hellwig * If the tree was still in single leaf format and needs to converted to
1388*f37a5f0eSChristoph Hellwig * real node format return 1 and let the caller handle that.
13896ca5a4a1SAllison Henderson */
1390e0c41089SDave Chinner static int
xfs_attr_node_try_addname(struct xfs_attr_intent * attr)1391e0c41089SDave Chinner xfs_attr_node_try_addname(
1392e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr)
13936ca5a4a1SAllison Henderson {
1394d68c51e9SAllison Henderson struct xfs_da_state *state = attr->xattri_da_state;
13956ca5a4a1SAllison Henderson struct xfs_da_state_blk *blk;
1396702e1ac4SChristoph Hellwig int error = 0;
13976ca5a4a1SAllison Henderson
139810930b25SDarrick J. Wong trace_xfs_attr_node_addname(state->args);
13996ca5a4a1SAllison Henderson
14006ca5a4a1SAllison Henderson blk = &state->path.blk[state->path.active-1];
14016ca5a4a1SAllison Henderson ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
14026ca5a4a1SAllison Henderson
1403702e1ac4SChristoph Hellwig if (!xfs_attr3_leaf_add(blk->bp, state->args)) {
140430f712c9SDave Chinner if (state->path.active == 1) {
140530f712c9SDave Chinner /*
140630f712c9SDave Chinner * Its really a single leaf node, but it had
140730f712c9SDave Chinner * out-of-line values so it looked like it *might*
14084e3d96a5SDave Chinner * have been a b-tree. Let the caller deal with this.
140930f712c9SDave Chinner */
1410*f37a5f0eSChristoph Hellwig error = 1;
1411d5a2e289SBrian Foster goto out;
141230f712c9SDave Chinner }
141330f712c9SDave Chinner
141430f712c9SDave Chinner /*
141530f712c9SDave Chinner * Split as many Btree elements as required.
141630f712c9SDave Chinner * This code tracks the new and old attr's location
141730f712c9SDave Chinner * in the index/blkno/rmtblkno/rmtblkcnt fields and
141830f712c9SDave Chinner * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
141930f712c9SDave Chinner */
142030f712c9SDave Chinner error = xfs_da3_split(state);
14218ad7c629SChristoph Hellwig if (error)
1422d5a2e289SBrian Foster goto out;
142330f712c9SDave Chinner } else {
142430f712c9SDave Chinner /*
142530f712c9SDave Chinner * Addition succeeded, update Btree hashvals.
142630f712c9SDave Chinner */
142730f712c9SDave Chinner xfs_da3_fixhashpath(state, &state->path);
142830f712c9SDave Chinner }
142930f712c9SDave Chinner
1430f0f7c502SAllison Henderson out:
1431f0f7c502SAllison Henderson xfs_da_state_free(state);
1432309001c2SDarrick J. Wong attr->xattri_da_state = NULL;
1433f0f7c502SAllison Henderson return error;
1434f0f7c502SAllison Henderson }
1435f0f7c502SAllison Henderson
143659782a23SDave Chinner static int
xfs_attr_node_removename(struct xfs_da_args * args,struct xfs_da_state * state)143759782a23SDave Chinner xfs_attr_node_removename(
143859782a23SDave Chinner struct xfs_da_args *args,
143959782a23SDave Chinner struct xfs_da_state *state)
144059782a23SDave Chinner {
144159782a23SDave Chinner struct xfs_da_state_blk *blk;
144259782a23SDave Chinner int retval;
144359782a23SDave Chinner
144459782a23SDave Chinner /*
144559782a23SDave Chinner * Remove the name and update the hashvals in the tree.
144659782a23SDave Chinner */
144759782a23SDave Chinner blk = &state->path.blk[state->path.active-1];
144859782a23SDave Chinner ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
144959782a23SDave Chinner retval = xfs_attr3_leaf_remove(blk->bp, args);
145059782a23SDave Chinner xfs_da3_fixhashpath(state, &state->path);
145159782a23SDave Chinner
145259782a23SDave Chinner return retval;
145359782a23SDave Chinner }
1454f0f7c502SAllison Henderson
1455b11fa61bSDave Chinner static int
xfs_attr_node_remove_attr(struct xfs_attr_intent * attr)1456b11fa61bSDave Chinner xfs_attr_node_remove_attr(
1457e3c5de22SDarrick J. Wong struct xfs_attr_intent *attr)
1458f0f7c502SAllison Henderson {
1459d68c51e9SAllison Henderson struct xfs_da_args *args = attr->xattri_da_args;
14603768f698SDarrick J. Wong struct xfs_da_state *state = xfs_da_state_alloc(args);
1461f0f7c502SAllison Henderson int retval = 0;
1462f0f7c502SAllison Henderson int error = 0;
1463f0f7c502SAllison Henderson
146430f712c9SDave Chinner /*
14654b9879b1SDave Chinner * The attr we are removing has already been marked incomplete, so
14664b9879b1SDave Chinner * we need to set the filter appropriately to re-find the "old"
14674b9879b1SDave Chinner * attribute entry after any split ops.
146830f712c9SDave Chinner */
1469254f800fSChristoph Hellwig args->attr_filter |= XFS_ATTR_INCOMPLETE;
147030f712c9SDave Chinner error = xfs_da3_node_lookup_int(state, &retval);
147130f712c9SDave Chinner if (error)
147230f712c9SDave Chinner goto out;
147330f712c9SDave Chinner
1474816c8e39SAllison Henderson error = xfs_attr_node_removename(args, state);
147530f712c9SDave Chinner
147630f712c9SDave Chinner /*
147730f712c9SDave Chinner * Check to see if the tree needs to be collapsed.
147830f712c9SDave Chinner */
147930f712c9SDave Chinner if (retval && (state->path.active > 1)) {
148030f712c9SDave Chinner error = xfs_da3_join(state);
14818ad7c629SChristoph Hellwig if (error)
1482d5a2e289SBrian Foster goto out;
148330f712c9SDave Chinner }
148430f712c9SDave Chinner retval = error = 0;
148530f712c9SDave Chinner
148630f712c9SDave Chinner out:
148730f712c9SDave Chinner xfs_da_state_free(state);
148830f712c9SDave Chinner if (error)
148930f712c9SDave Chinner return error;
149030f712c9SDave Chinner return retval;
149130f712c9SDave Chinner }
149230f712c9SDave Chinner
149330f712c9SDave Chinner /*
1494728bcaa3SDave Chinner * Retrieve the attribute data from a node attribute list.
149530f712c9SDave Chinner *
149630f712c9SDave Chinner * This routine gets called for any attribute fork that has more than one
149730f712c9SDave Chinner * block, ie: both true Btree attr lists and for single-leaf-blocks with
149830f712c9SDave Chinner * "remote" values taking up more blocks.
1499728bcaa3SDave Chinner *
1500728bcaa3SDave Chinner * Returns 0 on successful retrieval, otherwise an error.
150130f712c9SDave Chinner */
150230f712c9SDave Chinner STATIC int
xfs_attr_node_get(struct xfs_da_args * args)150307120f1aSAllison Collins xfs_attr_node_get(
150407120f1aSAllison Collins struct xfs_da_args *args)
150530f712c9SDave Chinner {
15064d0cdd2bSDarrick J. Wong struct xfs_da_state *state;
150707120f1aSAllison Collins struct xfs_da_state_blk *blk;
150830f712c9SDave Chinner int i;
150907120f1aSAllison Collins int error;
151030f712c9SDave Chinner
151130f712c9SDave Chinner trace_xfs_attr_node_get(args);
151230f712c9SDave Chinner
151330f712c9SDave Chinner /*
151430f712c9SDave Chinner * Search to see if name exists, and get back a pointer to it.
151530f712c9SDave Chinner */
15164d0cdd2bSDarrick J. Wong state = xfs_da_state_alloc(args);
15174d0cdd2bSDarrick J. Wong error = xfs_attr_node_lookup(args, state);
151807120f1aSAllison Collins if (error != -EEXIST)
1519728bcaa3SDave Chinner goto out_release;
152030f712c9SDave Chinner
152130f712c9SDave Chinner /*
152230f712c9SDave Chinner * Get the value, local or "remote"
152330f712c9SDave Chinner */
1524728bcaa3SDave Chinner blk = &state->path.blk[state->path.active - 1];
152507120f1aSAllison Collins error = xfs_attr3_leaf_getvalue(blk->bp, args);
152630f712c9SDave Chinner
152730f712c9SDave Chinner /*
152830f712c9SDave Chinner * If not in a transaction, we have to release all the buffers.
152930f712c9SDave Chinner */
1530728bcaa3SDave Chinner out_release:
15310f38063dSAndrey Strachuk for (i = 0; i < state->path.active; i++) {
153230f712c9SDave Chinner xfs_trans_brelse(args->trans, state->path.blk[i].bp);
153330f712c9SDave Chinner state->path.blk[i].bp = NULL;
153430f712c9SDave Chinner }
153530f712c9SDave Chinner
153630f712c9SDave Chinner xfs_da_state_free(state);
153707120f1aSAllison Collins return error;
153830f712c9SDave Chinner }
153965480536SDarrick J. Wong
15405689d234SDarrick J. Wong /* Enforce that there is at most one namespace bit per attr. */
xfs_attr_check_namespace(unsigned int attr_flags)15415689d234SDarrick J. Wong inline bool xfs_attr_check_namespace(unsigned int attr_flags)
15425689d234SDarrick J. Wong {
15435689d234SDarrick J. Wong return hweight32(attr_flags & XFS_ATTR_NSP_ONDISK_MASK) < 2;
15445689d234SDarrick J. Wong }
15455689d234SDarrick J. Wong
154665480536SDarrick J. Wong /* Returns true if the attribute entry name is valid. */
154765480536SDarrick J. Wong bool
xfs_attr_namecheck(unsigned int attr_flags,const void * name,size_t length)154865480536SDarrick J. Wong xfs_attr_namecheck(
15495689d234SDarrick J. Wong unsigned int attr_flags,
155065480536SDarrick J. Wong const void *name,
155165480536SDarrick J. Wong size_t length)
155265480536SDarrick J. Wong {
15535689d234SDarrick J. Wong /* Only one namespace bit allowed. */
15545689d234SDarrick J. Wong if (!xfs_attr_check_namespace(attr_flags))
15555689d234SDarrick J. Wong return false;
15565689d234SDarrick J. Wong
155765480536SDarrick J. Wong /*
155865480536SDarrick J. Wong * MAXNAMELEN includes the trailing null, but (name/length) leave it
155965480536SDarrick J. Wong * out, so use >= for the length check.
156065480536SDarrick J. Wong */
156165480536SDarrick J. Wong if (length >= MAXNAMELEN)
156265480536SDarrick J. Wong return false;
156365480536SDarrick J. Wong
156465480536SDarrick J. Wong /* There shouldn't be any nulls here */
156565480536SDarrick J. Wong return !memchr(name, 0, length);
156665480536SDarrick J. Wong }
1567e2c78949SDarrick J. Wong
1568e2c78949SDarrick J. Wong int __init
xfs_attr_intent_init_cache(void)1569e2c78949SDarrick J. Wong xfs_attr_intent_init_cache(void)
1570e2c78949SDarrick J. Wong {
1571e3c5de22SDarrick J. Wong xfs_attr_intent_cache = kmem_cache_create("xfs_attr_intent",
1572e3c5de22SDarrick J. Wong sizeof(struct xfs_attr_intent),
1573e2c78949SDarrick J. Wong 0, 0, NULL);
1574e2c78949SDarrick J. Wong
1575e2c78949SDarrick J. Wong return xfs_attr_intent_cache != NULL ? 0 : -ENOMEM;
1576e2c78949SDarrick J. Wong }
1577e2c78949SDarrick J. Wong
1578e2c78949SDarrick J. Wong void
xfs_attr_intent_destroy_cache(void)1579e2c78949SDarrick J. Wong xfs_attr_intent_destroy_cache(void)
1580e2c78949SDarrick J. Wong {
1581e2c78949SDarrick J. Wong kmem_cache_destroy(xfs_attr_intent_cache);
1582e2c78949SDarrick J. Wong xfs_attr_intent_cache = NULL;
1583e2c78949SDarrick J. Wong }
1584