brintos

brintos / linux-shallow public Read only

0
0
Text · 24.2 KiB · 0e51d07 Raw
653 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2/*3 * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc.4 * All Rights Reserved.5 */6#ifndef __XFS_ATTR_H__7#define	__XFS_ATTR_H__8 9struct xfs_inode;10struct xfs_da_args;11struct xfs_attr_list_context;12 13/*14 * Large attribute lists are structured around Btrees where all the data15 * elements are in the leaf nodes.  Attribute names are hashed into an int,16 * then that int is used as the index into the Btree.  Since the hashval17 * of an attribute name may not be unique, we may have duplicate keys.18 * The internal links in the Btree are logical block offsets into the file.19 *20 * Small attribute lists use a different format and are packed as tightly21 * as possible so as to fit into the literal area of the inode.22 */23 24/*25 * The maximum size (into the kernel or returned from the kernel) of an26 * attribute value or the buffer used for an attr_list() call.  Larger27 * sizes will result in an ERANGE return code.28 */29#define	ATTR_MAX_VALUELEN	(64*1024)	/* max length of a value */30 31/*32 * Kernel-internal version of the attrlist cursor.33 */34struct xfs_attrlist_cursor_kern {35	__u32	hashval;	/* hash value of next entry to add */36	__u32	blkno;		/* block containing entry (suggestion) */37	__u32	offset;		/* offset in list of equal-hashvals */38	__u16	pad1;		/* padding to match user-level */39	__u8	pad2;		/* padding to match user-level */40	__u8	initted;	/* T/F: cursor has been initialized */41};42 43 44/*========================================================================45 * Structure used to pass context around among the routines.46 *========================================================================*/47 48 49/* void; state communicated via *context */50typedef void (*put_listent_func_t)(struct xfs_attr_list_context *context,51		int flags, unsigned char *name, int namelen, void *value,52		int valuelen);53 54struct xfs_attr_list_context {55	struct xfs_trans	*tp;56	struct xfs_inode	*dp;		/* inode */57	struct xfs_attrlist_cursor_kern cursor;	/* position in list */58	void			*buffer;	/* output buffer */59 60	/*61	 * Abort attribute list iteration if non-zero.  Can be used to pass62	 * error values to the xfs_attr_list caller.63	 */64	int			seen_enough;65	bool			allow_incomplete;66 67	ssize_t			count;		/* num used entries */68	int			dupcnt;		/* count dup hashvals seen */69	int			bufsize;	/* total buffer size */70	int			firstu;		/* first used byte in buffer */71	unsigned int		attr_filter;	/* XFS_ATTR_{ROOT,SECURE} */72	int			resynch;	/* T/F: resynch with cursor */73	put_listent_func_t	put_listent;	/* list output fmt function */74	int			index;		/* index into output buffer */75};76 77 78/*79 * ========================================================================80 * Structure used to pass context around among the delayed routines.81 * ========================================================================82 */83 84/*85 * Below is a state machine diagram for attr remove operations. The  XFS_DAS_*86 * states indicate places where the function would return -EAGAIN, and then87 * immediately resume from after being called by the calling function. States88 * marked as a "subroutine state" indicate that they belong to a subroutine, and89 * so the calling function needs to pass them back to that subroutine to allow90 * it to finish where it left off. But they otherwise do not have a role in the91 * calling function other than just passing through.92 *93 * xfs_attr_remove_iter()94 *              │95 *              v96 *        have attr to remove? ──n──> done97 *              │98 *              y99 *              │100 *              v101 *        are we short form? ──y──> xfs_attr_shortform_remove ──> done102 *              │103 *              n104 *              │105 *              V106 *        are we leaf form? ──y──> xfs_attr_leaf_removename ──> done107 *              │108 *              n109 *              │110 *              V111 *   ┌── need to setup state?112 *   │          │113 *   n          y114 *   │          │115 *   │          v116 *   │ find attr and get state117 *   │ attr has remote blks? ──n─┐118 *   │          │                v119 *   │          │         find and invalidate120 *   │          y         the remote blocks.121 *   │          │         mark attr incomplete122 *   │          ├────────────────┘123 *   └──────────┤124 *              │125 *              v126 *   Have remote blks to remove? ───y─────┐127 *              │        ^          remove the blks128 *              │        │                │129 *              │        │                v130 *              │  XFS_DAS_RMTBLK <─n── done?131 *              │  re-enter with          │132 *              │  one less blk to        y133 *              │      remove             │134 *              │                         V135 *              │                  refill the state136 *              n                         │137 *              │                         v138 *              │                   XFS_DAS_RM_NAME139 *              │                         │140 *              ├─────────────────────────┘141 *              │142 *              v143 *       remove leaf and144 *       update hash with145 *   xfs_attr_node_remove_cleanup146 *              │147 *              v148 *           need to149 *        shrink tree? ─n─┐150 *              │         │151 *              y         │152 *              │         │153 *              v         │154 *          join leaf     │155 *              │         │156 *              v         │157 *      XFS_DAS_RM_SHRINK │158 *              │         │159 *              v         │160 *       do the shrink    │161 *              │         │162 *              v         │163 *          free state <──┘164 *              │165 *              v166 *            done167 *168 *169 * Below is a state machine diagram for attr set operations.170 *171 * It seems the challenge with understanding this system comes from trying to172 * absorb the state machine all at once, when really one should only be looking173 * at it with in the context of a single function. Once a state sensitive174 * function is called, the idea is that it "takes ownership" of the175 * state machine. It isn't concerned with the states that may have belonged to176 * it's calling parent. Only the states relevant to itself or any other177 * subroutines there in. Once a calling function hands off the state machine to178 * a subroutine, it needs to respect the simple rule that it doesn't "own" the179 * state machine anymore, and it's the responsibility of that calling function180 * to propagate the -EAGAIN back up the call stack. Upon reentry, it is181 * committed to re-calling that subroutine until it returns something other than182 * -EAGAIN. Once that subroutine signals completion (by returning anything other183 * than -EAGAIN), the calling function can resume using the state machine.184 *185 *  xfs_attr_set_iter()186 *              │187 *              v188 *   ┌─y─ has an attr fork?189 *   │          |190 *   │          n191 *   │          |192 *   │          V193 *   │       add a fork194 *   │          │195 *   └──────────┤196 *              │197 *              V198 *   ┌─── is shortform?199 *   │          │200 *   │          y201 *   │          │202 *   │          V203 *   │   xfs_attr_set_fmt204 *   │          |205 *   │          V206 *   │ xfs_attr_try_sf_addname207 *   │          │208 *   │          V209 *   │      had enough ──y──> done210 *   │        space?211 *   n          │212 *   │          n213 *   │          │214 *   │          V215 *   │   transform to leaf216 *   │          │217 *   │          V218 *   │   hold the leaf buffer219 *   │          │220 *   │          V221 *   │     return -EAGAIN222 *   │      Re-enter in223 *   │       leaf form224 *   │225 *   └─> release leaf buffer226 *          if needed227 *              │228 *              V229 *   ┌───n── fork has230 *   │      only 1 blk?231 *   │          │232 *   │          y233 *   │          │234 *   │          v235 *   │ xfs_attr_leaf_try_add()236 *   │          │237 *   │          v238 *   │      had enough ──────────────y─────────────┐239 *   │        space?                               │240 *   │          │                                  │241 *   │          n                                  │242 *   │          │                                  │243 *   │          v                                  │244 *   │    return -EAGAIN                           │245 *   │      re-enter in                            │246 *   │        node form                            │247 *   │          │                                  │248 *   └──────────┤                                  │249 *              │                                  │250 *              V                                  │251 * xfs_attr_node_addname_find_attr                 │252 *        determines if this                       │253 *       is create or rename                       │254 *     find space to store attr                    │255 *              │                                  │256 *              v                                  │257 *     xfs_attr_node_addname                       │258 *              │                                  │259 *              v                                  │260 *   fits in a node leaf? ────n─────┐              │261 *              │     ^             v              │262 *              │     │       single leaf node?    │263 *              │     │         │            │     │264 *              y     │         y            n     │265 *              │     │         │            │     │266 *              v     │         v            v     │267 *            update  │    grow the leaf  split if │268 *           hashvals └── return -EAGAIN   needed  │269 *              │         retry leaf add     │     │270 *              │           on reentry       │     │271 *              ├────────────────────────────┘     │272 *              │                                  │273 *              v                                  │274 *         need to alloc                           │275 *   ┌─y── or flip flag?                           │276 *   │          │                                  │277 *   │          n                                  │278 *   │          │                                  │279 *   │          v                                  │280 *   │         done                                │281 *   │                                             │282 *   │                                             │283 *   │         XFS_DAS_FOUND_LBLK <────────────────┘284 *   │                  │285 *   │                  V286 *   │        xfs_attr_leaf_addname()287 *   │                  │288 *   │                  v289 *   │      ┌──first time through?290 *   │      │          │291 *   │      │          y292 *   │      │          │293 *   │      n          v294 *   │      │    if we have rmt blks295 *   │      │    find space for them296 *   │      │          │297 *   │      └──────────┤298 *   │                 │299 *   │                 v300 *   │            still have301 *   │      ┌─n─ blks to alloc? <──┐302 *   │      │          │           │303 *   │      │          y           │304 *   │      │          │           │305 *   │      │          v           │306 *   │      │     alloc one blk    │307 *   │      │     return -EAGAIN ──┘308 *   │      │    re-enter with one309 *   │      │    less blk to alloc310 *   │      │311 *   │      │312 *   │      └───> set the rmt313 *   │               value314 *   │                 │315 *   │                 v316 *   │               was this317 *   │              a rename? ──n─┐318 *   │                 │          │319 *   │                 y          │320 *   │                 │          │321 *   │                 v          │322 *   │           flip incomplete  │323 *   │               flag         │324 *   │                 │          │325 *   │                 v          │326 *   │         XFS_DAS_FLIP_LFLAG │327 *   │                 │          │328 *   │                 v          │329 *   │          need to remove    │330 *   │              old bks? ──n──┤331 *   │                 │          │332 *   │                 y          │333 *   │                 │          │334 *   │                 V          │335 *   │               remove       │336 *   │        ┌───> old blks      │337 *   │        │        │          │338 *   │ XFS_DAS_RM_LBLK │          │339 *   │        ^        │          │340 *   │        │        v          │341 *   │        └──y── more to      │342 *   │              remove?       │343 *   │                 │          │344 *   │                 n          │345 *   │                 │          │346 *   │                 v          │347 *   │          XFS_DAS_RD_LEAF   │348 *   │                 │          │349 *   │                 v          │350 *   │            remove leaf     │351 *   │                 │          │352 *   │                 v          │353 *   │            shrink to sf    │354 *   │             if needed      │355 *   │                 │          │356 *   │                 v          │357 *   │                done <──────┘358 *   │359 *   └──────> XFS_DAS_FOUND_NBLK360 *                     │361 *                     v362 *       ┌─────n──  need to363 *       │        alloc blks?364 *       │             │365 *       │             y366 *       │             │367 *       │             v368 *       │        find space369 *       │             │370 *       │             v371 *       │  ┌─>XFS_DAS_ALLOC_NODE372 *       │  │          │373 *       │  │          v374 *       │  │      alloc blk375 *       │  │          │376 *       │  │          v377 *       │  └──y── need to alloc378 *       │         more blocks?379 *       │             │380 *       │             n381 *       │             │382 *       │             v383 *       │      set the rmt value384 *       │             │385 *       │             v386 *       │          was this387 *       └────────> a rename? ──n─┐388 *                     │          │389 *                     y          │390 *                     │          │391 *                     v          │392 *               flip incomplete  │393 *                   flag         │394 *                     │          │395 *                     v          │396 *             XFS_DAS_FLIP_NFLAG │397 *                     │          │398 *                     v          │399 *                 need to        │400 *               remove blks? ─n──┤401 *                     │          │402 *                     y          │403 *                     │          │404 *                     v          │405 *                   remove       │406 *        ┌────────> old blks     │407 *        │            │          │408 *  XFS_DAS_RM_NBLK    │          │409 *        ^            │          │410 *        │            v          │411 *        └──────y── more to      │412 *                   remove       │413 *                     │          │414 *                     n          │415 *                     │          │416 *                     v          │417 *              XFS_DAS_CLR_FLAG  │418 *                     │          │419 *                     v          │420 *                clear flags     │421 *                     │          │422 *                     ├──────────┘423 *                     │424 *                     v425 *                   done426 */427 428/*429 * Enum values for xfs_attr_intent.xattri_da_state430 *431 * These values are used by delayed attribute operations to keep track  of where432 * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the433 * calling function to roll the transaction, and then call the subroutine to434 * finish the operation.  The enum is then used by the subroutine to jump back435 * to where it was and resume executing where it left off.436 */437enum xfs_delattr_state {438	XFS_DAS_UNINIT		= 0,	/* No state has been set yet */439 440	/*441	 * Initial sequence states. The replace setup code relies on the442	 * ADD and REMOVE states for a specific format to be sequential so443	 * that we can transform the initial operation to be performed444	 * according to the xfs_has_larp() state easily.445	 */446	XFS_DAS_SF_ADD,			/* Initial sf add state */447	XFS_DAS_SF_REMOVE,		/* Initial sf replace/remove state */448 449	XFS_DAS_LEAF_ADD,		/* Initial leaf add state */450	XFS_DAS_LEAF_REMOVE,		/* Initial leaf replace/remove state */451 452	XFS_DAS_NODE_ADD,		/* Initial node add state */453	XFS_DAS_NODE_REMOVE,		/* Initial node replace/remove state */454 455	/* Leaf state set/replace/remove sequence */456	XFS_DAS_LEAF_SET_RMT,		/* set a remote xattr from a leaf */457	XFS_DAS_LEAF_ALLOC_RMT,		/* We are allocating remote blocks */458	XFS_DAS_LEAF_REPLACE,		/* Perform replace ops on a leaf */459	XFS_DAS_LEAF_REMOVE_OLD,	/* Start removing old attr from leaf */460	XFS_DAS_LEAF_REMOVE_RMT,	/* A rename is removing remote blocks */461	XFS_DAS_LEAF_REMOVE_ATTR,	/* Remove the old attr from a leaf */462 463	/* Node state sequence, must match leaf state above */464	XFS_DAS_NODE_SET_RMT,		/* set a remote xattr from a node */465	XFS_DAS_NODE_ALLOC_RMT,		/* We are allocating remote blocks */466	XFS_DAS_NODE_REPLACE,		/* Perform replace ops on a node */467	XFS_DAS_NODE_REMOVE_OLD,	/* Start removing old attr from node */468	XFS_DAS_NODE_REMOVE_RMT,	/* A rename is removing remote blocks */469	XFS_DAS_NODE_REMOVE_ATTR,	/* Remove the old attr from a node */470 471	XFS_DAS_DONE,			/* finished operation */472};473 474#define XFS_DAS_STRINGS	\475	{ XFS_DAS_UNINIT,		"XFS_DAS_UNINIT" }, \476	{ XFS_DAS_SF_ADD,		"XFS_DAS_SF_ADD" }, \477	{ XFS_DAS_SF_REMOVE,		"XFS_DAS_SF_REMOVE" }, \478	{ XFS_DAS_LEAF_ADD,		"XFS_DAS_LEAF_ADD" }, \479	{ XFS_DAS_LEAF_REMOVE,		"XFS_DAS_LEAF_REMOVE" }, \480	{ XFS_DAS_NODE_ADD,		"XFS_DAS_NODE_ADD" }, \481	{ XFS_DAS_NODE_REMOVE,		"XFS_DAS_NODE_REMOVE" }, \482	{ XFS_DAS_LEAF_SET_RMT,		"XFS_DAS_LEAF_SET_RMT" }, \483	{ XFS_DAS_LEAF_ALLOC_RMT,	"XFS_DAS_LEAF_ALLOC_RMT" }, \484	{ XFS_DAS_LEAF_REPLACE,		"XFS_DAS_LEAF_REPLACE" }, \485	{ XFS_DAS_LEAF_REMOVE_OLD,	"XFS_DAS_LEAF_REMOVE_OLD" }, \486	{ XFS_DAS_LEAF_REMOVE_RMT,	"XFS_DAS_LEAF_REMOVE_RMT" }, \487	{ XFS_DAS_LEAF_REMOVE_ATTR,	"XFS_DAS_LEAF_REMOVE_ATTR" }, \488	{ XFS_DAS_NODE_SET_RMT,		"XFS_DAS_NODE_SET_RMT" }, \489	{ XFS_DAS_NODE_ALLOC_RMT,	"XFS_DAS_NODE_ALLOC_RMT" },  \490	{ XFS_DAS_NODE_REPLACE,		"XFS_DAS_NODE_REPLACE" },  \491	{ XFS_DAS_NODE_REMOVE_OLD,	"XFS_DAS_NODE_REMOVE_OLD" }, \492	{ XFS_DAS_NODE_REMOVE_RMT,	"XFS_DAS_NODE_REMOVE_RMT" }, \493	{ XFS_DAS_NODE_REMOVE_ATTR,	"XFS_DAS_NODE_REMOVE_ATTR" }, \494	{ XFS_DAS_DONE,			"XFS_DAS_DONE" }495 496struct xfs_attri_log_nameval;497 498/*499 * Context used for keeping track of delayed attribute operations500 */501struct xfs_attr_intent {502	/*503	 * used to log this item to an intent containing a list of attrs to504	 * commit later505	 */506	struct list_head		xattri_list;507 508	/* Used in xfs_attr_node_removename to roll through removing blocks */509	struct xfs_da_state		*xattri_da_state;510 511	struct xfs_da_args		*xattri_da_args;512 513	/*514	 * Shared buffer containing the attr name, new name, and value so that515	 * the logging code can share large memory buffers between log items.516	 */517	struct xfs_attri_log_nameval	*xattri_nameval;518 519	/* Used to keep track of current state of delayed operation */520	enum xfs_delattr_state		xattri_dela_state;521 522	/*523	 * Attr operation being performed - XFS_ATTRI_OP_FLAGS_*524	 */525	unsigned int			xattri_op_flags;526 527	/* Used in xfs_attr_rmtval_set_blk to roll through allocating blocks */528	xfs_dablk_t			xattri_lblkno;529	int				xattri_blkcnt;530	struct xfs_bmbt_irec		xattri_map;531};532 533static inline unsigned int534xfs_attr_intent_op(const struct xfs_attr_intent *attr)535{536	return attr->xattri_op_flags & XFS_ATTRI_OP_FLAGS_TYPE_MASK;537}538 539/*========================================================================540 * Function prototypes for the kernel.541 *========================================================================*/542 543/*544 * Overall external interface routines.545 */546int xfs_attr_inactive(struct xfs_inode *dp);547int xfs_attr_list_ilocked(struct xfs_attr_list_context *);548int xfs_attr_list(struct xfs_attr_list_context *);549int xfs_inode_hasattr(struct xfs_inode *ip);550bool xfs_attr_is_leaf(struct xfs_inode *ip);551int xfs_attr_get_ilocked(struct xfs_da_args *args);552int xfs_attr_get(struct xfs_da_args *args);553 554enum xfs_attr_update {555	XFS_ATTRUPDATE_REMOVE,	/* remove attr */556	XFS_ATTRUPDATE_UPSERT,	/* set value, replace any existing attr */557	XFS_ATTRUPDATE_CREATE,	/* set value, fail if attr already exists */558	XFS_ATTRUPDATE_REPLACE,	/* set value, fail if attr does not exist */559};560 561int xfs_attr_set(struct xfs_da_args *args, enum xfs_attr_update op, bool rsvd);562int xfs_attr_set_iter(struct xfs_attr_intent *attr);563int xfs_attr_remove_iter(struct xfs_attr_intent *attr);564bool xfs_attr_check_namespace(unsigned int attr_flags);565bool xfs_attr_namecheck(unsigned int attr_flags, const void *name,566		size_t length);567int xfs_attr_calc_size(struct xfs_da_args *args, int *local);568struct xfs_trans_res xfs_attr_set_resv(const struct xfs_da_args *args);569 570/*571 * Check to see if the attr should be upgraded from non-existent or shortform to572 * single-leaf-block attribute list.573 */574static inline bool575xfs_attr_is_shortform(576	struct xfs_inode    *ip)577{578	return ip->i_af.if_format == XFS_DINODE_FMT_LOCAL ||579	       (ip->i_af.if_format == XFS_DINODE_FMT_EXTENTS &&580		ip->i_af.if_nextents == 0);581}582 583static inline enum xfs_delattr_state584xfs_attr_init_add_state(struct xfs_da_args *args)585{586	/*587	 * When called from the completion of a attr remove to determine the588	 * next state, the attribute fork may be null. This can occur only occur589	 * on a pure remove, but we grab the next state before we check if a590	 * replace operation is being performed. If we are called from any other591	 * context, i_af is guaranteed to exist. Hence if the attr fork is592	 * null, we were called from a pure remove operation and so we are done.593	 */594	if (!xfs_inode_has_attr_fork(args->dp))595		return XFS_DAS_DONE;596 597	args->op_flags |= XFS_DA_OP_ADDNAME;598	if (xfs_attr_is_shortform(args->dp))599		return XFS_DAS_SF_ADD;600	if (xfs_attr_is_leaf(args->dp))601		return XFS_DAS_LEAF_ADD;602	return XFS_DAS_NODE_ADD;603}604 605static inline enum xfs_delattr_state606xfs_attr_init_remove_state(struct xfs_da_args *args)607{608	if (xfs_attr_is_shortform(args->dp))609		return XFS_DAS_SF_REMOVE;610	if (xfs_attr_is_leaf(args->dp))611		return XFS_DAS_LEAF_REMOVE;612	return XFS_DAS_NODE_REMOVE;613}614 615/*616 * If we are logging the attributes, then we have to start with removal of the617 * old attribute so that there is always consistent state that we can recover618 * from if the system goes down part way through. We always log the new attr619 * value, so even when we remove the attr first we still have the information in620 * the log to finish the replace operation atomically.621 */622static inline enum xfs_delattr_state623xfs_attr_init_replace_state(struct xfs_da_args *args)624{625	args->op_flags |= XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE;626	if (args->op_flags & XFS_DA_OP_LOGGED)627		return xfs_attr_init_remove_state(args);628	return xfs_attr_init_add_state(args);629}630 631xfs_dahash_t xfs_attr_hashname(const uint8_t *name, int namelen);632 633xfs_dahash_t xfs_attr_hashval(struct xfs_mount *mp, unsigned int attr_flags,634		const uint8_t *name, int namelen, const void *value,635		int valuelen);636 637/* Set the hash value for any extended attribute from any namespace. */638static inline void xfs_attr_sethash(struct xfs_da_args *args)639{640	args->hashval = xfs_attr_hashval(args->dp->i_mount, args->attr_filter,641					 args->name, args->namelen,642					 args->value, args->valuelen);643}644 645extern struct kmem_cache *xfs_attr_intent_cache;646int __init xfs_attr_intent_init_cache(void);647void xfs_attr_intent_destroy_cache(void);648 649int xfs_attr_sf_totsize(struct xfs_inode *dp);650int xfs_attr_add_fork(struct xfs_inode *ip, int size, int rsvd);651 652#endif	/* __XFS_ATTR_H__ */653