Commit | Line | Data |
---|---|---|
6413a014 DW |
1 | /* |
2 | * Copyright (C) 2016 Oracle. All Rights Reserved. | |
3 | * | |
4 | * Author: Darrick J. Wong <darrick.wong@oracle.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version 2 | |
9 | * of the License, or (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it would be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write the Free Software Foundation, | |
18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | */ | |
20 | #include "xfs.h" | |
21 | #include "xfs_fs.h" | |
22 | #include "xfs_format.h" | |
23 | #include "xfs_log_format.h" | |
24 | #include "xfs_trans_resv.h" | |
25 | #include "xfs_mount.h" | |
26 | #include "xfs_trans.h" | |
27 | #include "xfs_trans_priv.h" | |
28 | #include "xfs_buf_item.h" | |
29 | #include "xfs_bmap_item.h" | |
30 | #include "xfs_log.h" | |
31 | ||
32 | ||
33 | kmem_zone_t *xfs_bui_zone; | |
34 | kmem_zone_t *xfs_bud_zone; | |
35 | ||
36 | static inline struct xfs_bui_log_item *BUI_ITEM(struct xfs_log_item *lip) | |
37 | { | |
38 | return container_of(lip, struct xfs_bui_log_item, bui_item); | |
39 | } | |
40 | ||
41 | void | |
42 | xfs_bui_item_free( | |
43 | struct xfs_bui_log_item *buip) | |
44 | { | |
45 | kmem_zone_free(xfs_bui_zone, buip); | |
46 | } | |
47 | ||
48 | STATIC void | |
49 | xfs_bui_item_size( | |
50 | struct xfs_log_item *lip, | |
51 | int *nvecs, | |
52 | int *nbytes) | |
53 | { | |
54 | struct xfs_bui_log_item *buip = BUI_ITEM(lip); | |
55 | ||
56 | *nvecs += 1; | |
57 | *nbytes += xfs_bui_log_format_sizeof(buip->bui_format.bui_nextents); | |
58 | } | |
59 | ||
60 | /* | |
61 | * This is called to fill in the vector of log iovecs for the | |
62 | * given bui log item. We use only 1 iovec, and we point that | |
63 | * at the bui_log_format structure embedded in the bui item. | |
64 | * It is at this point that we assert that all of the extent | |
65 | * slots in the bui item have been filled. | |
66 | */ | |
67 | STATIC void | |
68 | xfs_bui_item_format( | |
69 | struct xfs_log_item *lip, | |
70 | struct xfs_log_vec *lv) | |
71 | { | |
72 | struct xfs_bui_log_item *buip = BUI_ITEM(lip); | |
73 | struct xfs_log_iovec *vecp = NULL; | |
74 | ||
75 | ASSERT(atomic_read(&buip->bui_next_extent) == | |
76 | buip->bui_format.bui_nextents); | |
77 | ||
78 | buip->bui_format.bui_type = XFS_LI_BUI; | |
79 | buip->bui_format.bui_size = 1; | |
80 | ||
81 | xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_BUI_FORMAT, &buip->bui_format, | |
82 | xfs_bui_log_format_sizeof(buip->bui_format.bui_nextents)); | |
83 | } | |
84 | ||
85 | /* | |
86 | * Pinning has no meaning for an bui item, so just return. | |
87 | */ | |
88 | STATIC void | |
89 | xfs_bui_item_pin( | |
90 | struct xfs_log_item *lip) | |
91 | { | |
92 | } | |
93 | ||
94 | /* | |
95 | * The unpin operation is the last place an BUI is manipulated in the log. It is | |
96 | * either inserted in the AIL or aborted in the event of a log I/O error. In | |
97 | * either case, the BUI transaction has been successfully committed to make it | |
98 | * this far. Therefore, we expect whoever committed the BUI to either construct | |
99 | * and commit the BUD or drop the BUD's reference in the event of error. Simply | |
100 | * drop the log's BUI reference now that the log is done with it. | |
101 | */ | |
102 | STATIC void | |
103 | xfs_bui_item_unpin( | |
104 | struct xfs_log_item *lip, | |
105 | int remove) | |
106 | { | |
107 | struct xfs_bui_log_item *buip = BUI_ITEM(lip); | |
108 | ||
109 | xfs_bui_release(buip); | |
110 | } | |
111 | ||
112 | /* | |
113 | * BUI items have no locking or pushing. However, since BUIs are pulled from | |
114 | * the AIL when their corresponding BUDs are committed to disk, their situation | |
115 | * is very similar to being pinned. Return XFS_ITEM_PINNED so that the caller | |
116 | * will eventually flush the log. This should help in getting the BUI out of | |
117 | * the AIL. | |
118 | */ | |
119 | STATIC uint | |
120 | xfs_bui_item_push( | |
121 | struct xfs_log_item *lip, | |
122 | struct list_head *buffer_list) | |
123 | { | |
124 | return XFS_ITEM_PINNED; | |
125 | } | |
126 | ||
127 | /* | |
128 | * The BUI has been either committed or aborted if the transaction has been | |
129 | * cancelled. If the transaction was cancelled, an BUD isn't going to be | |
130 | * constructed and thus we free the BUI here directly. | |
131 | */ | |
132 | STATIC void | |
133 | xfs_bui_item_unlock( | |
134 | struct xfs_log_item *lip) | |
135 | { | |
136 | if (lip->li_flags & XFS_LI_ABORTED) | |
137 | xfs_bui_item_free(BUI_ITEM(lip)); | |
138 | } | |
139 | ||
140 | /* | |
141 | * The BUI is logged only once and cannot be moved in the log, so simply return | |
142 | * the lsn at which it's been logged. | |
143 | */ | |
144 | STATIC xfs_lsn_t | |
145 | xfs_bui_item_committed( | |
146 | struct xfs_log_item *lip, | |
147 | xfs_lsn_t lsn) | |
148 | { | |
149 | return lsn; | |
150 | } | |
151 | ||
152 | /* | |
153 | * The BUI dependency tracking op doesn't do squat. It can't because | |
154 | * it doesn't know where the free extent is coming from. The dependency | |
155 | * tracking has to be handled by the "enclosing" metadata object. For | |
156 | * example, for inodes, the inode is locked throughout the extent freeing | |
157 | * so the dependency should be recorded there. | |
158 | */ | |
159 | STATIC void | |
160 | xfs_bui_item_committing( | |
161 | struct xfs_log_item *lip, | |
162 | xfs_lsn_t lsn) | |
163 | { | |
164 | } | |
165 | ||
166 | /* | |
167 | * This is the ops vector shared by all bui log items. | |
168 | */ | |
169 | static const struct xfs_item_ops xfs_bui_item_ops = { | |
170 | .iop_size = xfs_bui_item_size, | |
171 | .iop_format = xfs_bui_item_format, | |
172 | .iop_pin = xfs_bui_item_pin, | |
173 | .iop_unpin = xfs_bui_item_unpin, | |
174 | .iop_unlock = xfs_bui_item_unlock, | |
175 | .iop_committed = xfs_bui_item_committed, | |
176 | .iop_push = xfs_bui_item_push, | |
177 | .iop_committing = xfs_bui_item_committing, | |
178 | }; | |
179 | ||
180 | /* | |
181 | * Allocate and initialize an bui item with the given number of extents. | |
182 | */ | |
183 | struct xfs_bui_log_item * | |
184 | xfs_bui_init( | |
185 | struct xfs_mount *mp) | |
186 | ||
187 | { | |
188 | struct xfs_bui_log_item *buip; | |
189 | ||
190 | buip = kmem_zone_zalloc(xfs_bui_zone, KM_SLEEP); | |
191 | ||
192 | xfs_log_item_init(mp, &buip->bui_item, XFS_LI_BUI, &xfs_bui_item_ops); | |
193 | buip->bui_format.bui_nextents = XFS_BUI_MAX_FAST_EXTENTS; | |
194 | buip->bui_format.bui_id = (uintptr_t)(void *)buip; | |
195 | atomic_set(&buip->bui_next_extent, 0); | |
196 | atomic_set(&buip->bui_refcount, 2); | |
197 | ||
198 | return buip; | |
199 | } | |
200 | ||
201 | /* | |
202 | * Freeing the BUI requires that we remove it from the AIL if it has already | |
203 | * been placed there. However, the BUI may not yet have been placed in the AIL | |
204 | * when called by xfs_bui_release() from BUD processing due to the ordering of | |
205 | * committed vs unpin operations in bulk insert operations. Hence the reference | |
206 | * count to ensure only the last caller frees the BUI. | |
207 | */ | |
208 | void | |
209 | xfs_bui_release( | |
210 | struct xfs_bui_log_item *buip) | |
211 | { | |
212 | if (atomic_dec_and_test(&buip->bui_refcount)) { | |
213 | xfs_trans_ail_remove(&buip->bui_item, SHUTDOWN_LOG_IO_ERROR); | |
214 | xfs_bui_item_free(buip); | |
215 | } | |
216 | } | |
217 | ||
218 | static inline struct xfs_bud_log_item *BUD_ITEM(struct xfs_log_item *lip) | |
219 | { | |
220 | return container_of(lip, struct xfs_bud_log_item, bud_item); | |
221 | } | |
222 | ||
223 | STATIC void | |
224 | xfs_bud_item_size( | |
225 | struct xfs_log_item *lip, | |
226 | int *nvecs, | |
227 | int *nbytes) | |
228 | { | |
229 | *nvecs += 1; | |
230 | *nbytes += sizeof(struct xfs_bud_log_format); | |
231 | } | |
232 | ||
233 | /* | |
234 | * This is called to fill in the vector of log iovecs for the | |
235 | * given bud log item. We use only 1 iovec, and we point that | |
236 | * at the bud_log_format structure embedded in the bud item. | |
237 | * It is at this point that we assert that all of the extent | |
238 | * slots in the bud item have been filled. | |
239 | */ | |
240 | STATIC void | |
241 | xfs_bud_item_format( | |
242 | struct xfs_log_item *lip, | |
243 | struct xfs_log_vec *lv) | |
244 | { | |
245 | struct xfs_bud_log_item *budp = BUD_ITEM(lip); | |
246 | struct xfs_log_iovec *vecp = NULL; | |
247 | ||
248 | budp->bud_format.bud_type = XFS_LI_BUD; | |
249 | budp->bud_format.bud_size = 1; | |
250 | ||
251 | xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_BUD_FORMAT, &budp->bud_format, | |
252 | sizeof(struct xfs_bud_log_format)); | |
253 | } | |
254 | ||
255 | /* | |
256 | * Pinning has no meaning for an bud item, so just return. | |
257 | */ | |
258 | STATIC void | |
259 | xfs_bud_item_pin( | |
260 | struct xfs_log_item *lip) | |
261 | { | |
262 | } | |
263 | ||
264 | /* | |
265 | * Since pinning has no meaning for an bud item, unpinning does | |
266 | * not either. | |
267 | */ | |
268 | STATIC void | |
269 | xfs_bud_item_unpin( | |
270 | struct xfs_log_item *lip, | |
271 | int remove) | |
272 | { | |
273 | } | |
274 | ||
275 | /* | |
276 | * There isn't much you can do to push on an bud item. It is simply stuck | |
277 | * waiting for the log to be flushed to disk. | |
278 | */ | |
279 | STATIC uint | |
280 | xfs_bud_item_push( | |
281 | struct xfs_log_item *lip, | |
282 | struct list_head *buffer_list) | |
283 | { | |
284 | return XFS_ITEM_PINNED; | |
285 | } | |
286 | ||
287 | /* | |
288 | * The BUD is either committed or aborted if the transaction is cancelled. If | |
289 | * the transaction is cancelled, drop our reference to the BUI and free the | |
290 | * BUD. | |
291 | */ | |
292 | STATIC void | |
293 | xfs_bud_item_unlock( | |
294 | struct xfs_log_item *lip) | |
295 | { | |
296 | struct xfs_bud_log_item *budp = BUD_ITEM(lip); | |
297 | ||
298 | if (lip->li_flags & XFS_LI_ABORTED) { | |
299 | xfs_bui_release(budp->bud_buip); | |
300 | kmem_zone_free(xfs_bud_zone, budp); | |
301 | } | |
302 | } | |
303 | ||
304 | /* | |
305 | * When the bud item is committed to disk, all we need to do is delete our | |
306 | * reference to our partner bui item and then free ourselves. Since we're | |
307 | * freeing ourselves we must return -1 to keep the transaction code from | |
308 | * further referencing this item. | |
309 | */ | |
310 | STATIC xfs_lsn_t | |
311 | xfs_bud_item_committed( | |
312 | struct xfs_log_item *lip, | |
313 | xfs_lsn_t lsn) | |
314 | { | |
315 | struct xfs_bud_log_item *budp = BUD_ITEM(lip); | |
316 | ||
317 | /* | |
318 | * Drop the BUI reference regardless of whether the BUD has been | |
319 | * aborted. Once the BUD transaction is constructed, it is the sole | |
320 | * responsibility of the BUD to release the BUI (even if the BUI is | |
321 | * aborted due to log I/O error). | |
322 | */ | |
323 | xfs_bui_release(budp->bud_buip); | |
324 | kmem_zone_free(xfs_bud_zone, budp); | |
325 | ||
326 | return (xfs_lsn_t)-1; | |
327 | } | |
328 | ||
329 | /* | |
330 | * The BUD dependency tracking op doesn't do squat. It can't because | |
331 | * it doesn't know where the free extent is coming from. The dependency | |
332 | * tracking has to be handled by the "enclosing" metadata object. For | |
333 | * example, for inodes, the inode is locked throughout the extent freeing | |
334 | * so the dependency should be recorded there. | |
335 | */ | |
336 | STATIC void | |
337 | xfs_bud_item_committing( | |
338 | struct xfs_log_item *lip, | |
339 | xfs_lsn_t lsn) | |
340 | { | |
341 | } | |
342 | ||
343 | /* | |
344 | * This is the ops vector shared by all bud log items. | |
345 | */ | |
346 | static const struct xfs_item_ops xfs_bud_item_ops = { | |
347 | .iop_size = xfs_bud_item_size, | |
348 | .iop_format = xfs_bud_item_format, | |
349 | .iop_pin = xfs_bud_item_pin, | |
350 | .iop_unpin = xfs_bud_item_unpin, | |
351 | .iop_unlock = xfs_bud_item_unlock, | |
352 | .iop_committed = xfs_bud_item_committed, | |
353 | .iop_push = xfs_bud_item_push, | |
354 | .iop_committing = xfs_bud_item_committing, | |
355 | }; | |
356 | ||
357 | /* | |
358 | * Allocate and initialize an bud item with the given number of extents. | |
359 | */ | |
360 | struct xfs_bud_log_item * | |
361 | xfs_bud_init( | |
362 | struct xfs_mount *mp, | |
363 | struct xfs_bui_log_item *buip) | |
364 | ||
365 | { | |
366 | struct xfs_bud_log_item *budp; | |
367 | ||
368 | budp = kmem_zone_zalloc(xfs_bud_zone, KM_SLEEP); | |
369 | xfs_log_item_init(mp, &budp->bud_item, XFS_LI_BUD, &xfs_bud_item_ops); | |
370 | budp->bud_buip = buip; | |
371 | budp->bud_format.bud_bui_id = buip->bui_format.bui_id; | |
372 | ||
373 | return budp; | |
374 | } |