Commit | Line | Data |
---|---|---|
0b61f8a4 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
77d61fe4 DW |
2 | /* |
3 | * Copyright (C) 2016 Oracle. All Rights Reserved. | |
77d61fe4 | 4 | * Author: Darrick J. Wong <darrick.wong@oracle.com> |
77d61fe4 DW |
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_trans.h" | |
15 | #include "xfs_trans_priv.h" | |
16 | #include "xfs_bmap_item.h" | |
17 | #include "xfs_alloc.h" | |
18 | #include "xfs_bmap.h" | |
19 | #include "xfs_inode.h" | |
bc9f2b7c | 20 | #include "xfs_defer.h" |
77d61fe4 DW |
21 | |
22 | /* | |
23 | * This routine is called to allocate a "bmap update done" | |
24 | * log item. | |
25 | */ | |
26 | struct xfs_bud_log_item * | |
27 | xfs_trans_get_bud( | |
28 | struct xfs_trans *tp, | |
29 | struct xfs_bui_log_item *buip) | |
30 | { | |
31 | struct xfs_bud_log_item *budp; | |
32 | ||
33 | budp = xfs_bud_init(tp->t_mountp, buip); | |
34 | xfs_trans_add_item(tp, &budp->bud_item); | |
35 | return budp; | |
36 | } | |
37 | ||
38 | /* | |
39 | * Finish an bmap update and log it to the BUD. Note that the | |
40 | * transaction is marked dirty regardless of whether the bmap update | |
41 | * succeeds or fails to support the BUI/BUD lifecycle rules. | |
42 | */ | |
43 | int | |
44 | xfs_trans_log_finish_bmap_update( | |
45 | struct xfs_trans *tp, | |
46 | struct xfs_bud_log_item *budp, | |
77d61fe4 DW |
47 | enum xfs_bmap_intent_type type, |
48 | struct xfs_inode *ip, | |
49 | int whichfork, | |
50 | xfs_fileoff_t startoff, | |
51 | xfs_fsblock_t startblock, | |
e1a4e37c | 52 | xfs_filblks_t *blockcount, |
77d61fe4 DW |
53 | xfs_exntst_t state) |
54 | { | |
55 | int error; | |
56 | ||
7dbddbac | 57 | error = xfs_bmap_finish_one(tp, ip, type, whichfork, startoff, |
9f3afb57 | 58 | startblock, blockcount, state); |
77d61fe4 DW |
59 | |
60 | /* | |
61 | * Mark the transaction dirty, even on error. This ensures the | |
62 | * transaction is aborted, which: | |
63 | * | |
64 | * 1.) releases the BUI and frees the BUD | |
65 | * 2.) shuts down the filesystem | |
66 | */ | |
67 | tp->t_flags |= XFS_TRANS_DIRTY; | |
e6631f85 | 68 | set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags); |
77d61fe4 DW |
69 | |
70 | return error; | |
71 | } | |
9f3afb57 DW |
72 | |
73 | /* Sort bmap intents by inode. */ | |
74 | static int | |
75 | xfs_bmap_update_diff_items( | |
76 | void *priv, | |
77 | struct list_head *a, | |
78 | struct list_head *b) | |
79 | { | |
80 | struct xfs_bmap_intent *ba; | |
81 | struct xfs_bmap_intent *bb; | |
82 | ||
83 | ba = container_of(a, struct xfs_bmap_intent, bi_list); | |
84 | bb = container_of(b, struct xfs_bmap_intent, bi_list); | |
85 | return ba->bi_owner->i_ino - bb->bi_owner->i_ino; | |
86 | } | |
87 | ||
88 | /* Get an BUI. */ | |
89 | STATIC void * | |
90 | xfs_bmap_update_create_intent( | |
91 | struct xfs_trans *tp, | |
92 | unsigned int count) | |
93 | { | |
94 | struct xfs_bui_log_item *buip; | |
95 | ||
96 | ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS); | |
97 | ASSERT(tp != NULL); | |
98 | ||
99 | buip = xfs_bui_init(tp->t_mountp); | |
100 | ASSERT(buip != NULL); | |
101 | ||
102 | /* | |
103 | * Get a log_item_desc to point at the new item. | |
104 | */ | |
105 | xfs_trans_add_item(tp, &buip->bui_item); | |
106 | return buip; | |
107 | } | |
108 | ||
109 | /* Set the map extent flags for this mapping. */ | |
110 | static void | |
111 | xfs_trans_set_bmap_flags( | |
112 | struct xfs_map_extent *bmap, | |
113 | enum xfs_bmap_intent_type type, | |
114 | int whichfork, | |
115 | xfs_exntst_t state) | |
116 | { | |
117 | bmap->me_flags = 0; | |
118 | switch (type) { | |
119 | case XFS_BMAP_MAP: | |
120 | case XFS_BMAP_UNMAP: | |
121 | bmap->me_flags = type; | |
122 | break; | |
123 | default: | |
124 | ASSERT(0); | |
125 | } | |
126 | if (state == XFS_EXT_UNWRITTEN) | |
127 | bmap->me_flags |= XFS_BMAP_EXTENT_UNWRITTEN; | |
128 | if (whichfork == XFS_ATTR_FORK) | |
129 | bmap->me_flags |= XFS_BMAP_EXTENT_ATTR_FORK; | |
130 | } | |
131 | ||
132 | /* Log bmap updates in the intent item. */ | |
133 | STATIC void | |
134 | xfs_bmap_update_log_item( | |
135 | struct xfs_trans *tp, | |
136 | void *intent, | |
137 | struct list_head *item) | |
138 | { | |
139 | struct xfs_bui_log_item *buip = intent; | |
140 | struct xfs_bmap_intent *bmap; | |
141 | uint next_extent; | |
142 | struct xfs_map_extent *map; | |
143 | ||
144 | bmap = container_of(item, struct xfs_bmap_intent, bi_list); | |
145 | ||
146 | tp->t_flags |= XFS_TRANS_DIRTY; | |
e6631f85 | 147 | set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags); |
9f3afb57 DW |
148 | |
149 | /* | |
150 | * atomic_inc_return gives us the value after the increment; | |
151 | * we want to use it as an array index so we need to subtract 1 from | |
152 | * it. | |
153 | */ | |
154 | next_extent = atomic_inc_return(&buip->bui_next_extent) - 1; | |
155 | ASSERT(next_extent < buip->bui_format.bui_nextents); | |
156 | map = &buip->bui_format.bui_extents[next_extent]; | |
157 | map->me_owner = bmap->bi_owner->i_ino; | |
158 | map->me_startblock = bmap->bi_bmap.br_startblock; | |
159 | map->me_startoff = bmap->bi_bmap.br_startoff; | |
160 | map->me_len = bmap->bi_bmap.br_blockcount; | |
161 | xfs_trans_set_bmap_flags(map, bmap->bi_type, bmap->bi_whichfork, | |
162 | bmap->bi_bmap.br_state); | |
163 | } | |
164 | ||
165 | /* Get an BUD so we can process all the deferred rmap updates. */ | |
166 | STATIC void * | |
167 | xfs_bmap_update_create_done( | |
168 | struct xfs_trans *tp, | |
169 | void *intent, | |
170 | unsigned int count) | |
171 | { | |
172 | return xfs_trans_get_bud(tp, intent); | |
173 | } | |
174 | ||
175 | /* Process a deferred rmap update. */ | |
176 | STATIC int | |
177 | xfs_bmap_update_finish_item( | |
178 | struct xfs_trans *tp, | |
9f3afb57 DW |
179 | struct list_head *item, |
180 | void *done_item, | |
181 | void **state) | |
182 | { | |
183 | struct xfs_bmap_intent *bmap; | |
e1a4e37c | 184 | xfs_filblks_t count; |
9f3afb57 DW |
185 | int error; |
186 | ||
187 | bmap = container_of(item, struct xfs_bmap_intent, bi_list); | |
e1a4e37c | 188 | count = bmap->bi_bmap.br_blockcount; |
7dbddbac | 189 | error = xfs_trans_log_finish_bmap_update(tp, done_item, |
9f3afb57 DW |
190 | bmap->bi_type, |
191 | bmap->bi_owner, bmap->bi_whichfork, | |
192 | bmap->bi_bmap.br_startoff, | |
193 | bmap->bi_bmap.br_startblock, | |
e1a4e37c | 194 | &count, |
9f3afb57 | 195 | bmap->bi_bmap.br_state); |
e1a4e37c DW |
196 | if (!error && count > 0) { |
197 | ASSERT(bmap->bi_type == XFS_BMAP_UNMAP); | |
198 | bmap->bi_bmap.br_blockcount = count; | |
199 | return -EAGAIN; | |
200 | } | |
9f3afb57 DW |
201 | kmem_free(bmap); |
202 | return error; | |
203 | } | |
204 | ||
205 | /* Abort all pending BUIs. */ | |
206 | STATIC void | |
207 | xfs_bmap_update_abort_intent( | |
208 | void *intent) | |
209 | { | |
210 | xfs_bui_release(intent); | |
211 | } | |
212 | ||
213 | /* Cancel a deferred rmap update. */ | |
214 | STATIC void | |
215 | xfs_bmap_update_cancel_item( | |
216 | struct list_head *item) | |
217 | { | |
218 | struct xfs_bmap_intent *bmap; | |
219 | ||
220 | bmap = container_of(item, struct xfs_bmap_intent, bi_list); | |
221 | kmem_free(bmap); | |
222 | } | |
223 | ||
bc9f2b7c | 224 | const struct xfs_defer_op_type xfs_bmap_update_defer_type = { |
9f3afb57 DW |
225 | .max_items = XFS_BUI_MAX_FAST_EXTENTS, |
226 | .diff_items = xfs_bmap_update_diff_items, | |
227 | .create_intent = xfs_bmap_update_create_intent, | |
228 | .abort_intent = xfs_bmap_update_abort_intent, | |
229 | .log_item = xfs_bmap_update_log_item, | |
230 | .create_done = xfs_bmap_update_create_done, | |
231 | .finish_item = xfs_bmap_update_finish_item, | |
232 | .cancel_item = xfs_bmap_update_cancel_item, | |
233 | }; |