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