]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/trans.c
libxfs: track transaction block reservation usage like the kernel
[thirdparty/xfsprogs-dev.git] / libxfs / trans.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
2bd0ea18 2/*
f1b058f9 3 * Copyright (c) 2000-2001,2005-2006 Silicon Graphics, Inc.
4329aa4c 4 * Copyright (C) 2010 Red Hat, Inc.
da23017d 5 * All Rights Reserved.
2bd0ea18
NS
6 */
7
9c799827 8#include "libxfs_priv.h"
b626fb59
DC
9#include "xfs_fs.h"
10#include "xfs_shared.h"
11#include "xfs_format.h"
12#include "xfs_log_format.h"
13#include "xfs_trans_resv.h"
14#include "xfs_mount.h"
15#include "xfs_inode_buf.h"
16#include "xfs_inode_fork.h"
17#include "xfs_inode.h"
18#include "xfs_trans.h"
19#include "xfs_sb.h"
2bd0ea18 20
7bcb8403 21static void xfs_trans_free_items(struct xfs_trans *tp);
f94c53c0
DW
22STATIC struct xfs_trans *xfs_trans_dup(struct xfs_trans *tp);
23static int xfs_trans_reserve(struct xfs_trans *tp, struct xfs_trans_res *resp,
24 uint blocks, uint rtextents);
25static int __xfs_trans_commit(struct xfs_trans *tp, bool regrant);
7bcb8403 26
2bd0ea18
NS
27/*
28 * Simple transaction interface
29 */
30
67d72279 31kmem_zone_t *xfs_trans_zone;
4329aa4c
DC
32
33/*
34 * Initialize the precomputed transaction reservation values
35 * in the mount structure.
36 */
37void
38libxfs_trans_init(
39 struct xfs_mount *mp)
40{
cf52c730 41 xfs_trans_resv_calc(mp, &mp->m_resv);
4329aa4c
DC
42}
43
44/*
45 * Add the given log item to the transaction's list of log items.
4329aa4c
DC
46 */
47void
48libxfs_trans_add_item(
49 struct xfs_trans *tp,
50 struct xfs_log_item *lip)
51{
4329aa4c
DC
52 ASSERT(lip->li_mountp == tp->t_mountp);
53 ASSERT(lip->li_ailp == tp->t_mountp->m_ail);
2fdd378a
DC
54 ASSERT(list_empty(&lip->li_trans));
55 ASSERT(!test_bit(XFS_LI_DIRTY, &lip->li_flags));
4329aa4c 56
2fdd378a 57 list_add_tail(&lip->li_trans, &tp->t_items);
a1c5615e
ES
58}
59
4329aa4c
DC
60/*
61 * Unlink and free the given descriptor.
62 */
63void
64libxfs_trans_del_item(
65 struct xfs_log_item *lip)
66{
2fdd378a
DC
67 clear_bit(XFS_LI_DIRTY, &lip->li_flags);
68 list_del_init(&lip->li_trans);
4329aa4c
DC
69}
70
71/*
72 * Roll from one trans in the sequence of PERMANENT transactions to
73 * the next: permanent transactions are only flushed out when
74 * committed with XFS_TRANS_RELEASE_LOG_RES, but we still want as soon
75 * as possible to let chunks of it go to the log. So we commit the
76 * chunk we've been working on and get a new transaction to continue.
77 */
78int
79libxfs_trans_roll(
d67406c9 80 struct xfs_trans **tpp)
4329aa4c 81{
d67406c9 82 struct xfs_trans *trans = *tpp;
48ea6cb9 83 struct xfs_trans_res tres;
4329aa4c
DC
84 int error;
85
4329aa4c
DC
86 /*
87 * Copy the critical parameters from one trans to the next.
88 */
48ea6cb9
DC
89 tres.tr_logres = trans->t_log_res;
90 tres.tr_logcount = trans->t_log_count;
f94c53c0
DW
91
92 *tpp = xfs_trans_dup(trans);
4329aa4c
DC
93
94 /*
95 * Commit the current transaction.
96 * If this commit failed, then it'd just unlock those items that
260c85e8 97 * are marked to be released. That also means that a filesystem shutdown
4329aa4c
DC
98 * is in progress. The caller takes the responsibility to cancel
99 * the duplicate transaction that gets returned.
100 */
f94c53c0 101 error = __xfs_trans_commit(trans, true);
4329aa4c 102 if (error)
af43ca9f 103 return error;
4329aa4c 104
4329aa4c 105 /*
d67406c9 106 * Reserve space in the log for the next transaction.
4329aa4c
DC
107 * This also pushes items in the "AIL", the list of logged items,
108 * out to disk if they are taking up space at the tail of the log
109 * that we want to use. This requires that either nothing be locked
110 * across this call, or that anything that is locked be logged in
111 * the prior and the next transactions.
112 */
48ea6cb9 113 tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
f94c53c0 114 return xfs_trans_reserve(*tpp, &tres, 0, 0);
4329aa4c
DC
115}
116
67d72279
ES
117/*
118 * Free the transaction structure. If there is more clean up
119 * to do when the structure is freed, add it here.
120 */
121static void
122xfs_trans_free(
123 struct xfs_trans *tp)
124{
125 kmem_zone_free(xfs_trans_zone, tp);
126}
127
f94c53c0
DW
128/*
129 * This is called to create a new transaction which will share the
130 * permanent log reservation of the given transaction. The remaining
131 * unused block and rt extent reservations are also inherited. This
132 * implies that the original transaction is no longer allowed to allocate
133 * blocks. Locks and log items, however, are no inherited. They must
134 * be added to the new transaction explicitly.
135 */
136STATIC struct xfs_trans *
137xfs_trans_dup(
138 struct xfs_trans *tp)
139{
140 struct xfs_trans *ntp;
141
142 ntp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP);
143
144 /*
145 * Initialize the new transaction structure.
146 */
147 ntp->t_mountp = tp->t_mountp;
148 INIT_LIST_HEAD(&ntp->t_items);
149
150 ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
151
152 ntp->t_flags = XFS_TRANS_PERM_LOG_RES |
153 (tp->t_flags & XFS_TRANS_RESERVE) |
154 (tp->t_flags & XFS_TRANS_NO_WRITECOUNT);
155 /* We gave our writer reference to the new transaction */
156 tp->t_flags |= XFS_TRANS_NO_WRITECOUNT;
9074815c 157
41ab9202
DW
158 ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used;
159 tp->t_blk_res = tp->t_blk_res_used;
160
f94c53c0
DW
161 ntp->t_agfl_dfops = tp->t_agfl_dfops;
162
163 return ntp;
164}
165
166/*
167 * This is called to reserve free disk blocks and log space for the
168 * given transaction. This must be done before allocating any resources
169 * within the transaction.
170 *
171 * This will return ENOSPC if there are not enough blocks available.
172 * It will sleep waiting for available log space.
173 * The only valid value for the flags parameter is XFS_RES_LOG_PERM, which
174 * is used by long running transactions. If any one of the reservations
175 * fails then they will all be backed out.
176 *
177 * This does not do quota reservations. That typically is done by the
178 * caller afterwards.
179 */
180static int
181xfs_trans_reserve(
182 struct xfs_trans *tp,
183 struct xfs_trans_res *resp,
184 uint blocks,
185 uint rtextents)
2bd0ea18 186{
f94c53c0 187 int error = 0;
9074815c
CH
188
189 /*
190 * Attempt to reserve the needed disk blocks by decrementing
f94c53c0 191 * the number needed from the number available. This will
9074815c
CH
192 * fail if the count would go below zero.
193 */
194 if (blocks > 0) {
f94c53c0 195 if (tp->t_mountp->m_sb.sb_fdblocks < blocks)
9074815c 196 return -ENOSPC;
f94c53c0 197 tp->t_blk_res += blocks;
9074815c 198 }
2bd0ea18 199
f94c53c0
DW
200 /*
201 * Reserve the log space needed for this transaction.
202 */
203 if (resp->tr_logres > 0) {
204 ASSERT(tp->t_log_res == 0 ||
205 tp->t_log_res == resp->tr_logres);
206 ASSERT(tp->t_log_count == 0 ||
207 tp->t_log_count == resp->tr_logcount);
208
209 if (resp->tr_logflags & XFS_TRANS_PERM_LOG_RES)
210 tp->t_flags |= XFS_TRANS_PERM_LOG_RES;
211 else
212 ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES));
213
214 tp->t_log_res = resp->tr_logres;
215 tp->t_log_count = resp->tr_logcount;
216 }
217
218 /*
219 * Attempt to reserve the needed realtime extents by decrementing
220 * the number needed from the number available. This will
221 * fail if the count would go below zero.
222 */
223 if (rtextents > 0) {
224 if (tp->t_mountp->m_sb.sb_rextents < rtextents) {
225 error = -ENOSPC;
226 goto undo_blocks;
227 }
228 }
229
230 return 0;
231
232 /*
233 * Error cases jump to one of these labels to undo any
234 * reservations which have already been performed.
235 */
236undo_blocks:
237 if (blocks > 0)
238 tp->t_blk_res = 0;
239
240 return error;
241}
242
243int
244libxfs_trans_alloc(
245 struct xfs_mount *mp,
246 struct xfs_trans_res *resp,
247 unsigned int blocks,
248 unsigned int rtextents,
249 unsigned int flags,
250 struct xfs_trans **tpp)
251
252{
253 struct xfs_trans *tp;
254 int error;
255
256 tp = kmem_zone_zalloc(xfs_trans_zone,
67d72279 257 (flags & XFS_TRANS_NOFS) ? KM_NOFS : KM_SLEEP);
f94c53c0
DW
258 tp->t_mountp = mp;
259 INIT_LIST_HEAD(&tp->t_items);
260
261 error = xfs_trans_reserve(tp, resp, blocks, rtextents);
262 if (error) {
263 xfs_trans_cancel(tp);
264 return error;
265 }
2bd0ea18 266#ifdef XACT_DEBUG
f94c53c0 267 fprintf(stderr, "allocated new transaction %p\n", tp);
2bd0ea18 268#endif
f94c53c0 269 *tpp = tp;
2bd0ea18
NS
270 return 0;
271}
272
d4e8eb2e
DW
273/*
274 * Create an empty transaction with no reservation. This is a defensive
275 * mechanism for routines that query metadata without actually modifying
276 * them -- if the metadata being queried is somehow cross-linked (think a
277 * btree block pointer that points higher in the tree), we risk deadlock.
278 * However, blocks grabbed as part of a transaction can be re-grabbed.
279 * The verifiers will notice the corrupt block and the operation will fail
280 * back to userspace without deadlocking.
281 *
282 * Note the zero-length reservation; this transaction MUST be cancelled
283 * without any dirty data.
284 */
285int
3680a764 286libxfs_trans_alloc_empty(
d4e8eb2e
DW
287 struct xfs_mount *mp,
288 struct xfs_trans **tpp)
289{
290 struct xfs_trans_res resv = {0};
291
292 return xfs_trans_alloc(mp, &resv, 0, 0, XFS_TRANS_NO_WRITECOUNT, tpp);
293}
294
225e4bb2
DW
295/*
296 * Allocate a transaction that can be rolled. Since userspace doesn't have
297 * a need for log reservations, we really only tr_itruncate to get the
298 * permanent log reservation flag to avoid blowing asserts.
299 */
300int
301libxfs_trans_alloc_rollable(
302 struct xfs_mount *mp,
303 unsigned int blocks,
304 struct xfs_trans **tpp)
305{
306 return libxfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, blocks,
307 0, 0, tpp);
308}
309
2bd0ea18 310void
ad10fb70 311libxfs_trans_cancel(
f94c53c0 312 struct xfs_trans *tp)
2bd0ea18
NS
313{
314#ifdef XACT_DEBUG
f94c53c0 315 struct xfs_trans *otp = tp;
2bd0ea18 316#endif
f94c53c0
DW
317 if (tp == NULL)
318 goto out;
319
320 xfs_trans_free_items(tp);
321 xfs_trans_free(tp);
322
323out:
2bd0ea18
NS
324#ifdef XACT_DEBUG
325 fprintf(stderr, "## cancelled transaction %p\n", otp);
326#endif
f94c53c0 327 return;
2bd0ea18
NS
328}
329
330int
ad10fb70
NS
331libxfs_trans_iget(
332 xfs_mount_t *mp,
333 xfs_trans_t *tp,
334 xfs_ino_t ino,
46eca962 335 uint flags,
ad10fb70
NS
336 uint lock_flags,
337 xfs_inode_t **ipp)
2bd0ea18
NS
338{
339 int error;
340 xfs_inode_t *ip;
341 xfs_inode_log_item_t *iip;
342
343 if (tp == NULL)
12ac6e04
DW
344 return libxfs_iget(mp, tp, ino, lock_flags, ipp,
345 &xfs_default_ifork_ops);
2bd0ea18 346
12ac6e04
DW
347 error = libxfs_iget(mp, tp, ino, lock_flags, &ip,
348 &xfs_default_ifork_ops);
2bd0ea18
NS
349 if (error)
350 return error;
351 ASSERT(ip != NULL);
352
353 if (ip->i_itemp == NULL)
354 xfs_inode_item_init(ip, mp);
355 iip = ip->i_itemp;
356 xfs_trans_add_item(tp, (xfs_log_item_t *)(iip));
357
358 /* initialize i_transp so we can find it incore */
359 ip->i_transp = tp;
360
361 *ipp = ip;
362 return 0;
363}
364
2bd0ea18 365void
ad10fb70
NS
366libxfs_trans_ijoin(
367 xfs_trans_t *tp,
368 xfs_inode_t *ip,
369 uint lock_flags)
2bd0ea18
NS
370{
371 xfs_inode_log_item_t *iip;
372
373 ASSERT(ip->i_transp == NULL);
374 if (ip->i_itemp == NULL)
375 xfs_inode_item_init(ip, ip->i_mount);
376 iip = ip->i_itemp;
377 ASSERT(iip->ili_flags == 0);
378 ASSERT(iip->ili_inode != NULL);
379
380 xfs_trans_add_item(tp, (xfs_log_item_t *)(iip));
381
382 ip->i_transp = tp;
383#ifdef XACT_DEBUG
384 fprintf(stderr, "ijoin'd inode %llu, transaction %p\n", ip->i_ino, tp);
385#endif
386}
387
c40bdaa2
DC
388void
389libxfs_trans_ijoin_ref(
390 xfs_trans_t *tp,
391 xfs_inode_t *ip,
392 int lock_flags)
393{
394 ASSERT(ip->i_transp == tp);
395 ASSERT(ip->i_itemp != NULL);
396
397 xfs_trans_ijoin(tp, ip, lock_flags);
c40bdaa2
DC
398
399#ifdef XACT_DEBUG
400 fprintf(stderr, "ijoin_ref'd inode %llu, transaction %p\n", ip->i_ino, tp);
401#endif
402}
403
2bd0ea18 404void
ad10fb70
NS
405libxfs_trans_inode_alloc_buf(
406 xfs_trans_t *tp,
407 xfs_buf_t *bp)
2bd0ea18 408{
37d086ca 409 xfs_buf_log_item_t *bip = bp->b_log_item;
2bd0ea18 410
cfc06b60 411 ASSERT(bp->bp_transp == tp);
38d096b6 412 ASSERT(bip != NULL);
2bd0ea18 413 bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF;
bdc16ee5 414 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DINO_BUF);
2bd0ea18
NS
415}
416
417/*
418 * This is called to mark the fields indicated in fieldmask as needing
419 * to be logged when the transaction is committed. The inode must
420 * already be associated with the given transaction.
421 *
2d4bfb91 422 * The values for fieldmask are defined in xfs_log_format.h. We always
2bd0ea18
NS
423 * log all of the core inode if any of it has changed, and we always log
424 * all of the inline data/extents/b-tree root if any of them has changed.
425 */
426void
427xfs_trans_log_inode(
ad10fb70
NS
428 xfs_trans_t *tp,
429 xfs_inode_t *ip,
430 uint flags)
2bd0ea18 431{
2bd0ea18
NS
432 ASSERT(ip->i_transp == tp);
433 ASSERT(ip->i_itemp != NULL);
434#ifdef XACT_DEBUG
435 fprintf(stderr, "dirtied inode %llu, transaction %p\n", ip->i_ino, tp);
436#endif
437
2bd0ea18 438 tp->t_flags |= XFS_TRANS_DIRTY;
2fdd378a 439 set_bit(XFS_LI_DIRTY, &ip->i_itemp->ili_item.li_flags);
2bd0ea18
NS
440
441 /*
442 * Always OR in the bits from the ili_last_fields field.
443 * This is to coordinate with the xfs_iflush() and xfs_iflush_done()
444 * routines in the eventual clearing of the ilf_fields bits.
445 * See the big comment in xfs_iflush() for an explanation of
446 * this coordination mechanism.
447 */
448 flags |= ip->i_itemp->ili_last_fields;
a2ceac1f 449 ip->i_itemp->ili_fields |= flags;
2bd0ea18
NS
450}
451
d67406c9
CH
452int
453libxfs_trans_roll_inode(
454 struct xfs_trans **tpp,
455 struct xfs_inode *ip)
456{
457 int error;
458
459 xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
460 error = xfs_trans_roll(tpp);
461 if (!error)
462 xfs_trans_ijoin(*tpp, ip, 0);
463 return error;
464}
465
466
59630067
BF
467/*
468 * Mark a buffer dirty in the transaction.
469 */
470void
471libxfs_trans_dirty_buf(
472 struct xfs_trans *tp,
473 struct xfs_buf *bp)
474{
37d086ca 475 struct xfs_buf_log_item *bip = bp->b_log_item;
59630067 476
cfc06b60 477 ASSERT(bp->bp_transp == tp);
38d096b6 478 ASSERT(bip != NULL);
59630067 479
59630067
BF
480#ifdef XACT_DEBUG
481 fprintf(stderr, "dirtied buffer %p, transaction %p\n", bp, tp);
482#endif
483 tp->t_flags |= XFS_TRANS_DIRTY;
2fdd378a 484 set_bit(XFS_LI_DIRTY, &bip->bli_item.li_flags);
59630067
BF
485}
486
2bd0ea18
NS
487/*
488 * This is called to mark bytes first through last inclusive of the given
489 * buffer as needing to be logged when the transaction is committed.
490 * The buffer must already be associated with the given transaction.
5000d01d 491 *
2bd0ea18
NS
492 * First and last are numbers relative to the beginning of this buffer,
493 * so the first byte in the buffer is numbered 0 regardless of the
494 * value of b_blkno.
495 */
496void
ad10fb70 497libxfs_trans_log_buf(
59630067
BF
498 struct xfs_trans *tp,
499 struct xfs_buf *bp,
ad10fb70
NS
500 uint first,
501 uint last)
2bd0ea18 502{
37d086ca 503 struct xfs_buf_log_item *bip = bp->b_log_item;
2bd0ea18 504
135e4bfe 505 ASSERT((first <= last) && (last < bp->b_bcount));
2bd0ea18 506
59630067 507 xfs_trans_dirty_buf(tp, bp);
2bd0ea18
NS
508 xfs_buf_item_log(bip, first, last);
509}
510
38fa71a7
BF
511/*
512 * For userspace, ordered buffers just need to be marked dirty so
513 * the transaction commit will write them and mark them up-to-date.
514 * In essence, they are just like any other logged buffer in userspace.
515 *
516 * If the buffer is already dirty, trigger the "already logged" return condition.
517 */
518bool
519libxfs_trans_ordered_buf(
520 struct xfs_trans *tp,
521 struct xfs_buf *bp)
522{
37d086ca 523 struct xfs_buf_log_item *bip = bp->b_log_item;
38fa71a7
BF
524 bool ret;
525
2fdd378a 526 ret = test_bit(XFS_LI_DIRTY, &bip->bli_item.li_flags);
38fa71a7
BF
527 libxfs_trans_log_buf(tp, bp, 0, bp->b_bcount);
528 return ret;
529}
530
2bd0ea18 531void
ad10fb70
NS
532libxfs_trans_brelse(
533 xfs_trans_t *tp,
534 xfs_buf_t *bp)
2bd0ea18
NS
535{
536 xfs_buf_log_item_t *bip;
2bd0ea18
NS
537#ifdef XACT_DEBUG
538 fprintf(stderr, "released buffer %p, transaction %p\n", bp, tp);
539#endif
540
541 if (tp == NULL) {
cfc06b60 542 ASSERT(bp->bp_transp == NULL);
2bd0ea18
NS
543 libxfs_putbuf(bp);
544 return;
545 }
cfc06b60 546 ASSERT(bp->bp_transp == tp);
37d086ca 547 bip = bp->b_log_item;
2bd0ea18 548 ASSERT(bip->bli_item.li_type == XFS_LI_BUF);
2bd0ea18
NS
549 if (bip->bli_recur > 0) {
550 bip->bli_recur--;
551 return;
552 }
f1b058f9
NS
553 /* If dirty/stale, can't release till transaction committed */
554 if (bip->bli_flags & XFS_BLI_STALE)
555 return;
2fdd378a 556 if (test_bit(XFS_LI_DIRTY, &bip->bli_item.li_flags))
2bd0ea18 557 return;
c40bdaa2 558 xfs_trans_del_item(&bip->bli_item);
f1b058f9 559 if (bip->bli_flags & XFS_BLI_HOLD)
2bd0ea18 560 bip->bli_flags &= ~XFS_BLI_HOLD;
cfc06b60 561 bp->b_transp = NULL;
2bd0ea18
NS
562 libxfs_putbuf(bp);
563}
564
565void
ad10fb70
NS
566libxfs_trans_binval(
567 xfs_trans_t *tp,
568 xfs_buf_t *bp)
2bd0ea18 569{
37d086ca 570 xfs_buf_log_item_t *bip = bp->b_log_item;
2bd0ea18
NS
571#ifdef XACT_DEBUG
572 fprintf(stderr, "binval'd buffer %p, transaction %p\n", bp, tp);
573#endif
574
cfc06b60 575 ASSERT(bp->bp_transp == tp);
38d096b6 576 ASSERT(bip != NULL);
2bd0ea18 577
f1b058f9
NS
578 if (bip->bli_flags & XFS_BLI_STALE)
579 return;
580 XFS_BUF_UNDELAYWRITE(bp);
a2ceac1f 581 xfs_buf_stale(bp);
f1b058f9
NS
582 bip->bli_flags |= XFS_BLI_STALE;
583 bip->bli_flags &= ~XFS_BLI_DIRTY;
c40bdaa2
DC
584 bip->bli_format.blf_flags &= ~XFS_BLF_INODE_BUF;
585 bip->bli_format.blf_flags |= XFS_BLF_CANCEL;
2fdd378a 586 set_bit(XFS_LI_DIRTY, &bip->bli_item.li_flags);
2bd0ea18
NS
587 tp->t_flags |= XFS_TRANS_DIRTY;
588}
589
590void
ad10fb70
NS
591libxfs_trans_bjoin(
592 xfs_trans_t *tp,
593 xfs_buf_t *bp)
2bd0ea18
NS
594{
595 xfs_buf_log_item_t *bip;
596
cfc06b60 597 ASSERT(bp->bp_transp == NULL);
2bd0ea18
NS
598#ifdef XACT_DEBUG
599 fprintf(stderr, "bjoin'd buffer %p, transaction %p\n", bp, tp);
600#endif
601
602 xfs_buf_item_init(bp, tp->t_mountp);
37d086ca 603 bip = bp->b_log_item;
2bd0ea18 604 xfs_trans_add_item(tp, (xfs_log_item_t *)bip);
cfc06b60 605 bp->b_transp = tp;
2bd0ea18
NS
606}
607
608void
ad10fb70
NS
609libxfs_trans_bhold(
610 xfs_trans_t *tp,
611 xfs_buf_t *bp)
2bd0ea18 612{
37d086ca 613 xfs_buf_log_item_t *bip = bp->b_log_item;
2bd0ea18 614
cfc06b60 615 ASSERT(bp->bp_transp == tp);
37d086ca 616 ASSERT(bip != NULL);
2bd0ea18
NS
617#ifdef XACT_DEBUG
618 fprintf(stderr, "bhold'd buffer %p, transaction %p\n", bp, tp);
619#endif
620
2bd0ea18
NS
621 bip->bli_flags |= XFS_BLI_HOLD;
622}
623
624xfs_buf_t *
a2ceac1f 625libxfs_trans_get_buf_map(
ad10fb70 626 xfs_trans_t *tp,
75c8b434 627 struct xfs_buftarg *btp,
a2ceac1f
DC
628 struct xfs_buf_map *map,
629 int nmaps,
ad10fb70 630 uint f)
2bd0ea18
NS
631{
632 xfs_buf_t *bp;
633 xfs_buf_log_item_t *bip;
2bd0ea18
NS
634
635 if (tp == NULL)
7e3ab890 636 return libxfs_getbuf_map(btp, map, nmaps, 0);
2bd0ea18 637
75c8b434 638 bp = xfs_trans_buf_item_match(tp, btp, map, nmaps);
2bd0ea18 639 if (bp != NULL) {
cfc06b60 640 ASSERT(bp->bp_transp == tp);
37d086ca 641 bip = bp->b_log_item;
2bd0ea18
NS
642 ASSERT(bip != NULL);
643 bip->bli_recur++;
644 return bp;
645 }
646
7e3ab890 647 bp = libxfs_getbuf_map(btp, map, nmaps, 0);
2bd0ea18
NS
648 if (bp == NULL)
649 return NULL;
650#ifdef XACT_DEBUG
651 fprintf(stderr, "trans_get_buf buffer %p, transaction %p\n", bp, tp);
652#endif
653
654 xfs_buf_item_init(bp, tp->t_mountp);
37d086ca 655 bip = bp->b_log_item;
2bd0ea18
NS
656 bip->bli_recur = 0;
657 xfs_trans_add_item(tp, (xfs_log_item_t *)bip);
658
cfc06b60
CH
659 /* initialize b_transp so we can find it incore */
660 bp->b_transp = tp;
2bd0ea18
NS
661 return bp;
662}
663
f1b058f9
NS
664xfs_buf_t *
665libxfs_trans_getsb(
666 xfs_trans_t *tp,
667 xfs_mount_t *mp,
668 int flags)
669{
670 xfs_buf_t *bp;
671 xfs_buf_log_item_t *bip;
a2ceac1f
DC
672 int len = XFS_FSS_TO_BB(mp, 1);
673 DEFINE_SINGLE_BUF_MAP(map, XFS_SB_DADDR, len);
f1b058f9
NS
674
675 if (tp == NULL)
676 return libxfs_getsb(mp, flags);
677
a2ceac1f 678 bp = xfs_trans_buf_item_match(tp, mp->m_dev, &map, 1);
f1b058f9 679 if (bp != NULL) {
cfc06b60 680 ASSERT(bp->bp_transp == tp);
37d086ca 681 bip = bp->b_log_item;
f1b058f9
NS
682 ASSERT(bip != NULL);
683 bip->bli_recur++;
684 return bp;
685 }
686
687 bp = libxfs_getsb(mp, flags);
688#ifdef XACT_DEBUG
689 fprintf(stderr, "trans_get_sb buffer %p, transaction %p\n", bp, tp);
690#endif
691
692 xfs_buf_item_init(bp, mp);
37d086ca 693 bip = bp->b_log_item;
f1b058f9
NS
694 bip->bli_recur = 0;
695 xfs_trans_add_item(tp, (xfs_log_item_t *)bip);
696
cfc06b60
CH
697 /* initialize b_transp so we can find it incore */
698 bp->b_transp = tp;
f1b058f9
NS
699 return bp;
700}
701
2bd0ea18 702int
a2ceac1f 703libxfs_trans_read_buf_map(
ad10fb70
NS
704 xfs_mount_t *mp,
705 xfs_trans_t *tp,
75c8b434 706 struct xfs_buftarg *btp,
a2ceac1f
DC
707 struct xfs_buf_map *map,
708 int nmaps,
f1b058f9 709 uint flags,
a2ceac1f
DC
710 xfs_buf_t **bpp,
711 const struct xfs_buf_ops *ops)
2bd0ea18
NS
712{
713 xfs_buf_t *bp;
714 xfs_buf_log_item_t *bip;
a6a7776a 715 int error;
2bd0ea18 716
00aea09f
CH
717 *bpp = NULL;
718
2bd0ea18 719 if (tp == NULL) {
75c8b434 720 bp = libxfs_readbuf_map(btp, map, nmaps, flags, ops);
00aea09f 721 if (!bp) {
12b53197 722 return (flags & XBF_TRYLOCK) ? -EAGAIN : -ENOMEM;
00aea09f 723 }
a6a7776a
CH
724 if (bp->b_error)
725 goto out_relse;
00aea09f 726 goto done;
2bd0ea18
NS
727 }
728
75c8b434 729 bp = xfs_trans_buf_item_match(tp, btp, map, nmaps);
2bd0ea18 730 if (bp != NULL) {
cfc06b60 731 ASSERT(bp->bp_transp == tp);
37d086ca
CM
732 ASSERT(bp->b_log_item != NULL);
733 bip = bp->b_log_item;
2bd0ea18 734 bip->bli_recur++;
00aea09f 735 goto done;
2bd0ea18
NS
736 }
737
75c8b434 738 bp = libxfs_readbuf_map(btp, map, nmaps, flags, ops);
00aea09f 739 if (!bp) {
12b53197 740 return (flags & XBF_TRYLOCK) ? -EAGAIN : -ENOMEM;
00aea09f 741 }
a6a7776a
CH
742 if (bp->b_error)
743 goto out_relse;
00aea09f 744
2bd0ea18
NS
745#ifdef XACT_DEBUG
746 fprintf(stderr, "trans_read_buf buffer %p, transaction %p\n", bp, tp);
747#endif
748
749 xfs_buf_item_init(bp, tp->t_mountp);
37d086ca 750 bip = bp->b_log_item;
2bd0ea18
NS
751 bip->bli_recur = 0;
752 xfs_trans_add_item(tp, (xfs_log_item_t *)bip);
753
cfc06b60
CH
754 /* initialise b_transp so we can find it incore */
755 bp->b_transp = tp;
00aea09f 756done:
2bd0ea18
NS
757 *bpp = bp;
758 return 0;
a6a7776a
CH
759out_relse:
760 error = bp->b_error;
761 xfs_buf_relse(bp);
762 return error;
2bd0ea18
NS
763}
764
765/*
766 * Record the indicated change to the given field for application
767 * to the file system's superblock when the transaction commits.
768 * For now, just store the change in the transaction structure.
769 * Mark the transaction structure to indicate that the superblock
5000d01d 770 * needs to be updated before committing.
2bd0ea18
NS
771 *
772 * Originally derived from xfs_trans_mod_sb().
773 */
774void
ad10fb70
NS
775libxfs_trans_mod_sb(
776 xfs_trans_t *tp,
777 uint field,
778 long delta)
2bd0ea18
NS
779{
780 switch (field) {
781 case XFS_TRANS_SB_RES_FDBLOCKS:
782 return;
783 case XFS_TRANS_SB_FDBLOCKS:
41ab9202
DW
784 if (delta < 0) {
785 tp->t_blk_res_used += (uint)-delta;
786 if (tp->t_blk_res_used > tp->t_blk_res) {
787 fprintf(stderr,
788_("Transaction block reservation exceeded! %u > %u\n"),
789 tp->t_blk_res_used, tp->t_blk_res);
790 ASSERT(0);
791 }
792 }
2bd0ea18
NS
793 tp->t_fdblocks_delta += delta;
794 break;
795 case XFS_TRANS_SB_ICOUNT:
796 ASSERT(delta > 0);
797 tp->t_icount_delta += delta;
798 break;
799 case XFS_TRANS_SB_IFREE:
800 tp->t_ifree_delta += delta;
801 break;
802 case XFS_TRANS_SB_FREXTENTS:
803 tp->t_frextents_delta += delta;
804 break;
805 default:
806 ASSERT(0);
807 return;
808 }
809 tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY);
810}
811
812
813/*
814 * Transaction commital code follows (i.e. write to disk in libxfs)
815 */
816
5e656dbb 817static void
ad10fb70
NS
818inode_item_done(
819 xfs_inode_log_item_t *iip)
2bd0ea18 820{
ad10fb70
NS
821 xfs_dinode_t *dip;
822 xfs_inode_t *ip;
823 xfs_mount_t *mp;
824 xfs_buf_t *bp;
ad10fb70 825 int error;
2bd0ea18
NS
826
827 ip = iip->ili_inode;
828 mp = iip->ili_item.li_mountp;
2bd0ea18
NS
829 ASSERT(ip != NULL);
830
a2ceac1f 831 if (!(iip->ili_fields & XFS_ILOG_ALL)) {
2bd0ea18
NS
832 ip->i_transp = NULL; /* disassociate from transaction */
833 iip->ili_flags = 0; /* reset all flags */
260c85e8 834 return;
2bd0ea18
NS
835 }
836
837 /*
838 * Get the buffer containing the on-disk inode.
839 */
a2ceac1f 840 error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, 0, 0);
2bd0ea18 841 if (error) {
a2ceac1f 842 fprintf(stderr, _("%s: warning - imap_to_bp failed (%d)\n"),
2bd0ea18 843 progname, error);
260c85e8 844 return;
2bd0ea18
NS
845 }
846
37d086ca 847 bp->b_log_item = iip;
2bd0ea18
NS
848 error = libxfs_iflush_int(ip, bp);
849 if (error) {
9440d84d 850 fprintf(stderr, _("%s: warning - iflush_int failed (%d)\n"),
2bd0ea18 851 progname, error);
260c85e8 852 return;
2bd0ea18
NS
853 }
854
855 ip->i_transp = NULL; /* disassociate from transaction */
37d086ca 856 bp->b_log_item = NULL; /* remove log item */
cfc06b60 857 bp->b_transp = NULL; /* remove xact ptr */
f1b058f9 858 libxfs_writebuf(bp, 0);
2bd0ea18 859#ifdef XACT_DEBUG
260c85e8
MT
860 fprintf(stderr, "flushing dirty inode %llu, buffer %p\n",
861 ip->i_ino, bp);
2bd0ea18 862#endif
2bd0ea18
NS
863}
864
5e656dbb 865static void
ad10fb70
NS
866buf_item_done(
867 xfs_buf_log_item_t *bip)
2bd0ea18 868{
ad10fb70
NS
869 xfs_buf_t *bp;
870 int hold;
5e656dbb 871 extern kmem_zone_t *xfs_buf_item_zone;
2bd0ea18
NS
872
873 bp = bip->bli_buf;
874 ASSERT(bp != NULL);
37d086ca 875 bp->b_log_item = NULL; /* remove log item */
cfc06b60 876 bp->b_transp = NULL; /* remove xact ptr */
2bd0ea18
NS
877
878 hold = (bip->bli_flags & XFS_BLI_HOLD);
2556c98b 879 if (bip->bli_flags & XFS_BLI_DIRTY) {
2bd0ea18 880#ifdef XACT_DEBUG
f1b058f9 881 fprintf(stderr, "flushing/staling buffer %p (hold=%d)\n",
2bd0ea18
NS
882 bp, hold);
883#endif
2556c98b 884 libxfs_writebuf_int(bp, 0);
2bd0ea18 885 }
2556c98b
BN
886 if (hold)
887 bip->bli_flags &= ~XFS_BLI_HOLD;
888 else
889 libxfs_putbuf(bp);
2bd0ea18
NS
890 /* release the buf item */
891 kmem_zone_free(xfs_buf_item_zone, bip);
892}
893
2bd0ea18 894static void
c40bdaa2
DC
895trans_committed(
896 xfs_trans_t *tp)
2bd0ea18 897{
2fdd378a 898 struct xfs_log_item *lip, *next;
c40bdaa2 899
2fdd378a 900 list_for_each_entry_safe(lip, next, &tp->t_items, li_trans) {
68f7f684 901 xfs_trans_del_item(lip);
a2ceac1f 902
2bd0ea18 903 if (lip->li_type == XFS_LI_BUF)
c40bdaa2 904 buf_item_done((xfs_buf_log_item_t *)lip);
2bd0ea18 905 else if (lip->li_type == XFS_LI_INODE)
c40bdaa2 906 inode_item_done((xfs_inode_log_item_t *)lip);
2bd0ea18 907 else {
9440d84d 908 fprintf(stderr, _("%s: unrecognised log item type\n"),
2bd0ea18
NS
909 progname);
910 ASSERT(0);
911 }
2fdd378a 912 }
2bd0ea18
NS
913}
914
5e656dbb 915static void
1bab604b
NS
916buf_item_unlock(
917 xfs_buf_log_item_t *bip)
918{
919 xfs_buf_t *bp = bip->bli_buf;
920 uint hold;
921
922 /* Clear the buffer's association with this transaction. */
cfc06b60 923 bip->bli_buf->b_transp = NULL;
1bab604b
NS
924
925 hold = bip->bli_flags & XFS_BLI_HOLD;
c40bdaa2 926 bip->bli_flags &= ~XFS_BLI_HOLD;
1bab604b
NS
927 if (!hold)
928 libxfs_putbuf(bp);
1bab604b
NS
929}
930
5e656dbb 931static void
1bab604b
NS
932inode_item_unlock(
933 xfs_inode_log_item_t *iip)
934{
935 xfs_inode_t *ip = iip->ili_inode;
1bab604b
NS
936
937 /* Clear the transaction pointer in the inode. */
938 ip->i_transp = NULL;
939
1bab604b
NS
940 iip->ili_flags = 0;
941}
942
2fdd378a 943/* Detach and unlock all of the items in a transaction */
7bcb8403 944static void
c40bdaa2 945xfs_trans_free_items(
7bcb8403 946 struct xfs_trans *tp)
2bd0ea18 947{
2fdd378a 948 struct xfs_log_item *lip, *next;
c40bdaa2 949
2fdd378a
DC
950 list_for_each_entry_safe(lip, next, &tp->t_items, li_trans) {
951 xfs_trans_del_item(lip);
1bab604b 952 if (lip->li_type == XFS_LI_BUF)
c40bdaa2 953 buf_item_unlock((xfs_buf_log_item_t *)lip);
1bab604b 954 else if (lip->li_type == XFS_LI_INODE)
c40bdaa2 955 inode_item_unlock((xfs_inode_log_item_t *)lip);
2bd0ea18 956 else {
9440d84d 957 fprintf(stderr, _("%s: unrecognised log item type\n"),
2bd0ea18
NS
958 progname);
959 ASSERT(0);
960 }
2bd0ea18 961 }
2bd0ea18
NS
962}
963
2bd0ea18
NS
964/*
965 * Commit the changes represented by this transaction
966 */
f94c53c0
DW
967static int
968__xfs_trans_commit(
969 struct xfs_trans *tp,
970 bool regrant)
2bd0ea18 971{
f94c53c0
DW
972 struct xfs_sb *sbp;
973 int error = 0;
2bd0ea18
NS
974
975 if (tp == NULL)
976 return 0;
977
f94c53c0
DW
978 ASSERT(!tp->t_agfl_dfops ||
979 !xfs_defer_has_unfinished_work(tp->t_agfl_dfops) || regrant);
980
2bd0ea18
NS
981 if (!(tp->t_flags & XFS_TRANS_DIRTY)) {
982#ifdef XACT_DEBUG
983 fprintf(stderr, "committed clean transaction %p\n", tp);
984#endif
f94c53c0 985 goto out_unreserve;
2bd0ea18
NS
986 }
987
988 if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
989 sbp = &(tp->t_mountp->m_sb);
990 if (tp->t_icount_delta)
991 sbp->sb_icount += tp->t_icount_delta;
992 if (tp->t_ifree_delta)
993 sbp->sb_ifree += tp->t_ifree_delta;
994 if (tp->t_fdblocks_delta)
995 sbp->sb_fdblocks += tp->t_fdblocks_delta;
996 if (tp->t_frextents_delta)
997 sbp->sb_frextents += tp->t_frextents_delta;
19ebedcf 998 xfs_log_sb(tp);
2bd0ea18
NS
999 }
1000
1001#ifdef XACT_DEBUG
1002 fprintf(stderr, "committing dirty transaction %p\n", tp);
1003#endif
1004 trans_committed(tp);
1005
1006 /* That's it for the transaction structure. Free it. */
67d72279 1007 xfs_trans_free(tp);
2bd0ea18 1008 return 0;
f94c53c0
DW
1009
1010out_unreserve:
1011 xfs_trans_free_items(tp);
1012 xfs_trans_free(tp);
1013 return error;
1014}
1015
1016int
1017libxfs_trans_commit(
1018 struct xfs_trans *tp)
1019{
1020 return __xfs_trans_commit(tp, false);
2bd0ea18 1021}