1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. |
4 | * All Rights Reserved. |
5 | */ |
6 | #include "xfs.h" |
7 | #include "xfs_fs.h" |
8 | #include "xfs_shared.h" |
9 | #include "xfs_format.h" |
10 | #include "xfs_log_format.h" |
11 | #include "xfs_trans_resv.h" |
12 | #include "xfs_mount.h" |
13 | #include "xfs_defer.h" |
14 | #include "xfs_da_format.h" |
15 | #include "xfs_da_btree.h" |
16 | #include "xfs_attr_sf.h" |
17 | #include "xfs_inode.h" |
18 | #include "xfs_trans.h" |
19 | #include "xfs_bmap.h" |
20 | #include "xfs_bmap_btree.h" |
21 | #include "xfs_attr.h" |
22 | #include "xfs_attr_leaf.h" |
23 | #include "xfs_attr_remote.h" |
24 | #include "xfs_quota.h" |
25 | #include "xfs_trans_space.h" |
26 | #include "xfs_trace.h" |
27 | #include "xfs_attr_item.h" |
28 | #include "xfs_xattr.h" |
29 | |
30 | struct kmem_cache *xfs_attr_intent_cache; |
31 | |
32 | /* |
33 | * xfs_attr.c |
34 | * |
35 | * Provide the external interfaces to manage attribute lists. |
36 | */ |
37 | |
38 | /*======================================================================== |
39 | * Function prototypes for the kernel. |
40 | *========================================================================*/ |
41 | |
42 | /* |
43 | * Internal routines when attribute list fits inside the inode. |
44 | */ |
45 | STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); |
46 | |
47 | /* |
48 | * Internal routines when attribute list is one block. |
49 | */ |
50 | STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); |
51 | STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); |
52 | STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp); |
53 | STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args); |
54 | |
55 | /* |
56 | * Internal routines when attribute list is more than one block. |
57 | */ |
58 | STATIC int xfs_attr_node_get(xfs_da_args_t *args); |
59 | STATIC void xfs_attr_restore_rmt_blk(struct xfs_da_args *args); |
60 | static int xfs_attr_node_try_addname(struct xfs_attr_intent *attr); |
61 | STATIC int xfs_attr_node_addname_find_attr(struct xfs_attr_intent *attr); |
62 | STATIC int xfs_attr_node_remove_attr(struct xfs_attr_intent *attr); |
63 | STATIC int xfs_attr_node_lookup(struct xfs_da_args *args, |
64 | struct xfs_da_state *state); |
65 | |
66 | int |
67 | xfs_inode_hasattr( |
68 | struct xfs_inode *ip) |
69 | { |
70 | if (!xfs_inode_has_attr_fork(ip)) |
71 | return 0; |
72 | if (ip->i_af.if_format == XFS_DINODE_FMT_EXTENTS && |
73 | ip->i_af.if_nextents == 0) |
74 | return 0; |
75 | return 1; |
76 | } |
77 | |
78 | /* |
79 | * Returns true if the there is exactly only block in the attr fork, in which |
80 | * case the attribute fork consists of a single leaf block entry. |
81 | */ |
82 | bool |
83 | xfs_attr_is_leaf( |
84 | struct xfs_inode *ip) |
85 | { |
86 | struct xfs_ifork *ifp = &ip->i_af; |
87 | struct xfs_iext_cursor icur; |
88 | struct xfs_bmbt_irec imap; |
89 | |
90 | if (ifp->if_nextents != 1 || ifp->if_format != XFS_DINODE_FMT_EXTENTS) |
91 | return false; |
92 | |
93 | xfs_iext_first(ifp, &icur); |
94 | xfs_iext_get_extent(ifp, &icur, &imap); |
95 | return imap.br_startoff == 0 && imap.br_blockcount == 1; |
96 | } |
97 | |
98 | /* |
99 | * XXX (dchinner): name path state saving and refilling is an optimisation to |
100 | * avoid needing to look up name entries after rolling transactions removing |
101 | * remote xattr blocks between the name entry lookup and name entry removal. |
102 | * This optimisation got sidelined when combining the set and remove state |
103 | * machines, but the code has been left in place because it is worthwhile to |
104 | * restore the optimisation once the combined state machine paths have settled. |
105 | * |
106 | * This comment is a public service announcement to remind Future Dave that he |
107 | * still needs to restore this code to working order. |
108 | */ |
109 | #if 0 |
110 | /* |
111 | * Fill in the disk block numbers in the state structure for the buffers |
112 | * that are attached to the state structure. |
113 | * This is done so that we can quickly reattach ourselves to those buffers |
114 | * after some set of transaction commits have released these buffers. |
115 | */ |
116 | static int |
117 | xfs_attr_fillstate(xfs_da_state_t *state) |
118 | { |
119 | xfs_da_state_path_t *path; |
120 | xfs_da_state_blk_t *blk; |
121 | int level; |
122 | |
123 | trace_xfs_attr_fillstate(state->args); |
124 | |
125 | /* |
126 | * Roll down the "path" in the state structure, storing the on-disk |
127 | * block number for those buffers in the "path". |
128 | */ |
129 | path = &state->path; |
130 | ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); |
131 | for (blk = path->blk, level = 0; level < path->active; blk++, level++) { |
132 | if (blk->bp) { |
133 | blk->disk_blkno = xfs_buf_daddr(blk->bp); |
134 | blk->bp = NULL; |
135 | } else { |
136 | blk->disk_blkno = 0; |
137 | } |
138 | } |
139 | |
140 | /* |
141 | * Roll down the "altpath" in the state structure, storing the on-disk |
142 | * block number for those buffers in the "altpath". |
143 | */ |
144 | path = &state->altpath; |
145 | ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); |
146 | for (blk = path->blk, level = 0; level < path->active; blk++, level++) { |
147 | if (blk->bp) { |
148 | blk->disk_blkno = xfs_buf_daddr(blk->bp); |
149 | blk->bp = NULL; |
150 | } else { |
151 | blk->disk_blkno = 0; |
152 | } |
153 | } |
154 | |
155 | return 0; |
156 | } |
157 | |
158 | /* |
159 | * Reattach the buffers to the state structure based on the disk block |
160 | * numbers stored in the state structure. |
161 | * This is done after some set of transaction commits have released those |
162 | * buffers from our grip. |
163 | */ |
164 | static int |
165 | xfs_attr_refillstate(xfs_da_state_t *state) |
166 | { |
167 | xfs_da_state_path_t *path; |
168 | xfs_da_state_blk_t *blk; |
169 | int level, error; |
170 | |
171 | trace_xfs_attr_refillstate(state->args); |
172 | |
173 | /* |
174 | * Roll down the "path" in the state structure, storing the on-disk |
175 | * block number for those buffers in the "path". |
176 | */ |
177 | path = &state->path; |
178 | ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); |
179 | for (blk = path->blk, level = 0; level < path->active; blk++, level++) { |
180 | if (blk->disk_blkno) { |
181 | error = xfs_da3_node_read_mapped(state->args->trans, |
182 | state->args->dp, blk->disk_blkno, |
183 | &blk->bp, XFS_ATTR_FORK); |
184 | if (error) |
185 | return error; |
186 | } else { |
187 | blk->bp = NULL; |
188 | } |
189 | } |
190 | |
191 | /* |
192 | * Roll down the "altpath" in the state structure, storing the on-disk |
193 | * block number for those buffers in the "altpath". |
194 | */ |
195 | path = &state->altpath; |
196 | ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); |
197 | for (blk = path->blk, level = 0; level < path->active; blk++, level++) { |
198 | if (blk->disk_blkno) { |
199 | error = xfs_da3_node_read_mapped(state->args->trans, |
200 | state->args->dp, blk->disk_blkno, |
201 | &blk->bp, XFS_ATTR_FORK); |
202 | if (error) |
203 | return error; |
204 | } else { |
205 | blk->bp = NULL; |
206 | } |
207 | } |
208 | |
209 | return 0; |
210 | } |
211 | #else |
212 | static int xfs_attr_fillstate(xfs_da_state_t *state) { return 0; } |
213 | #endif |
214 | |
215 | /*======================================================================== |
216 | * Overall external interface routines. |
217 | *========================================================================*/ |
218 | |
219 | /* |
220 | * Retrieve an extended attribute and its value. Must have ilock. |
221 | * Returns 0 on successful retrieval, otherwise an error. |
222 | */ |
223 | int |
224 | xfs_attr_get_ilocked( |
225 | struct xfs_da_args *args) |
226 | { |
227 | xfs_assert_ilocked(args->dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL); |
228 | |
229 | if (!xfs_inode_hasattr(args->dp)) |
230 | return -ENOATTR; |
231 | |
232 | if (args->dp->i_af.if_format == XFS_DINODE_FMT_LOCAL) |
233 | return xfs_attr_shortform_getvalue(args); |
234 | if (xfs_attr_is_leaf(args->dp)) |
235 | return xfs_attr_leaf_get(args); |
236 | return xfs_attr_node_get(args); |
237 | } |
238 | |
239 | /* |
240 | * Retrieve an extended attribute by name, and its value if requested. |
241 | * |
242 | * If args->valuelen is zero, then the caller does not want the value, just an |
243 | * indication whether the attribute exists and the size of the value if it |
244 | * exists. The size is returned in args.valuelen. |
245 | * |
246 | * If args->value is NULL but args->valuelen is non-zero, allocate the buffer |
247 | * for the value after existence of the attribute has been determined. The |
248 | * caller always has to free args->value if it is set, no matter if this |
249 | * function was successful or not. |
250 | * |
251 | * If the attribute is found, but exceeds the size limit set by the caller in |
252 | * args->valuelen, return -ERANGE with the size of the attribute that was found |
253 | * in args->valuelen. |
254 | */ |
255 | int |
256 | xfs_attr_get( |
257 | struct xfs_da_args *args) |
258 | { |
259 | uint lock_mode; |
260 | int error; |
261 | |
262 | XFS_STATS_INC(args->dp->i_mount, xs_attr_get); |
263 | |
264 | if (xfs_is_shutdown(args->dp->i_mount)) |
265 | return -EIO; |
266 | |
267 | args->geo = args->dp->i_mount->m_attr_geo; |
268 | args->whichfork = XFS_ATTR_FORK; |
269 | args->hashval = xfs_da_hashname(args->name, args->namelen); |
270 | |
271 | /* Entirely possible to look up a name which doesn't exist */ |
272 | args->op_flags = XFS_DA_OP_OKNOENT; |
273 | |
274 | lock_mode = xfs_ilock_attr_map_shared(args->dp); |
275 | error = xfs_attr_get_ilocked(args); |
276 | xfs_iunlock(args->dp, lock_mode); |
277 | |
278 | return error; |
279 | } |
280 | |
281 | /* |
282 | * Calculate how many blocks we need for the new attribute, |
283 | */ |
284 | int |
285 | xfs_attr_calc_size( |
286 | struct xfs_da_args *args, |
287 | int *local) |
288 | { |
289 | struct xfs_mount *mp = args->dp->i_mount; |
290 | int size; |
291 | int nblks; |
292 | |
293 | /* |
294 | * Determine space new attribute will use, and if it would be |
295 | * "local" or "remote" (note: local != inline). |
296 | */ |
297 | size = xfs_attr_leaf_newentsize(args, local); |
298 | nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); |
299 | if (*local) { |
300 | if (size > (args->geo->blksize / 2)) { |
301 | /* Double split possible */ |
302 | nblks *= 2; |
303 | } |
304 | } else { |
305 | /* |
306 | * Out of line attribute, cannot double split, but |
307 | * make room for the attribute value itself. |
308 | */ |
309 | uint dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen); |
310 | nblks += dblocks; |
311 | nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); |
312 | } |
313 | |
314 | return nblks; |
315 | } |
316 | |
317 | /* Initialize transaction reservation for attr operations */ |
318 | void |
319 | xfs_init_attr_trans( |
320 | struct xfs_da_args *args, |
321 | struct xfs_trans_res *tres, |
322 | unsigned int *total) |
323 | { |
324 | struct xfs_mount *mp = args->dp->i_mount; |
325 | |
326 | if (args->value) { |
327 | tres->tr_logres = M_RES(mp)->tr_attrsetm.tr_logres + |
328 | M_RES(mp)->tr_attrsetrt.tr_logres * |
329 | args->total; |
330 | tres->tr_logcount = XFS_ATTRSET_LOG_COUNT; |
331 | tres->tr_logflags = XFS_TRANS_PERM_LOG_RES; |
332 | *total = args->total; |
333 | } else { |
334 | *tres = M_RES(mp)->tr_attrrm; |
335 | *total = XFS_ATTRRM_SPACE_RES(mp); |
336 | } |
337 | } |
338 | |
339 | /* |
340 | * Add an attr to a shortform fork. If there is no space, |
341 | * xfs_attr_shortform_addname() will convert to leaf format and return -ENOSPC. |
342 | * to use. |
343 | */ |
344 | STATIC int |
345 | xfs_attr_try_sf_addname( |
346 | struct xfs_inode *dp, |
347 | struct xfs_da_args *args) |
348 | { |
349 | |
350 | int error; |
351 | |
352 | /* |
353 | * Build initial attribute list (if required). |
354 | */ |
355 | if (dp->i_af.if_format == XFS_DINODE_FMT_EXTENTS) |
356 | xfs_attr_shortform_create(args); |
357 | |
358 | error = xfs_attr_shortform_addname(args); |
359 | if (error == -ENOSPC) |
360 | return error; |
361 | |
362 | /* |
363 | * Commit the shortform mods, and we're done. |
364 | * NOTE: this is also the error path (EEXIST, etc). |
365 | */ |
366 | if (!error && !(args->op_flags & XFS_DA_OP_NOTIME)) |
367 | xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG); |
368 | |
369 | if (xfs_has_wsync(dp->i_mount)) |
370 | xfs_trans_set_sync(args->trans); |
371 | |
372 | return error; |
373 | } |
374 | |
375 | static int |
376 | xfs_attr_sf_addname( |
377 | struct xfs_attr_intent *attr) |
378 | { |
379 | struct xfs_da_args *args = attr->xattri_da_args; |
380 | struct xfs_inode *dp = args->dp; |
381 | int error = 0; |
382 | |
383 | error = xfs_attr_try_sf_addname(dp, args); |
384 | if (error != -ENOSPC) { |
385 | ASSERT(!error || error == -EEXIST); |
386 | attr->xattri_dela_state = XFS_DAS_DONE; |
387 | goto out; |
388 | } |
389 | |
390 | /* |
391 | * It won't fit in the shortform, transform to a leaf block. GROT: |
392 | * another possible req'mt for a double-split btree op. |
393 | */ |
394 | error = xfs_attr_shortform_to_leaf(args); |
395 | if (error) |
396 | return error; |
397 | |
398 | attr->xattri_dela_state = XFS_DAS_LEAF_ADD; |
399 | out: |
400 | trace_xfs_attr_sf_addname_return(attr->xattri_dela_state, args->dp); |
401 | return error; |
402 | } |
403 | |
404 | /* |
405 | * Handle the state change on completion of a multi-state attr operation. |
406 | * |
407 | * If the XFS_DA_OP_REPLACE flag is set, this means the operation was the first |
408 | * modification in a attr replace operation and we still have to do the second |
409 | * state, indicated by @replace_state. |
410 | * |
411 | * We consume the XFS_DA_OP_REPLACE flag so that when we are called again on |
412 | * completion of the second half of the attr replace operation we correctly |
413 | * signal that it is done. |
414 | */ |
415 | static enum xfs_delattr_state |
416 | xfs_attr_complete_op( |
417 | struct xfs_attr_intent *attr, |
418 | enum xfs_delattr_state replace_state) |
419 | { |
420 | struct xfs_da_args *args = attr->xattri_da_args; |
421 | bool do_replace = args->op_flags & XFS_DA_OP_REPLACE; |
422 | |
423 | args->op_flags &= ~XFS_DA_OP_REPLACE; |
424 | args->attr_filter &= ~XFS_ATTR_INCOMPLETE; |
425 | if (do_replace) |
426 | return replace_state; |
427 | |
428 | return XFS_DAS_DONE; |
429 | } |
430 | |
431 | static int |
432 | xfs_attr_leaf_addname( |
433 | struct xfs_attr_intent *attr) |
434 | { |
435 | struct xfs_da_args *args = attr->xattri_da_args; |
436 | int error; |
437 | |
438 | ASSERT(xfs_attr_is_leaf(args->dp)); |
439 | |
440 | /* |
441 | * Use the leaf buffer we may already hold locked as a result of |
442 | * a sf-to-leaf conversion. |
443 | */ |
444 | error = xfs_attr_leaf_try_add(args); |
445 | |
446 | if (error == -ENOSPC) { |
447 | error = xfs_attr3_leaf_to_node(args); |
448 | if (error) |
449 | return error; |
450 | |
451 | /* |
452 | * We're not in leaf format anymore, so roll the transaction and |
453 | * retry the add to the newly allocated node block. |
454 | */ |
455 | attr->xattri_dela_state = XFS_DAS_NODE_ADD; |
456 | goto out; |
457 | } |
458 | if (error) |
459 | return error; |
460 | |
461 | /* |
462 | * We need to commit and roll if we need to allocate remote xattr blocks |
463 | * or perform more xattr manipulations. Otherwise there is nothing more |
464 | * to do and we can return success. |
465 | */ |
466 | if (args->rmtblkno) |
467 | attr->xattri_dela_state = XFS_DAS_LEAF_SET_RMT; |
468 | else |
469 | attr->xattri_dela_state = xfs_attr_complete_op(attr, |
470 | replace_state: XFS_DAS_LEAF_REPLACE); |
471 | out: |
472 | trace_xfs_attr_leaf_addname_return(attr->xattri_dela_state, args->dp); |
473 | return error; |
474 | } |
475 | |
476 | /* |
477 | * Add an entry to a node format attr tree. |
478 | * |
479 | * Note that we might still have a leaf here - xfs_attr_is_leaf() cannot tell |
480 | * the difference between leaf + remote attr blocks and a node format tree, |
481 | * so we may still end up having to convert from leaf to node format here. |
482 | */ |
483 | static int |
484 | xfs_attr_node_addname( |
485 | struct xfs_attr_intent *attr) |
486 | { |
487 | struct xfs_da_args *args = attr->xattri_da_args; |
488 | int error; |
489 | |
490 | error = xfs_attr_node_addname_find_attr(attr); |
491 | if (error) |
492 | return error; |
493 | |
494 | error = xfs_attr_node_try_addname(attr); |
495 | if (error == -ENOSPC) { |
496 | error = xfs_attr3_leaf_to_node(args); |
497 | if (error) |
498 | return error; |
499 | /* |
500 | * No state change, we really are in node form now |
501 | * but we need the transaction rolled to continue. |
502 | */ |
503 | goto out; |
504 | } |
505 | if (error) |
506 | return error; |
507 | |
508 | if (args->rmtblkno) |
509 | attr->xattri_dela_state = XFS_DAS_NODE_SET_RMT; |
510 | else |
511 | attr->xattri_dela_state = xfs_attr_complete_op(attr, |
512 | replace_state: XFS_DAS_NODE_REPLACE); |
513 | out: |
514 | trace_xfs_attr_node_addname_return(attr->xattri_dela_state, args->dp); |
515 | return error; |
516 | } |
517 | |
518 | static int |
519 | xfs_attr_rmtval_alloc( |
520 | struct xfs_attr_intent *attr) |
521 | { |
522 | struct xfs_da_args *args = attr->xattri_da_args; |
523 | int error = 0; |
524 | |
525 | /* |
526 | * If there was an out-of-line value, allocate the blocks we |
527 | * identified for its storage and copy the value. This is done |
528 | * after we create the attribute so that we don't overflow the |
529 | * maximum size of a transaction and/or hit a deadlock. |
530 | */ |
531 | if (attr->xattri_blkcnt > 0) { |
532 | error = xfs_attr_rmtval_set_blk(attr); |
533 | if (error) |
534 | return error; |
535 | /* Roll the transaction only if there is more to allocate. */ |
536 | if (attr->xattri_blkcnt > 0) |
537 | goto out; |
538 | } |
539 | |
540 | error = xfs_attr_rmtval_set_value(args); |
541 | if (error) |
542 | return error; |
543 | |
544 | attr->xattri_dela_state = xfs_attr_complete_op(attr, |
545 | replace_state: ++attr->xattri_dela_state); |
546 | /* |
547 | * If we are not doing a rename, we've finished the operation but still |
548 | * have to clear the incomplete flag protecting the new attr from |
549 | * exposing partially initialised state if we crash during creation. |
550 | */ |
551 | if (attr->xattri_dela_state == XFS_DAS_DONE) |
552 | error = xfs_attr3_leaf_clearflag(args); |
553 | out: |
554 | trace_xfs_attr_rmtval_alloc(attr->xattri_dela_state, args->dp); |
555 | return error; |
556 | } |
557 | |
558 | /* |
559 | * Mark an attribute entry INCOMPLETE and save pointers to the relevant buffers |
560 | * for later deletion of the entry. |
561 | */ |
562 | static int |
563 | xfs_attr_leaf_mark_incomplete( |
564 | struct xfs_da_args *args, |
565 | struct xfs_da_state *state) |
566 | { |
567 | int error; |
568 | |
569 | /* |
570 | * Fill in disk block numbers in the state structure |
571 | * so that we can get the buffers back after we commit |
572 | * several transactions in the following calls. |
573 | */ |
574 | error = xfs_attr_fillstate(state); |
575 | if (error) |
576 | return error; |
577 | |
578 | /* |
579 | * Mark the attribute as INCOMPLETE |
580 | */ |
581 | return xfs_attr3_leaf_setflag(args); |
582 | } |
583 | |
584 | /* Ensure the da state of an xattr deferred work item is ready to go. */ |
585 | static inline void |
586 | xfs_attr_item_init_da_state( |
587 | struct xfs_attr_intent *attr) |
588 | { |
589 | struct xfs_da_args *args = attr->xattri_da_args; |
590 | |
591 | if (!attr->xattri_da_state) |
592 | attr->xattri_da_state = xfs_da_state_alloc(args); |
593 | else |
594 | xfs_da_state_reset(state: attr->xattri_da_state, args); |
595 | } |
596 | |
597 | /* |
598 | * Initial setup for xfs_attr_node_removename. Make sure the attr is there and |
599 | * the blocks are valid. Attr keys with remote blocks will be marked |
600 | * incomplete. |
601 | */ |
602 | static |
603 | int xfs_attr_node_removename_setup( |
604 | struct xfs_attr_intent *attr) |
605 | { |
606 | struct xfs_da_args *args = attr->xattri_da_args; |
607 | struct xfs_da_state *state; |
608 | int error; |
609 | |
610 | xfs_attr_item_init_da_state(attr); |
611 | error = xfs_attr_node_lookup(args, attr->xattri_da_state); |
612 | if (error != -EEXIST) |
613 | goto out; |
614 | error = 0; |
615 | |
616 | state = attr->xattri_da_state; |
617 | ASSERT(state->path.blk[state->path.active - 1].bp != NULL); |
618 | ASSERT(state->path.blk[state->path.active - 1].magic == |
619 | XFS_ATTR_LEAF_MAGIC); |
620 | |
621 | error = xfs_attr_leaf_mark_incomplete(args, state); |
622 | if (error) |
623 | goto out; |
624 | if (args->rmtblkno > 0) |
625 | error = xfs_attr_rmtval_invalidate(args); |
626 | out: |
627 | if (error) { |
628 | xfs_da_state_free(state: attr->xattri_da_state); |
629 | attr->xattri_da_state = NULL; |
630 | } |
631 | |
632 | return error; |
633 | } |
634 | |
635 | /* |
636 | * Remove the original attr we have just replaced. This is dependent on the |
637 | * original lookup and insert placing the old attr in args->blkno/args->index |
638 | * and the new attr in args->blkno2/args->index2. |
639 | */ |
640 | static int |
641 | xfs_attr_leaf_remove_attr( |
642 | struct xfs_attr_intent *attr) |
643 | { |
644 | struct xfs_da_args *args = attr->xattri_da_args; |
645 | struct xfs_inode *dp = args->dp; |
646 | struct xfs_buf *bp = NULL; |
647 | int forkoff; |
648 | int error; |
649 | |
650 | error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, |
651 | &bp); |
652 | if (error) |
653 | return error; |
654 | |
655 | xfs_attr3_leaf_remove(leaf_buffer: bp, args); |
656 | |
657 | forkoff = xfs_attr_shortform_allfit(bp, dp); |
658 | if (forkoff) |
659 | error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); |
660 | /* bp is gone due to xfs_da_shrink_inode */ |
661 | |
662 | return error; |
663 | } |
664 | |
665 | /* |
666 | * Shrink an attribute from leaf to shortform. Used by the node format remove |
667 | * path when the node format collapses to a single block and so we have to check |
668 | * if it can be collapsed further. |
669 | */ |
670 | static int |
671 | xfs_attr_leaf_shrink( |
672 | struct xfs_da_args *args) |
673 | { |
674 | struct xfs_inode *dp = args->dp; |
675 | struct xfs_buf *bp; |
676 | int forkoff; |
677 | int error; |
678 | |
679 | if (!xfs_attr_is_leaf(dp)) |
680 | return 0; |
681 | |
682 | error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp); |
683 | if (error) |
684 | return error; |
685 | |
686 | forkoff = xfs_attr_shortform_allfit(bp, dp); |
687 | if (forkoff) { |
688 | error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); |
689 | /* bp is gone due to xfs_da_shrink_inode */ |
690 | } else { |
691 | xfs_trans_brelse(args->trans, bp); |
692 | } |
693 | |
694 | return error; |
695 | } |
696 | |
697 | /* |
698 | * Run the attribute operation specified in @attr. |
699 | * |
700 | * This routine is meant to function as a delayed operation and will set the |
701 | * state to XFS_DAS_DONE when the operation is complete. Calling functions will |
702 | * need to handle this, and recall the function until either an error or |
703 | * XFS_DAS_DONE is detected. |
704 | */ |
705 | int |
706 | xfs_attr_set_iter( |
707 | struct xfs_attr_intent *attr) |
708 | { |
709 | struct xfs_da_args *args = attr->xattri_da_args; |
710 | int error = 0; |
711 | |
712 | /* State machine switch */ |
713 | next_state: |
714 | switch (attr->xattri_dela_state) { |
715 | case XFS_DAS_UNINIT: |
716 | ASSERT(0); |
717 | return -EFSCORRUPTED; |
718 | case XFS_DAS_SF_ADD: |
719 | return xfs_attr_sf_addname(attr); |
720 | case XFS_DAS_LEAF_ADD: |
721 | return xfs_attr_leaf_addname(attr); |
722 | case XFS_DAS_NODE_ADD: |
723 | return xfs_attr_node_addname(attr); |
724 | |
725 | case XFS_DAS_SF_REMOVE: |
726 | error = xfs_attr_sf_removename(args); |
727 | attr->xattri_dela_state = xfs_attr_complete_op(attr, |
728 | replace_state: xfs_attr_init_add_state(args)); |
729 | break; |
730 | case XFS_DAS_LEAF_REMOVE: |
731 | error = xfs_attr_leaf_removename(args); |
732 | attr->xattri_dela_state = xfs_attr_complete_op(attr, |
733 | replace_state: xfs_attr_init_add_state(args)); |
734 | break; |
735 | case XFS_DAS_NODE_REMOVE: |
736 | error = xfs_attr_node_removename_setup(attr); |
737 | if (error == -ENOATTR && |
738 | (args->op_flags & XFS_DA_OP_RECOVERY)) { |
739 | attr->xattri_dela_state = xfs_attr_complete_op(attr, |
740 | replace_state: xfs_attr_init_add_state(args)); |
741 | error = 0; |
742 | break; |
743 | } |
744 | if (error) |
745 | return error; |
746 | attr->xattri_dela_state = XFS_DAS_NODE_REMOVE_RMT; |
747 | if (args->rmtblkno == 0) |
748 | attr->xattri_dela_state++; |
749 | break; |
750 | |
751 | case XFS_DAS_LEAF_SET_RMT: |
752 | case XFS_DAS_NODE_SET_RMT: |
753 | error = xfs_attr_rmtval_find_space(attr); |
754 | if (error) |
755 | return error; |
756 | attr->xattri_dela_state++; |
757 | fallthrough; |
758 | |
759 | case XFS_DAS_LEAF_ALLOC_RMT: |
760 | case XFS_DAS_NODE_ALLOC_RMT: |
761 | error = xfs_attr_rmtval_alloc(attr); |
762 | if (error) |
763 | return error; |
764 | if (attr->xattri_dela_state == XFS_DAS_DONE) |
765 | break; |
766 | goto next_state; |
767 | |
768 | case XFS_DAS_LEAF_REPLACE: |
769 | case XFS_DAS_NODE_REPLACE: |
770 | /* |
771 | * We must "flip" the incomplete flags on the "new" and "old" |
772 | * attribute/value pairs so that one disappears and one appears |
773 | * atomically. |
774 | */ |
775 | error = xfs_attr3_leaf_flipflags(args); |
776 | if (error) |
777 | return error; |
778 | /* |
779 | * We must commit the flag value change now to make it atomic |
780 | * and then we can start the next trans in series at REMOVE_OLD. |
781 | */ |
782 | attr->xattri_dela_state++; |
783 | break; |
784 | |
785 | case XFS_DAS_LEAF_REMOVE_OLD: |
786 | case XFS_DAS_NODE_REMOVE_OLD: |
787 | /* |
788 | * If we have a remote attr, start the process of removing it |
789 | * by invalidating any cached buffers. |
790 | * |
791 | * If we don't have a remote attr, we skip the remote block |
792 | * removal state altogether with a second state increment. |
793 | */ |
794 | xfs_attr_restore_rmt_blk(args); |
795 | if (args->rmtblkno) { |
796 | error = xfs_attr_rmtval_invalidate(args); |
797 | if (error) |
798 | return error; |
799 | } else { |
800 | attr->xattri_dela_state++; |
801 | } |
802 | |
803 | attr->xattri_dela_state++; |
804 | goto next_state; |
805 | |
806 | case XFS_DAS_LEAF_REMOVE_RMT: |
807 | case XFS_DAS_NODE_REMOVE_RMT: |
808 | error = xfs_attr_rmtval_remove(attr); |
809 | if (error == -EAGAIN) { |
810 | error = 0; |
811 | break; |
812 | } |
813 | if (error) |
814 | return error; |
815 | |
816 | /* |
817 | * We've finished removing the remote attr blocks, so commit the |
818 | * transaction and move on to removing the attr name from the |
819 | * leaf/node block. Removing the attr might require a full |
820 | * transaction reservation for btree block freeing, so we |
821 | * can't do that in the same transaction where we removed the |
822 | * remote attr blocks. |
823 | */ |
824 | attr->xattri_dela_state++; |
825 | break; |
826 | |
827 | case XFS_DAS_LEAF_REMOVE_ATTR: |
828 | error = xfs_attr_leaf_remove_attr(attr); |
829 | attr->xattri_dela_state = xfs_attr_complete_op(attr, |
830 | replace_state: xfs_attr_init_add_state(args)); |
831 | break; |
832 | |
833 | case XFS_DAS_NODE_REMOVE_ATTR: |
834 | error = xfs_attr_node_remove_attr(attr); |
835 | if (!error) |
836 | error = xfs_attr_leaf_shrink(args); |
837 | attr->xattri_dela_state = xfs_attr_complete_op(attr, |
838 | replace_state: xfs_attr_init_add_state(args)); |
839 | break; |
840 | default: |
841 | ASSERT(0); |
842 | break; |
843 | } |
844 | |
845 | trace_xfs_attr_set_iter_return(attr->xattri_dela_state, args->dp); |
846 | return error; |
847 | } |
848 | |
849 | |
850 | /* |
851 | * Return EEXIST if attr is found, or ENOATTR if not |
852 | */ |
853 | static int |
854 | xfs_attr_lookup( |
855 | struct xfs_da_args *args) |
856 | { |
857 | struct xfs_inode *dp = args->dp; |
858 | struct xfs_buf *bp = NULL; |
859 | struct xfs_da_state *state; |
860 | int error; |
861 | |
862 | if (!xfs_inode_hasattr(dp)) |
863 | return -ENOATTR; |
864 | |
865 | if (dp->i_af.if_format == XFS_DINODE_FMT_LOCAL) { |
866 | if (xfs_attr_sf_findname(args)) |
867 | return -EEXIST; |
868 | return -ENOATTR; |
869 | } |
870 | |
871 | if (xfs_attr_is_leaf(dp)) { |
872 | error = xfs_attr_leaf_hasname(args, &bp); |
873 | |
874 | if (bp) |
875 | xfs_trans_brelse(args->trans, bp); |
876 | |
877 | return error; |
878 | } |
879 | |
880 | state = xfs_da_state_alloc(args); |
881 | error = xfs_attr_node_lookup(args, state); |
882 | xfs_da_state_free(state); |
883 | return error; |
884 | } |
885 | |
886 | static void |
887 | xfs_attr_defer_add( |
888 | struct xfs_da_args *args, |
889 | unsigned int op_flags) |
890 | { |
891 | |
892 | struct xfs_attr_intent *new; |
893 | |
894 | new = kmem_cache_zalloc(xfs_attr_intent_cache, |
895 | GFP_KERNEL | __GFP_NOFAIL); |
896 | new->xattri_op_flags = op_flags; |
897 | new->xattri_da_args = args; |
898 | |
899 | switch (op_flags) { |
900 | case XFS_ATTRI_OP_FLAGS_SET: |
901 | new->xattri_dela_state = xfs_attr_init_add_state(args); |
902 | break; |
903 | case XFS_ATTRI_OP_FLAGS_REPLACE: |
904 | new->xattri_dela_state = xfs_attr_init_replace_state(args); |
905 | break; |
906 | case XFS_ATTRI_OP_FLAGS_REMOVE: |
907 | new->xattri_dela_state = xfs_attr_init_remove_state(args); |
908 | break; |
909 | default: |
910 | ASSERT(0); |
911 | } |
912 | |
913 | xfs_defer_add(tp: args->trans, h: &new->xattri_list, ops: &xfs_attr_defer_type); |
914 | trace_xfs_attr_defer_add(new->xattri_dela_state, args->dp); |
915 | } |
916 | |
917 | /* |
918 | * Note: If args->value is NULL the attribute will be removed, just like the |
919 | * Linux ->setattr API. |
920 | */ |
921 | int |
922 | xfs_attr_set( |
923 | struct xfs_da_args *args) |
924 | { |
925 | struct xfs_inode *dp = args->dp; |
926 | struct xfs_mount *mp = dp->i_mount; |
927 | struct xfs_trans_res tres; |
928 | bool rsvd = (args->attr_filter & XFS_ATTR_ROOT); |
929 | int error, local; |
930 | int rmt_blks = 0; |
931 | unsigned int total; |
932 | |
933 | if (xfs_is_shutdown(dp->i_mount)) |
934 | return -EIO; |
935 | |
936 | error = xfs_qm_dqattach(dp); |
937 | if (error) |
938 | return error; |
939 | |
940 | args->geo = mp->m_attr_geo; |
941 | args->whichfork = XFS_ATTR_FORK; |
942 | args->hashval = xfs_da_hashname(args->name, args->namelen); |
943 | |
944 | /* |
945 | * We have no control over the attribute names that userspace passes us |
946 | * to remove, so we have to allow the name lookup prior to attribute |
947 | * removal to fail as well. Preserve the logged flag, since we need |
948 | * to pass that through to the logging code. |
949 | */ |
950 | args->op_flags = XFS_DA_OP_OKNOENT | |
951 | (args->op_flags & XFS_DA_OP_LOGGED); |
952 | |
953 | if (args->value) { |
954 | XFS_STATS_INC(mp, xs_attr_set); |
955 | args->total = xfs_attr_calc_size(args, local: &local); |
956 | |
957 | /* |
958 | * If the inode doesn't have an attribute fork, add one. |
959 | * (inode must not be locked when we call this routine) |
960 | */ |
961 | if (xfs_inode_has_attr_fork(dp) == 0) { |
962 | int sf_size = sizeof(struct xfs_attr_sf_hdr) + |
963 | xfs_attr_sf_entsize_byname(args->namelen, |
964 | args->valuelen); |
965 | |
966 | error = xfs_bmap_add_attrfork(dp, sf_size, rsvd); |
967 | if (error) |
968 | return error; |
969 | } |
970 | |
971 | if (!local) |
972 | rmt_blks = xfs_attr3_rmt_blocks(mp, attrlen: args->valuelen); |
973 | } else { |
974 | XFS_STATS_INC(mp, xs_attr_remove); |
975 | rmt_blks = xfs_attr3_rmt_blocks(mp, XFS_XATTR_SIZE_MAX); |
976 | } |
977 | |
978 | /* |
979 | * Root fork attributes can use reserved data blocks for this |
980 | * operation if necessary |
981 | */ |
982 | xfs_init_attr_trans(args, tres: &tres, total: &total); |
983 | error = xfs_trans_alloc_inode(dp, &tres, total, 0, rsvd, &args->trans); |
984 | if (error) |
985 | return error; |
986 | |
987 | if (args->value || xfs_inode_hasattr(ip: dp)) { |
988 | error = xfs_iext_count_may_overflow(dp, XFS_ATTR_FORK, |
989 | XFS_IEXT_ATTR_MANIP_CNT(rmt_blks)); |
990 | if (error == -EFBIG) |
991 | error = xfs_iext_count_upgrade(args->trans, dp, |
992 | XFS_IEXT_ATTR_MANIP_CNT(rmt_blks)); |
993 | if (error) |
994 | goto out_trans_cancel; |
995 | } |
996 | |
997 | error = xfs_attr_lookup(args); |
998 | switch (error) { |
999 | case -EEXIST: |
1000 | if (!args->value) { |
1001 | /* if no value, we are performing a remove operation */ |
1002 | xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_REMOVE); |
1003 | break; |
1004 | } |
1005 | |
1006 | /* Pure create fails if the attr already exists */ |
1007 | if (args->attr_flags & XATTR_CREATE) |
1008 | goto out_trans_cancel; |
1009 | xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_REPLACE); |
1010 | break; |
1011 | case -ENOATTR: |
1012 | /* Can't remove what isn't there. */ |
1013 | if (!args->value) |
1014 | goto out_trans_cancel; |
1015 | |
1016 | /* Pure replace fails if no existing attr to replace. */ |
1017 | if (args->attr_flags & XATTR_REPLACE) |
1018 | goto out_trans_cancel; |
1019 | xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_SET); |
1020 | break; |
1021 | default: |
1022 | goto out_trans_cancel; |
1023 | } |
1024 | |
1025 | /* |
1026 | * If this is a synchronous mount, make sure that the |
1027 | * transaction goes to disk before returning to the user. |
1028 | */ |
1029 | if (xfs_has_wsync(mp)) |
1030 | xfs_trans_set_sync(args->trans); |
1031 | |
1032 | if (!(args->op_flags & XFS_DA_OP_NOTIME)) |
1033 | xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG); |
1034 | |
1035 | /* |
1036 | * Commit the last in the sequence of transactions. |
1037 | */ |
1038 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); |
1039 | error = xfs_trans_commit(args->trans); |
1040 | out_unlock: |
1041 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
1042 | return error; |
1043 | |
1044 | out_trans_cancel: |
1045 | if (args->trans) |
1046 | xfs_trans_cancel(args->trans); |
1047 | goto out_unlock; |
1048 | } |
1049 | |
1050 | /*======================================================================== |
1051 | * External routines when attribute list is inside the inode |
1052 | *========================================================================*/ |
1053 | |
1054 | static inline int xfs_attr_sf_totsize(struct xfs_inode *dp) |
1055 | { |
1056 | struct xfs_attr_sf_hdr *sf = dp->i_af.if_data; |
1057 | |
1058 | return be16_to_cpu(sf->totsize); |
1059 | } |
1060 | |
1061 | /* |
1062 | * Add a name to the shortform attribute list structure |
1063 | * This is the external routine. |
1064 | */ |
1065 | static int |
1066 | xfs_attr_shortform_addname( |
1067 | struct xfs_da_args *args) |
1068 | { |
1069 | int newsize, forkoff; |
1070 | |
1071 | trace_xfs_attr_sf_addname(args); |
1072 | |
1073 | if (xfs_attr_sf_findname(args)) { |
1074 | int error; |
1075 | |
1076 | ASSERT(args->op_flags & XFS_DA_OP_REPLACE); |
1077 | |
1078 | error = xfs_attr_sf_removename(args); |
1079 | if (error) |
1080 | return error; |
1081 | |
1082 | /* |
1083 | * Since we have removed the old attr, clear XFS_DA_OP_REPLACE |
1084 | * so that the new attr doesn't fit in shortform format, the |
1085 | * leaf format add routine won't trip over the attr not being |
1086 | * around. |
1087 | */ |
1088 | args->op_flags &= ~XFS_DA_OP_REPLACE; |
1089 | } else { |
1090 | ASSERT(!(args->op_flags & XFS_DA_OP_REPLACE)); |
1091 | } |
1092 | |
1093 | if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX || |
1094 | args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX) |
1095 | return -ENOSPC; |
1096 | |
1097 | newsize = xfs_attr_sf_totsize(dp: args->dp); |
1098 | newsize += xfs_attr_sf_entsize_byname(args->namelen, args->valuelen); |
1099 | |
1100 | forkoff = xfs_attr_shortform_bytesfit(dp: args->dp, bytes: newsize); |
1101 | if (!forkoff) |
1102 | return -ENOSPC; |
1103 | |
1104 | xfs_attr_shortform_add(args, forkoff); |
1105 | return 0; |
1106 | } |
1107 | |
1108 | |
1109 | /*======================================================================== |
1110 | * External routines when attribute list is one block |
1111 | *========================================================================*/ |
1112 | |
1113 | /* Save the current remote block info and clear the current pointers. */ |
1114 | static void |
1115 | xfs_attr_save_rmt_blk( |
1116 | struct xfs_da_args *args) |
1117 | { |
1118 | args->blkno2 = args->blkno; |
1119 | args->index2 = args->index; |
1120 | args->rmtblkno2 = args->rmtblkno; |
1121 | args->rmtblkcnt2 = args->rmtblkcnt; |
1122 | args->rmtvaluelen2 = args->rmtvaluelen; |
1123 | args->rmtblkno = 0; |
1124 | args->rmtblkcnt = 0; |
1125 | args->rmtvaluelen = 0; |
1126 | } |
1127 | |
1128 | /* Set stored info about a remote block */ |
1129 | static void |
1130 | xfs_attr_restore_rmt_blk( |
1131 | struct xfs_da_args *args) |
1132 | { |
1133 | args->blkno = args->blkno2; |
1134 | args->index = args->index2; |
1135 | args->rmtblkno = args->rmtblkno2; |
1136 | args->rmtblkcnt = args->rmtblkcnt2; |
1137 | args->rmtvaluelen = args->rmtvaluelen2; |
1138 | } |
1139 | |
1140 | /* |
1141 | * Tries to add an attribute to an inode in leaf form |
1142 | * |
1143 | * This function is meant to execute as part of a delayed operation and leaves |
1144 | * the transaction handling to the caller. On success the attribute is added |
1145 | * and the inode and transaction are left dirty. If there is not enough space, |
1146 | * the attr data is converted to node format and -ENOSPC is returned. Caller is |
1147 | * responsible for handling the dirty inode and transaction or adding the attr |
1148 | * in node format. |
1149 | */ |
1150 | STATIC int |
1151 | xfs_attr_leaf_try_add( |
1152 | struct xfs_da_args *args) |
1153 | { |
1154 | struct xfs_buf *bp; |
1155 | int error; |
1156 | |
1157 | error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp); |
1158 | if (error) |
1159 | return error; |
1160 | |
1161 | /* |
1162 | * Look up the xattr name to set the insertion point for the new xattr. |
1163 | */ |
1164 | error = xfs_attr3_leaf_lookup_int(leaf: bp, args); |
1165 | switch (error) { |
1166 | case -ENOATTR: |
1167 | if (args->op_flags & XFS_DA_OP_REPLACE) |
1168 | goto out_brelse; |
1169 | break; |
1170 | case -EEXIST: |
1171 | if (!(args->op_flags & XFS_DA_OP_REPLACE)) |
1172 | goto out_brelse; |
1173 | |
1174 | trace_xfs_attr_leaf_replace(args); |
1175 | /* |
1176 | * Save the existing remote attr state so that the current |
1177 | * values reflect the state of the new attribute we are about to |
1178 | * add, not the attribute we just found and will remove later. |
1179 | */ |
1180 | xfs_attr_save_rmt_blk(args); |
1181 | break; |
1182 | case 0: |
1183 | break; |
1184 | default: |
1185 | goto out_brelse; |
1186 | } |
1187 | |
1188 | return xfs_attr3_leaf_add(leaf_buffer: bp, args); |
1189 | |
1190 | out_brelse: |
1191 | xfs_trans_brelse(args->trans, bp); |
1192 | return error; |
1193 | } |
1194 | |
1195 | /* |
1196 | * Return EEXIST if attr is found, or ENOATTR if not |
1197 | */ |
1198 | STATIC int |
1199 | xfs_attr_leaf_hasname( |
1200 | struct xfs_da_args *args, |
1201 | struct xfs_buf **bp) |
1202 | { |
1203 | int error = 0; |
1204 | |
1205 | error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp); |
1206 | if (error) |
1207 | return error; |
1208 | |
1209 | error = xfs_attr3_leaf_lookup_int(leaf: *bp, args); |
1210 | if (error != -ENOATTR && error != -EEXIST) |
1211 | xfs_trans_brelse(args->trans, *bp); |
1212 | |
1213 | return error; |
1214 | } |
1215 | |
1216 | /* |
1217 | * Remove a name from the leaf attribute list structure |
1218 | * |
1219 | * This leaf block cannot have a "remote" value, we only call this routine |
1220 | * if bmap_one_block() says there is only one block (ie: no remote blks). |
1221 | */ |
1222 | STATIC int |
1223 | xfs_attr_leaf_removename( |
1224 | struct xfs_da_args *args) |
1225 | { |
1226 | struct xfs_inode *dp; |
1227 | struct xfs_buf *bp; |
1228 | int error, forkoff; |
1229 | |
1230 | trace_xfs_attr_leaf_removename(args); |
1231 | |
1232 | /* |
1233 | * Remove the attribute. |
1234 | */ |
1235 | dp = args->dp; |
1236 | |
1237 | error = xfs_attr_leaf_hasname(args, &bp); |
1238 | if (error == -ENOATTR) { |
1239 | xfs_trans_brelse(args->trans, bp); |
1240 | if (args->op_flags & XFS_DA_OP_RECOVERY) |
1241 | return 0; |
1242 | return error; |
1243 | } else if (error != -EEXIST) |
1244 | return error; |
1245 | |
1246 | xfs_attr3_leaf_remove(leaf_buffer: bp, args); |
1247 | |
1248 | /* |
1249 | * If the result is small enough, shrink it all into the inode. |
1250 | */ |
1251 | forkoff = xfs_attr_shortform_allfit(bp, dp); |
1252 | if (forkoff) |
1253 | return xfs_attr3_leaf_to_shortform(bp, args, forkoff); |
1254 | /* bp is gone due to xfs_da_shrink_inode */ |
1255 | |
1256 | return 0; |
1257 | } |
1258 | |
1259 | /* |
1260 | * Look up a name in a leaf attribute list structure. |
1261 | * |
1262 | * This leaf block cannot have a "remote" value, we only call this routine |
1263 | * if bmap_one_block() says there is only one block (ie: no remote blks). |
1264 | * |
1265 | * Returns 0 on successful retrieval, otherwise an error. |
1266 | */ |
1267 | STATIC int |
1268 | xfs_attr_leaf_get(xfs_da_args_t *args) |
1269 | { |
1270 | struct xfs_buf *bp; |
1271 | int error; |
1272 | |
1273 | trace_xfs_attr_leaf_get(args); |
1274 | |
1275 | error = xfs_attr_leaf_hasname(args, &bp); |
1276 | |
1277 | if (error == -ENOATTR) { |
1278 | xfs_trans_brelse(args->trans, bp); |
1279 | return error; |
1280 | } else if (error != -EEXIST) |
1281 | return error; |
1282 | |
1283 | |
1284 | error = xfs_attr3_leaf_getvalue(bp, args); |
1285 | xfs_trans_brelse(args->trans, bp); |
1286 | return error; |
1287 | } |
1288 | |
1289 | /* Return EEXIST if attr is found, or ENOATTR if not. */ |
1290 | STATIC int |
1291 | xfs_attr_node_lookup( |
1292 | struct xfs_da_args *args, |
1293 | struct xfs_da_state *state) |
1294 | { |
1295 | int retval, error; |
1296 | |
1297 | /* |
1298 | * Search to see if name exists, and get back a pointer to it. |
1299 | */ |
1300 | error = xfs_da3_node_lookup_int(state, result: &retval); |
1301 | if (error) |
1302 | return error; |
1303 | |
1304 | return retval; |
1305 | } |
1306 | |
1307 | /*======================================================================== |
1308 | * External routines when attribute list size > geo->blksize |
1309 | *========================================================================*/ |
1310 | |
1311 | STATIC int |
1312 | xfs_attr_node_addname_find_attr( |
1313 | struct xfs_attr_intent *attr) |
1314 | { |
1315 | struct xfs_da_args *args = attr->xattri_da_args; |
1316 | int error; |
1317 | |
1318 | /* |
1319 | * Search to see if name already exists, and get back a pointer |
1320 | * to where it should go. |
1321 | */ |
1322 | xfs_attr_item_init_da_state(attr); |
1323 | error = xfs_attr_node_lookup(args, attr->xattri_da_state); |
1324 | switch (error) { |
1325 | case -ENOATTR: |
1326 | if (args->op_flags & XFS_DA_OP_REPLACE) |
1327 | goto error; |
1328 | break; |
1329 | case -EEXIST: |
1330 | if (!(args->op_flags & XFS_DA_OP_REPLACE)) |
1331 | goto error; |
1332 | |
1333 | |
1334 | trace_xfs_attr_node_replace(args); |
1335 | /* |
1336 | * Save the existing remote attr state so that the current |
1337 | * values reflect the state of the new attribute we are about to |
1338 | * add, not the attribute we just found and will remove later. |
1339 | */ |
1340 | xfs_attr_save_rmt_blk(args); |
1341 | break; |
1342 | case 0: |
1343 | break; |
1344 | default: |
1345 | goto error; |
1346 | } |
1347 | |
1348 | return 0; |
1349 | error: |
1350 | if (attr->xattri_da_state) { |
1351 | xfs_da_state_free(state: attr->xattri_da_state); |
1352 | attr->xattri_da_state = NULL; |
1353 | } |
1354 | return error; |
1355 | } |
1356 | |
1357 | /* |
1358 | * Add a name to a Btree-format attribute list. |
1359 | * |
1360 | * This will involve walking down the Btree, and may involve splitting |
1361 | * leaf nodes and even splitting intermediate nodes up to and including |
1362 | * the root node (a special case of an intermediate node). |
1363 | */ |
1364 | static int |
1365 | xfs_attr_node_try_addname( |
1366 | struct xfs_attr_intent *attr) |
1367 | { |
1368 | struct xfs_da_state *state = attr->xattri_da_state; |
1369 | struct xfs_da_state_blk *blk; |
1370 | int error; |
1371 | |
1372 | trace_xfs_attr_node_addname(state->args); |
1373 | |
1374 | blk = &state->path.blk[state->path.active-1]; |
1375 | ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); |
1376 | |
1377 | error = xfs_attr3_leaf_add(leaf_buffer: blk->bp, args: state->args); |
1378 | if (error == -ENOSPC) { |
1379 | if (state->path.active == 1) { |
1380 | /* |
1381 | * Its really a single leaf node, but it had |
1382 | * out-of-line values so it looked like it *might* |
1383 | * have been a b-tree. Let the caller deal with this. |
1384 | */ |
1385 | goto out; |
1386 | } |
1387 | |
1388 | /* |
1389 | * Split as many Btree elements as required. |
1390 | * This code tracks the new and old attr's location |
1391 | * in the index/blkno/rmtblkno/rmtblkcnt fields and |
1392 | * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields. |
1393 | */ |
1394 | error = xfs_da3_split(state); |
1395 | if (error) |
1396 | goto out; |
1397 | } else { |
1398 | /* |
1399 | * Addition succeeded, update Btree hashvals. |
1400 | */ |
1401 | xfs_da3_fixhashpath(state, path_to_to_fix: &state->path); |
1402 | } |
1403 | |
1404 | out: |
1405 | xfs_da_state_free(state); |
1406 | attr->xattri_da_state = NULL; |
1407 | return error; |
1408 | } |
1409 | |
1410 | static int |
1411 | xfs_attr_node_removename( |
1412 | struct xfs_da_args *args, |
1413 | struct xfs_da_state *state) |
1414 | { |
1415 | struct xfs_da_state_blk *blk; |
1416 | int retval; |
1417 | |
1418 | /* |
1419 | * Remove the name and update the hashvals in the tree. |
1420 | */ |
1421 | blk = &state->path.blk[state->path.active-1]; |
1422 | ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); |
1423 | retval = xfs_attr3_leaf_remove(leaf_buffer: blk->bp, args); |
1424 | xfs_da3_fixhashpath(state, path_to_to_fix: &state->path); |
1425 | |
1426 | return retval; |
1427 | } |
1428 | |
1429 | static int |
1430 | xfs_attr_node_remove_attr( |
1431 | struct xfs_attr_intent *attr) |
1432 | { |
1433 | struct xfs_da_args *args = attr->xattri_da_args; |
1434 | struct xfs_da_state *state = xfs_da_state_alloc(args); |
1435 | int retval = 0; |
1436 | int error = 0; |
1437 | |
1438 | /* |
1439 | * The attr we are removing has already been marked incomplete, so |
1440 | * we need to set the filter appropriately to re-find the "old" |
1441 | * attribute entry after any split ops. |
1442 | */ |
1443 | args->attr_filter |= XFS_ATTR_INCOMPLETE; |
1444 | error = xfs_da3_node_lookup_int(state, result: &retval); |
1445 | if (error) |
1446 | goto out; |
1447 | |
1448 | error = xfs_attr_node_removename(args, state); |
1449 | |
1450 | /* |
1451 | * Check to see if the tree needs to be collapsed. |
1452 | */ |
1453 | if (retval && (state->path.active > 1)) { |
1454 | error = xfs_da3_join(state); |
1455 | if (error) |
1456 | goto out; |
1457 | } |
1458 | retval = error = 0; |
1459 | |
1460 | out: |
1461 | xfs_da_state_free(state); |
1462 | if (error) |
1463 | return error; |
1464 | return retval; |
1465 | } |
1466 | |
1467 | /* |
1468 | * Retrieve the attribute data from a node attribute list. |
1469 | * |
1470 | * This routine gets called for any attribute fork that has more than one |
1471 | * block, ie: both true Btree attr lists and for single-leaf-blocks with |
1472 | * "remote" values taking up more blocks. |
1473 | * |
1474 | * Returns 0 on successful retrieval, otherwise an error. |
1475 | */ |
1476 | STATIC int |
1477 | xfs_attr_node_get( |
1478 | struct xfs_da_args *args) |
1479 | { |
1480 | struct xfs_da_state *state; |
1481 | struct xfs_da_state_blk *blk; |
1482 | int i; |
1483 | int error; |
1484 | |
1485 | trace_xfs_attr_node_get(args); |
1486 | |
1487 | /* |
1488 | * Search to see if name exists, and get back a pointer to it. |
1489 | */ |
1490 | state = xfs_da_state_alloc(args); |
1491 | error = xfs_attr_node_lookup(args, state); |
1492 | if (error != -EEXIST) |
1493 | goto out_release; |
1494 | |
1495 | /* |
1496 | * Get the value, local or "remote" |
1497 | */ |
1498 | blk = &state->path.blk[state->path.active - 1]; |
1499 | error = xfs_attr3_leaf_getvalue(bp: blk->bp, args); |
1500 | |
1501 | /* |
1502 | * If not in a transaction, we have to release all the buffers. |
1503 | */ |
1504 | out_release: |
1505 | for (i = 0; i < state->path.active; i++) { |
1506 | xfs_trans_brelse(args->trans, state->path.blk[i].bp); |
1507 | state->path.blk[i].bp = NULL; |
1508 | } |
1509 | |
1510 | xfs_da_state_free(state); |
1511 | return error; |
1512 | } |
1513 | |
1514 | /* Returns true if the attribute entry name is valid. */ |
1515 | bool |
1516 | xfs_attr_namecheck( |
1517 | const void *name, |
1518 | size_t length) |
1519 | { |
1520 | /* |
1521 | * MAXNAMELEN includes the trailing null, but (name/length) leave it |
1522 | * out, so use >= for the length check. |
1523 | */ |
1524 | if (length >= MAXNAMELEN) |
1525 | return false; |
1526 | |
1527 | /* There shouldn't be any nulls here */ |
1528 | return !memchr(name, 0, length); |
1529 | } |
1530 | |
1531 | int __init |
1532 | xfs_attr_intent_init_cache(void) |
1533 | { |
1534 | xfs_attr_intent_cache = kmem_cache_create("xfs_attr_intent" , |
1535 | sizeof(struct xfs_attr_intent), |
1536 | 0, 0, NULL); |
1537 | |
1538 | return xfs_attr_intent_cache != NULL ? 0 : -ENOMEM; |
1539 | } |
1540 | |
1541 | void |
1542 | xfs_attr_intent_destroy_cache(void) |
1543 | { |
1544 | kmem_cache_destroy(xfs_attr_intent_cache); |
1545 | xfs_attr_intent_cache = NULL; |
1546 | } |
1547 | |