2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * Simple transaction interface
32 if ((ptr
= calloc(sizeof(xfs_trans_t
), 1)) == NULL
) {
33 fprintf(stderr
, _("%s: xact calloc failed (%d bytes): %s\n"),
34 progname
, (int)sizeof(xfs_trans_t
), strerror(errno
));
39 ptr
->t_items_free
= XFS_LIC_NUM_SLOTS
;
40 XFS_LIC_INIT(&(ptr
->t_items
));
42 fprintf(stderr
, "allocated new transaction %p\n", ptr
);
53 ptr
= libxfs_trans_alloc(tp
->t_mountp
, tp
->t_type
);
55 fprintf(stderr
, "duplicated transaction %p (new=%p)\n", tp
, ptr
);
69 xfs_sb_t
*mpsb
= &tp
->t_mountp
->m_sb
;
72 * Attempt to reserve the needed disk blocks by decrementing
73 * the number needed from the number available. This will
74 * fail if the count would go below zero.
77 if (mpsb
->sb_fdblocks
< blocks
)
80 /* user space, don't need log/RT stuff (preserve the API though) */
90 xfs_trans_t
*otp
= tp
;
93 xfs_trans_free_items(tp
, flags
);
98 fprintf(stderr
, "## cancelled transaction %p\n", otp
);
113 xfs_inode_log_item_t
*iip
;
116 return libxfs_iread(mp
, tp
, ino
, ipp
, 0);
118 error
= libxfs_iread(mp
, tp
, ino
, &ip
, 0);
123 if (ip
->i_itemp
== NULL
)
124 xfs_inode_item_init(ip
, mp
);
126 xfs_trans_add_item(tp
, (xfs_log_item_t
*)(iip
));
128 /* initialize i_transp so we can find it incore */
141 xfs_inode_log_item_t
*iip
;
142 xfs_log_item_desc_t
*lidp
;
145 libxfs_iput(ip
, lock_flags
);
149 ASSERT(ip
->i_transp
== tp
);
153 lidp
= xfs_trans_find_item(tp
, (xfs_log_item_t
*)iip
);
154 ASSERT(lidp
!= NULL
);
155 ASSERT(lidp
->lid_item
== (xfs_log_item_t
*)iip
);
156 ASSERT(!(lidp
->lid_flags
& XFS_LID_DIRTY
));
157 xfs_trans_free_item(tp
, lidp
);
159 libxfs_iput(ip
, lock_flags
);
168 xfs_inode_log_item_t
*iip
;
170 ASSERT(ip
->i_transp
== NULL
);
171 if (ip
->i_itemp
== NULL
)
172 xfs_inode_item_init(ip
, ip
->i_mount
);
174 ASSERT(iip
->ili_flags
== 0);
175 ASSERT(iip
->ili_inode
!= NULL
);
177 xfs_trans_add_item(tp
, (xfs_log_item_t
*)(iip
));
181 fprintf(stderr
, "ijoin'd inode %llu, transaction %p\n", ip
->i_ino
, tp
);
190 ASSERT(ip
->i_transp
== tp
);
191 ASSERT(ip
->i_itemp
!= NULL
);
193 ip
->i_itemp
->ili_flags
|= XFS_ILI_HOLD
;
195 fprintf(stderr
, "ihold'd inode %llu, transaction %p\n", ip
->i_ino
, tp
);
200 libxfs_trans_inode_alloc_buf(
204 xfs_buf_log_item_t
*bip
;
206 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
207 ASSERT(XFS_BUF_FSPRIVATE(bp
, void *) != NULL
);
208 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
209 bip
->bli_flags
|= XFS_BLI_INODE_ALLOC_BUF
;
213 * This is called to mark the fields indicated in fieldmask as needing
214 * to be logged when the transaction is committed. The inode must
215 * already be associated with the given transaction.
217 * The values for fieldmask are defined in xfs_inode_item.h. We always
218 * log all of the core inode if any of it has changed, and we always log
219 * all of the inline data/extents/b-tree root if any of them has changed.
227 xfs_log_item_desc_t
*lidp
;
229 ASSERT(ip
->i_transp
== tp
);
230 ASSERT(ip
->i_itemp
!= NULL
);
232 fprintf(stderr
, "dirtied inode %llu, transaction %p\n", ip
->i_ino
, tp
);
235 lidp
= xfs_trans_find_item(tp
, (xfs_log_item_t
*)(ip
->i_itemp
));
236 ASSERT(lidp
!= NULL
);
238 tp
->t_flags
|= XFS_TRANS_DIRTY
;
239 lidp
->lid_flags
|= XFS_LID_DIRTY
;
242 * Always OR in the bits from the ili_last_fields field.
243 * This is to coordinate with the xfs_iflush() and xfs_iflush_done()
244 * routines in the eventual clearing of the ilf_fields bits.
245 * See the big comment in xfs_iflush() for an explanation of
246 * this coordination mechanism.
248 flags
|= ip
->i_itemp
->ili_last_fields
;
249 ip
->i_itemp
->ili_format
.ilf_fields
|= flags
;
253 * This is called to mark bytes first through last inclusive of the given
254 * buffer as needing to be logged when the transaction is committed.
255 * The buffer must already be associated with the given transaction.
257 * First and last are numbers relative to the beginning of this buffer,
258 * so the first byte in the buffer is numbered 0 regardless of the
262 libxfs_trans_log_buf(
268 xfs_buf_log_item_t
*bip
;
269 xfs_log_item_desc_t
*lidp
;
271 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
272 ASSERT(XFS_BUF_FSPRIVATE(bp
, void *) != NULL
);
273 ASSERT((first
<= last
) && (last
< XFS_BUF_COUNT(bp
)));
275 fprintf(stderr
, "dirtied buffer %p, transaction %p\n", bp
, tp
);
278 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
280 lidp
= xfs_trans_find_item(tp
, (xfs_log_item_t
*)bip
);
281 ASSERT(lidp
!= NULL
);
283 tp
->t_flags
|= XFS_TRANS_DIRTY
;
284 lidp
->lid_flags
|= XFS_LID_DIRTY
;
285 xfs_buf_item_log(bip
, first
, last
);
293 xfs_buf_log_item_t
*bip
;
294 xfs_log_item_desc_t
*lidp
;
296 fprintf(stderr
, "released buffer %p, transaction %p\n", bp
, tp
);
300 ASSERT(XFS_BUF_FSPRIVATE2(bp
, void *) == NULL
);
304 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
305 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
306 ASSERT(bip
->bli_item
.li_type
== XFS_LI_BUF
);
307 lidp
= xfs_trans_find_item(tp
, (xfs_log_item_t
*)bip
);
308 ASSERT(lidp
!= NULL
);
309 if (bip
->bli_recur
> 0) {
313 /* If dirty, can't release till transaction committed */
314 if (lidp
->lid_flags
& XFS_LID_DIRTY
) {
317 xfs_trans_free_item(tp
, lidp
);
318 if (bip
->bli_flags
& XFS_BLI_HOLD
) {
319 bip
->bli_flags
&= ~XFS_BLI_HOLD
;
321 XFS_BUF_SET_FSPRIVATE2(bp
, NULL
);
330 xfs_log_item_desc_t
*lidp
;
331 xfs_buf_log_item_t
*bip
;
333 fprintf(stderr
, "binval'd buffer %p, transaction %p\n", bp
, tp
);
336 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
337 ASSERT(XFS_BUF_FSPRIVATE(bp
, void *) != NULL
);
339 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
340 lidp
= xfs_trans_find_item(tp
, (xfs_log_item_t
*)bip
);
341 ASSERT(lidp
!= NULL
);
342 bip
->bli_flags
&= ~(XFS_BLI_DIRTY
);
343 bip
->bli_format
.blf_flags
&= ~XFS_BLI_INODE_BUF
;
344 bip
->bli_format
.blf_flags
|= XFS_BLI_CANCEL
;
345 lidp
->lid_flags
|= XFS_LID_DIRTY
;
346 tp
->t_flags
|= XFS_TRANS_DIRTY
;
354 xfs_buf_log_item_t
*bip
;
356 ASSERT(XFS_BUF_FSPRIVATE2(bp
, void *) == NULL
);
358 fprintf(stderr
, "bjoin'd buffer %p, transaction %p\n", bp
, tp
);
361 xfs_buf_item_init(bp
, tp
->t_mountp
);
362 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
363 xfs_trans_add_item(tp
, (xfs_log_item_t
*)bip
);
364 XFS_BUF_SET_FSPRIVATE2(bp
, tp
);
372 xfs_buf_log_item_t
*bip
;
374 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
375 ASSERT(XFS_BUF_FSPRIVATE(bp
, void *) != NULL
);
377 fprintf(stderr
, "bhold'd buffer %p, transaction %p\n", bp
, tp
);
380 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
381 bip
->bli_flags
|= XFS_BLI_HOLD
;
385 libxfs_trans_get_buf(
393 xfs_buf_log_item_t
*bip
;
394 xfs_buftarg_t bdev
= { dev
};
397 return libxfs_getbuf(dev
, d
, len
);
399 if (tp
->t_items
.lic_next
== NULL
)
400 bp
= xfs_trans_buf_item_match(tp
, &bdev
, d
, len
);
402 bp
= xfs_trans_buf_item_match_all(tp
, &bdev
, d
, len
);
404 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
405 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
411 bp
= libxfs_getbuf(dev
, d
, len
);
415 fprintf(stderr
, "trans_get_buf buffer %p, transaction %p\n", bp
, tp
);
418 xfs_buf_item_init(bp
, tp
->t_mountp
);
419 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
421 xfs_trans_add_item(tp
, (xfs_log_item_t
*)bip
);
423 /* initialize b_fsprivate2 so we can find it incore */
424 XFS_BUF_SET_FSPRIVATE2(bp
, tp
);
429 libxfs_trans_read_buf(
439 xfs_buf_log_item_t
*bip
;
441 xfs_buftarg_t bdev
= { dev
};
444 bp
= libxfs_getbuf(mp
->m_dev
, blkno
, len
);
445 error
= libxfs_readbufr(dev
, blkno
, bp
, len
, 0);
450 if (tp
->t_items
.lic_next
== NULL
)
451 bp
= xfs_trans_buf_item_match(tp
, &bdev
, blkno
, len
);
453 bp
= xfs_trans_buf_item_match_all(tp
, &bdev
, blkno
, len
);
455 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
456 ASSERT(XFS_BUF_FSPRIVATE(bp
, void *) != NULL
);
457 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
463 bp
= libxfs_getbuf(mp
->m_dev
, blkno
, len
);
464 error
= libxfs_readbufr(dev
, blkno
, bp
, len
, 0);
470 fprintf(stderr
, "trans_read_buf buffer %p, transaction %p\n", bp
, tp
);
473 xfs_buf_item_init(bp
, tp
->t_mountp
);
474 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
476 xfs_trans_add_item(tp
, (xfs_log_item_t
*)bip
);
478 /* initialise b_fsprivate2 so we can find it incore */
479 XFS_BUF_SET_FSPRIVATE2(bp
, tp
);
485 * Record the indicated change to the given field for application
486 * to the file system's superblock when the transaction commits.
487 * For now, just store the change in the transaction structure.
488 * Mark the transaction structure to indicate that the superblock
489 * needs to be updated before committing.
491 * Originally derived from xfs_trans_mod_sb().
500 case XFS_TRANS_SB_RES_FDBLOCKS
:
502 case XFS_TRANS_SB_FDBLOCKS
:
503 tp
->t_fdblocks_delta
+= delta
;
505 case XFS_TRANS_SB_ICOUNT
:
507 tp
->t_icount_delta
+= delta
;
509 case XFS_TRANS_SB_IFREE
:
510 tp
->t_ifree_delta
+= delta
;
512 case XFS_TRANS_SB_FREXTENTS
:
513 tp
->t_frextents_delta
+= delta
;
519 tp
->t_flags
|= (XFS_TRANS_SB_DIRTY
| XFS_TRANS_DIRTY
);
524 * Transaction commital code follows (i.e. write to disk in libxfs)
529 xfs_inode_log_item_t
*iip
)
537 extern xfs_zone_t
*xfs_ili_zone
;
540 mp
= iip
->ili_item
.li_mountp
;
541 hold
= iip
->ili_flags
& XFS_ILI_HOLD
;
544 if (!(iip
->ili_format
.ilf_fields
& XFS_ILOG_ALL
)) {
545 ip
->i_transp
= NULL
; /* disassociate from transaction */
546 iip
->ili_flags
= 0; /* reset all flags */
553 * Get the buffer containing the on-disk inode.
555 error
= libxfs_itobp(mp
, NULL
, ip
, &dip
, &bp
, 0);
557 fprintf(stderr
, _("%s: warning - itobp failed (%d)\n"),
562 XFS_BUF_SET_FSPRIVATE(bp
, iip
);
563 error
= libxfs_iflush_int(ip
, bp
);
565 fprintf(stderr
, _("%s: warning - iflush_int failed (%d)\n"),
570 ip
->i_transp
= NULL
; /* disassociate from transaction */
571 XFS_BUF_SET_FSPRIVATE(bp
, NULL
); /* remove log item */
572 XFS_BUF_SET_FSPRIVATE2(bp
, NULL
); /* remove xact ptr */
573 libxfs_writebuf_int(bp
, 0);
575 fprintf(stderr
, "flushing dirty inode %llu, buffer %p (hold=%u)\n",
576 ip
->i_ino
, bp
, hold
);
579 iip
->ili_flags
&= ~XFS_ILI_HOLD
;
583 /*libxfs_iput(iip->ili_inode, 0); - nathans TODO? */
589 kmem_zone_free(xfs_ili_zone
, ip
->i_itemp
);
597 xfs_buf_log_item_t
*bip
)
601 extern xfs_zone_t
*xfs_buf_item_zone
;
605 XFS_BUF_SET_FSPRIVATE(bp
, NULL
); /* remove log item */
606 XFS_BUF_SET_FSPRIVATE2(bp
, NULL
); /* remove xact ptr */
608 hold
= (bip
->bli_flags
& XFS_BLI_HOLD
);
609 if (bip
->bli_flags
& XFS_BLI_DIRTY
) {
611 fprintf(stderr
, "flushing dirty buffer %p (hold=%d)\n",
614 libxfs_writebuf_int(bp
, 0);
616 bip
->bli_flags
&= ~XFS_BLI_HOLD
;
620 /* release the buf item */
621 kmem_zone_free(xfs_buf_item_zone
, bip
);
625 * This is called to perform the commit processing for each
626 * item described by the given chunk.
629 trans_chunk_committed(
630 xfs_log_item_chunk_t
*licp
)
632 xfs_log_item_desc_t
*lidp
;
636 lidp
= licp
->lic_descs
;
637 for (i
= 0; i
< licp
->lic_unused
; i
++, lidp
++) {
638 if (XFS_LIC_ISFREE(licp
, i
))
640 lip
= lidp
->lid_item
;
641 if (lip
->li_type
== XFS_LI_BUF
)
642 buf_item_done((xfs_buf_log_item_t
*)lidp
->lid_item
);
643 else if (lip
->li_type
== XFS_LI_INODE
)
644 inode_item_done((xfs_inode_log_item_t
*)lidp
->lid_item
);
646 fprintf(stderr
, _("%s: unrecognised log item type\n"),
654 * Calls trans_chunk_committed() to process the items in each chunk.
660 xfs_log_item_chunk_t
*licp
;
661 xfs_log_item_chunk_t
*next_licp
;
664 * Special case the chunk embedded in the transaction.
666 licp
= &(tp
->t_items
);
667 if (!(XFS_LIC_ARE_ALL_FREE(licp
))) {
668 trans_chunk_committed(licp
);
672 * Process the items in each chunk in turn.
674 licp
= licp
->lic_next
;
675 while (licp
!= NULL
) {
676 trans_chunk_committed(licp
);
677 next_licp
= licp
->lic_next
;
678 kmem_free(licp
, sizeof(xfs_log_item_chunk_t
));
684 * Unlock each item pointed to by a descriptor in the given chunk.
685 * Free descriptors pointing to items which are not dirty if freeing_chunk
686 * is zero. If freeing_chunk is non-zero, then we need to unlock all
687 * items in the chunk. Return the number of descriptors freed.
688 * Originally based on xfs_trans_unlock_chunk() - adapted for libxfs
689 * transactions though.
692 xfs_trans_unlock_chunk(
693 xfs_log_item_chunk_t
*licp
,
696 xfs_lsn_t commit_lsn
) /* nb: unused */
698 xfs_log_item_desc_t
*lidp
;
704 lidp
= licp
->lic_descs
;
705 for (i
= 0; i
< licp
->lic_unused
; i
++, lidp
++) {
706 if (XFS_LIC_ISFREE(licp
, i
)) {
709 lip
= lidp
->lid_item
;
713 * Disassociate the logged item from this transaction
715 if (lip
->li_type
== XFS_LI_BUF
) {
716 xfs_buf_log_item_t
*bip
;
718 bip
= (xfs_buf_log_item_t
*)lidp
->lid_item
;
719 XFS_BUF_SET_FSPRIVATE2(bip
->bli_buf
, NULL
);
720 bip
->bli_flags
&= ~XFS_BLI_HOLD
;
722 else if (lip
->li_type
== XFS_LI_INODE
) {
723 xfs_inode_log_item_t
*iip
;
725 iip
= (xfs_inode_log_item_t
*)lidp
->lid_item
;
726 iip
->ili_inode
->i_transp
= NULL
;
727 iip
->ili_flags
&= ~XFS_ILI_HOLD
;
730 fprintf(stderr
, _("%s: unrecognised log item type\n"),
736 * Free the descriptor if the item is not dirty
737 * within this transaction and the caller is not
738 * going to just free the entire thing regardless.
740 if (!(freeing_chunk
) &&
741 (!(lidp
->lid_flags
& XFS_LID_DIRTY
) || abort
)) {
742 XFS_LIC_RELSE(licp
, i
);
752 * Commit the changes represented by this transaction
758 xfs_lsn_t
*commit_lsn_p
)
765 if (!(tp
->t_flags
& XFS_TRANS_DIRTY
)) {
767 fprintf(stderr
, "committed clean transaction %p\n", tp
);
769 xfs_trans_free_items(tp
, flags
);
775 if (tp
->t_flags
& XFS_TRANS_SB_DIRTY
) {
776 sbp
= &(tp
->t_mountp
->m_sb
);
777 if (tp
->t_icount_delta
)
778 sbp
->sb_icount
+= tp
->t_icount_delta
;
779 if (tp
->t_ifree_delta
)
780 sbp
->sb_ifree
+= tp
->t_ifree_delta
;
781 if (tp
->t_fdblocks_delta
)
782 sbp
->sb_fdblocks
+= tp
->t_fdblocks_delta
;
783 if (tp
->t_frextents_delta
)
784 sbp
->sb_frextents
+= tp
->t_frextents_delta
;
785 libxfs_mod_sb(tp
, XFS_SB_ALL_BITS
);
789 fprintf(stderr
, "committing dirty transaction %p\n", tp
);
793 /* That's it for the transaction structure. Free it. */