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