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__ */ 622