Linux Audio

Check our new training course

Loading...
v6.9.4
  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 data
 15 * 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 hashval
 17 * 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 tightly
 21 * 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 an
 26 * attribute value or the buffer used for an attr_list() call.  Larger
 27 * 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 *, int,
 51			      unsigned char *, int, int);
 
 52
 53struct xfs_attr_list_context {
 54	struct xfs_trans	*tp;
 55	struct xfs_inode	*dp;		/* inode */
 56	struct xfs_attrlist_cursor_kern cursor;	/* position in list */
 57	void			*buffer;	/* output buffer */
 58
 59	/*
 60	 * Abort attribute list iteration if non-zero.  Can be used to pass
 61	 * error values to the xfs_attr_list caller.
 62	 */
 63	int			seen_enough;
 64	bool			allow_incomplete;
 65
 66	ssize_t			count;		/* num used entries */
 67	int			dupcnt;		/* count dup hashvals seen */
 68	int			bufsize;	/* total buffer size */
 69	int			firstu;		/* first used byte in buffer */
 70	unsigned int		attr_filter;	/* XFS_ATTR_{ROOT,SECURE} */
 71	int			resynch;	/* T/F: resynch with cursor */
 72	put_listent_func_t	put_listent;	/* list output fmt function */
 73	int			index;		/* index into output buffer */
 74};
 75
 76
 77/*
 78 * ========================================================================
 79 * Structure used to pass context around among the delayed routines.
 80 * ========================================================================
 81 */
 82
 83/*
 84 * Below is a state machine diagram for attr remove operations. The  XFS_DAS_*
 85 * states indicate places where the function would return -EAGAIN, and then
 86 * immediately resume from after being called by the calling function. States
 87 * marked as a "subroutine state" indicate that they belong to a subroutine, and
 88 * so the calling function needs to pass them back to that subroutine to allow
 89 * it to finish where it left off. But they otherwise do not have a role in the
 90 * calling function other than just passing through.
 91 *
 92 * xfs_attr_remove_iter()
 93 *              │
 94 *              v
 95 *        have attr to remove? ──n──> done
 96 *              │
 97 *              y
 98 *              │
 99 *              v
100 *        are we short form? ──y──> xfs_attr_shortform_remove ──> done
101 *              │
102 *              n
103 *              │
104 *              V
105 *        are we leaf form? ──y──> xfs_attr_leaf_removename ──> done
106 *              │
107 *              n
108 *              │
109 *              V
110 *   ┌── need to setup state?
111 *   │          │
112 *   n          y
113 *   │          │
114 *   │          v
115 *   │ find attr and get state
116 *   │ attr has remote blks? ──n─┐
117 *   │          │                v
118 *   │          │         find and invalidate
119 *   │          y         the remote blocks.
120 *   │          │         mark attr incomplete
121 *   │          ├────────────────┘
122 *   └──────────┤
123 *              │
124 *              v
125 *   Have remote blks to remove? ───y─────┐
126 *              │        ^          remove the blks
127 *              │        │                │
128 *              │        │                v
129 *              │  XFS_DAS_RMTBLK <─n── done?
130 *              │  re-enter with          │
131 *              │  one less blk to        y
132 *              │      remove             │
133 *              │                         V
134 *              │                  refill the state
135 *              n                         │
136 *              │                         v
137 *              │                   XFS_DAS_RM_NAME
138 *              │                         │
139 *              ├─────────────────────────┘
140 *              │
141 *              v
142 *       remove leaf and
143 *       update hash with
144 *   xfs_attr_node_remove_cleanup
145 *              │
146 *              v
147 *           need to
148 *        shrink tree? ─n─┐
149 *              │         │
150 *              y         │
151 *              │         │
152 *              v         │
153 *          join leaf     │
154 *              │         │
155 *              v         │
156 *      XFS_DAS_RM_SHRINK │
157 *              │         │
158 *              v         │
159 *       do the shrink    │
160 *              │         │
161 *              v         │
162 *          free state <──┘
163 *              │
164 *              v
165 *            done
166 *
167 *
168 * Below is a state machine diagram for attr set operations.
169 *
170 * It seems the challenge with understanding this system comes from trying to
171 * absorb the state machine all at once, when really one should only be looking
172 * at it with in the context of a single function. Once a state sensitive
173 * function is called, the idea is that it "takes ownership" of the
174 * state machine. It isn't concerned with the states that may have belonged to
175 * it's calling parent. Only the states relevant to itself or any other
176 * subroutines there in. Once a calling function hands off the state machine to
177 * a subroutine, it needs to respect the simple rule that it doesn't "own" the
178 * state machine anymore, and it's the responsibility of that calling function
179 * to propagate the -EAGAIN back up the call stack. Upon reentry, it is
180 * committed to re-calling that subroutine until it returns something other than
181 * -EAGAIN. Once that subroutine signals completion (by returning anything other
182 * than -EAGAIN), the calling function can resume using the state machine.
183 *
184 *  xfs_attr_set_iter()
185 *              │
186 *              v
187 *   ┌─y─ has an attr fork?
188 *   │          |
189 *   │          n
190 *   │          |
191 *   │          V
192 *   │       add a fork
193 *   │          │
194 *   └──────────┤
195 *              │
196 *              V
197 *   ┌─── is shortform?
198 *   │          │
199 *   │          y
200 *   │          │
201 *   │          V
202 *   │   xfs_attr_set_fmt
203 *   │          |
204 *   │          V
205 *   │ xfs_attr_try_sf_addname
206 *   │          │
207 *   │          V
208 *   │      had enough ──y──> done
209 *   │        space?
210 *   n          │
211 *   │          n
212 *   │          │
213 *   │          V
214 *   │   transform to leaf
215 *   │          │
216 *   │          V
217 *   │   hold the leaf buffer
218 *   │          │
219 *   │          V
220 *   │     return -EAGAIN
221 *   │      Re-enter in
222 *   │       leaf form
223 *   │
224 *   └─> release leaf buffer
225 *          if needed
226 *              │
227 *              V
228 *   ┌───n── fork has
229 *   │      only 1 blk?
230 *   │          │
231 *   │          y
232 *   │          │
233 *   │          v
234 *   │ xfs_attr_leaf_try_add()
235 *   │          │
236 *   │          v
237 *   │      had enough ──────────────y─────────────┐
238 *   │        space?                               │
239 *   │          │                                  │
240 *   │          n                                  │
241 *   │          │                                  │
242 *   │          v                                  │
243 *   │    return -EAGAIN                           │
244 *   │      re-enter in                            │
245 *   │        node form                            │
246 *   │          │                                  │
247 *   └──────────┤                                  │
248 *              │                                  │
249 *              V                                  │
250 * xfs_attr_node_addname_find_attr                 │
251 *        determines if this                       │
252 *       is create or rename                       │
253 *     find space to store attr                    │
254 *              │                                  │
255 *              v                                  │
256 *     xfs_attr_node_addname                       │
257 *              │                                  │
258 *              v                                  │
259 *   fits in a node leaf? ────n─────┐              │
260 *              │     ^             v              │
261 *              │     │       single leaf node?    │
262 *              │     │         │            │     │
263 *              y     │         y            n     │
264 *              │     │         │            │     │
265 *              v     │         v            v     │
266 *            update  │    grow the leaf  split if │
267 *           hashvals └── return -EAGAIN   needed  │
268 *              │         retry leaf add     │     │
269 *              │           on reentry       │     │
270 *              ├────────────────────────────┘     │
271 *              │                                  │
272 *              v                                  │
273 *         need to alloc                           │
274 *   ┌─y── or flip flag?                           │
275 *   │          │                                  │
276 *   │          n                                  │
277 *   │          │                                  │
278 *   │          v                                  │
279 *   │         done                                │
280 *   │                                             │
281 *   │                                             │
282 *   │         XFS_DAS_FOUND_LBLK <────────────────┘
283 *   │                  │
284 *   │                  V
285 *   │        xfs_attr_leaf_addname()
286 *   │                  │
287 *   │                  v
288 *   │      ┌──first time through?
289 *   │      │          │
290 *   │      │          y
291 *   │      │          │
292 *   │      n          v
293 *   │      │    if we have rmt blks
294 *   │      │    find space for them
295 *   │      │          │
296 *   │      └──────────┤
297 *   │                 │
298 *   │                 v
299 *   │            still have
300 *   │      ┌─n─ blks to alloc? <──┐
301 *   │      │          │           │
302 *   │      │          y           │
303 *   │      │          │           │
304 *   │      │          v           │
305 *   │      │     alloc one blk    │
306 *   │      │     return -EAGAIN ──┘
307 *   │      │    re-enter with one
308 *   │      │    less blk to alloc
309 *   │      │
310 *   │      │
311 *   │      └───> set the rmt
312 *   │               value
313 *   │                 │
314 *   │                 v
315 *   │               was this
316 *   │              a rename? ──n─┐
317 *   │                 │          │
318 *   │                 y          │
319 *   │                 │          │
320 *   │                 v          │
321 *   │           flip incomplete  │
322 *   │               flag         │
323 *   │                 │          │
324 *   │                 v          │
325 *   │         XFS_DAS_FLIP_LFLAG │
326 *   │                 │          │
327 *   │                 v          │
328 *   │          need to remove    │
329 *   │              old bks? ──n──┤
330 *   │                 │          │
331 *   │                 y          │
332 *   │                 │          │
333 *   │                 V          │
334 *   │               remove       │
335 *   │        ┌───> old blks      │
336 *   │        │        │          │
337 *   │ XFS_DAS_RM_LBLK │          │
338 *   │        ^        │          │
339 *   │        │        v          │
340 *   │        └──y── more to      │
341 *   │              remove?       │
342 *   │                 │          │
343 *   │                 n          │
344 *   │                 │          │
345 *   │                 v          │
346 *   │          XFS_DAS_RD_LEAF   │
347 *   │                 │          │
348 *   │                 v          │
349 *   │            remove leaf     │
350 *   │                 │          │
351 *   │                 v          │
352 *   │            shrink to sf    │
353 *   │             if needed      │
354 *   │                 │          │
355 *   │                 v          │
356 *   │                done <──────┘
357 *   │
358 *   └──────> XFS_DAS_FOUND_NBLK
359 *                     │
360 *                     v
361 *       ┌─────n──  need to
362 *       │        alloc blks?
363 *       │             │
364 *       │             y
365 *       │             │
366 *       │             v
367 *       │        find space
368 *       │             │
369 *       │             v
370 *       │  ┌─>XFS_DAS_ALLOC_NODE
371 *       │  │          │
372 *       │  │          v
373 *       │  │      alloc blk
374 *       │  │          │
375 *       │  │          v
376 *       │  └──y── need to alloc
377 *       │         more blocks?
378 *       │             │
379 *       │             n
380 *       │             │
381 *       │             v
382 *       │      set the rmt value
383 *       │             │
384 *       │             v
385 *       │          was this
386 *       └────────> a rename? ──n─┐
387 *                     │          │
388 *                     y          │
389 *                     │          │
390 *                     v          │
391 *               flip incomplete  │
392 *                   flag         │
393 *                     │          │
394 *                     v          │
395 *             XFS_DAS_FLIP_NFLAG │
396 *                     │          │
397 *                     v          │
398 *                 need to        │
399 *               remove blks? ─n──┤
400 *                     │          │
401 *                     y          │
402 *                     │          │
403 *                     v          │
404 *                   remove       │
405 *        ┌────────> old blks     │
406 *        │            │          │
407 *  XFS_DAS_RM_NBLK    │          │
408 *        ^            │          │
409 *        │            v          │
410 *        └──────y── more to      │
411 *                   remove       │
412 *                     │          │
413 *                     n          │
414 *                     │          │
415 *                     v          │
416 *              XFS_DAS_CLR_FLAG  │
417 *                     │          │
418 *                     v          │
419 *                clear flags     │
420 *                     │          │
421 *                     ├──────────┘
422 *                     │
423 *                     v
424 *                   done
425 */
426
427/*
428 * Enum values for xfs_attr_intent.xattri_da_state
429 *
430 * These values are used by delayed attribute operations to keep track  of where
431 * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
432 * calling function to roll the transaction, and then call the subroutine to
433 * finish the operation.  The enum is then used by the subroutine to jump back
434 * to where it was and resume executing where it left off.
435 */
436enum xfs_delattr_state {
437	XFS_DAS_UNINIT		= 0,	/* No state has been set yet */
438
439	/*
440	 * Initial sequence states. The replace setup code relies on the
441	 * ADD and REMOVE states for a specific format to be sequential so
442	 * that we can transform the initial operation to be performed
443	 * according to the xfs_has_larp() state easily.
444	 */
445	XFS_DAS_SF_ADD,			/* Initial sf add state */
446	XFS_DAS_SF_REMOVE,		/* Initial sf replace/remove state */
447
448	XFS_DAS_LEAF_ADD,		/* Initial leaf add state */
449	XFS_DAS_LEAF_REMOVE,		/* Initial leaf replace/remove state */
450
451	XFS_DAS_NODE_ADD,		/* Initial node add state */
452	XFS_DAS_NODE_REMOVE,		/* Initial node replace/remove state */
453
454	/* Leaf state set/replace/remove sequence */
455	XFS_DAS_LEAF_SET_RMT,		/* set a remote xattr from a leaf */
456	XFS_DAS_LEAF_ALLOC_RMT,		/* We are allocating remote blocks */
457	XFS_DAS_LEAF_REPLACE,		/* Perform replace ops on a leaf */
458	XFS_DAS_LEAF_REMOVE_OLD,	/* Start removing old attr from leaf */
459	XFS_DAS_LEAF_REMOVE_RMT,	/* A rename is removing remote blocks */
460	XFS_DAS_LEAF_REMOVE_ATTR,	/* Remove the old attr from a leaf */
461
462	/* Node state sequence, must match leaf state above */
463	XFS_DAS_NODE_SET_RMT,		/* set a remote xattr from a node */
464	XFS_DAS_NODE_ALLOC_RMT,		/* We are allocating remote blocks */
465	XFS_DAS_NODE_REPLACE,		/* Perform replace ops on a node */
466	XFS_DAS_NODE_REMOVE_OLD,	/* Start removing old attr from node */
467	XFS_DAS_NODE_REMOVE_RMT,	/* A rename is removing remote blocks */
468	XFS_DAS_NODE_REMOVE_ATTR,	/* Remove the old attr from a node */
469
470	XFS_DAS_DONE,			/* finished operation */
471};
472
473#define XFS_DAS_STRINGS	\
474	{ XFS_DAS_UNINIT,		"XFS_DAS_UNINIT" }, \
475	{ XFS_DAS_SF_ADD,		"XFS_DAS_SF_ADD" }, \
476	{ XFS_DAS_SF_REMOVE,		"XFS_DAS_SF_REMOVE" }, \
477	{ XFS_DAS_LEAF_ADD,		"XFS_DAS_LEAF_ADD" }, \
478	{ XFS_DAS_LEAF_REMOVE,		"XFS_DAS_LEAF_REMOVE" }, \
479	{ XFS_DAS_NODE_ADD,		"XFS_DAS_NODE_ADD" }, \
480	{ XFS_DAS_NODE_REMOVE,		"XFS_DAS_NODE_REMOVE" }, \
481	{ XFS_DAS_LEAF_SET_RMT,		"XFS_DAS_LEAF_SET_RMT" }, \
482	{ XFS_DAS_LEAF_ALLOC_RMT,	"XFS_DAS_LEAF_ALLOC_RMT" }, \
483	{ XFS_DAS_LEAF_REPLACE,		"XFS_DAS_LEAF_REPLACE" }, \
484	{ XFS_DAS_LEAF_REMOVE_OLD,	"XFS_DAS_LEAF_REMOVE_OLD" }, \
485	{ XFS_DAS_LEAF_REMOVE_RMT,	"XFS_DAS_LEAF_REMOVE_RMT" }, \
486	{ XFS_DAS_LEAF_REMOVE_ATTR,	"XFS_DAS_LEAF_REMOVE_ATTR" }, \
487	{ XFS_DAS_NODE_SET_RMT,		"XFS_DAS_NODE_SET_RMT" }, \
488	{ XFS_DAS_NODE_ALLOC_RMT,	"XFS_DAS_NODE_ALLOC_RMT" },  \
489	{ XFS_DAS_NODE_REPLACE,		"XFS_DAS_NODE_REPLACE" },  \
490	{ XFS_DAS_NODE_REMOVE_OLD,	"XFS_DAS_NODE_REMOVE_OLD" }, \
491	{ XFS_DAS_NODE_REMOVE_RMT,	"XFS_DAS_NODE_REMOVE_RMT" }, \
492	{ XFS_DAS_NODE_REMOVE_ATTR,	"XFS_DAS_NODE_REMOVE_ATTR" }, \
493	{ XFS_DAS_DONE,			"XFS_DAS_DONE" }
494
495struct xfs_attri_log_nameval;
496
497/*
498 * Context used for keeping track of delayed attribute operations
499 */
500struct xfs_attr_intent {
501	/*
502	 * used to log this item to an intent containing a list of attrs to
503	 * commit later
504	 */
505	struct list_head		xattri_list;
506
507	/* Used in xfs_attr_node_removename to roll through removing blocks */
508	struct xfs_da_state		*xattri_da_state;
509
510	struct xfs_da_args		*xattri_da_args;
511
512	/*
513	 * Shared buffer containing the attr name and value so that the logging
514	 * code can share large memory buffers between log items.
515	 */
516	struct xfs_attri_log_nameval	*xattri_nameval;
517
518	/* Used to keep track of current state of delayed operation */
519	enum xfs_delattr_state		xattri_dela_state;
520
521	/*
522	 * Attr operation being performed - XFS_ATTRI_OP_FLAGS_*
523	 */
524	unsigned int			xattri_op_flags;
525
526	/* Used in xfs_attr_rmtval_set_blk to roll through allocating blocks */
527	xfs_dablk_t			xattri_lblkno;
528	int				xattri_blkcnt;
529	struct xfs_bmbt_irec		xattri_map;
530};
531
 
 
 
 
 
