xref: /kernel/linux/linux-6.6/fs/xfs/libxfs/xfs_attr.h (revision 62306a36)
162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc.
462306a36Sopenharmony_ci * All Rights Reserved.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#ifndef __XFS_ATTR_H__
762306a36Sopenharmony_ci#define	__XFS_ATTR_H__
862306a36Sopenharmony_ci
962306a36Sopenharmony_cistruct xfs_inode;
1062306a36Sopenharmony_cistruct xfs_da_args;
1162306a36Sopenharmony_cistruct xfs_attr_list_context;
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * Large attribute lists are structured around Btrees where all the data
1562306a36Sopenharmony_ci * elements are in the leaf nodes.  Attribute names are hashed into an int,
1662306a36Sopenharmony_ci * then that int is used as the index into the Btree.  Since the hashval
1762306a36Sopenharmony_ci * of an attribute name may not be unique, we may have duplicate keys.
1862306a36Sopenharmony_ci * The internal links in the Btree are logical block offsets into the file.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * Small attribute lists use a different format and are packed as tightly
2162306a36Sopenharmony_ci * as possible so as to fit into the literal area of the inode.
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/*
2562306a36Sopenharmony_ci * The maximum size (into the kernel or returned from the kernel) of an
2662306a36Sopenharmony_ci * attribute value or the buffer used for an attr_list() call.  Larger
2762306a36Sopenharmony_ci * sizes will result in an ERANGE return code.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ci#define	ATTR_MAX_VALUELEN	(64*1024)	/* max length of a value */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/*
3262306a36Sopenharmony_ci * Kernel-internal version of the attrlist cursor.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_cistruct xfs_attrlist_cursor_kern {
3562306a36Sopenharmony_ci	__u32	hashval;	/* hash value of next entry to add */
3662306a36Sopenharmony_ci	__u32	blkno;		/* block containing entry (suggestion) */
3762306a36Sopenharmony_ci	__u32	offset;		/* offset in list of equal-hashvals */
3862306a36Sopenharmony_ci	__u16	pad1;		/* padding to match user-level */
3962306a36Sopenharmony_ci	__u8	pad2;		/* padding to match user-level */
4062306a36Sopenharmony_ci	__u8	initted;	/* T/F: cursor has been initialized */
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/*========================================================================
4562306a36Sopenharmony_ci * Structure used to pass context around among the routines.
4662306a36Sopenharmony_ci *========================================================================*/
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* void; state communicated via *context */
5062306a36Sopenharmony_citypedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
5162306a36Sopenharmony_ci			      unsigned char *, int, int);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct xfs_attr_list_context {
5462306a36Sopenharmony_ci	struct xfs_trans	*tp;
5562306a36Sopenharmony_ci	struct xfs_inode	*dp;		/* inode */
5662306a36Sopenharmony_ci	struct xfs_attrlist_cursor_kern cursor;	/* position in list */
5762306a36Sopenharmony_ci	void			*buffer;	/* output buffer */
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/*
6062306a36Sopenharmony_ci	 * Abort attribute list iteration if non-zero.  Can be used to pass
6162306a36Sopenharmony_ci	 * error values to the xfs_attr_list caller.
6262306a36Sopenharmony_ci	 */
6362306a36Sopenharmony_ci	int			seen_enough;
6462306a36Sopenharmony_ci	bool			allow_incomplete;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	ssize_t			count;		/* num used entries */
6762306a36Sopenharmony_ci	int			dupcnt;		/* count dup hashvals seen */
6862306a36Sopenharmony_ci	int			bufsize;	/* total buffer size */
6962306a36Sopenharmony_ci	int			firstu;		/* first used byte in buffer */
7062306a36Sopenharmony_ci	unsigned int		attr_filter;	/* XFS_ATTR_{ROOT,SECURE} */
7162306a36Sopenharmony_ci	int			resynch;	/* T/F: resynch with cursor */
7262306a36Sopenharmony_ci	put_listent_func_t	put_listent;	/* list output fmt function */
7362306a36Sopenharmony_ci	int			index;		/* index into output buffer */
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci * ========================================================================
7962306a36Sopenharmony_ci * Structure used to pass context around among the delayed routines.
8062306a36Sopenharmony_ci * ========================================================================
8162306a36Sopenharmony_ci */
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/*
8462306a36Sopenharmony_ci * Below is a state machine diagram for attr remove operations. The  XFS_DAS_*
8562306a36Sopenharmony_ci * states indicate places where the function would return -EAGAIN, and then
8662306a36Sopenharmony_ci * immediately resume from after being called by the calling function. States
8762306a36Sopenharmony_ci * marked as a "subroutine state" indicate that they belong to a subroutine, and
8862306a36Sopenharmony_ci * so the calling function needs to pass them back to that subroutine to allow
8962306a36Sopenharmony_ci * it to finish where it left off. But they otherwise do not have a role in the
9062306a36Sopenharmony_ci * calling function other than just passing through.
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci * xfs_attr_remove_iter()
9362306a36Sopenharmony_ci *              │
9462306a36Sopenharmony_ci *              v
9562306a36Sopenharmony_ci *        have attr to remove? ──n──> done
9662306a36Sopenharmony_ci *              │
9762306a36Sopenharmony_ci *              y
9862306a36Sopenharmony_ci *              │
9962306a36Sopenharmony_ci *              v
10062306a36Sopenharmony_ci *        are we short form? ──y──> xfs_attr_shortform_remove ──> done
10162306a36Sopenharmony_ci *              │
10262306a36Sopenharmony_ci *              n
10362306a36Sopenharmony_ci *              │
10462306a36Sopenharmony_ci *              V
10562306a36Sopenharmony_ci *        are we leaf form? ──y──> xfs_attr_leaf_removename ──> done
10662306a36Sopenharmony_ci *              │
10762306a36Sopenharmony_ci *              n
10862306a36Sopenharmony_ci *              │
10962306a36Sopenharmony_ci *              V
11062306a36Sopenharmony_ci *   ┌── need to setup state?
11162306a36Sopenharmony_ci *   │          │
11262306a36Sopenharmony_ci *   n          y
11362306a36Sopenharmony_ci *   │          │
11462306a36Sopenharmony_ci *   │          v
11562306a36Sopenharmony_ci *   │ find attr and get state
11662306a36Sopenharmony_ci *   │ attr has remote blks? ──n─┐
11762306a36Sopenharmony_ci *   │          │                v
11862306a36Sopenharmony_ci *   │          │         find and invalidate
11962306a36Sopenharmony_ci *   │          y         the remote blocks.
12062306a36Sopenharmony_ci *   │          │         mark attr incomplete
12162306a36Sopenharmony_ci *   │          ├────────────────┘
12262306a36Sopenharmony_ci *   └──────────┤
12362306a36Sopenharmony_ci *              │
12462306a36Sopenharmony_ci *              v
12562306a36Sopenharmony_ci *   Have remote blks to remove? ───y─────┐
12662306a36Sopenharmony_ci *              │        ^          remove the blks
12762306a36Sopenharmony_ci *              │        │                │
12862306a36Sopenharmony_ci *              │        │                v
12962306a36Sopenharmony_ci *              │  XFS_DAS_RMTBLK <─n── done?
13062306a36Sopenharmony_ci *              │  re-enter with          │
13162306a36Sopenharmony_ci *              │  one less blk to        y
13262306a36Sopenharmony_ci *              │      remove             │
13362306a36Sopenharmony_ci *              │                         V
13462306a36Sopenharmony_ci *              │                  refill the state
13562306a36Sopenharmony_ci *              n                         │
13662306a36Sopenharmony_ci *              │                         v
13762306a36Sopenharmony_ci *              │                   XFS_DAS_RM_NAME
13862306a36Sopenharmony_ci *              │                         │
13962306a36Sopenharmony_ci *              ├─────────────────────────┘
14062306a36Sopenharmony_ci *              │
14162306a36Sopenharmony_ci *              v
14262306a36Sopenharmony_ci *       remove leaf and
14362306a36Sopenharmony_ci *       update hash with
14462306a36Sopenharmony_ci *   xfs_attr_node_remove_cleanup
14562306a36Sopenharmony_ci *              │
14662306a36Sopenharmony_ci *              v
14762306a36Sopenharmony_ci *           need to
14862306a36Sopenharmony_ci *        shrink tree? ─n─┐
14962306a36Sopenharmony_ci *              │         │
15062306a36Sopenharmony_ci *              y         │
15162306a36Sopenharmony_ci *              │         │
15262306a36Sopenharmony_ci *              v         │
15362306a36Sopenharmony_ci *          join leaf     │
15462306a36Sopenharmony_ci *              │         │
15562306a36Sopenharmony_ci *              v         │
15662306a36Sopenharmony_ci *      XFS_DAS_RM_SHRINK │
15762306a36Sopenharmony_ci *              │         │
15862306a36Sopenharmony_ci *              v         │
15962306a36Sopenharmony_ci *       do the shrink    │
16062306a36Sopenharmony_ci *              │         │
16162306a36Sopenharmony_ci *              v         │
16262306a36Sopenharmony_ci *          free state <──┘
16362306a36Sopenharmony_ci *              │
16462306a36Sopenharmony_ci *              v
16562306a36Sopenharmony_ci *            done
16662306a36Sopenharmony_ci *
16762306a36Sopenharmony_ci *
16862306a36Sopenharmony_ci * Below is a state machine diagram for attr set operations.
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * It seems the challenge with understanding this system comes from trying to
17162306a36Sopenharmony_ci * absorb the state machine all at once, when really one should only be looking
17262306a36Sopenharmony_ci * at it with in the context of a single function. Once a state sensitive
17362306a36Sopenharmony_ci * function is called, the idea is that it "takes ownership" of the
17462306a36Sopenharmony_ci * state machine. It isn't concerned with the states that may have belonged to
17562306a36Sopenharmony_ci * it's calling parent. Only the states relevant to itself or any other
17662306a36Sopenharmony_ci * subroutines there in. Once a calling function hands off the state machine to
17762306a36Sopenharmony_ci * a subroutine, it needs to respect the simple rule that it doesn't "own" the
17862306a36Sopenharmony_ci * state machine anymore, and it's the responsibility of that calling function
17962306a36Sopenharmony_ci * to propagate the -EAGAIN back up the call stack. Upon reentry, it is
18062306a36Sopenharmony_ci * committed to re-calling that subroutine until it returns something other than
18162306a36Sopenharmony_ci * -EAGAIN. Once that subroutine signals completion (by returning anything other
18262306a36Sopenharmony_ci * than -EAGAIN), the calling function can resume using the state machine.
18362306a36Sopenharmony_ci *
18462306a36Sopenharmony_ci *  xfs_attr_set_iter()
18562306a36Sopenharmony_ci *              │
18662306a36Sopenharmony_ci *              v
18762306a36Sopenharmony_ci *   ┌─y─ has an attr fork?
18862306a36Sopenharmony_ci *   │          |
18962306a36Sopenharmony_ci *   │          n
19062306a36Sopenharmony_ci *   │          |
19162306a36Sopenharmony_ci *   │          V
19262306a36Sopenharmony_ci *   │       add a fork
19362306a36Sopenharmony_ci *   │          │
19462306a36Sopenharmony_ci *   └──────────┤
19562306a36Sopenharmony_ci *              │
19662306a36Sopenharmony_ci *              V
19762306a36Sopenharmony_ci *   ┌─── is shortform?
19862306a36Sopenharmony_ci *   │          │
19962306a36Sopenharmony_ci *   │          y
20062306a36Sopenharmony_ci *   │          │
20162306a36Sopenharmony_ci *   │          V
20262306a36Sopenharmony_ci *   │   xfs_attr_set_fmt
20362306a36Sopenharmony_ci *   │          |
20462306a36Sopenharmony_ci *   │          V
20562306a36Sopenharmony_ci *   │ xfs_attr_try_sf_addname
20662306a36Sopenharmony_ci *   │          │
20762306a36Sopenharmony_ci *   │          V
20862306a36Sopenharmony_ci *   │      had enough ──y──> done
20962306a36Sopenharmony_ci *   │        space?
21062306a36Sopenharmony_ci *   n          │
21162306a36Sopenharmony_ci *   │          n
21262306a36Sopenharmony_ci *   │          │
21362306a36Sopenharmony_ci *   │          V
21462306a36Sopenharmony_ci *   │   transform to leaf
21562306a36Sopenharmony_ci *   │          │
21662306a36Sopenharmony_ci *   │          V
21762306a36Sopenharmony_ci *   │   hold the leaf buffer
21862306a36Sopenharmony_ci *   │          │
21962306a36Sopenharmony_ci *   │          V
22062306a36Sopenharmony_ci *   │     return -EAGAIN
22162306a36Sopenharmony_ci *   │      Re-enter in
22262306a36Sopenharmony_ci *   │       leaf form
22362306a36Sopenharmony_ci *   │
22462306a36Sopenharmony_ci *   └─> release leaf buffer
22562306a36Sopenharmony_ci *          if needed
22662306a36Sopenharmony_ci *              │
22762306a36Sopenharmony_ci *              V
22862306a36Sopenharmony_ci *   ┌───n── fork has
22962306a36Sopenharmony_ci *   │      only 1 blk?
23062306a36Sopenharmony_ci *   │          │
23162306a36Sopenharmony_ci *   │          y
23262306a36Sopenharmony_ci *   │          │
23362306a36Sopenharmony_ci *   │          v
23462306a36Sopenharmony_ci *   │ xfs_attr_leaf_try_add()
23562306a36Sopenharmony_ci *   │          │
23662306a36Sopenharmony_ci *   │          v
23762306a36Sopenharmony_ci *   │      had enough ──────────────y─────────────┐
23862306a36Sopenharmony_ci *   │        space?                               │
23962306a36Sopenharmony_ci *   │          │                                  │
24062306a36Sopenharmony_ci *   │          n                                  │
24162306a36Sopenharmony_ci *   │          │                                  │
24262306a36Sopenharmony_ci *   │          v                                  │
24362306a36Sopenharmony_ci *   │    return -EAGAIN                           │
24462306a36Sopenharmony_ci *   │      re-enter in                            │
24562306a36Sopenharmony_ci *   │        node form                            │
24662306a36Sopenharmony_ci *   │          │                                  │
24762306a36Sopenharmony_ci *   └──────────┤                                  │
24862306a36Sopenharmony_ci *              │                                  │
24962306a36Sopenharmony_ci *              V                                  │
25062306a36Sopenharmony_ci * xfs_attr_node_addname_find_attr                 │
25162306a36Sopenharmony_ci *        determines if this                       │
25262306a36Sopenharmony_ci *       is create or rename                       │
25362306a36Sopenharmony_ci *     find space to store attr                    │
25462306a36Sopenharmony_ci *              │                                  │
25562306a36Sopenharmony_ci *              v                                  │
25662306a36Sopenharmony_ci *     xfs_attr_node_addname                       │
25762306a36Sopenharmony_ci *              │                                  │
25862306a36Sopenharmony_ci *              v                                  │
25962306a36Sopenharmony_ci *   fits in a node leaf? ────n─────┐              │
26062306a36Sopenharmony_ci *              │     ^             v              │
26162306a36Sopenharmony_ci *              │     │       single leaf node?    │
26262306a36Sopenharmony_ci *              │     │         │            │     │
26362306a36Sopenharmony_ci *              y     │         y            n     │
26462306a36Sopenharmony_ci *              │     │         │            │     │
26562306a36Sopenharmony_ci *              v     │         v            v     │
26662306a36Sopenharmony_ci *            update  │    grow the leaf  split if │
26762306a36Sopenharmony_ci *           hashvals └── return -EAGAIN   needed  │
26862306a36Sopenharmony_ci *              │         retry leaf add     │     │
26962306a36Sopenharmony_ci *              │           on reentry       │     │
27062306a36Sopenharmony_ci *              ├────────────────────────────┘     │
27162306a36Sopenharmony_ci *              │                                  │
27262306a36Sopenharmony_ci *              v                                  │
27362306a36Sopenharmony_ci *         need to alloc                           │
27462306a36Sopenharmony_ci *   ┌─y── or flip flag?                           │
27562306a36Sopenharmony_ci *   │          │                                  │
27662306a36Sopenharmony_ci *   │          n                                  │
27762306a36Sopenharmony_ci *   │          │                                  │
27862306a36Sopenharmony_ci *   │          v                                  │
27962306a36Sopenharmony_ci *   │         done                                │
28062306a36Sopenharmony_ci *   │                                             │
28162306a36Sopenharmony_ci *   │                                             │
28262306a36Sopenharmony_ci *   │         XFS_DAS_FOUND_LBLK <────────────────┘
28362306a36Sopenharmony_ci *   │                  │
28462306a36Sopenharmony_ci *   │                  V
28562306a36Sopenharmony_ci *   │        xfs_attr_leaf_addname()
28662306a36Sopenharmony_ci *   │                  │
28762306a36Sopenharmony_ci *   │                  v
28862306a36Sopenharmony_ci *   │      ┌──first time through?
28962306a36Sopenharmony_ci *   │      │          │
29062306a36Sopenharmony_ci *   │      │          y
29162306a36Sopenharmony_ci *   │      │          │
29262306a36Sopenharmony_ci *   │      n          v
29362306a36Sopenharmony_ci *   │      │    if we have rmt blks
29462306a36Sopenharmony_ci *   │      │    find space for them
29562306a36Sopenharmony_ci *   │      │          │
29662306a36Sopenharmony_ci *   │      └──────────┤
29762306a36Sopenharmony_ci *   │                 │
29862306a36Sopenharmony_ci *   │                 v
29962306a36Sopenharmony_ci *   │            still have
30062306a36Sopenharmony_ci *   │      ┌─n─ blks to alloc? <──┐
30162306a36Sopenharmony_ci *   │      │          │           │
30262306a36Sopenharmony_ci *   │      │          y           │
30362306a36Sopenharmony_ci *   │      │          │           │
30462306a36Sopenharmony_ci *   │      │          v           │
30562306a36Sopenharmony_ci *   │      │     alloc one blk    │
30662306a36Sopenharmony_ci *   │      │     return -EAGAIN ──┘
30762306a36Sopenharmony_ci *   │      │    re-enter with one
30862306a36Sopenharmony_ci *   │      │    less blk to alloc
30962306a36Sopenharmony_ci *   │      │
31062306a36Sopenharmony_ci *   │      │
31162306a36Sopenharmony_ci *   │      └───> set the rmt
31262306a36Sopenharmony_ci *   │               value
31362306a36Sopenharmony_ci *   │                 │
31462306a36Sopenharmony_ci *   │                 v
31562306a36Sopenharmony_ci *   │               was this
31662306a36Sopenharmony_ci *   │              a rename? ──n─┐
31762306a36Sopenharmony_ci *   │                 │          │
31862306a36Sopenharmony_ci *   │                 y          │
31962306a36Sopenharmony_ci *   │                 │          │
32062306a36Sopenharmony_ci *   │                 v          │
32162306a36Sopenharmony_ci *   │           flip incomplete  │
32262306a36Sopenharmony_ci *   │               flag         │
32362306a36Sopenharmony_ci *   │                 │          │
32462306a36Sopenharmony_ci *   │                 v          │
32562306a36Sopenharmony_ci *   │         XFS_DAS_FLIP_LFLAG │
32662306a36Sopenharmony_ci *   │                 │          │
32762306a36Sopenharmony_ci *   │                 v          │
32862306a36Sopenharmony_ci *   │          need to remove    │
32962306a36Sopenharmony_ci *   │              old bks? ──n──┤
33062306a36Sopenharmony_ci *   │                 │          │
33162306a36Sopenharmony_ci *   │                 y          │
33262306a36Sopenharmony_ci *   │                 │          │
33362306a36Sopenharmony_ci *   │                 V          │
33462306a36Sopenharmony_ci *   │               remove       │
33562306a36Sopenharmony_ci *   │        ┌───> old blks      │
33662306a36Sopenharmony_ci *   │        │        │          │
33762306a36Sopenharmony_ci *   │ XFS_DAS_RM_LBLK │          │
33862306a36Sopenharmony_ci *   │        ^        │          │
33962306a36Sopenharmony_ci *   │        │        v          │
34062306a36Sopenharmony_ci *   │        └──y── more to      │
34162306a36Sopenharmony_ci *   │              remove?       │
34262306a36Sopenharmony_ci *   │                 │          │
34362306a36Sopenharmony_ci *   │                 n          │
34462306a36Sopenharmony_ci *   │                 │          │
34562306a36Sopenharmony_ci *   │                 v          │
34662306a36Sopenharmony_ci *   │          XFS_DAS_RD_LEAF   │
34762306a36Sopenharmony_ci *   │                 │          │
34862306a36Sopenharmony_ci *   │                 v          │
34962306a36Sopenharmony_ci *   │            remove leaf     │
35062306a36Sopenharmony_ci *   │                 │          │
35162306a36Sopenharmony_ci *   │                 v          │
35262306a36Sopenharmony_ci *   │            shrink to sf    │
35362306a36Sopenharmony_ci *   │             if needed      │
35462306a36Sopenharmony_ci *   │                 │          │
35562306a36Sopenharmony_ci *   │                 v          │
35662306a36Sopenharmony_ci *   │                done <──────┘
35762306a36Sopenharmony_ci *   │
35862306a36Sopenharmony_ci *   └──────> XFS_DAS_FOUND_NBLK
35962306a36Sopenharmony_ci *                     │
36062306a36Sopenharmony_ci *                     v
36162306a36Sopenharmony_ci *       ┌─────n──  need to
36262306a36Sopenharmony_ci *       │        alloc blks?
36362306a36Sopenharmony_ci *       │             │
36462306a36Sopenharmony_ci *       │             y
36562306a36Sopenharmony_ci *       │             │
36662306a36Sopenharmony_ci *       │             v
36762306a36Sopenharmony_ci *       │        find space
36862306a36Sopenharmony_ci *       │             │
36962306a36Sopenharmony_ci *       │             v
37062306a36Sopenharmony_ci *       │  ┌─>XFS_DAS_ALLOC_NODE
37162306a36Sopenharmony_ci *       │  │          │
37262306a36Sopenharmony_ci *       │  │          v
37362306a36Sopenharmony_ci *       │  │      alloc blk
37462306a36Sopenharmony_ci *       │  │          │
37562306a36Sopenharmony_ci *       │  │          v
37662306a36Sopenharmony_ci *       │  └──y── need to alloc
37762306a36Sopenharmony_ci *       │         more blocks?
37862306a36Sopenharmony_ci *       │             │
37962306a36Sopenharmony_ci *       │             n
38062306a36Sopenharmony_ci *       │             │
38162306a36Sopenharmony_ci *       │             v
38262306a36Sopenharmony_ci *       │      set the rmt value
38362306a36Sopenharmony_ci *       │             │
38462306a36Sopenharmony_ci *       │             v
38562306a36Sopenharmony_ci *       │          was this
38662306a36Sopenharmony_ci *       └────────> a rename? ──n─┐
38762306a36Sopenharmony_ci *                     │          │
38862306a36Sopenharmony_ci *                     y          │
38962306a36Sopenharmony_ci *                     │          │
39062306a36Sopenharmony_ci *                     v          │
39162306a36Sopenharmony_ci *               flip incomplete  │
39262306a36Sopenharmony_ci *                   flag         │
39362306a36Sopenharmony_ci *                     │          │
39462306a36Sopenharmony_ci *                     v          │
39562306a36Sopenharmony_ci *             XFS_DAS_FLIP_NFLAG │
39662306a36Sopenharmony_ci *                     │          │
39762306a36Sopenharmony_ci *                     v          │
39862306a36Sopenharmony_ci *                 need to        │
39962306a36Sopenharmony_ci *               remove blks? ─n──┤
40062306a36Sopenharmony_ci *                     │          │
40162306a36Sopenharmony_ci *                     y          │
40262306a36Sopenharmony_ci *                     │          │
40362306a36Sopenharmony_ci *                     v          │
40462306a36Sopenharmony_ci *                   remove       │
40562306a36Sopenharmony_ci *        ┌────────> old blks     │
40662306a36Sopenharmony_ci *        │            │          │
40762306a36Sopenharmony_ci *  XFS_DAS_RM_NBLK    │          │
40862306a36Sopenharmony_ci *        ^            │          │
40962306a36Sopenharmony_ci *        │            v          │
41062306a36Sopenharmony_ci *        └──────y── more to      │
41162306a36Sopenharmony_ci *                   remove       │
41262306a36Sopenharmony_ci *                     │          │
41362306a36Sopenharmony_ci *                     n          │
41462306a36Sopenharmony_ci *                     │          │
41562306a36Sopenharmony_ci *                     v          │
41662306a36Sopenharmony_ci *              XFS_DAS_CLR_FLAG  │
41762306a36Sopenharmony_ci *                     │          │
41862306a36Sopenharmony_ci *                     v          │
41962306a36Sopenharmony_ci *                clear flags     │
42062306a36Sopenharmony_ci *                     │          │
42162306a36Sopenharmony_ci *                     ├──────────┘
42262306a36Sopenharmony_ci *                     │
42362306a36Sopenharmony_ci *                     v
42462306a36Sopenharmony_ci *                   done
42562306a36Sopenharmony_ci */
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/*
42862306a36Sopenharmony_ci * Enum values for xfs_attr_intent.xattri_da_state
42962306a36Sopenharmony_ci *
43062306a36Sopenharmony_ci * These values are used by delayed attribute operations to keep track  of where
43162306a36Sopenharmony_ci * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
43262306a36Sopenharmony_ci * calling function to roll the transaction, and then call the subroutine to
43362306a36Sopenharmony_ci * finish the operation.  The enum is then used by the subroutine to jump back
43462306a36Sopenharmony_ci * to where it was and resume executing where it left off.
43562306a36Sopenharmony_ci */
43662306a36Sopenharmony_cienum xfs_delattr_state {
43762306a36Sopenharmony_ci	XFS_DAS_UNINIT		= 0,	/* No state has been set yet */
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	/*
44062306a36Sopenharmony_ci	 * Initial sequence states. The replace setup code relies on the
44162306a36Sopenharmony_ci	 * ADD and REMOVE states for a specific format to be sequential so
44262306a36Sopenharmony_ci	 * that we can transform the initial operation to be performed
44362306a36Sopenharmony_ci	 * according to the xfs_has_larp() state easily.
44462306a36Sopenharmony_ci	 */
44562306a36Sopenharmony_ci	XFS_DAS_SF_ADD,			/* Initial sf add state */
44662306a36Sopenharmony_ci	XFS_DAS_SF_REMOVE,		/* Initial sf replace/remove state */
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	XFS_DAS_LEAF_ADD,		/* Initial leaf add state */
44962306a36Sopenharmony_ci	XFS_DAS_LEAF_REMOVE,		/* Initial leaf replace/remove state */
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	XFS_DAS_NODE_ADD,		/* Initial node add state */
45262306a36Sopenharmony_ci	XFS_DAS_NODE_REMOVE,		/* Initial node replace/remove state */
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* Leaf state set/replace/remove sequence */
45562306a36Sopenharmony_ci	XFS_DAS_LEAF_SET_RMT,		/* set a remote xattr from a leaf */
45662306a36Sopenharmony_ci	XFS_DAS_LEAF_ALLOC_RMT,		/* We are allocating remote blocks */
45762306a36Sopenharmony_ci	XFS_DAS_LEAF_REPLACE,		/* Perform replace ops on a leaf */
45862306a36Sopenharmony_ci	XFS_DAS_LEAF_REMOVE_OLD,	/* Start removing old attr from leaf */
45962306a36Sopenharmony_ci	XFS_DAS_LEAF_REMOVE_RMT,	/* A rename is removing remote blocks */
46062306a36Sopenharmony_ci	XFS_DAS_LEAF_REMOVE_ATTR,	/* Remove the old attr from a leaf */
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	/* Node state sequence, must match leaf state above */
46362306a36Sopenharmony_ci	XFS_DAS_NODE_SET_RMT,		/* set a remote xattr from a node */
46462306a36Sopenharmony_ci	XFS_DAS_NODE_ALLOC_RMT,		/* We are allocating remote blocks */
46562306a36Sopenharmony_ci	XFS_DAS_NODE_REPLACE,		/* Perform replace ops on a node */
46662306a36Sopenharmony_ci	XFS_DAS_NODE_REMOVE_OLD,	/* Start removing old attr from node */
46762306a36Sopenharmony_ci	XFS_DAS_NODE_REMOVE_RMT,	/* A rename is removing remote blocks */
46862306a36Sopenharmony_ci	XFS_DAS_NODE_REMOVE_ATTR,	/* Remove the old attr from a node */
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	XFS_DAS_DONE,			/* finished operation */
47162306a36Sopenharmony_ci};
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci#define XFS_DAS_STRINGS	\
47462306a36Sopenharmony_ci	{ XFS_DAS_UNINIT,		"XFS_DAS_UNINIT" }, \
47562306a36Sopenharmony_ci	{ XFS_DAS_SF_ADD,		"XFS_DAS_SF_ADD" }, \
47662306a36Sopenharmony_ci	{ XFS_DAS_SF_REMOVE,		"XFS_DAS_SF_REMOVE" }, \
47762306a36Sopenharmony_ci	{ XFS_DAS_LEAF_ADD,		"XFS_DAS_LEAF_ADD" }, \
47862306a36Sopenharmony_ci	{ XFS_DAS_LEAF_REMOVE,		"XFS_DAS_LEAF_REMOVE" }, \
47962306a36Sopenharmony_ci	{ XFS_DAS_NODE_ADD,		"XFS_DAS_NODE_ADD" }, \
48062306a36Sopenharmony_ci	{ XFS_DAS_NODE_REMOVE,		"XFS_DAS_NODE_REMOVE" }, \
48162306a36Sopenharmony_ci	{ XFS_DAS_LEAF_SET_RMT,		"XFS_DAS_LEAF_SET_RMT" }, \
48262306a36Sopenharmony_ci	{ XFS_DAS_LEAF_ALLOC_RMT,	"XFS_DAS_LEAF_ALLOC_RMT" }, \
48362306a36Sopenharmony_ci	{ XFS_DAS_LEAF_REPLACE,		"XFS_DAS_LEAF_REPLACE" }, \
48462306a36Sopenharmony_ci	{ XFS_DAS_LEAF_REMOVE_OLD,	"XFS_DAS_LEAF_REMOVE_OLD" }, \
48562306a36Sopenharmony_ci	{ XFS_DAS_LEAF_REMOVE_RMT,	"XFS_DAS_LEAF_REMOVE_RMT" }, \
48662306a36Sopenharmony_ci	{ XFS_DAS_LEAF_REMOVE_ATTR,	"XFS_DAS_LEAF_REMOVE_ATTR" }, \
48762306a36Sopenharmony_ci	{ XFS_DAS_NODE_SET_RMT,		"XFS_DAS_NODE_SET_RMT" }, \
48862306a36Sopenharmony_ci	{ XFS_DAS_NODE_ALLOC_RMT,	"XFS_DAS_NODE_ALLOC_RMT" },  \
48962306a36Sopenharmony_ci	{ XFS_DAS_NODE_REPLACE,		"XFS_DAS_NODE_REPLACE" },  \
49062306a36Sopenharmony_ci	{ XFS_DAS_NODE_REMOVE_OLD,	"XFS_DAS_NODE_REMOVE_OLD" }, \
49162306a36Sopenharmony_ci	{ XFS_DAS_NODE_REMOVE_RMT,	"XFS_DAS_NODE_REMOVE_RMT" }, \
49262306a36Sopenharmony_ci	{ XFS_DAS_NODE_REMOVE_ATTR,	"XFS_DAS_NODE_REMOVE_ATTR" }, \
49362306a36Sopenharmony_ci	{ XFS_DAS_DONE,			"XFS_DAS_DONE" }
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistruct xfs_attri_log_nameval;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci/*
49862306a36Sopenharmony_ci * Context used for keeping track of delayed attribute operations
49962306a36Sopenharmony_ci */
50062306a36Sopenharmony_cistruct xfs_attr_intent {
50162306a36Sopenharmony_ci	/*
50262306a36Sopenharmony_ci	 * used to log this item to an intent containing a list of attrs to
50362306a36Sopenharmony_ci	 * commit later
50462306a36Sopenharmony_ci	 */
50562306a36Sopenharmony_ci	struct list_head		xattri_list;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/* Used in xfs_attr_node_removename to roll through removing blocks */
50862306a36Sopenharmony_ci	struct xfs_da_state		*xattri_da_state;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	struct xfs_da_args		*xattri_da_args;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/*
51362306a36Sopenharmony_ci	 * Shared buffer containing the attr name and value so that the logging
51462306a36Sopenharmony_ci	 * code can share large memory buffers between log items.
51562306a36Sopenharmony_ci	 */
51662306a36Sopenharmony_ci	struct xfs_attri_log_nameval	*xattri_nameval;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* Used to keep track of current state of delayed operation */
51962306a36Sopenharmony_ci	enum xfs_delattr_state		xattri_dela_state;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/*
52262306a36Sopenharmony_ci	 * Attr operation being performed - XFS_ATTRI_OP_FLAGS_*
52362306a36Sopenharmony_ci	 */
52462306a36Sopenharmony_ci	unsigned int			xattri_op_flags;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	/* Used in xfs_attr_rmtval_set_blk to roll through allocating blocks */
52762306a36Sopenharmony_ci	xfs_dablk_t			xattri_lblkno;
52862306a36Sopenharmony_ci	int				xattri_blkcnt;
52962306a36Sopenharmony_ci	struct xfs_bmbt_irec		xattri_map;
53062306a36Sopenharmony_ci};
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci/*========================================================================
53462306a36Sopenharmony_ci * Function prototypes for the kernel.
53562306a36Sopenharmony_ci *========================================================================*/
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci/*
53862306a36Sopenharmony_ci * Overall external interface routines.
53962306a36Sopenharmony_ci */
54062306a36Sopenharmony_ciint xfs_attr_inactive(struct xfs_inode *dp);
54162306a36Sopenharmony_ciint xfs_attr_list_ilocked(struct xfs_attr_list_context *);
54262306a36Sopenharmony_ciint xfs_attr_list(struct xfs_attr_list_context *);
54362306a36Sopenharmony_ciint xfs_inode_hasattr(struct xfs_inode *ip);
54462306a36Sopenharmony_cibool xfs_attr_is_leaf(struct xfs_inode *ip);
54562306a36Sopenharmony_ciint xfs_attr_get_ilocked(struct xfs_da_args *args);
54662306a36Sopenharmony_ciint xfs_attr_get(struct xfs_da_args *args);
54762306a36Sopenharmony_ciint xfs_attr_set(struct xfs_da_args *args);
54862306a36Sopenharmony_ciint xfs_attr_set_iter(struct xfs_attr_intent *attr);
54962306a36Sopenharmony_ciint xfs_attr_remove_iter(struct xfs_attr_intent *attr);
55062306a36Sopenharmony_cibool xfs_attr_namecheck(const void *name, size_t length);
55162306a36Sopenharmony_ciint xfs_attr_calc_size(struct xfs_da_args *args, int *local);
55262306a36Sopenharmony_civoid xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres,
55362306a36Sopenharmony_ci			 unsigned int *total);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci/*
55662306a36Sopenharmony_ci * Check to see if the attr should be upgraded from non-existent or shortform to
55762306a36Sopenharmony_ci * single-leaf-block attribute list.
55862306a36Sopenharmony_ci */
55962306a36Sopenharmony_cistatic inline bool
56062306a36Sopenharmony_cixfs_attr_is_shortform(
56162306a36Sopenharmony_ci	struct xfs_inode    *ip)
56262306a36Sopenharmony_ci{
56362306a36Sopenharmony_ci	return ip->i_af.if_format == XFS_DINODE_FMT_LOCAL ||
56462306a36Sopenharmony_ci	       (ip->i_af.if_format == XFS_DINODE_FMT_EXTENTS &&
56562306a36Sopenharmony_ci		ip->i_af.if_nextents == 0);
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic inline enum xfs_delattr_state
56962306a36Sopenharmony_cixfs_attr_init_add_state(struct xfs_da_args *args)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	/*
57262306a36Sopenharmony_ci	 * When called from the completion of a attr remove to determine the
57362306a36Sopenharmony_ci	 * next state, the attribute fork may be null. This can occur only occur
57462306a36Sopenharmony_ci	 * on a pure remove, but we grab the next state before we check if a
57562306a36Sopenharmony_ci	 * replace operation is being performed. If we are called from any other
57662306a36Sopenharmony_ci	 * context, i_af is guaranteed to exist. Hence if the attr fork is
57762306a36Sopenharmony_ci	 * null, we were called from a pure remove operation and so we are done.
57862306a36Sopenharmony_ci	 */
57962306a36Sopenharmony_ci	if (!xfs_inode_has_attr_fork(args->dp))
58062306a36Sopenharmony_ci		return XFS_DAS_DONE;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	args->op_flags |= XFS_DA_OP_ADDNAME;
58362306a36Sopenharmony_ci	if (xfs_attr_is_shortform(args->dp))
58462306a36Sopenharmony_ci		return XFS_DAS_SF_ADD;
58562306a36Sopenharmony_ci	if (xfs_attr_is_leaf(args->dp))
58662306a36Sopenharmony_ci		return XFS_DAS_LEAF_ADD;
58762306a36Sopenharmony_ci	return XFS_DAS_NODE_ADD;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic inline enum xfs_delattr_state
59162306a36Sopenharmony_cixfs_attr_init_remove_state(struct xfs_da_args *args)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	args->op_flags |= XFS_DA_OP_REMOVE;
59462306a36Sopenharmony_ci	if (xfs_attr_is_shortform(args->dp))
59562306a36Sopenharmony_ci		return XFS_DAS_SF_REMOVE;
59662306a36Sopenharmony_ci	if (xfs_attr_is_leaf(args->dp))
59762306a36Sopenharmony_ci		return XFS_DAS_LEAF_REMOVE;
59862306a36Sopenharmony_ci	return XFS_DAS_NODE_REMOVE;
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci/*
60262306a36Sopenharmony_ci * If we are logging the attributes, then we have to start with removal of the
60362306a36Sopenharmony_ci * old attribute so that there is always consistent state that we can recover
60462306a36Sopenharmony_ci * from if the system goes down part way through. We always log the new attr
60562306a36Sopenharmony_ci * value, so even when we remove the attr first we still have the information in
60662306a36Sopenharmony_ci * the log to finish the replace operation atomically.
60762306a36Sopenharmony_ci */
60862306a36Sopenharmony_cistatic inline enum xfs_delattr_state
60962306a36Sopenharmony_cixfs_attr_init_replace_state(struct xfs_da_args *args)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	args->op_flags |= XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE;
61262306a36Sopenharmony_ci	if (args->op_flags & XFS_DA_OP_LOGGED)
61362306a36Sopenharmony_ci		return xfs_attr_init_remove_state(args);
61462306a36Sopenharmony_ci	return xfs_attr_init_add_state(args);
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ciextern struct kmem_cache *xfs_attr_intent_cache;
61862306a36Sopenharmony_ciint __init xfs_attr_intent_init_cache(void);
61962306a36Sopenharmony_civoid xfs_attr_intent_destroy_cache(void);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci#endif	/* __XFS_ATTR_H__ */
622