Line data Source code
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 :
9 : struct xfs_inode;
10 : struct xfs_da_args;
11 : struct 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 : */
34 : struct 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 */
50 : typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
51 : unsigned char *, int, int);
52 :
53 : struct 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 : */
436 : enum 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 :
495 : struct xfs_attri_log_nameval;
496 :
497 : /*
498 : * Context used for keeping track of delayed attribute operations
499 : */
500 : struct 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 : */
540 : int xfs_attr_inactive(struct xfs_inode *dp);
541 : int xfs_attr_list_ilocked(struct xfs_attr_list_context *);
542 : int xfs_attr_list(struct xfs_attr_list_context *);
543 : int xfs_inode_hasattr(struct xfs_inode *ip);
544 : bool xfs_attr_is_leaf(struct xfs_inode *ip);
545 : int xfs_attr_get_ilocked(struct xfs_da_args *args);
546 : int xfs_attr_get(struct xfs_da_args *args);
547 : int xfs_attr_set(struct xfs_da_args *args);
548 : int xfs_attr_set_iter(struct xfs_attr_intent *attr);
549 : int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
550 : bool xfs_attr_namecheck(const void *name, size_t length);
551 : int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
552 : void 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 : */
559 : static inline bool
560 : xfs_attr_is_shortform(
561 : struct xfs_inode *ip)
562 : {
563 95730012 : return ip->i_af.if_format == XFS_DINODE_FMT_LOCAL ||
564 95767416 : (ip->i_af.if_format == XFS_DINODE_FMT_EXTENTS &&
565 95767416 : ip->i_af.if_nextents == 0);
566 : }
567 :
568 : static inline enum xfs_delattr_state
569 103736796 : xfs_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 103736796 : if (!xfs_inode_has_attr_fork(args->dp))
580 : return XFS_DAS_DONE;
581 :
582 102834617 : args->op_flags |= XFS_DA_OP_ADDNAME;
583 180686394 : if (xfs_attr_is_shortform(args->dp))
584 : return XFS_DAS_SF_ADD;
585 72955908 : if (xfs_attr_is_leaf(args->dp))
586 71166060 : return XFS_DAS_LEAF_ADD;
587 : return XFS_DAS_NODE_ADD;
588 : }
589 :
590 : static inline enum xfs_delattr_state
591 23310333 : xfs_attr_init_remove_state(struct xfs_da_args *args)
592 : {
593 23310333 : args->op_flags |= XFS_DA_OP_REMOVE;
594 41188568 : if (xfs_attr_is_shortform(args->dp))
595 : return XFS_DAS_SF_REMOVE;
596 17868761 : if (xfs_attr_is_leaf(args->dp))
597 17494721 : 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 : */
608 : static inline enum xfs_delattr_state
609 16831803 : xfs_attr_init_replace_state(struct xfs_da_args *args)
610 : {
611 16831803 : args->op_flags |= XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE;
612 16831803 : if (args->op_flags & XFS_DA_OP_LOGGED)
613 251850 : return xfs_attr_init_remove_state(args);
614 16579953 : return xfs_attr_init_add_state(args);
615 : }
616 :
617 : extern struct kmem_cache *xfs_attr_intent_cache;
618 : int __init xfs_attr_intent_init_cache(void);
619 : void xfs_attr_intent_destroy_cache(void);
620 :
621 : #endif /* __XFS_ATTR_H__ */
|