]>
Commit | Line | Data |
---|---|---|
2bd0ea18 | 1 | /* |
f1b058f9 | 2 | * Copyright (c) 2000-2001,2005-2006 Silicon Graphics, Inc. |
4329aa4c | 3 | * Copyright (C) 2010 Red Hat, Inc. |
da23017d | 4 | * All Rights Reserved. |
2bd0ea18 | 5 | * |
da23017d NS |
6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License as | |
2bd0ea18 NS |
8 | * published by the Free Software Foundation. |
9 | * | |
da23017d NS |
10 | * This program is distributed in the hope that it would be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
2bd0ea18 | 14 | * |
da23017d NS |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write the Free Software Foundation, | |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
2bd0ea18 NS |
18 | */ |
19 | ||
9c799827 | 20 | #include "libxfs_priv.h" |
b626fb59 DC |
21 | #include "xfs_fs.h" |
22 | #include "xfs_shared.h" | |
23 | #include "xfs_format.h" | |
24 | #include "xfs_log_format.h" | |
25 | #include "xfs_trans_resv.h" | |
26 | #include "xfs_mount.h" | |
27 | #include "xfs_inode_buf.h" | |
28 | #include "xfs_inode_fork.h" | |
29 | #include "xfs_inode.h" | |
30 | #include "xfs_trans.h" | |
31 | #include "xfs_sb.h" | |
2bd0ea18 | 32 | |
7bcb8403 CH |
33 | static void xfs_trans_free_items(struct xfs_trans *tp); |
34 | ||
2bd0ea18 NS |
35 | /* |
36 | * Simple transaction interface | |
37 | */ | |
38 | ||
4329aa4c DC |
39 | kmem_zone_t *xfs_log_item_desc_zone; |
40 | ||
41 | /* | |
42 | * Initialize the precomputed transaction reservation values | |
43 | * in the mount structure. | |
44 | */ | |
45 | void | |
46 | libxfs_trans_init( | |
47 | struct xfs_mount *mp) | |
48 | { | |
cf52c730 | 49 | xfs_trans_resv_calc(mp, &mp->m_resv); |
4329aa4c DC |
50 | } |
51 | ||
52 | /* | |
53 | * Add the given log item to the transaction's list of log items. | |
54 | * | |
55 | * The log item will now point to its new descriptor with its li_desc field. | |
56 | */ | |
57 | void | |
58 | libxfs_trans_add_item( | |
59 | struct xfs_trans *tp, | |
60 | struct xfs_log_item *lip) | |
61 | { | |
62 | struct xfs_log_item_desc *lidp; | |
63 | ||
64 | ASSERT(lip->li_mountp == tp->t_mountp); | |
65 | ASSERT(lip->li_ailp == tp->t_mountp->m_ail); | |
66 | ||
67 | lidp = calloc(sizeof(struct xfs_log_item_desc), 1); | |
68 | if (!lidp) { | |
69 | fprintf(stderr, _("%s: lidp calloc failed (%d bytes): %s\n"), | |
70 | progname, (int)sizeof(struct xfs_log_item_desc), | |
71 | strerror(errno)); | |
72 | exit(1); | |
73 | } | |
74 | ||
75 | lidp->lid_item = lip; | |
76 | lidp->lid_flags = 0; | |
77 | list_add_tail(&lidp->lid_trans, &tp->t_items); | |
78 | ||
79 | lip->li_desc = lidp; | |
80 | } | |
81 | ||
82 | /* | |
83 | * Unlink and free the given descriptor. | |
84 | */ | |
85 | void | |
86 | libxfs_trans_del_item( | |
87 | struct xfs_log_item *lip) | |
88 | { | |
89 | list_del_init(&lip->li_desc->lid_trans); | |
90 | free(lip->li_desc); | |
91 | lip->li_desc = NULL; | |
92 | } | |
93 | ||
94 | /* | |
95 | * Roll from one trans in the sequence of PERMANENT transactions to | |
96 | * the next: permanent transactions are only flushed out when | |
97 | * committed with XFS_TRANS_RELEASE_LOG_RES, but we still want as soon | |
98 | * as possible to let chunks of it go to the log. So we commit the | |
99 | * chunk we've been working on and get a new transaction to continue. | |
100 | */ | |
101 | int | |
102 | libxfs_trans_roll( | |
103 | struct xfs_trans **tpp, | |
104 | struct xfs_inode *dp) | |
105 | { | |
87307113 | 106 | struct xfs_mount *mp; |
4329aa4c | 107 | struct xfs_trans *trans; |
48ea6cb9 | 108 | struct xfs_trans_res tres; |
4329aa4c DC |
109 | int error; |
110 | ||
111 | /* | |
112 | * Ensure that the inode is always logged. | |
113 | */ | |
114 | trans = *tpp; | |
d262295d CH |
115 | if (dp) |
116 | xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); | |
4329aa4c DC |
117 | |
118 | /* | |
119 | * Copy the critical parameters from one trans to the next. | |
120 | */ | |
87307113 | 121 | mp = trans->t_mountp; |
48ea6cb9 DC |
122 | tres.tr_logres = trans->t_log_res; |
123 | tres.tr_logcount = trans->t_log_count; | |
4329aa4c DC |
124 | |
125 | /* | |
126 | * Commit the current transaction. | |
127 | * If this commit failed, then it'd just unlock those items that | |
260c85e8 | 128 | * are marked to be released. That also means that a filesystem shutdown |
4329aa4c DC |
129 | * is in progress. The caller takes the responsibility to cancel |
130 | * the duplicate transaction that gets returned. | |
131 | */ | |
de5a3f46 | 132 | error = xfs_trans_commit(trans); |
4329aa4c | 133 | if (error) |
af43ca9f | 134 | return error; |
4329aa4c | 135 | |
4329aa4c DC |
136 | |
137 | /* | |
138 | * Reserve space in the log for th next transaction. | |
139 | * This also pushes items in the "AIL", the list of logged items, | |
140 | * out to disk if they are taking up space at the tail of the log | |
141 | * that we want to use. This requires that either nothing be locked | |
142 | * across this call, or that anything that is locked be logged in | |
143 | * the prior and the next transactions. | |
144 | */ | |
48ea6cb9 | 145 | tres.tr_logflags = XFS_TRANS_PERM_LOG_RES; |
87307113 | 146 | error = libxfs_trans_alloc(mp, &tres, 0, 0, 0, tpp); |
9074815c | 147 | trans = *tpp; |
4329aa4c DC |
148 | /* |
149 | * Ensure that the inode is in the new transaction and locked. | |
150 | */ | |
151 | if (error) | |
152 | return error; | |
153 | ||
d262295d CH |
154 | if (dp) |
155 | xfs_trans_ijoin(trans, dp, 0); | |
4329aa4c DC |
156 | return 0; |
157 | } | |
158 | ||
9074815c | 159 | int |
ad10fb70 | 160 | libxfs_trans_alloc( |
9074815c CH |
161 | struct xfs_mount *mp, |
162 | struct xfs_trans_res *resp, | |
163 | unsigned int blocks, | |
164 | unsigned int rtextents, | |
165 | unsigned int flags, | |
166 | struct xfs_trans **tpp) | |
167 | ||
2bd0ea18 | 168 | { |
9074815c CH |
169 | struct xfs_sb *sb = &mp->m_sb; |
170 | struct xfs_trans *ptr; | |
171 | ||
172 | /* | |
173 | * Attempt to reserve the needed disk blocks by decrementing | |
174 | * the number needed from the number available. This will | |
175 | * fail if the count would go below zero. | |
176 | */ | |
177 | if (blocks > 0) { | |
178 | if (sb->sb_fdblocks < blocks) | |
179 | return -ENOSPC; | |
180 | } | |
2bd0ea18 NS |
181 | |
182 | if ((ptr = calloc(sizeof(xfs_trans_t), 1)) == NULL) { | |
9440d84d | 183 | fprintf(stderr, _("%s: xact calloc failed (%d bytes): %s\n"), |
5b64e00a | 184 | progname, (int)sizeof(xfs_trans_t), strerror(errno)); |
2bd0ea18 NS |
185 | exit(1); |
186 | } | |
187 | ptr->t_mountp = mp; | |
c40bdaa2 | 188 | INIT_LIST_HEAD(&ptr->t_items); |
2bd0ea18 NS |
189 | #ifdef XACT_DEBUG |
190 | fprintf(stderr, "allocated new transaction %p\n", ptr); | |
2bd0ea18 | 191 | #endif |
9074815c | 192 | *tpp = ptr; |
2bd0ea18 NS |
193 | return 0; |
194 | } | |
195 | ||
d4e8eb2e DW |
196 | /* |
197 | * Create an empty transaction with no reservation. This is a defensive | |
198 | * mechanism for routines that query metadata without actually modifying | |
199 | * them -- if the metadata being queried is somehow cross-linked (think a | |
200 | * btree block pointer that points higher in the tree), we risk deadlock. | |
201 | * However, blocks grabbed as part of a transaction can be re-grabbed. | |
202 | * The verifiers will notice the corrupt block and the operation will fail | |
203 | * back to userspace without deadlocking. | |
204 | * | |
205 | * Note the zero-length reservation; this transaction MUST be cancelled | |
206 | * without any dirty data. | |
207 | */ | |
208 | int | |
3680a764 | 209 | libxfs_trans_alloc_empty( |
d4e8eb2e DW |
210 | struct xfs_mount *mp, |
211 | struct xfs_trans **tpp) | |
212 | { | |
213 | struct xfs_trans_res resv = {0}; | |
214 | ||
215 | return xfs_trans_alloc(mp, &resv, 0, 0, XFS_TRANS_NO_WRITECOUNT, tpp); | |
216 | } | |
217 | ||
2bd0ea18 | 218 | void |
ad10fb70 | 219 | libxfs_trans_cancel( |
3d7434fe | 220 | xfs_trans_t *tp) |
2bd0ea18 NS |
221 | { |
222 | #ifdef XACT_DEBUG | |
ad10fb70 | 223 | xfs_trans_t *otp = tp; |
2bd0ea18 NS |
224 | #endif |
225 | if (tp != NULL) { | |
7bcb8403 | 226 | xfs_trans_free_items(tp); |
2bd0ea18 NS |
227 | free(tp); |
228 | tp = NULL; | |
229 | } | |
230 | #ifdef XACT_DEBUG | |
231 | fprintf(stderr, "## cancelled transaction %p\n", otp); | |
232 | #endif | |
233 | } | |
234 | ||
235 | int | |
ad10fb70 NS |
236 | libxfs_trans_iget( |
237 | xfs_mount_t *mp, | |
238 | xfs_trans_t *tp, | |
239 | xfs_ino_t ino, | |
46eca962 | 240 | uint flags, |
ad10fb70 NS |
241 | uint lock_flags, |
242 | xfs_inode_t **ipp) | |
2bd0ea18 NS |
243 | { |
244 | int error; | |
245 | xfs_inode_t *ip; | |
246 | xfs_inode_log_item_t *iip; | |
247 | ||
248 | if (tp == NULL) | |
81f8132a | 249 | return libxfs_iget(mp, tp, ino, lock_flags, ipp); |
2bd0ea18 | 250 | |
81f8132a | 251 | error = libxfs_iget(mp, tp, ino, lock_flags, &ip); |
2bd0ea18 NS |
252 | if (error) |
253 | return error; | |
254 | ASSERT(ip != NULL); | |
255 | ||
256 | if (ip->i_itemp == NULL) | |
257 | xfs_inode_item_init(ip, mp); | |
258 | iip = ip->i_itemp; | |
259 | xfs_trans_add_item(tp, (xfs_log_item_t *)(iip)); | |
260 | ||
261 | /* initialize i_transp so we can find it incore */ | |
262 | ip->i_transp = tp; | |
263 | ||
264 | *ipp = ip; | |
265 | return 0; | |
266 | } | |
267 | ||
2bd0ea18 | 268 | void |
ad10fb70 NS |
269 | libxfs_trans_ijoin( |
270 | xfs_trans_t *tp, | |
271 | xfs_inode_t *ip, | |
272 | uint lock_flags) | |
2bd0ea18 NS |
273 | { |
274 | xfs_inode_log_item_t *iip; | |
275 | ||
276 | ASSERT(ip->i_transp == NULL); | |
277 | if (ip->i_itemp == NULL) | |
278 | xfs_inode_item_init(ip, ip->i_mount); | |
279 | iip = ip->i_itemp; | |
280 | ASSERT(iip->ili_flags == 0); | |
281 | ASSERT(iip->ili_inode != NULL); | |
282 | ||
283 | xfs_trans_add_item(tp, (xfs_log_item_t *)(iip)); | |
284 | ||
285 | ip->i_transp = tp; | |
286 | #ifdef XACT_DEBUG | |
287 | fprintf(stderr, "ijoin'd inode %llu, transaction %p\n", ip->i_ino, tp); | |
288 | #endif | |
289 | } | |
290 | ||
c40bdaa2 DC |
291 | void |
292 | libxfs_trans_ijoin_ref( | |
293 | xfs_trans_t *tp, | |
294 | xfs_inode_t *ip, | |
295 | int lock_flags) | |
296 | { | |
297 | ASSERT(ip->i_transp == tp); | |
298 | ASSERT(ip->i_itemp != NULL); | |
299 | ||
300 | xfs_trans_ijoin(tp, ip, lock_flags); | |
c40bdaa2 DC |
301 | |
302 | #ifdef XACT_DEBUG | |
303 | fprintf(stderr, "ijoin_ref'd inode %llu, transaction %p\n", ip->i_ino, tp); | |
304 | #endif | |
305 | } | |
306 | ||
2bd0ea18 | 307 | void |
ad10fb70 NS |
308 | libxfs_trans_inode_alloc_buf( |
309 | xfs_trans_t *tp, | |
310 | xfs_buf_t *bp) | |
2bd0ea18 NS |
311 | { |
312 | xfs_buf_log_item_t *bip; | |
313 | ||
314 | ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); | |
315 | ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); | |
316 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); | |
317 | bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF; | |
bdc16ee5 | 318 | xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DINO_BUF); |
2bd0ea18 NS |
319 | } |
320 | ||
321 | /* | |
322 | * This is called to mark the fields indicated in fieldmask as needing | |
323 | * to be logged when the transaction is committed. The inode must | |
324 | * already be associated with the given transaction. | |
325 | * | |
2d4bfb91 | 326 | * The values for fieldmask are defined in xfs_log_format.h. We always |
2bd0ea18 NS |
327 | * log all of the core inode if any of it has changed, and we always log |
328 | * all of the inline data/extents/b-tree root if any of them has changed. | |
329 | */ | |
330 | void | |
331 | xfs_trans_log_inode( | |
ad10fb70 NS |
332 | xfs_trans_t *tp, |
333 | xfs_inode_t *ip, | |
334 | uint flags) | |
2bd0ea18 | 335 | { |
2bd0ea18 NS |
336 | ASSERT(ip->i_transp == tp); |
337 | ASSERT(ip->i_itemp != NULL); | |
338 | #ifdef XACT_DEBUG | |
339 | fprintf(stderr, "dirtied inode %llu, transaction %p\n", ip->i_ino, tp); | |
340 | #endif | |
341 | ||
2bd0ea18 | 342 | tp->t_flags |= XFS_TRANS_DIRTY; |
c40bdaa2 | 343 | ip->i_itemp->ili_item.li_desc->lid_flags |= XFS_LID_DIRTY; |
2bd0ea18 NS |
344 | |
345 | /* | |
346 | * Always OR in the bits from the ili_last_fields field. | |
347 | * This is to coordinate with the xfs_iflush() and xfs_iflush_done() | |
348 | * routines in the eventual clearing of the ilf_fields bits. | |
349 | * See the big comment in xfs_iflush() for an explanation of | |
350 | * this coordination mechanism. | |
351 | */ | |
352 | flags |= ip->i_itemp->ili_last_fields; | |
a2ceac1f | 353 | ip->i_itemp->ili_fields |= flags; |
2bd0ea18 NS |
354 | } |
355 | ||
356 | /* | |
357 | * This is called to mark bytes first through last inclusive of the given | |
358 | * buffer as needing to be logged when the transaction is committed. | |
359 | * The buffer must already be associated with the given transaction. | |
5000d01d | 360 | * |
2bd0ea18 NS |
361 | * First and last are numbers relative to the beginning of this buffer, |
362 | * so the first byte in the buffer is numbered 0 regardless of the | |
363 | * value of b_blkno. | |
364 | */ | |
365 | void | |
ad10fb70 NS |
366 | libxfs_trans_log_buf( |
367 | xfs_trans_t *tp, | |
368 | xfs_buf_t *bp, | |
369 | uint first, | |
370 | uint last) | |
2bd0ea18 NS |
371 | { |
372 | xfs_buf_log_item_t *bip; | |
2bd0ea18 NS |
373 | |
374 | ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); | |
375 | ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); | |
376 | ASSERT((first <= last) && (last < XFS_BUF_COUNT(bp))); | |
377 | #ifdef XACT_DEBUG | |
378 | fprintf(stderr, "dirtied buffer %p, transaction %p\n", bp, tp); | |
379 | #endif | |
380 | ||
381 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); | |
382 | ||
2bd0ea18 | 383 | tp->t_flags |= XFS_TRANS_DIRTY; |
c40bdaa2 | 384 | bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY; |
2bd0ea18 NS |
385 | xfs_buf_item_log(bip, first, last); |
386 | } | |
387 | ||
388 | void | |
ad10fb70 NS |
389 | libxfs_trans_brelse( |
390 | xfs_trans_t *tp, | |
391 | xfs_buf_t *bp) | |
2bd0ea18 NS |
392 | { |
393 | xfs_buf_log_item_t *bip; | |
2bd0ea18 NS |
394 | #ifdef XACT_DEBUG |
395 | fprintf(stderr, "released buffer %p, transaction %p\n", bp, tp); | |
396 | #endif | |
397 | ||
398 | if (tp == NULL) { | |
399 | ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL); | |
400 | libxfs_putbuf(bp); | |
401 | return; | |
402 | } | |
403 | ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); | |
404 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); | |
405 | ASSERT(bip->bli_item.li_type == XFS_LI_BUF); | |
2bd0ea18 NS |
406 | if (bip->bli_recur > 0) { |
407 | bip->bli_recur--; | |
408 | return; | |
409 | } | |
f1b058f9 NS |
410 | /* If dirty/stale, can't release till transaction committed */ |
411 | if (bip->bli_flags & XFS_BLI_STALE) | |
412 | return; | |
c40bdaa2 | 413 | if (bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY) |
2bd0ea18 | 414 | return; |
c40bdaa2 | 415 | xfs_trans_del_item(&bip->bli_item); |
f1b058f9 | 416 | if (bip->bli_flags & XFS_BLI_HOLD) |
2bd0ea18 | 417 | bip->bli_flags &= ~XFS_BLI_HOLD; |
2bd0ea18 NS |
418 | XFS_BUF_SET_FSPRIVATE2(bp, NULL); |
419 | libxfs_putbuf(bp); | |
420 | } | |
421 | ||
422 | void | |
ad10fb70 NS |
423 | libxfs_trans_binval( |
424 | xfs_trans_t *tp, | |
425 | xfs_buf_t *bp) | |
2bd0ea18 | 426 | { |
2bd0ea18 NS |
427 | xfs_buf_log_item_t *bip; |
428 | #ifdef XACT_DEBUG | |
429 | fprintf(stderr, "binval'd buffer %p, transaction %p\n", bp, tp); | |
430 | #endif | |
431 | ||
432 | ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); | |
433 | ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); | |
434 | ||
435 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); | |
f1b058f9 NS |
436 | if (bip->bli_flags & XFS_BLI_STALE) |
437 | return; | |
438 | XFS_BUF_UNDELAYWRITE(bp); | |
a2ceac1f | 439 | xfs_buf_stale(bp); |
f1b058f9 NS |
440 | bip->bli_flags |= XFS_BLI_STALE; |
441 | bip->bli_flags &= ~XFS_BLI_DIRTY; | |
c40bdaa2 DC |
442 | bip->bli_format.blf_flags &= ~XFS_BLF_INODE_BUF; |
443 | bip->bli_format.blf_flags |= XFS_BLF_CANCEL; | |
444 | bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY; | |
2bd0ea18 NS |
445 | tp->t_flags |= XFS_TRANS_DIRTY; |
446 | } | |
447 | ||
448 | void | |
ad10fb70 NS |
449 | libxfs_trans_bjoin( |
450 | xfs_trans_t *tp, | |
451 | xfs_buf_t *bp) | |
2bd0ea18 NS |
452 | { |
453 | xfs_buf_log_item_t *bip; | |
454 | ||
455 | ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL); | |
456 | #ifdef XACT_DEBUG | |
457 | fprintf(stderr, "bjoin'd buffer %p, transaction %p\n", bp, tp); | |
458 | #endif | |
459 | ||
460 | xfs_buf_item_init(bp, tp->t_mountp); | |
461 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); | |
462 | xfs_trans_add_item(tp, (xfs_log_item_t *)bip); | |
463 | XFS_BUF_SET_FSPRIVATE2(bp, tp); | |
464 | } | |
465 | ||
466 | void | |
ad10fb70 NS |
467 | libxfs_trans_bhold( |
468 | xfs_trans_t *tp, | |
469 | xfs_buf_t *bp) | |
2bd0ea18 NS |
470 | { |
471 | xfs_buf_log_item_t *bip; | |
472 | ||
473 | ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); | |
474 | ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); | |
475 | #ifdef XACT_DEBUG | |
476 | fprintf(stderr, "bhold'd buffer %p, transaction %p\n", bp, tp); | |
477 | #endif | |
478 | ||
479 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); | |
480 | bip->bli_flags |= XFS_BLI_HOLD; | |
481 | } | |
482 | ||
483 | xfs_buf_t * | |
a2ceac1f | 484 | libxfs_trans_get_buf_map( |
ad10fb70 | 485 | xfs_trans_t *tp, |
75c8b434 | 486 | struct xfs_buftarg *btp, |
a2ceac1f DC |
487 | struct xfs_buf_map *map, |
488 | int nmaps, | |
ad10fb70 | 489 | uint f) |
2bd0ea18 NS |
490 | { |
491 | xfs_buf_t *bp; | |
492 | xfs_buf_log_item_t *bip; | |
2bd0ea18 NS |
493 | |
494 | if (tp == NULL) | |
7e3ab890 | 495 | return libxfs_getbuf_map(btp, map, nmaps, 0); |
2bd0ea18 | 496 | |
75c8b434 | 497 | bp = xfs_trans_buf_item_match(tp, btp, map, nmaps); |
2bd0ea18 NS |
498 | if (bp != NULL) { |
499 | ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); | |
500 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); | |
501 | ASSERT(bip != NULL); | |
502 | bip->bli_recur++; | |
503 | return bp; | |
504 | } | |
505 | ||
7e3ab890 | 506 | bp = libxfs_getbuf_map(btp, map, nmaps, 0); |
2bd0ea18 NS |
507 | if (bp == NULL) |
508 | return NULL; | |
509 | #ifdef XACT_DEBUG | |
510 | fprintf(stderr, "trans_get_buf buffer %p, transaction %p\n", bp, tp); | |
511 | #endif | |
512 | ||
513 | xfs_buf_item_init(bp, tp->t_mountp); | |
514 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); | |
515 | bip->bli_recur = 0; | |
516 | xfs_trans_add_item(tp, (xfs_log_item_t *)bip); | |
517 | ||
518 | /* initialize b_fsprivate2 so we can find it incore */ | |
519 | XFS_BUF_SET_FSPRIVATE2(bp, tp); | |
520 | return bp; | |
521 | } | |
522 | ||
f1b058f9 NS |
523 | xfs_buf_t * |
524 | libxfs_trans_getsb( | |
525 | xfs_trans_t *tp, | |
526 | xfs_mount_t *mp, | |
527 | int flags) | |
528 | { | |
529 | xfs_buf_t *bp; | |
530 | xfs_buf_log_item_t *bip; | |
a2ceac1f DC |
531 | int len = XFS_FSS_TO_BB(mp, 1); |
532 | DEFINE_SINGLE_BUF_MAP(map, XFS_SB_DADDR, len); | |
f1b058f9 NS |
533 | |
534 | if (tp == NULL) | |
535 | return libxfs_getsb(mp, flags); | |
536 | ||
a2ceac1f | 537 | bp = xfs_trans_buf_item_match(tp, mp->m_dev, &map, 1); |
f1b058f9 NS |
538 | if (bp != NULL) { |
539 | ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); | |
540 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); | |
541 | ASSERT(bip != NULL); | |
542 | bip->bli_recur++; | |
543 | return bp; | |
544 | } | |
545 | ||
546 | bp = libxfs_getsb(mp, flags); | |
547 | #ifdef XACT_DEBUG | |
548 | fprintf(stderr, "trans_get_sb buffer %p, transaction %p\n", bp, tp); | |
549 | #endif | |
550 | ||
551 | xfs_buf_item_init(bp, mp); | |
552 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); | |
553 | bip->bli_recur = 0; | |
554 | xfs_trans_add_item(tp, (xfs_log_item_t *)bip); | |
555 | ||
556 | /* initialize b_fsprivate2 so we can find it incore */ | |
557 | XFS_BUF_SET_FSPRIVATE2(bp, tp); | |
558 | return bp; | |
559 | } | |
560 | ||
2bd0ea18 | 561 | int |
a2ceac1f | 562 | libxfs_trans_read_buf_map( |
ad10fb70 NS |
563 | xfs_mount_t *mp, |
564 | xfs_trans_t *tp, | |
75c8b434 | 565 | struct xfs_buftarg *btp, |
a2ceac1f DC |
566 | struct xfs_buf_map *map, |
567 | int nmaps, | |
f1b058f9 | 568 | uint flags, |
a2ceac1f DC |
569 | xfs_buf_t **bpp, |
570 | const struct xfs_buf_ops *ops) | |
2bd0ea18 NS |
571 | { |
572 | xfs_buf_t *bp; | |
573 | xfs_buf_log_item_t *bip; | |
a6a7776a | 574 | int error; |
2bd0ea18 | 575 | |
00aea09f CH |
576 | *bpp = NULL; |
577 | ||
2bd0ea18 | 578 | if (tp == NULL) { |
75c8b434 | 579 | bp = libxfs_readbuf_map(btp, map, nmaps, flags, ops); |
00aea09f | 580 | if (!bp) { |
12b53197 | 581 | return (flags & XBF_TRYLOCK) ? -EAGAIN : -ENOMEM; |
00aea09f | 582 | } |
a6a7776a CH |
583 | if (bp->b_error) |
584 | goto out_relse; | |
00aea09f | 585 | goto done; |
2bd0ea18 NS |
586 | } |
587 | ||
75c8b434 | 588 | bp = xfs_trans_buf_item_match(tp, btp, map, nmaps); |
2bd0ea18 NS |
589 | if (bp != NULL) { |
590 | ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); | |
591 | ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); | |
592 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); | |
593 | bip->bli_recur++; | |
00aea09f | 594 | goto done; |
2bd0ea18 NS |
595 | } |
596 | ||
75c8b434 | 597 | bp = libxfs_readbuf_map(btp, map, nmaps, flags, ops); |
00aea09f | 598 | if (!bp) { |
12b53197 | 599 | return (flags & XBF_TRYLOCK) ? -EAGAIN : -ENOMEM; |
00aea09f | 600 | } |
a6a7776a CH |
601 | if (bp->b_error) |
602 | goto out_relse; | |
00aea09f | 603 | |
2bd0ea18 NS |
604 | #ifdef XACT_DEBUG |
605 | fprintf(stderr, "trans_read_buf buffer %p, transaction %p\n", bp, tp); | |
606 | #endif | |
607 | ||
608 | xfs_buf_item_init(bp, tp->t_mountp); | |
609 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); | |
610 | bip->bli_recur = 0; | |
611 | xfs_trans_add_item(tp, (xfs_log_item_t *)bip); | |
612 | ||
613 | /* initialise b_fsprivate2 so we can find it incore */ | |
614 | XFS_BUF_SET_FSPRIVATE2(bp, tp); | |
00aea09f | 615 | done: |
2bd0ea18 NS |
616 | *bpp = bp; |
617 | return 0; | |
a6a7776a CH |
618 | out_relse: |
619 | error = bp->b_error; | |
620 | xfs_buf_relse(bp); | |
621 | return error; | |
2bd0ea18 NS |
622 | } |
623 | ||
624 | /* | |
625 | * Record the indicated change to the given field for application | |
626 | * to the file system's superblock when the transaction commits. | |
627 | * For now, just store the change in the transaction structure. | |
628 | * Mark the transaction structure to indicate that the superblock | |
5000d01d | 629 | * needs to be updated before committing. |
2bd0ea18 NS |
630 | * |
631 | * Originally derived from xfs_trans_mod_sb(). | |
632 | */ | |
633 | void | |
ad10fb70 NS |
634 | libxfs_trans_mod_sb( |
635 | xfs_trans_t *tp, | |
636 | uint field, | |
637 | long delta) | |
2bd0ea18 NS |
638 | { |
639 | switch (field) { | |
640 | case XFS_TRANS_SB_RES_FDBLOCKS: | |
641 | return; | |
642 | case XFS_TRANS_SB_FDBLOCKS: | |
643 | tp->t_fdblocks_delta += delta; | |
644 | break; | |
645 | case XFS_TRANS_SB_ICOUNT: | |
646 | ASSERT(delta > 0); | |
647 | tp->t_icount_delta += delta; | |
648 | break; | |
649 | case XFS_TRANS_SB_IFREE: | |
650 | tp->t_ifree_delta += delta; | |
651 | break; | |
652 | case XFS_TRANS_SB_FREXTENTS: | |
653 | tp->t_frextents_delta += delta; | |
654 | break; | |
655 | default: | |
656 | ASSERT(0); | |
657 | return; | |
658 | } | |
659 | tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY); | |
660 | } | |
661 | ||
662 | ||
663 | /* | |
664 | * Transaction commital code follows (i.e. write to disk in libxfs) | |
665 | */ | |
666 | ||
5e656dbb | 667 | static void |
ad10fb70 NS |
668 | inode_item_done( |
669 | xfs_inode_log_item_t *iip) | |
2bd0ea18 | 670 | { |
ad10fb70 NS |
671 | xfs_dinode_t *dip; |
672 | xfs_inode_t *ip; | |
673 | xfs_mount_t *mp; | |
674 | xfs_buf_t *bp; | |
ad10fb70 | 675 | int error; |
2bd0ea18 NS |
676 | |
677 | ip = iip->ili_inode; | |
678 | mp = iip->ili_item.li_mountp; | |
2bd0ea18 NS |
679 | ASSERT(ip != NULL); |
680 | ||
a2ceac1f | 681 | if (!(iip->ili_fields & XFS_ILOG_ALL)) { |
2bd0ea18 NS |
682 | ip->i_transp = NULL; /* disassociate from transaction */ |
683 | iip->ili_flags = 0; /* reset all flags */ | |
260c85e8 | 684 | return; |
2bd0ea18 NS |
685 | } |
686 | ||
687 | /* | |
688 | * Get the buffer containing the on-disk inode. | |
689 | */ | |
a2ceac1f | 690 | error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, 0, 0); |
2bd0ea18 | 691 | if (error) { |
a2ceac1f | 692 | fprintf(stderr, _("%s: warning - imap_to_bp failed (%d)\n"), |
2bd0ea18 | 693 | progname, error); |
260c85e8 | 694 | return; |
2bd0ea18 NS |
695 | } |
696 | ||
697 | XFS_BUF_SET_FSPRIVATE(bp, iip); | |
698 | error = libxfs_iflush_int(ip, bp); | |
699 | if (error) { | |
9440d84d | 700 | fprintf(stderr, _("%s: warning - iflush_int failed (%d)\n"), |
2bd0ea18 | 701 | progname, error); |
260c85e8 | 702 | return; |
2bd0ea18 NS |
703 | } |
704 | ||
705 | ip->i_transp = NULL; /* disassociate from transaction */ | |
706 | XFS_BUF_SET_FSPRIVATE(bp, NULL); /* remove log item */ | |
707 | XFS_BUF_SET_FSPRIVATE2(bp, NULL); /* remove xact ptr */ | |
f1b058f9 | 708 | libxfs_writebuf(bp, 0); |
2bd0ea18 | 709 | #ifdef XACT_DEBUG |
260c85e8 MT |
710 | fprintf(stderr, "flushing dirty inode %llu, buffer %p\n", |
711 | ip->i_ino, bp); | |
2bd0ea18 | 712 | #endif |
2bd0ea18 NS |
713 | } |
714 | ||
5e656dbb | 715 | static void |
ad10fb70 NS |
716 | buf_item_done( |
717 | xfs_buf_log_item_t *bip) | |
2bd0ea18 | 718 | { |
ad10fb70 NS |
719 | xfs_buf_t *bp; |
720 | int hold; | |
5e656dbb | 721 | extern kmem_zone_t *xfs_buf_item_zone; |
2bd0ea18 NS |
722 | |
723 | bp = bip->bli_buf; | |
724 | ASSERT(bp != NULL); | |
725 | XFS_BUF_SET_FSPRIVATE(bp, NULL); /* remove log item */ | |
726 | XFS_BUF_SET_FSPRIVATE2(bp, NULL); /* remove xact ptr */ | |
727 | ||
728 | hold = (bip->bli_flags & XFS_BLI_HOLD); | |
2556c98b | 729 | if (bip->bli_flags & XFS_BLI_DIRTY) { |
2bd0ea18 | 730 | #ifdef XACT_DEBUG |
f1b058f9 | 731 | fprintf(stderr, "flushing/staling buffer %p (hold=%d)\n", |
2bd0ea18 NS |
732 | bp, hold); |
733 | #endif | |
2556c98b | 734 | libxfs_writebuf_int(bp, 0); |
2bd0ea18 | 735 | } |
2556c98b BN |
736 | if (hold) |
737 | bip->bli_flags &= ~XFS_BLI_HOLD; | |
738 | else | |
739 | libxfs_putbuf(bp); | |
2bd0ea18 NS |
740 | /* release the buf item */ |
741 | kmem_zone_free(xfs_buf_item_zone, bip); | |
742 | } | |
743 | ||
2bd0ea18 | 744 | static void |
c40bdaa2 DC |
745 | trans_committed( |
746 | xfs_trans_t *tp) | |
2bd0ea18 | 747 | { |
c40bdaa2 DC |
748 | struct xfs_log_item_desc *lidp, *next; |
749 | ||
750 | list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) { | |
751 | struct xfs_log_item *lip = lidp->lid_item; | |
752 | ||
753 | xfs_trans_del_item(lip); | |
a2ceac1f | 754 | |
2bd0ea18 | 755 | if (lip->li_type == XFS_LI_BUF) |
c40bdaa2 | 756 | buf_item_done((xfs_buf_log_item_t *)lip); |
2bd0ea18 | 757 | else if (lip->li_type == XFS_LI_INODE) |
c40bdaa2 | 758 | inode_item_done((xfs_inode_log_item_t *)lip); |
2bd0ea18 | 759 | else { |
9440d84d | 760 | fprintf(stderr, _("%s: unrecognised log item type\n"), |
2bd0ea18 NS |
761 | progname); |
762 | ASSERT(0); | |
763 | } | |
c40bdaa2 | 764 | } |
2bd0ea18 NS |
765 | } |
766 | ||
5e656dbb | 767 | static void |
1bab604b NS |
768 | buf_item_unlock( |
769 | xfs_buf_log_item_t *bip) | |
770 | { | |
771 | xfs_buf_t *bp = bip->bli_buf; | |
772 | uint hold; | |
773 | ||
774 | /* Clear the buffer's association with this transaction. */ | |
775 | XFS_BUF_SET_FSPRIVATE2(bip->bli_buf, NULL); | |
776 | ||
777 | hold = bip->bli_flags & XFS_BLI_HOLD; | |
c40bdaa2 | 778 | bip->bli_flags &= ~XFS_BLI_HOLD; |
1bab604b NS |
779 | if (!hold) |
780 | libxfs_putbuf(bp); | |
1bab604b NS |
781 | } |
782 | ||
5e656dbb | 783 | static void |
1bab604b NS |
784 | inode_item_unlock( |
785 | xfs_inode_log_item_t *iip) | |
786 | { | |
787 | xfs_inode_t *ip = iip->ili_inode; | |
1bab604b NS |
788 | |
789 | /* Clear the transaction pointer in the inode. */ | |
790 | ip->i_transp = NULL; | |
791 | ||
1bab604b NS |
792 | iip->ili_flags = 0; |
793 | } | |
794 | ||
2bd0ea18 | 795 | /* |
c40bdaa2 DC |
796 | * Unlock all of the items of a transaction and free all the descriptors |
797 | * of that transaction. | |
2bd0ea18 | 798 | */ |
7bcb8403 | 799 | static void |
c40bdaa2 | 800 | xfs_trans_free_items( |
7bcb8403 | 801 | struct xfs_trans *tp) |
2bd0ea18 | 802 | { |
c40bdaa2 | 803 | struct xfs_log_item_desc *lidp, *next; |
2bd0ea18 | 804 | |
c40bdaa2 DC |
805 | list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) { |
806 | struct xfs_log_item *lip = lidp->lid_item; | |
807 | ||
808 | xfs_trans_del_item(lip); | |
1bab604b | 809 | if (lip->li_type == XFS_LI_BUF) |
c40bdaa2 | 810 | buf_item_unlock((xfs_buf_log_item_t *)lip); |
1bab604b | 811 | else if (lip->li_type == XFS_LI_INODE) |
c40bdaa2 | 812 | inode_item_unlock((xfs_inode_log_item_t *)lip); |
2bd0ea18 | 813 | else { |
9440d84d | 814 | fprintf(stderr, _("%s: unrecognised log item type\n"), |
2bd0ea18 NS |
815 | progname); |
816 | ASSERT(0); | |
817 | } | |
2bd0ea18 | 818 | } |
2bd0ea18 NS |
819 | } |
820 | ||
2bd0ea18 NS |
821 | /* |
822 | * Commit the changes represented by this transaction | |
823 | */ | |
824 | int | |
ad10fb70 | 825 | libxfs_trans_commit( |
de5a3f46 | 826 | xfs_trans_t *tp) |
2bd0ea18 NS |
827 | { |
828 | xfs_sb_t *sbp; | |
2bd0ea18 NS |
829 | |
830 | if (tp == NULL) | |
831 | return 0; | |
832 | ||
833 | if (!(tp->t_flags & XFS_TRANS_DIRTY)) { | |
834 | #ifdef XACT_DEBUG | |
835 | fprintf(stderr, "committed clean transaction %p\n", tp); | |
836 | #endif | |
7bcb8403 | 837 | xfs_trans_free_items(tp); |
2bd0ea18 NS |
838 | free(tp); |
839 | tp = NULL; | |
840 | return 0; | |
841 | } | |
842 | ||
843 | if (tp->t_flags & XFS_TRANS_SB_DIRTY) { | |
844 | sbp = &(tp->t_mountp->m_sb); | |
845 | if (tp->t_icount_delta) | |
846 | sbp->sb_icount += tp->t_icount_delta; | |
847 | if (tp->t_ifree_delta) | |
848 | sbp->sb_ifree += tp->t_ifree_delta; | |
849 | if (tp->t_fdblocks_delta) | |
850 | sbp->sb_fdblocks += tp->t_fdblocks_delta; | |
851 | if (tp->t_frextents_delta) | |
852 | sbp->sb_frextents += tp->t_frextents_delta; | |
19ebedcf | 853 | xfs_log_sb(tp); |
2bd0ea18 NS |
854 | } |
855 | ||
856 | #ifdef XACT_DEBUG | |
857 | fprintf(stderr, "committing dirty transaction %p\n", tp); | |
858 | #endif | |
859 | trans_committed(tp); | |
860 | ||
861 | /* That's it for the transaction structure. Free it. */ | |
862 | free(tp); | |
863 | tp = NULL; | |
864 | return 0; | |
865 | } |