2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
36 * Simple transaction interface
40 libxfs_trans_alloc(xfs_mount_t
*mp
, int type
)
44 if ((ptr
= calloc(sizeof(xfs_trans_t
), 1)) == NULL
) {
45 fprintf(stderr
, "%s: xact calloc failed (%d bytes): %s\n",
46 progname
, sizeof(xfs_trans_t
), strerror(errno
));
51 ptr
->t_items_free
= XFS_LIC_NUM_SLOTS
;
52 XFS_LIC_INIT(&(ptr
->t_items
));
54 fprintf(stderr
, "allocated new transaction %p\n", ptr
);
60 libxfs_trans_dup(xfs_trans_t
*tp
)
64 ptr
= libxfs_trans_alloc(tp
->t_mountp
, tp
->t_type
);
66 fprintf(stderr
, "duplicated transaction %p (new=%p)\n", tp
, ptr
);
72 libxfs_trans_reserve(xfs_trans_t
*tp
,
73 uint blocks
, uint logspace
, uint rtextents
, uint flags
, uint logcount
)
75 xfs_sb_t
*mpsb
= &tp
->t_mountp
->m_sb
;
78 * Attempt to reserve the needed disk blocks by decrementing
79 * the number needed from the number available. This will
80 * fail if the count would go below zero.
83 if (mpsb
->sb_fdblocks
< blocks
)
86 /* user space, don't need log/RT stuff (preserve the API though) */
91 libxfs_trans_cancel(xfs_trans_t
*tp
, int flags
)
94 xfs_trans_t
*otp
= tp
;
97 xfs_trans_free_items(tp
, flags
);
102 fprintf(stderr
, "## cancelled transaction %p\n", otp
);
107 libxfs_trans_iget(xfs_mount_t
*mp
, xfs_trans_t
*tp
, xfs_ino_t ino
,
108 uint lock_flags
, xfs_inode_t
**ipp
)
112 xfs_inode_log_item_t
*iip
;
115 return libxfs_iread(mp
, tp
, ino
, ipp
, 0);
117 error
= libxfs_iread(mp
, tp
, ino
, &ip
, 0);
122 if (ip
->i_itemp
== NULL
)
123 xfs_inode_item_init(ip
, mp
);
125 xfs_trans_add_item(tp
, (xfs_log_item_t
*)(iip
));
127 /* initialize i_transp so we can find it incore */
135 libxfs_trans_iput(xfs_trans_t
*tp
, xfs_inode_t
*ip
, uint lock_flags
)
137 xfs_inode_log_item_t
*iip
;
138 xfs_log_item_desc_t
*lidp
;
141 libxfs_iput(ip
, lock_flags
);
145 ASSERT(ip
->i_transp
== tp
);
149 lidp
= xfs_trans_find_item(tp
, (xfs_log_item_t
*)iip
);
150 ASSERT(lidp
!= NULL
);
151 ASSERT(lidp
->lid_item
== (xfs_log_item_t
*)iip
);
152 ASSERT(!(lidp
->lid_flags
& XFS_LID_DIRTY
));
153 xfs_trans_free_item(tp
, lidp
);
155 libxfs_iput(ip
, lock_flags
);
159 libxfs_trans_ijoin(xfs_trans_t
*tp
, xfs_inode_t
*ip
, uint lock_flags
)
161 xfs_inode_log_item_t
*iip
;
163 ASSERT(ip
->i_transp
== NULL
);
164 if (ip
->i_itemp
== NULL
)
165 xfs_inode_item_init(ip
, ip
->i_mount
);
167 ASSERT(iip
->ili_flags
== 0);
168 ASSERT(iip
->ili_inode
!= NULL
);
170 xfs_trans_add_item(tp
, (xfs_log_item_t
*)(iip
));
174 fprintf(stderr
, "ijoin'd inode %llu, transaction %p\n", ip
->i_ino
, tp
);
179 libxfs_trans_ihold(xfs_trans_t
*tp
, xfs_inode_t
*ip
)
181 ASSERT(ip
->i_transp
== tp
);
182 ASSERT(ip
->i_itemp
!= NULL
);
184 ip
->i_itemp
->ili_flags
|= XFS_ILI_HOLD
;
186 fprintf(stderr
, "ihold'd inode %llu, transaction %p\n", ip
->i_ino
, tp
);
191 libxfs_trans_inode_alloc_buf(xfs_trans_t
*tp
, xfs_buf_t
*bp
)
193 xfs_buf_log_item_t
*bip
;
195 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
196 ASSERT(XFS_BUF_FSPRIVATE(bp
, void *) != NULL
);
197 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
198 bip
->bli_flags
|= XFS_BLI_INODE_ALLOC_BUF
;
202 * This is called to mark the fields indicated in fieldmask as needing
203 * to be logged when the transaction is committed. The inode must
204 * already be associated with the given transaction.
206 * The values for fieldmask are defined in xfs_inode_item.h. We always
207 * log all of the core inode if any of it has changed, and we always log
208 * all of the inline data/extents/b-tree root if any of them has changed.
216 xfs_log_item_desc_t
*lidp
;
218 ASSERT(ip
->i_transp
== tp
);
219 ASSERT(ip
->i_itemp
!= NULL
);
221 fprintf(stderr
, "dirtied inode %llu, transaction %p\n", ip
->i_ino
, tp
);
224 lidp
= xfs_trans_find_item(tp
, (xfs_log_item_t
*)(ip
->i_itemp
));
225 ASSERT(lidp
!= NULL
);
227 tp
->t_flags
|= XFS_TRANS_DIRTY
;
228 lidp
->lid_flags
|= XFS_LID_DIRTY
;
231 * Always OR in the bits from the ili_last_fields field.
232 * This is to coordinate with the xfs_iflush() and xfs_iflush_done()
233 * routines in the eventual clearing of the ilf_fields bits.
234 * See the big comment in xfs_iflush() for an explanation of
235 * this coordination mechanism.
237 flags
|= ip
->i_itemp
->ili_last_fields
;
238 ip
->i_itemp
->ili_format
.ilf_fields
|= flags
;
242 * This is called to mark bytes first through last inclusive of the given
243 * buffer as needing to be logged when the transaction is committed.
244 * The buffer must already be associated with the given transaction.
246 * First and last are numbers relative to the beginning of this buffer,
247 * so the first byte in the buffer is numbered 0 regardless of the
251 libxfs_trans_log_buf(xfs_trans_t
*tp
, xfs_buf_t
*bp
, uint first
, uint last
)
253 xfs_buf_log_item_t
*bip
;
254 xfs_log_item_desc_t
*lidp
;
256 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
257 ASSERT(XFS_BUF_FSPRIVATE(bp
, void *) != NULL
);
258 ASSERT((first
<= last
) && (last
< XFS_BUF_COUNT(bp
)));
260 fprintf(stderr
, "dirtied buffer %p, transaction %p\n", bp
, tp
);
263 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
265 lidp
= xfs_trans_find_item(tp
, (xfs_log_item_t
*)bip
);
266 ASSERT(lidp
!= NULL
);
268 tp
->t_flags
|= XFS_TRANS_DIRTY
;
269 lidp
->lid_flags
|= XFS_LID_DIRTY
;
270 xfs_buf_item_log(bip
, first
, last
);
274 libxfs_trans_brelse(xfs_trans_t
*tp
, xfs_buf_t
*bp
)
276 xfs_buf_log_item_t
*bip
;
277 xfs_log_item_desc_t
*lidp
;
279 fprintf(stderr
, "released buffer %p, transaction %p\n", bp
, tp
);
283 ASSERT(XFS_BUF_FSPRIVATE2(bp
, void *) == NULL
);
287 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
288 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
289 ASSERT(bip
->bli_item
.li_type
== XFS_LI_BUF
);
290 lidp
= xfs_trans_find_item(tp
, (xfs_log_item_t
*)bip
);
291 ASSERT(lidp
!= NULL
);
292 if (bip
->bli_recur
> 0) {
296 /* If dirty, can't release till transaction committed */
297 if (lidp
->lid_flags
& XFS_LID_DIRTY
) {
300 xfs_trans_free_item(tp
, lidp
);
301 if (bip
->bli_flags
& XFS_BLI_HOLD
) {
302 bip
->bli_flags
&= ~XFS_BLI_HOLD
;
304 XFS_BUF_SET_FSPRIVATE2(bp
, NULL
);
309 libxfs_trans_binval(xfs_trans_t
*tp
, xfs_buf_t
*bp
)
311 xfs_log_item_desc_t
*lidp
;
312 xfs_buf_log_item_t
*bip
;
314 fprintf(stderr
, "binval'd buffer %p, transaction %p\n", bp
, tp
);
317 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
318 ASSERT(XFS_BUF_FSPRIVATE(bp
, void *) != NULL
);
320 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
321 lidp
= xfs_trans_find_item(tp
, (xfs_log_item_t
*)bip
);
322 ASSERT(lidp
!= NULL
);
323 bip
->bli_flags
&= ~(XFS_BLI_DIRTY
);
324 bip
->bli_format
.blf_flags
&= ~XFS_BLI_INODE_BUF
;
325 bip
->bli_format
.blf_flags
|= XFS_BLI_CANCEL
;
326 lidp
->lid_flags
|= XFS_LID_DIRTY
;
327 tp
->t_flags
|= XFS_TRANS_DIRTY
;
331 libxfs_trans_bjoin(xfs_trans_t
*tp
, xfs_buf_t
*bp
)
333 xfs_buf_log_item_t
*bip
;
335 ASSERT(XFS_BUF_FSPRIVATE2(bp
, void *) == NULL
);
337 fprintf(stderr
, "bjoin'd buffer %p, transaction %p\n", bp
, tp
);
340 xfs_buf_item_init(bp
, tp
->t_mountp
);
341 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
342 xfs_trans_add_item(tp
, (xfs_log_item_t
*)bip
);
343 XFS_BUF_SET_FSPRIVATE2(bp
, tp
);
347 libxfs_trans_bhold(xfs_trans_t
*tp
, xfs_buf_t
*bp
)
349 xfs_buf_log_item_t
*bip
;
351 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
352 ASSERT(XFS_BUF_FSPRIVATE(bp
, void *) != NULL
);
354 fprintf(stderr
, "bhold'd buffer %p, transaction %p\n", bp
, tp
);
357 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
358 bip
->bli_flags
|= XFS_BLI_HOLD
;
362 libxfs_trans_get_buf(xfs_trans_t
*tp
, dev_t dev
, xfs_daddr_t d
, int len
, uint f
)
365 xfs_buf_log_item_t
*bip
;
366 buftarg_t bdev
= { dev
};
369 return libxfs_getbuf(dev
, d
, len
);
371 if (tp
->t_items
.lic_next
== NULL
)
372 bp
= xfs_trans_buf_item_match(tp
, &bdev
, d
, len
);
374 bp
= xfs_trans_buf_item_match_all(tp
, &bdev
, d
, len
);
376 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
377 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
383 bp
= libxfs_getbuf(dev
, d
, len
);
387 fprintf(stderr
, "trans_get_buf buffer %p, transaction %p\n", bp
, tp
);
390 xfs_buf_item_init(bp
, tp
->t_mountp
);
391 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
393 xfs_trans_add_item(tp
, (xfs_log_item_t
*)bip
);
395 /* initialize b_fsprivate2 so we can find it incore */
396 XFS_BUF_SET_FSPRIVATE2(bp
, tp
);
401 libxfs_trans_read_buf(xfs_mount_t
*mp
, xfs_trans_t
*tp
, dev_t dev
,
402 xfs_daddr_t blkno
, int len
, uint f
, xfs_buf_t
**bpp
)
405 xfs_buf_log_item_t
*bip
;
407 buftarg_t bdev
= { dev
};
410 bp
= libxfs_getbuf(mp
->m_dev
, blkno
, len
);
411 error
= libxfs_readbufr(dev
, blkno
, bp
, len
, 0);
416 if (tp
->t_items
.lic_next
== NULL
)
417 bp
= xfs_trans_buf_item_match(tp
, &bdev
, blkno
, len
);
419 bp
= xfs_trans_buf_item_match_all(tp
, &bdev
, blkno
, len
);
421 ASSERT(XFS_BUF_FSPRIVATE2(bp
, xfs_trans_t
*) == tp
);
422 ASSERT(XFS_BUF_FSPRIVATE(bp
, void *) != NULL
);
423 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
429 bp
= libxfs_getbuf(mp
->m_dev
, blkno
, len
);
430 error
= libxfs_readbufr(dev
, blkno
, bp
, len
, 0);
436 fprintf(stderr
, "trans_read_buf buffer %p, transaction %p\n", bp
, tp
);
439 xfs_buf_item_init(bp
, tp
->t_mountp
);
440 bip
= XFS_BUF_FSPRIVATE(bp
, xfs_buf_log_item_t
*);
442 xfs_trans_add_item(tp
, (xfs_log_item_t
*)bip
);
444 /* initialise b_fsprivate2 so we can find it incore */
445 XFS_BUF_SET_FSPRIVATE2(bp
, tp
);
451 * Record the indicated change to the given field for application
452 * to the file system's superblock when the transaction commits.
453 * For now, just store the change in the transaction structure.
454 * Mark the transaction structure to indicate that the superblock
455 * needs to be updated before committing.
457 * Originally derived from xfs_trans_mod_sb().
460 libxfs_trans_mod_sb(xfs_trans_t
*tp
, uint field
, long delta
)
463 case XFS_TRANS_SB_RES_FDBLOCKS
:
465 case XFS_TRANS_SB_FDBLOCKS
:
466 tp
->t_fdblocks_delta
+= delta
;
468 case XFS_TRANS_SB_ICOUNT
:
470 tp
->t_icount_delta
+= delta
;
472 case XFS_TRANS_SB_IFREE
:
473 tp
->t_ifree_delta
+= delta
;
475 case XFS_TRANS_SB_FREXTENTS
:
476 tp
->t_frextents_delta
+= delta
;
482 tp
->t_flags
|= (XFS_TRANS_SB_DIRTY
| XFS_TRANS_DIRTY
);
487 * Transaction commital code follows (i.e. write to disk in libxfs)
491 inode_item_done(xfs_inode_log_item_t
*iip
)
499 extern xfs_zone_t
*xfs_ili_zone
;
502 mp
= iip
->ili_item
.li_mountp
;
503 hold
= iip
->ili_flags
& XFS_ILI_HOLD
;
506 if (!(iip
->ili_format
.ilf_fields
& XFS_ILOG_ALL
)) {
507 ip
->i_transp
= NULL
; /* disassociate from transaction */
508 iip
->ili_flags
= 0; /* reset all flags */
515 * Get the buffer containing the on-disk inode.
517 error
= libxfs_itobp(mp
, NULL
, ip
, &dip
, &bp
, 0);
519 fprintf(stderr
, "%s: warning - itobp failed (%d)\n",
524 XFS_BUF_SET_FSPRIVATE(bp
, iip
);
525 error
= libxfs_iflush_int(ip
, bp
);
527 fprintf(stderr
, "%s: warning - iflush_int failed (%d)\n",
532 ip
->i_transp
= NULL
; /* disassociate from transaction */
533 XFS_BUF_SET_FSPRIVATE(bp
, NULL
); /* remove log item */
534 XFS_BUF_SET_FSPRIVATE2(bp
, NULL
); /* remove xact ptr */
535 libxfs_writebuf_int(bp
, 0);
537 fprintf(stderr
, "flushing dirty inode %llu, buffer %p (hold=%u)\n",
538 ip
->i_ino
, bp
, hold
);
541 iip
->ili_flags
&= ~XFS_ILI_HOLD
;
545 /*libxfs_iput(iip->ili_inode, 0); - nathans TODO? */
551 kmem_zone_free(xfs_ili_zone
, ip
->i_itemp
);
558 buf_item_done(xfs_buf_log_item_t
*bip
)
560 extern xfs_zone_t
*xfs_buf_item_zone
;
566 XFS_BUF_SET_FSPRIVATE(bp
, NULL
); /* remove log item */
567 XFS_BUF_SET_FSPRIVATE2(bp
, NULL
); /* remove xact ptr */
569 hold
= (bip
->bli_flags
& XFS_BLI_HOLD
);
570 if (bip
->bli_flags
& XFS_BLI_DIRTY
) {
572 fprintf(stderr
, "flushing dirty buffer %p (hold=%d)\n",
575 libxfs_writebuf_int(bp
, 0);
577 bip
->bli_flags
&= ~XFS_BLI_HOLD
;
581 /* release the buf item */
582 kmem_zone_free(xfs_buf_item_zone
, bip
);
586 * This is called to perform the commit processing for each
587 * item described by the given chunk.
590 trans_chunk_committed(xfs_log_item_chunk_t
*licp
)
592 xfs_log_item_desc_t
*lidp
;
596 lidp
= licp
->lic_descs
;
597 for (i
= 0; i
< licp
->lic_unused
; i
++, lidp
++) {
598 if (XFS_LIC_ISFREE(licp
, i
))
600 lip
= lidp
->lid_item
;
601 if (lip
->li_type
== XFS_LI_BUF
)
602 buf_item_done((xfs_buf_log_item_t
*)lidp
->lid_item
);
603 else if (lip
->li_type
== XFS_LI_INODE
)
604 inode_item_done((xfs_inode_log_item_t
*)lidp
->lid_item
);
606 fprintf(stderr
, "%s: unrecognised log item type\n",
614 * Calls trans_chunk_committed() to process the items in each chunk.
617 trans_committed(xfs_trans_t
*tp
)
619 xfs_log_item_chunk_t
*licp
;
620 xfs_log_item_chunk_t
*next_licp
;
623 * Special case the chunk embedded in the transaction.
625 licp
= &(tp
->t_items
);
626 if (!(XFS_LIC_ARE_ALL_FREE(licp
))) {
627 trans_chunk_committed(licp
);
631 * Process the items in each chunk in turn.
633 licp
= licp
->lic_next
;
634 while (licp
!= NULL
) {
635 trans_chunk_committed(licp
);
636 next_licp
= licp
->lic_next
;
637 kmem_free(licp
, sizeof(xfs_log_item_chunk_t
));
643 * Unlock each item pointed to by a descriptor in the given chunk.
644 * Free descriptors pointing to items which are not dirty if freeing_chunk
645 * is zero. If freeing_chunk is non-zero, then we need to unlock all
646 * items in the chunk. Return the number of descriptors freed.
647 * Originally based on xfs_trans_unlock_chunk() - adapted for libxfs
648 * transactions though.
651 xfs_trans_unlock_chunk(
652 xfs_log_item_chunk_t
*licp
,
655 xfs_lsn_t commit_lsn
) /* nb: unused */
657 xfs_log_item_desc_t
*lidp
;
663 lidp
= licp
->lic_descs
;
664 for (i
= 0; i
< licp
->lic_unused
; i
++, lidp
++) {
665 if (XFS_LIC_ISFREE(licp
, i
)) {
668 lip
= lidp
->lid_item
;
672 * Disassociate the logged item from this transaction
674 if (lip
->li_type
== XFS_LI_BUF
) {
675 xfs_buf_log_item_t
*bip
;
677 bip
= (xfs_buf_log_item_t
*)lidp
->lid_item
;
678 XFS_BUF_SET_FSPRIVATE2(bip
->bli_buf
, NULL
);
679 bip
->bli_flags
&= ~XFS_BLI_HOLD
;
681 else if (lip
->li_type
== XFS_LI_INODE
) {
682 xfs_inode_log_item_t
*iip
;
684 iip
= (xfs_inode_log_item_t
*)lidp
->lid_item
;
685 iip
->ili_inode
->i_transp
= NULL
;
686 iip
->ili_flags
&= ~XFS_ILI_HOLD
;
689 fprintf(stderr
, "%s: unrecognised log item type\n",
695 * Free the descriptor if the item is not dirty
696 * within this transaction and the caller is not
697 * going to just free the entire thing regardless.
699 if (!(freeing_chunk
) &&
700 (!(lidp
->lid_flags
& XFS_LID_DIRTY
) || abort
)) {
701 XFS_LIC_RELSE(licp
, i
);
711 * Commit the changes represented by this transaction
714 libxfs_trans_commit(xfs_trans_t
*tp
, uint flags
, xfs_lsn_t
*commit_lsn_p
)
722 if (!(tp
->t_flags
& XFS_TRANS_DIRTY
)) {
724 fprintf(stderr
, "committed clean transaction %p\n", tp
);
726 xfs_trans_free_items(tp
, flags
);
732 if (tp
->t_flags
& XFS_TRANS_SB_DIRTY
) {
733 sbp
= &(tp
->t_mountp
->m_sb
);
734 if (tp
->t_icount_delta
)
735 sbp
->sb_icount
+= tp
->t_icount_delta
;
736 if (tp
->t_ifree_delta
)
737 sbp
->sb_ifree
+= tp
->t_ifree_delta
;
738 if (tp
->t_fdblocks_delta
)
739 sbp
->sb_fdblocks
+= tp
->t_fdblocks_delta
;
740 if (tp
->t_frextents_delta
)
741 sbp
->sb_frextents
+= tp
->t_frextents_delta
;
742 libxfs_mod_sb(tp
, XFS_SB_ALL_BITS
);
746 fprintf(stderr
, "committing dirty transaction %p\n", tp
);
750 /* That's it for the transaction structure. Free it. */