532
533/*========================================================================
534 * Function prototypes for the kernel.
535 *========================================================================*/
536
537/*
538 * Overall external interface routines.
539 */
540int xfs_attr_inactive(struct xfs_inode *dp);
541int xfs_attr_list_ilocked(struct xfs_attr_list_context *);
542int xfs_attr_list(struct xfs_attr_list_context *);
543int xfs_inode_hasattr(struct xfs_inode *ip);
544bool xfs_attr_is_leaf(struct xfs_inode *ip);
545int xfs_attr_get_ilocked(struct xfs_da_args *args);
546int xfs_attr_get(struct xfs_da_args *args);
547int xfs_attr_set(struct xfs_da_args *args);
 
 
 
 
 
 
 
 
548int xfs_attr_set_iter(struct xfs_attr_intent *attr);
549int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
550bool xfs_attr_namecheck(const void *name, size_t length);
 
 
551int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
552void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres,
553			 unsigned int *total);
554
555/*
556 * Check to see if the attr should be upgraded from non-existent or shortform to
557 * single-leaf-block attribute list.
558 */
559static inline bool
560xfs_attr_is_shortform(
561	struct xfs_inode    *ip)
562{
563	return ip->i_af.if_format == XFS_DINODE_FMT_LOCAL ||
564	       (ip->i_af.if_format == XFS_DINODE_FMT_EXTENTS &&
565		ip->i_af.if_nextents == 0);
566}
567
568static inline enum xfs_delattr_state
569xfs_attr_init_add_state(struct xfs_da_args *args)
570{
571	/*
572	 * When called from the completion of a attr remove to determine the
573	 * next state, the attribute fork may be null. This can occur only occur
574	 * on a pure remove, but we grab the next state before we check if a
575	 * replace operation is being performed. If we are called from any other
576	 * context, i_af is guaranteed to exist. Hence if the attr fork is
577	 * null, we were called from a pure remove operation and so we are done.
578	 */
579	if (!xfs_inode_has_attr_fork(args->dp))
580		return XFS_DAS_DONE;
581
582	args->op_flags |= XFS_DA_OP_ADDNAME;
583	if (xfs_attr_is_shortform(args->dp))
584		return XFS_DAS_SF_ADD;
585	if (xfs_attr_is_leaf(args->dp))
586		return XFS_DAS_LEAF_ADD;
587	return XFS_DAS_NODE_ADD;
588}
589
590static inline enum xfs_delattr_state
591xfs_attr_init_remove_state(struct xfs_da_args *args)
592{
593	args->op_flags |= XFS_DA_OP_REMOVE;
594	if (xfs_attr_is_shortform(args->dp))
595		return XFS_DAS_SF_REMOVE;
596	if (xfs_attr_is_leaf(args->dp))
597		return XFS_DAS_LEAF_REMOVE;
598	return XFS_DAS_NODE_REMOVE;
599}
600
601/*
602 * If we are logging the attributes, then we have to start with removal of the
603 * old attribute so that there is always consistent state that we can recover
604 * from if the system goes down part way through. We always log the new attr
605 * value, so even when we remove the attr first we still have the information in
606 * the log to finish the replace operation atomically.
607 */
608static inline enum xfs_delattr_state
609xfs_attr_init_replace_state(struct xfs_da_args *args)
610{
611	args->op_flags |= XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE;
612	if (args->op_flags & XFS_DA_OP_LOGGED)
613		return xfs_attr_init_remove_state(args);
614	return xfs_attr_init_add_state(args);
615}
616
 
 
 
 
 
 
 
 
 
 
 
 
 
 
617extern struct kmem_cache *xfs_attr_intent_cache;
618int __init xfs_attr_intent_init_cache(void);
619void xfs_attr_intent_destroy_cache(void);
 
 
 
