1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Copyright (C) 2016 Oracle. All Rights Reserved. |
4 | * Author: Darrick J. Wong <darrick.wong@oracle.com> |
5 | */ |
6 | #include "xfs.h" |
7 | #include "xfs_fs.h" |
8 | #include "xfs_format.h" |
9 | #include "xfs_log_format.h" |
10 | #include "xfs_trans_resv.h" |
11 | #include "xfs_bit.h" |
12 | #include "xfs_shared.h" |
13 | #include "xfs_mount.h" |
14 | #include "xfs_defer.h" |
15 | #include "xfs_trans.h" |
16 | #include "xfs_trans_priv.h" |
17 | #include "xfs_rmap_item.h" |
18 | #include "xfs_log.h" |
19 | #include "xfs_rmap.h" |
20 | #include "xfs_error.h" |
21 | #include "xfs_log_priv.h" |
22 | #include "xfs_log_recover.h" |
23 | #include "xfs_ag.h" |
24 | |
25 | struct kmem_cache *xfs_rui_cache; |
26 | struct kmem_cache *xfs_rud_cache; |
27 | |
28 | static const struct xfs_item_ops xfs_rui_item_ops; |
29 | |
30 | static inline struct xfs_rui_log_item *RUI_ITEM(struct xfs_log_item *lip) |
31 | { |
32 | return container_of(lip, struct xfs_rui_log_item, rui_item); |
33 | } |
34 | |
35 | STATIC void |
36 | xfs_rui_item_free( |
37 | struct xfs_rui_log_item *ruip) |
38 | { |
39 | kvfree(addr: ruip->rui_item.li_lv_shadow); |
40 | if (ruip->rui_format.rui_nextents > XFS_RUI_MAX_FAST_EXTENTS) |
41 | kfree(objp: ruip); |
42 | else |
43 | kmem_cache_free(s: xfs_rui_cache, objp: ruip); |
44 | } |
45 | |
46 | /* |
47 | * Freeing the RUI requires that we remove it from the AIL if it has already |
48 | * been placed there. However, the RUI may not yet have been placed in the AIL |
49 | * when called by xfs_rui_release() from RUD processing due to the ordering of |
50 | * committed vs unpin operations in bulk insert operations. Hence the reference |
51 | * count to ensure only the last caller frees the RUI. |
52 | */ |
53 | STATIC void |
54 | xfs_rui_release( |
55 | struct xfs_rui_log_item *ruip) |
56 | { |
57 | ASSERT(atomic_read(&ruip->rui_refcount) > 0); |
58 | if (!atomic_dec_and_test(v: &ruip->rui_refcount)) |
59 | return; |
60 | |
61 | xfs_trans_ail_delete(lip: &ruip->rui_item, shutdown_type: 0); |
62 | xfs_rui_item_free(ruip); |
63 | } |
64 | |
65 | STATIC void |
66 | xfs_rui_item_size( |
67 | struct xfs_log_item *lip, |
68 | int *nvecs, |
69 | int *nbytes) |
70 | { |
71 | struct xfs_rui_log_item *ruip = RUI_ITEM(lip); |
72 | |
73 | *nvecs += 1; |
74 | *nbytes += xfs_rui_log_format_sizeof(ruip->rui_format.rui_nextents); |
75 | } |
76 | |
77 | /* |
78 | * This is called to fill in the vector of log iovecs for the |
79 | * given rui log item. We use only 1 iovec, and we point that |
80 | * at the rui_log_format structure embedded in the rui item. |
81 | * It is at this point that we assert that all of the extent |
82 | * slots in the rui item have been filled. |
83 | */ |
84 | STATIC void |
85 | xfs_rui_item_format( |
86 | struct xfs_log_item *lip, |
87 | struct xfs_log_vec *lv) |
88 | { |
89 | struct xfs_rui_log_item *ruip = RUI_ITEM(lip); |
90 | struct xfs_log_iovec *vecp = NULL; |
91 | |
92 | ASSERT(atomic_read(&ruip->rui_next_extent) == |
93 | ruip->rui_format.rui_nextents); |
94 | |
95 | ruip->rui_format.rui_type = XFS_LI_RUI; |
96 | ruip->rui_format.rui_size = 1; |
97 | |
98 | xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_RUI_FORMAT, &ruip->rui_format, |
99 | xfs_rui_log_format_sizeof(ruip->rui_format.rui_nextents)); |
100 | } |
101 | |
102 | /* |
103 | * The unpin operation is the last place an RUI is manipulated in the log. It is |
104 | * either inserted in the AIL or aborted in the event of a log I/O error. In |
105 | * either case, the RUI transaction has been successfully committed to make it |
106 | * this far. Therefore, we expect whoever committed the RUI to either construct |
107 | * and commit the RUD or drop the RUD's reference in the event of error. Simply |
108 | * drop the log's RUI reference now that the log is done with it. |
109 | */ |
110 | STATIC void |
111 | xfs_rui_item_unpin( |
112 | struct xfs_log_item *lip, |
113 | int remove) |
114 | { |
115 | struct xfs_rui_log_item *ruip = RUI_ITEM(lip); |
116 | |
117 | xfs_rui_release(ruip); |
118 | } |
119 | |
120 | /* |
121 | * The RUI has been either committed or aborted if the transaction has been |
122 | * cancelled. If the transaction was cancelled, an RUD isn't going to be |
123 | * constructed and thus we free the RUI here directly. |
124 | */ |
125 | STATIC void |
126 | xfs_rui_item_release( |
127 | struct xfs_log_item *lip) |
128 | { |
129 | xfs_rui_release(ruip: RUI_ITEM(lip)); |
130 | } |
131 | |
132 | /* |
133 | * Allocate and initialize an rui item with the given number of extents. |
134 | */ |
135 | STATIC struct xfs_rui_log_item * |
136 | xfs_rui_init( |
137 | struct xfs_mount *mp, |
138 | uint nextents) |
139 | |
140 | { |
141 | struct xfs_rui_log_item *ruip; |
142 | |
143 | ASSERT(nextents > 0); |
144 | if (nextents > XFS_RUI_MAX_FAST_EXTENTS) |
145 | ruip = kzalloc(size: xfs_rui_log_item_sizeof(nr: nextents), |
146 | GFP_KERNEL | __GFP_NOFAIL); |
147 | else |
148 | ruip = kmem_cache_zalloc(k: xfs_rui_cache, |
149 | GFP_KERNEL | __GFP_NOFAIL); |
150 | |
151 | xfs_log_item_init(mp, &ruip->rui_item, XFS_LI_RUI, &xfs_rui_item_ops); |
152 | ruip->rui_format.rui_nextents = nextents; |
153 | ruip->rui_format.rui_id = (uintptr_t)(void *)ruip; |
154 | atomic_set(v: &ruip->rui_next_extent, i: 0); |
155 | atomic_set(v: &ruip->rui_refcount, i: 2); |
156 | |
157 | return ruip; |
158 | } |
159 | |
160 | static inline struct xfs_rud_log_item *RUD_ITEM(struct xfs_log_item *lip) |
161 | { |
162 | return container_of(lip, struct xfs_rud_log_item, rud_item); |
163 | } |
164 | |
165 | STATIC void |
166 | xfs_rud_item_size( |
167 | struct xfs_log_item *lip, |
168 | int *nvecs, |
169 | int *nbytes) |
170 | { |
171 | *nvecs += 1; |
172 | *nbytes += sizeof(struct xfs_rud_log_format); |
173 | } |
174 | |
175 | /* |
176 | * This is called to fill in the vector of log iovecs for the |
177 | * given rud log item. We use only 1 iovec, and we point that |
178 | * at the rud_log_format structure embedded in the rud item. |
179 | * It is at this point that we assert that all of the extent |
180 | * slots in the rud item have been filled. |
181 | */ |
182 | STATIC void |
183 | xfs_rud_item_format( |
184 | struct xfs_log_item *lip, |
185 | struct xfs_log_vec *lv) |
186 | { |
187 | struct xfs_rud_log_item *rudp = RUD_ITEM(lip); |
188 | struct xfs_log_iovec *vecp = NULL; |
189 | |
190 | rudp->rud_format.rud_type = XFS_LI_RUD; |
191 | rudp->rud_format.rud_size = 1; |
192 | |
193 | xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_RUD_FORMAT, &rudp->rud_format, |
194 | sizeof(struct xfs_rud_log_format)); |
195 | } |
196 | |
197 | /* |
198 | * The RUD is either committed or aborted if the transaction is cancelled. If |
199 | * the transaction is cancelled, drop our reference to the RUI and free the |
200 | * RUD. |
201 | */ |
202 | STATIC void |
203 | xfs_rud_item_release( |
204 | struct xfs_log_item *lip) |
205 | { |
206 | struct xfs_rud_log_item *rudp = RUD_ITEM(lip); |
207 | |
208 | xfs_rui_release(ruip: rudp->rud_ruip); |
209 | kvfree(addr: rudp->rud_item.li_lv_shadow); |
210 | kmem_cache_free(s: xfs_rud_cache, objp: rudp); |
211 | } |
212 | |
213 | static struct xfs_log_item * |
214 | xfs_rud_item_intent( |
215 | struct xfs_log_item *lip) |
216 | { |
217 | return &RUD_ITEM(lip)->rud_ruip->rui_item; |
218 | } |
219 | |
220 | static const struct xfs_item_ops xfs_rud_item_ops = { |
221 | .flags = XFS_ITEM_RELEASE_WHEN_COMMITTED | |
222 | XFS_ITEM_INTENT_DONE, |
223 | .iop_size = xfs_rud_item_size, |
224 | .iop_format = xfs_rud_item_format, |
225 | .iop_release = xfs_rud_item_release, |
226 | .iop_intent = xfs_rud_item_intent, |
227 | }; |
228 | |
229 | /* Set the map extent flags for this reverse mapping. */ |
230 | static void |
231 | xfs_trans_set_rmap_flags( |
232 | struct xfs_map_extent *map, |
233 | enum xfs_rmap_intent_type type, |
234 | int whichfork, |
235 | xfs_exntst_t state) |
236 | { |
237 | map->me_flags = 0; |
238 | if (state == XFS_EXT_UNWRITTEN) |
239 | map->me_flags |= XFS_RMAP_EXTENT_UNWRITTEN; |
240 | if (whichfork == XFS_ATTR_FORK) |
241 | map->me_flags |= XFS_RMAP_EXTENT_ATTR_FORK; |
242 | switch (type) { |
243 | case XFS_RMAP_MAP: |
244 | map->me_flags |= XFS_RMAP_EXTENT_MAP; |
245 | break; |
246 | case XFS_RMAP_MAP_SHARED: |
247 | map->me_flags |= XFS_RMAP_EXTENT_MAP_SHARED; |
248 | break; |
249 | case XFS_RMAP_UNMAP: |
250 | map->me_flags |= XFS_RMAP_EXTENT_UNMAP; |
251 | break; |
252 | case XFS_RMAP_UNMAP_SHARED: |
253 | map->me_flags |= XFS_RMAP_EXTENT_UNMAP_SHARED; |
254 | break; |
255 | case XFS_RMAP_CONVERT: |
256 | map->me_flags |= XFS_RMAP_EXTENT_CONVERT; |
257 | break; |
258 | case XFS_RMAP_CONVERT_SHARED: |
259 | map->me_flags |= XFS_RMAP_EXTENT_CONVERT_SHARED; |
260 | break; |
261 | case XFS_RMAP_ALLOC: |
262 | map->me_flags |= XFS_RMAP_EXTENT_ALLOC; |
263 | break; |
264 | case XFS_RMAP_FREE: |
265 | map->me_flags |= XFS_RMAP_EXTENT_FREE; |
266 | break; |
267 | default: |
268 | ASSERT(0); |
269 | } |
270 | } |
271 | |
272 | /* Sort rmap intents by AG. */ |
273 | static int |
274 | xfs_rmap_update_diff_items( |
275 | void *priv, |
276 | const struct list_head *a, |
277 | const struct list_head *b) |
278 | { |
279 | struct xfs_rmap_intent *ra; |
280 | struct xfs_rmap_intent *rb; |
281 | |
282 | ra = container_of(a, struct xfs_rmap_intent, ri_list); |
283 | rb = container_of(b, struct xfs_rmap_intent, ri_list); |
284 | |
285 | return ra->ri_pag->pag_agno - rb->ri_pag->pag_agno; |
286 | } |
287 | |
288 | /* Log rmap updates in the intent item. */ |
289 | STATIC void |
290 | xfs_rmap_update_log_item( |
291 | struct xfs_trans *tp, |
292 | struct xfs_rui_log_item *ruip, |
293 | struct xfs_rmap_intent *ri) |
294 | { |
295 | uint next_extent; |
296 | struct xfs_map_extent *map; |
297 | |
298 | /* |
299 | * atomic_inc_return gives us the value after the increment; |
300 | * we want to use it as an array index so we need to subtract 1 from |
301 | * it. |
302 | */ |
303 | next_extent = atomic_inc_return(v: &ruip->rui_next_extent) - 1; |
304 | ASSERT(next_extent < ruip->rui_format.rui_nextents); |
305 | map = &ruip->rui_format.rui_extents[next_extent]; |
306 | map->me_owner = ri->ri_owner; |
307 | map->me_startblock = ri->ri_bmap.br_startblock; |
308 | map->me_startoff = ri->ri_bmap.br_startoff; |
309 | map->me_len = ri->ri_bmap.br_blockcount; |
310 | xfs_trans_set_rmap_flags(map, ri->ri_type, ri->ri_whichfork, |
311 | ri->ri_bmap.br_state); |
312 | } |
313 | |
314 | static struct xfs_log_item * |
315 | xfs_rmap_update_create_intent( |
316 | struct xfs_trans *tp, |
317 | struct list_head *items, |
318 | unsigned int count, |
319 | bool sort) |
320 | { |
321 | struct xfs_mount *mp = tp->t_mountp; |
322 | struct xfs_rui_log_item *ruip = xfs_rui_init(mp, nextents: count); |
323 | struct xfs_rmap_intent *ri; |
324 | |
325 | ASSERT(count > 0); |
326 | |
327 | if (sort) |
328 | list_sort(priv: mp, head: items, cmp: xfs_rmap_update_diff_items); |
329 | list_for_each_entry(ri, items, ri_list) |
330 | xfs_rmap_update_log_item(tp, ruip, ri); |
331 | return &ruip->rui_item; |
332 | } |
333 | |
334 | /* Get an RUD so we can process all the deferred rmap updates. */ |
335 | static struct xfs_log_item * |
336 | xfs_rmap_update_create_done( |
337 | struct xfs_trans *tp, |
338 | struct xfs_log_item *intent, |
339 | unsigned int count) |
340 | { |
341 | struct xfs_rui_log_item *ruip = RUI_ITEM(lip: intent); |
342 | struct xfs_rud_log_item *rudp; |
343 | |
344 | rudp = kmem_cache_zalloc(k: xfs_rud_cache, GFP_KERNEL | __GFP_NOFAIL); |
345 | xfs_log_item_init(tp->t_mountp, &rudp->rud_item, XFS_LI_RUD, |
346 | &xfs_rud_item_ops); |
347 | rudp->rud_ruip = ruip; |
348 | rudp->rud_format.rud_rui_id = ruip->rui_format.rui_id; |
349 | |
350 | return &rudp->rud_item; |
351 | } |
352 | |
353 | /* Take a passive ref to the AG containing the space we're rmapping. */ |
354 | void |
355 | xfs_rmap_update_get_group( |
356 | struct xfs_mount *mp, |
357 | struct xfs_rmap_intent *ri) |
358 | { |
359 | xfs_agnumber_t agno; |
360 | |
361 | agno = XFS_FSB_TO_AGNO(mp, ri->ri_bmap.br_startblock); |
362 | ri->ri_pag = xfs_perag_intent_get(mp, agno); |
363 | } |
364 | |
365 | /* Release a passive AG ref after finishing rmapping work. */ |
366 | static inline void |
367 | xfs_rmap_update_put_group( |
368 | struct xfs_rmap_intent *ri) |
369 | { |
370 | xfs_perag_intent_put(pag: ri->ri_pag); |
371 | } |
372 | |
373 | /* Process a deferred rmap update. */ |
374 | STATIC int |
375 | xfs_rmap_update_finish_item( |
376 | struct xfs_trans *tp, |
377 | struct xfs_log_item *done, |
378 | struct list_head *item, |
379 | struct xfs_btree_cur **state) |
380 | { |
381 | struct xfs_rmap_intent *ri; |
382 | int error; |
383 | |
384 | ri = container_of(item, struct xfs_rmap_intent, ri_list); |
385 | |
386 | error = xfs_rmap_finish_one(tp, ri, state); |
387 | |
388 | xfs_rmap_update_put_group(ri); |
389 | kmem_cache_free(xfs_rmap_intent_cache, ri); |
390 | return error; |
391 | } |
392 | |
393 | /* Abort all pending RUIs. */ |
394 | STATIC void |
395 | xfs_rmap_update_abort_intent( |
396 | struct xfs_log_item *intent) |
397 | { |
398 | xfs_rui_release(ruip: RUI_ITEM(lip: intent)); |
399 | } |
400 | |
401 | /* Cancel a deferred rmap update. */ |
402 | STATIC void |
403 | xfs_rmap_update_cancel_item( |
404 | struct list_head *item) |
405 | { |
406 | struct xfs_rmap_intent *ri; |
407 | |
408 | ri = container_of(item, struct xfs_rmap_intent, ri_list); |
409 | |
410 | xfs_rmap_update_put_group(ri); |
411 | kmem_cache_free(xfs_rmap_intent_cache, ri); |
412 | } |
413 | |
414 | /* Is this recovered RUI ok? */ |
415 | static inline bool |
416 | xfs_rui_validate_map( |
417 | struct xfs_mount *mp, |
418 | struct xfs_map_extent *map) |
419 | { |
420 | if (!xfs_has_rmapbt(mp)) |
421 | return false; |
422 | |
423 | if (map->me_flags & ~XFS_RMAP_EXTENT_FLAGS) |
424 | return false; |
425 | |
426 | switch (map->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) { |
427 | case XFS_RMAP_EXTENT_MAP: |
428 | case XFS_RMAP_EXTENT_MAP_SHARED: |
429 | case XFS_RMAP_EXTENT_UNMAP: |
430 | case XFS_RMAP_EXTENT_UNMAP_SHARED: |
431 | case XFS_RMAP_EXTENT_CONVERT: |
432 | case XFS_RMAP_EXTENT_CONVERT_SHARED: |
433 | case XFS_RMAP_EXTENT_ALLOC: |
434 | case XFS_RMAP_EXTENT_FREE: |
435 | break; |
436 | default: |
437 | return false; |
438 | } |
439 | |
440 | if (!XFS_RMAP_NON_INODE_OWNER(map->me_owner) && |
441 | !xfs_verify_ino(mp, map->me_owner)) |
442 | return false; |
443 | |
444 | if (!xfs_verify_fileext(mp, map->me_startoff, map->me_len)) |
445 | return false; |
446 | |
447 | return xfs_verify_fsbext(mp, map->me_startblock, map->me_len); |
448 | } |
449 | |
450 | static inline void |
451 | xfs_rui_recover_work( |
452 | struct xfs_mount *mp, |
453 | struct xfs_defer_pending *dfp, |
454 | const struct xfs_map_extent *map) |
455 | { |
456 | struct xfs_rmap_intent *ri; |
457 | |
458 | ri = kmem_cache_alloc(xfs_rmap_intent_cache, GFP_KERNEL | __GFP_NOFAIL); |
459 | |
460 | switch (map->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) { |
461 | case XFS_RMAP_EXTENT_MAP: |
462 | ri->ri_type = XFS_RMAP_MAP; |
463 | break; |
464 | case XFS_RMAP_EXTENT_MAP_SHARED: |
465 | ri->ri_type = XFS_RMAP_MAP_SHARED; |
466 | break; |
467 | case XFS_RMAP_EXTENT_UNMAP: |
468 | ri->ri_type = XFS_RMAP_UNMAP; |
469 | break; |
470 | case XFS_RMAP_EXTENT_UNMAP_SHARED: |
471 | ri->ri_type = XFS_RMAP_UNMAP_SHARED; |
472 | break; |
473 | case XFS_RMAP_EXTENT_CONVERT: |
474 | ri->ri_type = XFS_RMAP_CONVERT; |
475 | break; |
476 | case XFS_RMAP_EXTENT_CONVERT_SHARED: |
477 | ri->ri_type = XFS_RMAP_CONVERT_SHARED; |
478 | break; |
479 | case XFS_RMAP_EXTENT_ALLOC: |
480 | ri->ri_type = XFS_RMAP_ALLOC; |
481 | break; |
482 | case XFS_RMAP_EXTENT_FREE: |
483 | ri->ri_type = XFS_RMAP_FREE; |
484 | break; |
485 | default: |
486 | ASSERT(0); |
487 | return; |
488 | } |
489 | |
490 | ri->ri_owner = map->me_owner; |
491 | ri->ri_whichfork = (map->me_flags & XFS_RMAP_EXTENT_ATTR_FORK) ? |
492 | XFS_ATTR_FORK : XFS_DATA_FORK; |
493 | ri->ri_bmap.br_startblock = map->me_startblock; |
494 | ri->ri_bmap.br_startoff = map->me_startoff; |
495 | ri->ri_bmap.br_blockcount = map->me_len; |
496 | ri->ri_bmap.br_state = (map->me_flags & XFS_RMAP_EXTENT_UNWRITTEN) ? |
497 | XFS_EXT_UNWRITTEN : XFS_EXT_NORM; |
498 | xfs_rmap_update_get_group(mp, ri); |
499 | |
500 | xfs_defer_add_item(dfp, &ri->ri_list); |
501 | } |
502 | |
503 | /* |
504 | * Process an rmap update intent item that was recovered from the log. |
505 | * We need to update the rmapbt. |
506 | */ |
507 | STATIC int |
508 | xfs_rmap_recover_work( |
509 | struct xfs_defer_pending *dfp, |
510 | struct list_head *capture_list) |
511 | { |
512 | struct xfs_trans_res resv; |
513 | struct xfs_log_item *lip = dfp->dfp_intent; |
514 | struct xfs_rui_log_item *ruip = RUI_ITEM(lip); |
515 | struct xfs_trans *tp; |
516 | struct xfs_mount *mp = lip->li_log->l_mp; |
517 | int i; |
518 | int error = 0; |
519 | |
520 | /* |
521 | * First check the validity of the extents described by the |
522 | * RUI. If any are bad, then assume that all are bad and |
523 | * just toss the RUI. |
524 | */ |
525 | for (i = 0; i < ruip->rui_format.rui_nextents; i++) { |
526 | if (!xfs_rui_validate_map(mp, |
527 | map: &ruip->rui_format.rui_extents[i])) { |
528 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, |
529 | &ruip->rui_format, |
530 | sizeof(ruip->rui_format)); |
531 | return -EFSCORRUPTED; |
532 | } |
533 | |
534 | xfs_rui_recover_work(mp, dfp, map: &ruip->rui_format.rui_extents[i]); |
535 | } |
536 | |
537 | resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate); |
538 | error = xfs_trans_alloc(mp, &resv, mp->m_rmap_maxlevels, 0, |
539 | XFS_TRANS_RESERVE, &tp); |
540 | if (error) |
541 | return error; |
542 | |
543 | error = xlog_recover_finish_intent(tp, dfp); |
544 | if (error == -EFSCORRUPTED) |
545 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, |
546 | &ruip->rui_format, |
547 | sizeof(ruip->rui_format)); |
548 | if (error) |
549 | goto abort_error; |
550 | |
551 | return xfs_defer_ops_capture_and_commit(tp, capture_list); |
552 | |
553 | abort_error: |
554 | xfs_trans_cancel(tp); |
555 | return error; |
556 | } |
557 | |
558 | /* Relog an intent item to push the log tail forward. */ |
559 | static struct xfs_log_item * |
560 | xfs_rmap_relog_intent( |
561 | struct xfs_trans *tp, |
562 | struct xfs_log_item *intent, |
563 | struct xfs_log_item *done_item) |
564 | { |
565 | struct xfs_rui_log_item *ruip; |
566 | struct xfs_map_extent *map; |
567 | unsigned int count; |
568 | |
569 | count = RUI_ITEM(lip: intent)->rui_format.rui_nextents; |
570 | map = RUI_ITEM(lip: intent)->rui_format.rui_extents; |
571 | |
572 | ruip = xfs_rui_init(mp: tp->t_mountp, nextents: count); |
573 | memcpy(ruip->rui_format.rui_extents, map, count * sizeof(*map)); |
574 | atomic_set(v: &ruip->rui_next_extent, i: count); |
575 | |
576 | return &ruip->rui_item; |
577 | } |
578 | |
579 | const struct xfs_defer_op_type xfs_rmap_update_defer_type = { |
580 | .name = "rmap" , |
581 | .max_items = XFS_RUI_MAX_FAST_EXTENTS, |
582 | .create_intent = xfs_rmap_update_create_intent, |
583 | .abort_intent = xfs_rmap_update_abort_intent, |
584 | .create_done = xfs_rmap_update_create_done, |
585 | .finish_item = xfs_rmap_update_finish_item, |
586 | .finish_cleanup = xfs_rmap_finish_one_cleanup, |
587 | .cancel_item = xfs_rmap_update_cancel_item, |
588 | .recover_work = xfs_rmap_recover_work, |
589 | .relog_intent = xfs_rmap_relog_intent, |
590 | }; |
591 | |
592 | STATIC bool |
593 | xfs_rui_item_match( |
594 | struct xfs_log_item *lip, |
595 | uint64_t intent_id) |
596 | { |
597 | return RUI_ITEM(lip)->rui_format.rui_id == intent_id; |
598 | } |
599 | |
600 | static const struct xfs_item_ops xfs_rui_item_ops = { |
601 | .flags = XFS_ITEM_INTENT, |
602 | .iop_size = xfs_rui_item_size, |
603 | .iop_format = xfs_rui_item_format, |
604 | .iop_unpin = xfs_rui_item_unpin, |
605 | .iop_release = xfs_rui_item_release, |
606 | .iop_match = xfs_rui_item_match, |
607 | }; |
608 | |
609 | static inline void |
610 | xfs_rui_copy_format( |
611 | struct xfs_rui_log_format *dst, |
612 | const struct xfs_rui_log_format *src) |
613 | { |
614 | unsigned int i; |
615 | |
616 | memcpy(dst, src, offsetof(struct xfs_rui_log_format, rui_extents)); |
617 | |
618 | for (i = 0; i < src->rui_nextents; i++) |
619 | memcpy(&dst->rui_extents[i], &src->rui_extents[i], |
620 | sizeof(struct xfs_map_extent)); |
621 | } |
622 | |
623 | /* |
624 | * This routine is called to create an in-core extent rmap update |
625 | * item from the rui format structure which was logged on disk. |
626 | * It allocates an in-core rui, copies the extents from the format |
627 | * structure into it, and adds the rui to the AIL with the given |
628 | * LSN. |
629 | */ |
630 | STATIC int |
631 | xlog_recover_rui_commit_pass2( |
632 | struct xlog *log, |
633 | struct list_head *buffer_list, |
634 | struct xlog_recover_item *item, |
635 | xfs_lsn_t lsn) |
636 | { |
637 | struct xfs_mount *mp = log->l_mp; |
638 | struct xfs_rui_log_item *ruip; |
639 | struct xfs_rui_log_format *rui_formatp; |
640 | size_t len; |
641 | |
642 | rui_formatp = item->ri_buf[0].i_addr; |
643 | |
644 | if (item->ri_buf[0].i_len < xfs_rui_log_format_sizeof(0)) { |
645 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, |
646 | item->ri_buf[0].i_addr, item->ri_buf[0].i_len); |
647 | return -EFSCORRUPTED; |
648 | } |
649 | |
650 | len = xfs_rui_log_format_sizeof(rui_formatp->rui_nextents); |
651 | if (item->ri_buf[0].i_len != len) { |
652 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, |
653 | item->ri_buf[0].i_addr, item->ri_buf[0].i_len); |
654 | return -EFSCORRUPTED; |
655 | } |
656 | |
657 | ruip = xfs_rui_init(mp, nextents: rui_formatp->rui_nextents); |
658 | xfs_rui_copy_format(dst: &ruip->rui_format, src: rui_formatp); |
659 | atomic_set(v: &ruip->rui_next_extent, i: rui_formatp->rui_nextents); |
660 | |
661 | xlog_recover_intent_item(log, &ruip->rui_item, lsn, |
662 | &xfs_rmap_update_defer_type); |
663 | return 0; |
664 | } |
665 | |
666 | const struct xlog_recover_item_ops xlog_rui_item_ops = { |
667 | .item_type = XFS_LI_RUI, |
668 | .commit_pass2 = xlog_recover_rui_commit_pass2, |
669 | }; |
670 | |
671 | /* |
672 | * This routine is called when an RUD format structure is found in a committed |
673 | * transaction in the log. Its purpose is to cancel the corresponding RUI if it |
674 | * was still in the log. To do this it searches the AIL for the RUI with an id |
675 | * equal to that in the RUD format structure. If we find it we drop the RUD |
676 | * reference, which removes the RUI from the AIL and frees it. |
677 | */ |
678 | STATIC int |
679 | xlog_recover_rud_commit_pass2( |
680 | struct xlog *log, |
681 | struct list_head *buffer_list, |
682 | struct xlog_recover_item *item, |
683 | xfs_lsn_t lsn) |
684 | { |
685 | struct xfs_rud_log_format *rud_formatp; |
686 | |
687 | rud_formatp = item->ri_buf[0].i_addr; |
688 | if (item->ri_buf[0].i_len != sizeof(struct xfs_rud_log_format)) { |
689 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp, |
690 | rud_formatp, item->ri_buf[0].i_len); |
691 | return -EFSCORRUPTED; |
692 | } |
693 | |
694 | xlog_recover_release_intent(log, XFS_LI_RUI, rud_formatp->rud_rui_id); |
695 | return 0; |
696 | } |
697 | |
698 | const struct xlog_recover_item_ops xlog_rud_item_ops = { |
699 | .item_type = XFS_LI_RUD, |
700 | .commit_pass2 = xlog_recover_rud_commit_pass2, |
701 | }; |
702 | |