]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/defer_item.c
xfsprogs: Release v6.7.0
[thirdparty/xfsprogs-dev.git] / libxfs / defer_item.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0+
dc3bce02
DW
2/*
3 * Copyright (C) 2016 Oracle. All Rights Reserved.
dc3bce02 4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
dc3bce02
DW
5 */
6#include "libxfs_priv.h"
7#include "xfs_fs.h"
8#include "xfs_shared.h"
9#include "xfs_format.h"
10#include "xfs_log_format.h"
c6ad4bc1 11#include "xfs_da_format.h"
dc3bce02
DW
12#include "xfs_trans_resv.h"
13#include "xfs_bit.h"
14#include "xfs_sb.h"
15#include "xfs_mount.h"
16#include "xfs_defer.h"
17#include "xfs_trans.h"
18#include "xfs_bmap.h"
19#include "xfs_alloc.h"
20#include "xfs_rmap.h"
cdc9cf25 21#include "xfs_refcount.h"
f8f8c8a0
DW
22#include "xfs_bmap.h"
23#include "xfs_inode.h"
c6ad4bc1
AH
24#include "xfs_da_btree.h"
25#include "xfs_attr.h"
f9084bd9 26#include "libxfs.h"
dc3bce02
DW
27
28/* Dummy defer item ops, since we don't do logging. */
29
30/* Extent Freeing */
31
32/* Sort bmap items by AG. */
33static int
34xfs_extent_free_diff_items(
35 void *priv,
c6b593ee
DW
36 const struct list_head *a,
37 const struct list_head *b)
dc3bce02 38{
c6b593ee
DW
39 const struct xfs_extent_free_item *ra;
40 const struct xfs_extent_free_item *rb;
dc3bce02
DW
41
42 ra = container_of(a, struct xfs_extent_free_item, xefi_list);
43 rb = container_of(b, struct xfs_extent_free_item, xefi_list);
7fef0c11
DW
44
45 return ra->xefi_pag->pag_agno - rb->xefi_pag->pag_agno;
dc3bce02
DW
46}
47
48/* Get an EFI. */
18d0d657 49static struct xfs_log_item *
dc3bce02
DW
50xfs_extent_free_create_intent(
51 struct xfs_trans *tp,
8d81fcd0 52 struct list_head *items,
74a7f5fa
CH
53 unsigned int count,
54 bool sort)
dc3bce02 55{
74a7f5fa
CH
56 struct xfs_mount *mp = tp->t_mountp;
57
58 if (sort)
59 list_sort(mp, items, xfs_extent_free_diff_items);
dc3bce02
DW
60 return NULL;
61}
62
dc3bce02 63/* Get an EFD so we can process all the free extents. */
95e01274 64static struct xfs_log_item *
dc3bce02
DW
65xfs_extent_free_create_done(
66 struct xfs_trans *tp,
18d0d657 67 struct xfs_log_item *intent,
dc3bce02
DW
68 unsigned int count)
69{
70 return NULL;
71}
72
4d3226b6 73/* Take an active ref to the AG containing the space we're freeing. */
7fef0c11
DW
74void
75xfs_extent_free_get_group(
76 struct xfs_mount *mp,
77 struct xfs_extent_free_item *xefi)
78{
79 xfs_agnumber_t agno;
80
81 agno = XFS_FSB_TO_AGNO(mp, xefi->xefi_startblock);
4d3226b6 82 xefi->xefi_pag = xfs_perag_intent_get(mp, agno);
7fef0c11
DW
83}
84
4d3226b6 85/* Release an active AG ref after some freeing work. */
7fef0c11
DW
86static inline void
87xfs_extent_free_put_group(
88 struct xfs_extent_free_item *xefi)
89{
4d3226b6 90 xfs_perag_intent_put(xefi->xefi_pag);
7fef0c11
DW
91}
92
dc3bce02
DW
93/* Process a free extent. */
94STATIC int
95xfs_extent_free_finish_item(
96 struct xfs_trans *tp,
95e01274 97 struct xfs_log_item *done,
dc3bce02 98 struct list_head *item,
4371b480 99 struct xfs_btree_cur **state)
dc3bce02 100{
6d72c6ea 101 struct xfs_owner_info oinfo = { };
36100197 102 struct xfs_extent_free_item *xefi;
42c1e5c1 103 xfs_agblock_t agbno;
dc3bce02
DW
104 int error;
105
36100197 106 xefi = container_of(item, struct xfs_extent_free_item, xefi_list);
4d3226b6 107
36100197
CM
108 oinfo.oi_owner = xefi->xefi_owner;
109 if (xefi->xefi_flags & XFS_EFI_ATTR_FORK)
6d72c6ea 110 oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
36100197 111 if (xefi->xefi_flags & XFS_EFI_BMBT_BLOCK)
6d72c6ea 112 oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
42c1e5c1 113
42c1e5c1 114 agbno = XFS_FSB_TO_AGBNO(tp->t_mountp, xefi->xefi_startblock);
7fef0c11
DW
115 error = xfs_free_extent(tp, xefi->xefi_pag, agbno,
116 xefi->xefi_blockcount, &oinfo, XFS_AG_RESV_NONE);
42c1e5c1 117
b9166aea
DW
118 /*
119 * Don't free the XEFI if we need a new transaction to complete
120 * processing of it.
121 */
122 if (error == -EAGAIN)
123 return error;
124
7fef0c11 125 xfs_extent_free_put_group(xefi);
36100197 126 kmem_cache_free(xfs_extfree_item_cache, xefi);
dc3bce02
DW
127 return error;
128}
129
130/* Abort all pending EFIs. */
131STATIC void
132xfs_extent_free_abort_intent(
18d0d657 133 struct xfs_log_item *intent)
dc3bce02
DW
134{
135}
136
137/* Cancel a free extent. */
138STATIC void
139xfs_extent_free_cancel_item(
140 struct list_head *item)
141{
36100197 142 struct xfs_extent_free_item *xefi;
dc3bce02 143
36100197 144 xefi = container_of(item, struct xfs_extent_free_item, xefi_list);
7fef0c11
DW
145
146 xfs_extent_free_put_group(xefi);
36100197 147 kmem_cache_free(xfs_extfree_item_cache, xefi);
dc3bce02
DW
148}
149
29ce8c42 150const struct xfs_defer_op_type xfs_extent_free_defer_type = {
dc3bce02
DW
151 .create_intent = xfs_extent_free_create_intent,
152 .abort_intent = xfs_extent_free_abort_intent,
dc3bce02
DW
153 .create_done = xfs_extent_free_create_done,
154 .finish_item = xfs_extent_free_finish_item,
155 .cancel_item = xfs_extent_free_cancel_item,
156};
157
c8dc76e2
DW
158/*
159 * AGFL blocks are accounted differently in the reserve pools and are not
160 * inserted into the busy extent list.
161 */
162STATIC int
163xfs_agfl_free_finish_item(
164 struct xfs_trans *tp,
95e01274 165 struct xfs_log_item *done,
c8dc76e2 166 struct list_head *item,
4371b480 167 struct xfs_btree_cur **state)
c8dc76e2 168{
6d72c6ea 169 struct xfs_owner_info oinfo = { };
c8dc76e2 170 struct xfs_mount *mp = tp->t_mountp;
36100197 171 struct xfs_extent_free_item *xefi;
c8dc76e2
DW
172 struct xfs_buf *agbp;
173 int error;
c8dc76e2
DW
174 xfs_agblock_t agbno;
175
36100197 176 xefi = container_of(item, struct xfs_extent_free_item, xefi_list);
4d3226b6 177
36100197 178 ASSERT(xefi->xefi_blockcount == 1);
36100197
CM
179 agbno = XFS_FSB_TO_AGBNO(mp, xefi->xefi_startblock);
180 oinfo.oi_owner = xefi->xefi_owner;
c8dc76e2 181
7fef0c11 182 error = xfs_alloc_read_agf(xefi->xefi_pag, tp, 0, &agbp);
c8dc76e2 183 if (!error)
7fef0c11
DW
184 error = xfs_free_agfl_block(tp, xefi->xefi_pag->pag_agno,
185 agbno, agbp, &oinfo);
186
187 xfs_extent_free_put_group(xefi);
36100197 188 kmem_cache_free(xfs_extfree_item_cache, xefi);
c8dc76e2
DW
189 return error;
190}
191
192/* sub-type with special handling for AGFL deferred frees */
29ce8c42 193const struct xfs_defer_op_type xfs_agfl_free_defer_type = {
c8dc76e2
DW
194 .create_intent = xfs_extent_free_create_intent,
195 .abort_intent = xfs_extent_free_abort_intent,
c8dc76e2
DW
196 .create_done = xfs_extent_free_create_done,
197 .finish_item = xfs_agfl_free_finish_item,
198 .cancel_item = xfs_extent_free_cancel_item,
199};
200
dc3bce02
DW
201/* Reverse Mapping */
202
203/* Sort rmap intents by AG. */
204static int
205xfs_rmap_update_diff_items(
206 void *priv,
c6b593ee
DW
207 const struct list_head *a,
208 const struct list_head *b)
dc3bce02 209{
c6b593ee
DW
210 const struct xfs_rmap_intent *ra;
211 const struct xfs_rmap_intent *rb;
dc3bce02
DW
212
213 ra = container_of(a, struct xfs_rmap_intent, ri_list);
214 rb = container_of(b, struct xfs_rmap_intent, ri_list);
818f0c29
DW
215
216 return ra->ri_pag->pag_agno - rb->ri_pag->pag_agno;
dc3bce02
DW
217}
218
219/* Get an RUI. */
18d0d657 220static struct xfs_log_item *
dc3bce02
DW
221xfs_rmap_update_create_intent(
222 struct xfs_trans *tp,
8d81fcd0 223 struct list_head *items,
74a7f5fa
CH
224 unsigned int count,
225 bool sort)
dc3bce02 226{
74a7f5fa
CH
227 struct xfs_mount *mp = tp->t_mountp;
228
229 if (sort)
230 list_sort(mp, items, xfs_rmap_update_diff_items);
dc3bce02
DW
231 return NULL;
232}
233
dc3bce02 234/* Get an RUD so we can process all the deferred rmap updates. */
95e01274 235static struct xfs_log_item *
dc3bce02
DW
236xfs_rmap_update_create_done(
237 struct xfs_trans *tp,
18d0d657 238 struct xfs_log_item *intent,
dc3bce02
DW
239 unsigned int count)
240{
241 return NULL;
242}
243
4d3226b6 244/* Take an active ref to the AG containing the space we're rmapping. */
818f0c29
DW
245void
246xfs_rmap_update_get_group(
247 struct xfs_mount *mp,
248 struct xfs_rmap_intent *ri)
249{
250 xfs_agnumber_t agno;
251
252 agno = XFS_FSB_TO_AGNO(mp, ri->ri_bmap.br_startblock);
4d3226b6 253 ri->ri_pag = xfs_perag_intent_get(mp, agno);
818f0c29
DW
254}
255
4d3226b6 256/* Release an active AG ref after finishing rmapping work. */
818f0c29
DW
257static inline void
258xfs_rmap_update_put_group(
259 struct xfs_rmap_intent *ri)
260{
4d3226b6 261 xfs_perag_intent_put(ri->ri_pag);
818f0c29
DW
262}
263
dc3bce02
DW
264/* Process a deferred rmap update. */
265STATIC int
266xfs_rmap_update_finish_item(
267 struct xfs_trans *tp,
95e01274 268 struct xfs_log_item *done,
dc3bce02 269 struct list_head *item,
4371b480 270 struct xfs_btree_cur **state)
dc3bce02 271{
74492d88 272 struct xfs_rmap_intent *ri;
dc3bce02
DW
273 int error;
274
74492d88 275 ri = container_of(item, struct xfs_rmap_intent, ri_list);
818f0c29 276
74492d88 277 error = xfs_rmap_finish_one(tp, ri, state);
818f0c29
DW
278
279 xfs_rmap_update_put_group(ri);
74492d88 280 kmem_cache_free(xfs_rmap_intent_cache, ri);
dc3bce02
DW
281 return error;
282}
283
dc3bce02
DW
284/* Abort all pending RUIs. */
285STATIC void
286xfs_rmap_update_abort_intent(
18d0d657 287 struct xfs_log_item *intent)
dc3bce02
DW
288{
289}
290
291/* Cancel a deferred rmap update. */
292STATIC void
293xfs_rmap_update_cancel_item(
294 struct list_head *item)
295{
74492d88 296 struct xfs_rmap_intent *ri;
dc3bce02 297
74492d88 298 ri = container_of(item, struct xfs_rmap_intent, ri_list);
818f0c29
DW
299
300 xfs_rmap_update_put_group(ri);
74492d88 301 kmem_cache_free(xfs_rmap_intent_cache, ri);
dc3bce02
DW
302}
303
29ce8c42 304const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
dc3bce02
DW
305 .create_intent = xfs_rmap_update_create_intent,
306 .abort_intent = xfs_rmap_update_abort_intent,
dc3bce02
DW
307 .create_done = xfs_rmap_update_create_done,
308 .finish_item = xfs_rmap_update_finish_item,
4371b480 309 .finish_cleanup = xfs_rmap_finish_one_cleanup,
dc3bce02
DW
310 .cancel_item = xfs_rmap_update_cancel_item,
311};
312
cdc9cf25
DW
313/* Reference Counting */
314
315/* Sort refcount intents by AG. */
316static int
317xfs_refcount_update_diff_items(
318 void *priv,
c6b593ee
DW
319 const struct list_head *a,
320 const struct list_head *b)
cdc9cf25 321{
c6b593ee
DW
322 const struct xfs_refcount_intent *ra;
323 const struct xfs_refcount_intent *rb;
cdc9cf25
DW
324
325 ra = container_of(a, struct xfs_refcount_intent, ri_list);
326 rb = container_of(b, struct xfs_refcount_intent, ri_list);
b2c5c83d
DW
327
328 return ra->ri_pag->pag_agno - rb->ri_pag->pag_agno;
cdc9cf25
DW
329}
330
331/* Get an CUI. */
18d0d657 332static struct xfs_log_item *
cdc9cf25
DW
333xfs_refcount_update_create_intent(
334 struct xfs_trans *tp,
8d81fcd0 335 struct list_head *items,
74a7f5fa
CH
336 unsigned int count,
337 bool sort)
cdc9cf25 338{
74a7f5fa
CH
339 struct xfs_mount *mp = tp->t_mountp;
340
341 if (sort)
342 list_sort(mp, items, xfs_refcount_update_diff_items);
cdc9cf25
DW
343 return NULL;
344}
345
cdc9cf25 346/* Get an CUD so we can process all the deferred refcount updates. */
95e01274 347static struct xfs_log_item *
cdc9cf25
DW
348xfs_refcount_update_create_done(
349 struct xfs_trans *tp,
18d0d657 350 struct xfs_log_item *intent,
cdc9cf25
DW
351 unsigned int count)
352{
353 return NULL;
354}
355
4d3226b6 356/* Take an active ref to the AG containing the space we're refcounting. */
b2c5c83d
DW
357void
358xfs_refcount_update_get_group(
359 struct xfs_mount *mp,
360 struct xfs_refcount_intent *ri)
361{
362 xfs_agnumber_t agno;
363
364 agno = XFS_FSB_TO_AGNO(mp, ri->ri_startblock);
4d3226b6 365 ri->ri_pag = xfs_perag_intent_get(mp, agno);
b2c5c83d
DW
366}
367
4d3226b6 368/* Release an active AG ref after finishing refcounting work. */
b2c5c83d
DW
369static inline void
370xfs_refcount_update_put_group(
371 struct xfs_refcount_intent *ri)
372{
4d3226b6 373 xfs_perag_intent_put(ri->ri_pag);
b2c5c83d
DW
374}
375
cdc9cf25
DW
376/* Process a deferred refcount update. */
377STATIC int
378xfs_refcount_update_finish_item(
379 struct xfs_trans *tp,
95e01274 380 struct xfs_log_item *done,
cdc9cf25 381 struct list_head *item,
4371b480 382 struct xfs_btree_cur **state)
cdc9cf25 383{
f72f073f 384 struct xfs_refcount_intent *ri;
cdc9cf25
DW
385 int error;
386
f72f073f
DW
387 ri = container_of(item, struct xfs_refcount_intent, ri_list);
388 error = xfs_refcount_finish_one(tp, ri, state);
389
cdc9cf25 390 /* Did we run out of reservation? Requeue what we didn't finish. */
f72f073f
DW
391 if (!error && ri->ri_blockcount > 0) {
392 ASSERT(ri->ri_type == XFS_REFCOUNT_INCREASE ||
393 ri->ri_type == XFS_REFCOUNT_DECREASE);
cdc9cf25
DW
394 return -EAGAIN;
395 }
b2c5c83d
DW
396
397 xfs_refcount_update_put_group(ri);
f72f073f 398 kmem_cache_free(xfs_refcount_intent_cache, ri);
cdc9cf25
DW
399 return error;
400}
401
cdc9cf25
DW
402/* Abort all pending CUIs. */
403STATIC void
404xfs_refcount_update_abort_intent(
18d0d657 405 struct xfs_log_item *intent)
cdc9cf25
DW
406{
407}
408
409/* Cancel a deferred refcount update. */
410STATIC void
411xfs_refcount_update_cancel_item(
412 struct list_head *item)
413{
f72f073f 414 struct xfs_refcount_intent *ri;
cdc9cf25 415
f72f073f 416 ri = container_of(item, struct xfs_refcount_intent, ri_list);
b2c5c83d
DW
417
418 xfs_refcount_update_put_group(ri);
f72f073f 419 kmem_cache_free(xfs_refcount_intent_cache, ri);
cdc9cf25
DW
420}
421
29ce8c42 422const struct xfs_defer_op_type xfs_refcount_update_defer_type = {
cdc9cf25
DW
423 .create_intent = xfs_refcount_update_create_intent,
424 .abort_intent = xfs_refcount_update_abort_intent,
cdc9cf25
DW
425 .create_done = xfs_refcount_update_create_done,
426 .finish_item = xfs_refcount_update_finish_item,
4371b480 427 .finish_cleanup = xfs_refcount_finish_one_cleanup,
cdc9cf25
DW
428 .cancel_item = xfs_refcount_update_cancel_item,
429};
430
f8f8c8a0
DW
431/* Inode Block Mapping */
432
433/* Sort bmap intents by inode. */
434static int
435xfs_bmap_update_diff_items(
436 void *priv,
c6b593ee
DW
437 const struct list_head *a,
438 const struct list_head *b)
f8f8c8a0 439{
c6b593ee
DW
440 const struct xfs_bmap_intent *ba;
441 const struct xfs_bmap_intent *bb;
f8f8c8a0
DW
442
443 ba = container_of(a, struct xfs_bmap_intent, bi_list);
444 bb = container_of(b, struct xfs_bmap_intent, bi_list);
445 return ba->bi_owner->i_ino - bb->bi_owner->i_ino;
446}
447
448/* Get an BUI. */
18d0d657 449static struct xfs_log_item *
f8f8c8a0
DW
450xfs_bmap_update_create_intent(
451 struct xfs_trans *tp,
8d81fcd0 452 struct list_head *items,
74a7f5fa
CH
453 unsigned int count,
454 bool sort)
f8f8c8a0 455{
74a7f5fa
CH
456 struct xfs_mount *mp = tp->t_mountp;
457
458 if (sort)
459 list_sort(mp, items, xfs_bmap_update_diff_items);
f8f8c8a0
DW
460 return NULL;
461}
462
f8f8c8a0 463/* Get an BUD so we can process all the deferred rmap updates. */
95e01274 464static struct xfs_log_item *
f8f8c8a0
DW
465xfs_bmap_update_create_done(
466 struct xfs_trans *tp,
18d0d657 467 struct xfs_log_item *intent,
f8f8c8a0
DW
468 unsigned int count)
469{
470 return NULL;
471}
472
4d3226b6 473/* Take an active ref to the AG containing the space we're mapping. */
32debad7
DW
474void
475xfs_bmap_update_get_group(
476 struct xfs_mount *mp,
477 struct xfs_bmap_intent *bi)
478{
479 xfs_agnumber_t agno;
480
481 agno = XFS_FSB_TO_AGNO(mp, bi->bi_bmap.br_startblock);
4d3226b6
DW
482
483 /*
484 * Bump the intent count on behalf of the deferred rmap and refcount
485 * intent items that that we can queue when we finish this bmap work.
486 * This new intent item will bump the intent count before the bmap
487 * intent drops the intent count, ensuring that the intent count
488 * remains nonzero across the transaction roll.
489 */
490 bi->bi_pag = xfs_perag_intent_get(mp, agno);
32debad7
DW
491}
492
4d3226b6 493/* Release an active AG ref after finishing mapping work. */
32debad7
DW
494static inline void
495xfs_bmap_update_put_group(
496 struct xfs_bmap_intent *bi)
497{
4d3226b6 498 xfs_perag_intent_put(bi->bi_pag);
32debad7
DW
499}
500
f8f8c8a0
DW
501/* Process a deferred rmap update. */
502STATIC int
503xfs_bmap_update_finish_item(
504 struct xfs_trans *tp,
95e01274 505 struct xfs_log_item *done,
f8f8c8a0 506 struct list_head *item,
4371b480 507 struct xfs_btree_cur **state)
f8f8c8a0 508{
afe1175f 509 struct xfs_bmap_intent *bi;
f8f8c8a0
DW
510 int error;
511
afe1175f
DW
512 bi = container_of(item, struct xfs_bmap_intent, bi_list);
513 error = xfs_bmap_finish_one(tp, bi);
514 if (!error && bi->bi_bmap.br_blockcount > 0) {
515 ASSERT(bi->bi_type == XFS_BMAP_UNMAP);
594956fa
DW
516 return -EAGAIN;
517 }
32debad7
DW
518
519 xfs_bmap_update_put_group(bi);
afe1175f 520 kmem_cache_free(xfs_bmap_intent_cache, bi);
f8f8c8a0
DW
521 return error;
522}
523
524/* Abort all pending BUIs. */
525STATIC void
526xfs_bmap_update_abort_intent(
18d0d657 527 struct xfs_log_item *intent)
f8f8c8a0
DW
528{
529}
530
531/* Cancel a deferred rmap update. */
532STATIC void
533xfs_bmap_update_cancel_item(
534 struct list_head *item)
535{
afe1175f 536 struct xfs_bmap_intent *bi;
f8f8c8a0 537
afe1175f 538 bi = container_of(item, struct xfs_bmap_intent, bi_list);
32debad7
DW
539
540 xfs_bmap_update_put_group(bi);
afe1175f 541 kmem_cache_free(xfs_bmap_intent_cache, bi);
f8f8c8a0
DW
542}
543
29ce8c42 544const struct xfs_defer_op_type xfs_bmap_update_defer_type = {
f8f8c8a0
DW
545 .create_intent = xfs_bmap_update_create_intent,
546 .abort_intent = xfs_bmap_update_abort_intent,
f8f8c8a0
DW
547 .create_done = xfs_bmap_update_create_done,
548 .finish_item = xfs_bmap_update_finish_item,
549 .cancel_item = xfs_bmap_update_cancel_item,
550};
c6ad4bc1
AH
551
552/* Get an ATTRI. */
553static struct xfs_log_item *
554xfs_attr_create_intent(
555 struct xfs_trans *tp,
556 struct list_head *items,
557 unsigned int count,
558 bool sort)
559{
560 return NULL;
561}
562
563/* Abort all pending ATTRs. */
564static void
565xfs_attr_abort_intent(
566 struct xfs_log_item *intent)
567{
568}
569
570/* Get an ATTRD so we can process all the attrs. */
571static struct xfs_log_item *
572xfs_attr_create_done(
573 struct xfs_trans *tp,
574 struct xfs_log_item *intent,
575 unsigned int count)
576{
577 return NULL;
578}
579
5b391189
DW
580static inline void
581xfs_attr_free_item(
eff5933f 582 struct xfs_attr_intent *attr)
5b391189
DW
583{
584 if (attr->xattri_da_state)
585 xfs_da_state_free(attr->xattri_da_state);
3b0ca632
DW
586 if (attr->xattri_da_args->op_flags & XFS_DA_OP_RECOVERY)
587 kmem_free(attr);
588 else
589 kmem_cache_free(xfs_attr_intent_cache, attr);
5b391189
DW
590}
591
c6ad4bc1
AH
592/* Process an attr. */
593static int
594xfs_attr_finish_item(
595 struct xfs_trans *tp,
596 struct xfs_log_item *done,
597 struct list_head *item,
598 struct xfs_btree_cur **state)
599{
eff5933f 600 struct xfs_attr_intent *attr;
c6ad4bc1 601 int error;
c6ad4bc1 602 struct xfs_da_args *args;
c6ad4bc1 603
eff5933f 604 attr = container_of(item, struct xfs_attr_intent, xattri_list);
a951e052 605 args = attr->xattri_da_args;
c6ad4bc1
AH
606
607 /*
608 * Always reset trans after EAGAIN cycle
609 * since the transaction is new
610 */
611 args->trans = tp;
612
a2832031
AH
613 if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_LARP)) {
614 error = -EIO;
615 goto out;
616 }
617
fc32183a
DC
618 error = xfs_attr_set_iter(attr);
619 if (!error && attr->xattri_dela_state != XFS_DAS_DONE)
620 error = -EAGAIN;
a2832031 621out:
c6ad4bc1 622 if (error != -EAGAIN)
5b391189 623 xfs_attr_free_item(attr);
c6ad4bc1
AH
624
625 return error;
626}
627
628/* Cancel an attr */
629static void
630xfs_attr_cancel_item(
631 struct list_head *item)
632{
eff5933f 633 struct xfs_attr_intent *attr;
c6ad4bc1 634
eff5933f 635 attr = container_of(item, struct xfs_attr_intent, xattri_list);
5b391189 636 xfs_attr_free_item(attr);
c6ad4bc1
AH
637}
638
639const struct xfs_defer_op_type xfs_attr_defer_type = {
640 .max_items = 1,
641 .create_intent = xfs_attr_create_intent,
642 .abort_intent = xfs_attr_abort_intent,
643 .create_done = xfs_attr_create_done,
644 .finish_item = xfs_attr_finish_item,
645 .cancel_item = xfs_attr_cancel_item,
646};