620
621#endif	/* __XFS_ATTR_H__ */
v6.13.7
  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 data
 15 * 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 hashval
 17 * 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 tightly
 21 * 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 an
 26 * attribute value or the buffer used for an attr_list() call.  Larger
 27 * 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 pass
 62	 * 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 then
 87 * immediately resume from after being called by the calling function. States
 88 * marked as a "subroutine state" indicate that they belong to a subroutine, and
 89 * so the calling function needs to pass them back to that subroutine to allow
 90 * it to finish where it left off. But they otherwise do not have a role in the
 91 * calling function other than just passing through.
 92 *
 93 * xfs_attr_remove_iter()
 94 *              │
 95 *              v
 96 *        have attr to remove? ──n──> done
 97 *              │
 98 *              y
 99 *              │
100 *              v
101 *        are we short form? ──y──> xfs_attr_shortform_remove ──> done
102 *              │
103 *              n
104 *              │
105 *              V
106 *        are we leaf form? ──y──> xfs_attr_leaf_removename ──> done
107 *              │
108 *              n
109 *              │
110 *              V
111 *   ┌── need to setup state?
112 *   │          │
113 *   n          y
114 *   │          │
115 *   │          v
116 *   │ find attr and get state
117 *   │ attr has remote blks? ──n─┐
118 *   │          │                v
119 *   │          │         find and invalidate
120 *   │          y         the remote blocks.
121 *   │          │         mark attr incomplete
122 *   │          ├────────────────┘
123 *   └──────────┤
124 *              │
125 *              v
126 *   Have remote blks to remove? ───y─────┐
127 *              │        ^          remove the blks
128 *              │        │                │
129 *              │        │                v
130 *              │  XFS_DAS_RMTBLK <─n── done?
131 *              │  re-enter with          │
132 *              │  one less blk to        y
133 *              │      remove             │
134 *              │                         V
135 *              │                  refill the state
136 *              n                         │
137 *              │                         v
138 *              │                   XFS_DAS_RM_NAME
139 *              │                         │
140 *              ├─────────────────────────┘
141 *              │
142 *              v
143 *       remove leaf and
144 *       update hash with
145 *   xfs_attr_node_remove_cleanup
146 *              │
147 *              v
148 *           need to
149 *        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 *              v
166 *            done
167 *
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 to
172 * absorb the state machine all at once, when really one should only be looking
173 * at it with in the context of a single function. Once a state sensitive
174 * function is called, the idea is that it "takes ownership" of the
175 * state machine. It isn't concerned with the states that may have belonged to
176 * it's calling parent. Only the states relevant to itself or any other
177 * subroutines there in. Once a calling function hands off the state machine to
178 * a subroutine, it needs to respect the simple rule that it doesn't "own" the
179 * state machine anymore, and it's the responsibility of that calling function
180 * to propagate the -EAGAIN back up the call stack. Upon reentry, it is
181 * committed to re-calling that subroutine until it returns something other than
182 * -EAGAIN. Once that subroutine signals completion (by returning anything other
183 * than -EAGAIN), the calling function can resume using the state machine.
184 *
185 *  xfs_attr_set_iter()
186 *              │
187 *              v
188 *   ┌─y─ has an attr fork?
189 *   │          |
190 *   │          n
191 *   │          |
192 *   │          V
193 *   │       add a fork
194 *   │          │
195 *   └──────────┤
196 *              │
197 *              V
198 *   ┌─── is shortform?
199 *   │          │
200 *   │          y
201 *   │          │
202 *   │          V
203 *   │   xfs_attr_set_fmt
204 *   │          |
205 *   │          V
206 *   │ xfs_attr_try_sf_addname
207 *   │          │
208 *   │          V
209 *   │      had enough ──y──> done
210 *   │        space?
211 *   n          │
212 *   │          n
213 *   │          │
214 *   │          V
215 *   │   transform to leaf
216 *   │          │
217 *   │          V
218 *   │   hold the leaf buffer
219 *   │          │
220 *   │          V
221 *   │     return -EAGAIN
222 *   │      Re-enter in
223 *   │       leaf form
224 *   │
225 *   └─> release leaf buffer
226 *          if needed
227 *              │
228 *              V
229 *   ┌───n── fork has
230 *   │      only 1 blk?
231 *   │          │
232 *   │          y
233 *   │          │
234 *   │          v
235 *   │ xfs_attr_leaf_try_add()
236 *   │          │
237 *   │          v
238 *   │      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 *   │                  V
286 *   │        xfs_attr_leaf_addname()
287 *   │                  │
288 *   │                  v
289 *   │      ┌──first time through?
290 *   │      │          │
291 *   │      │          y
292 *   │      │          │
293 *   │      n          v
294 *   │      │    if we have rmt blks
295 *   │      │    find space for them
296 *   │      │          │
297 *   │      └──────────┤
298 *   │                 │
299 *   │                 v
300 *   │            still have
301 *   │      ┌─n─ blks to alloc? <──┐
302 *   │      │          │           │
303 *   │      │          y           │
304 *   │      │          │           │
305 *   │      │          v           │
306 *   │      │     alloc one blk    │
307 *   │      │     return -EAGAIN ──┘
308 *   │      │    re-enter with one
309 *   │      │    less blk to alloc
310 *   │      │
311 *   │      │
312 *   │      └───> set the rmt
313 *   │               value
314 *   │                 │
315 *   │                 v
316 *   │               was this
317 *   │              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_NBLK
360 *                     │
361 *                     v
362 *       ┌─────n──  need to
363 *       │        alloc blks?
364 *       │             │
365 *       │             y
366 *       │             │
367 *       │             v
368 *       │        find space
369 *       │             │
370 *       │             v
371 *       │  ┌─>XFS_DAS_ALLOC_NODE
372 *       │  │          │
373 *       │  │          v
374 *       │  │      alloc blk
375 *       │  │          │
376 *       │  │          v
377 *       │  └──y── need to alloc
378 *       │         more blocks?
379 *       │             │
380 *       │             n
381 *       │             │
382 *       │             v
383 *       │      set the rmt value
384 *       │             │
385 *       │             v
386 *       │          was this
387 *       └────────> 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 *                     v
425 *                   done
426 */
427
428/*
429 * Enum values for xfs_attr_intent.xattri_da_state
430 *
431 * These values are used by delayed attribute operations to keep track  of where
432 * they were before they returned -EAGAIN.  A return code of -EAGAIN signals the
433 * calling function to roll the transaction, and then call the subroutine to
434 * finish the operation.  The enum is then used by the subroutine to jump back
435 * 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 the
442	 * ADD and REMOVE states for a specific format to be sequential so
443	 * that we can transform the initial operation to be performed
444	 * 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 operations
500 */
501struct xfs_attr_intent {
502	/*
503	 * used to log this item to an intent containing a list of attrs to
504	 * commit later
505	 */
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 that
515	 * 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 int
534xfs_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 to
572 * single-leaf-block attribute list.
573 */
574static inline bool
575xfs_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_state
584xfs_attr_init_add_state(struct xfs_da_args *args)
585{
586	/*
587	 * When called from the completion of a attr remove to determine the
588	 * next state, the attribute fork may be null. This can occur only occur
589	 * on a pure remove, but we grab the next state before we check if a
590	 * replace operation is being performed. If we are called from any other
591	 * context, i_af is guaranteed to exist. Hence if the attr fork is
592	 * 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_state
606xfs_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 the
617 * old attribute so that there is always consistent state that we can recover
618 * from if the system goes down part way through. We always log the new attr
619 * value, so even when we remove the attr first we still have the information in
620 * the log to finish the replace operation atomically.
621 */
622static inline enum xfs_delattr_state
623xfs_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__ */