xfs: split out iclog writing from xfs_trans_commit()
Split the the part of xfs_trans_commit() that deals with writing the transaction into the iclog into a separate function. This isolates the physical commit process from the logical commit operation and makes it easier to insert different transaction commit paths without affecting the existing algorithm adversely. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Родитель
713bf88bba
Коммит
0924378a68
|
@ -47,8 +47,6 @@
|
||||||
|
|
||||||
|
|
||||||
STATIC void xfs_trans_apply_sb_deltas(xfs_trans_t *);
|
STATIC void xfs_trans_apply_sb_deltas(xfs_trans_t *);
|
||||||
STATIC uint xfs_trans_count_vecs(xfs_trans_t *);
|
|
||||||
STATIC void xfs_trans_fill_vecs(xfs_trans_t *, xfs_log_iovec_t *);
|
|
||||||
STATIC void xfs_trans_uncommit(xfs_trans_t *, uint);
|
STATIC void xfs_trans_uncommit(xfs_trans_t *, uint);
|
||||||
STATIC void xfs_trans_committed(xfs_trans_t *, int);
|
STATIC void xfs_trans_committed(xfs_trans_t *, int);
|
||||||
STATIC void xfs_trans_chunk_committed(xfs_log_item_chunk_t *, xfs_lsn_t, int);
|
STATIC void xfs_trans_chunk_committed(xfs_log_item_chunk_t *, xfs_lsn_t, int);
|
||||||
|
@ -764,94 +762,126 @@ xfs_trans_unreserve_and_mod_sb(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xfs_trans_commit
|
* Total up the number of log iovecs needed to commit this
|
||||||
*
|
* transaction. The transaction itself needs one for the
|
||||||
* Commit the given transaction to the log a/synchronously.
|
* transaction header. Ask each dirty item in turn how many
|
||||||
*
|
* it needs to get the total.
|
||||||
* XFS disk error handling mechanism is not based on a typical
|
|
||||||
* transaction abort mechanism. Logically after the filesystem
|
|
||||||
* gets marked 'SHUTDOWN', we can't let any new transactions
|
|
||||||
* be durable - ie. committed to disk - because some metadata might
|
|
||||||
* be inconsistent. In such cases, this returns an error, and the
|
|
||||||
* caller may assume that all locked objects joined to the transaction
|
|
||||||
* have already been unlocked as if the commit had succeeded.
|
|
||||||
* Do not reference the transaction structure after this call.
|
|
||||||
*/
|
*/
|
||||||
/*ARGSUSED*/
|
static uint
|
||||||
int
|
xfs_trans_count_vecs(
|
||||||
_xfs_trans_commit(
|
xfs_trans_t *tp)
|
||||||
xfs_trans_t *tp,
|
{
|
||||||
uint flags,
|
int nvecs;
|
||||||
int *log_flushed)
|
xfs_log_item_desc_t *lidp;
|
||||||
|
|
||||||
|
nvecs = 1;
|
||||||
|
lidp = xfs_trans_first_item(tp);
|
||||||
|
ASSERT(lidp != NULL);
|
||||||
|
|
||||||
|
/* In the non-debug case we need to start bailing out if we
|
||||||
|
* didn't find a log_item here, return zero and let trans_commit
|
||||||
|
* deal with it.
|
||||||
|
*/
|
||||||
|
if (lidp == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (lidp != NULL) {
|
||||||
|
/*
|
||||||
|
* Skip items which aren't dirty in this transaction.
|
||||||
|
*/
|
||||||
|
if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
|
||||||
|
lidp = xfs_trans_next_item(tp, lidp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lidp->lid_size = IOP_SIZE(lidp->lid_item);
|
||||||
|
nvecs += lidp->lid_size;
|
||||||
|
lidp = xfs_trans_next_item(tp, lidp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nvecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill in the vector with pointers to data to be logged
|
||||||
|
* by this transaction. The transaction header takes
|
||||||
|
* the first vector, and then each dirty item takes the
|
||||||
|
* number of vectors it indicated it needed in xfs_trans_count_vecs().
|
||||||
|
*
|
||||||
|
* As each item fills in the entries it needs, also pin the item
|
||||||
|
* so that it cannot be flushed out until the log write completes.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
xfs_trans_fill_vecs(
|
||||||
|
struct xfs_trans *tp,
|
||||||
|
struct xfs_log_iovec *log_vector)
|
||||||
|
{
|
||||||
|
xfs_log_item_desc_t *lidp;
|
||||||
|
struct xfs_log_iovec *vecp;
|
||||||
|
uint nitems;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip over the entry for the transaction header, we'll
|
||||||
|
* fill that in at the end.
|
||||||
|
*/
|
||||||
|
vecp = log_vector + 1;
|
||||||
|
|
||||||
|
nitems = 0;
|
||||||
|
lidp = xfs_trans_first_item(tp);
|
||||||
|
ASSERT(lidp);
|
||||||
|
while (lidp) {
|
||||||
|
/* Skip items which aren't dirty in this transaction. */
|
||||||
|
if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
|
||||||
|
lidp = xfs_trans_next_item(tp, lidp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The item may be marked dirty but not log anything. This can
|
||||||
|
* be used to get called when a transaction is committed.
|
||||||
|
*/
|
||||||
|
if (lidp->lid_size)
|
||||||
|
nitems++;
|
||||||
|
IOP_FORMAT(lidp->lid_item, vecp);
|
||||||
|
vecp += lidp->lid_size;
|
||||||
|
IOP_PIN(lidp->lid_item);
|
||||||
|
lidp = xfs_trans_next_item(tp, lidp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that we've counted the number of items in this transaction, fill
|
||||||
|
* in the transaction header. Note that the transaction header does not
|
||||||
|
* have a log item.
|
||||||
|
*/
|
||||||
|
tp->t_header.th_magic = XFS_TRANS_HEADER_MAGIC;
|
||||||
|
tp->t_header.th_type = tp->t_type;
|
||||||
|
tp->t_header.th_num_items = nitems;
|
||||||
|
log_vector->i_addr = (xfs_caddr_t)&tp->t_header;
|
||||||
|
log_vector->i_len = sizeof(xfs_trans_header_t);
|
||||||
|
log_vector->i_type = XLOG_REG_TYPE_TRANSHDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format the transaction direct to the iclog. This isolates the physical
|
||||||
|
* transaction commit operation from the logical operation and hence allows
|
||||||
|
* other methods to be introduced without affecting the existing commit path.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xfs_trans_commit_iclog(
|
||||||
|
struct xfs_mount *mp,
|
||||||
|
struct xfs_trans *tp,
|
||||||
|
xfs_lsn_t *commit_lsn,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
xfs_log_iovec_t *log_vector;
|
|
||||||
int nvec;
|
|
||||||
xfs_mount_t *mp;
|
|
||||||
xfs_lsn_t commit_lsn;
|
|
||||||
/* REFERENCED */
|
|
||||||
int error;
|
|
||||||
int log_flags;
|
|
||||||
int sync;
|
|
||||||
#define XFS_TRANS_LOGVEC_COUNT 16
|
|
||||||
xfs_log_iovec_t log_vector_fast[XFS_TRANS_LOGVEC_COUNT];
|
|
||||||
struct xlog_in_core *commit_iclog;
|
|
||||||
int shutdown;
|
int shutdown;
|
||||||
|
int error;
|
||||||
|
int log_flags = 0;
|
||||||
|
struct xlog_in_core *commit_iclog;
|
||||||
|
#define XFS_TRANS_LOGVEC_COUNT 16
|
||||||
|
struct xfs_log_iovec log_vector_fast[XFS_TRANS_LOGVEC_COUNT];
|
||||||
|
struct xfs_log_iovec *log_vector;
|
||||||
|
uint nvec;
|
||||||
|
|
||||||
commit_lsn = -1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine whether this commit is releasing a permanent
|
|
||||||
* log reservation or not.
|
|
||||||
*/
|
|
||||||
if (flags & XFS_TRANS_RELEASE_LOG_RES) {
|
|
||||||
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
|
|
||||||
log_flags = XFS_LOG_REL_PERM_RESERV;
|
|
||||||
} else {
|
|
||||||
log_flags = 0;
|
|
||||||
}
|
|
||||||
mp = tp->t_mountp;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there is nothing to be logged by the transaction,
|
|
||||||
* then unlock all of the items associated with the
|
|
||||||
* transaction and free the transaction structure.
|
|
||||||
* Also make sure to return any reserved blocks to
|
|
||||||
* the free pool.
|
|
||||||
*/
|
|
||||||
shut_us_down:
|
|
||||||
shutdown = XFS_FORCED_SHUTDOWN(mp) ? EIO : 0;
|
|
||||||
if (!(tp->t_flags & XFS_TRANS_DIRTY) || shutdown) {
|
|
||||||
xfs_trans_unreserve_and_mod_sb(tp);
|
|
||||||
/*
|
|
||||||
* It is indeed possible for the transaction to be
|
|
||||||
* not dirty but the dqinfo portion to be. All that
|
|
||||||
* means is that we have some (non-persistent) quota
|
|
||||||
* reservations that need to be unreserved.
|
|
||||||
*/
|
|
||||||
xfs_trans_unreserve_and_mod_dquots(tp);
|
|
||||||
if (tp->t_ticket) {
|
|
||||||
commit_lsn = xfs_log_done(mp, tp->t_ticket,
|
|
||||||
NULL, log_flags);
|
|
||||||
if (commit_lsn == -1 && !shutdown)
|
|
||||||
shutdown = XFS_ERROR(EIO);
|
|
||||||
}
|
|
||||||
current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
|
|
||||||
xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0);
|
|
||||||
xfs_trans_free_busy(tp);
|
|
||||||
xfs_trans_free(tp);
|
|
||||||
XFS_STATS_INC(xs_trans_empty);
|
|
||||||
return (shutdown);
|
|
||||||
}
|
|
||||||
ASSERT(tp->t_ticket != NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we need to update the superblock, then do it now.
|
|
||||||
*/
|
|
||||||
if (tp->t_flags & XFS_TRANS_SB_DIRTY)
|
|
||||||
xfs_trans_apply_sb_deltas(tp);
|
|
||||||
xfs_trans_apply_dquot_deltas(tp);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ask each log item how many log_vector entries it will
|
* Ask each log item how many log_vector entries it will
|
||||||
|
@ -861,8 +891,7 @@ shut_us_down:
|
||||||
*/
|
*/
|
||||||
nvec = xfs_trans_count_vecs(tp);
|
nvec = xfs_trans_count_vecs(tp);
|
||||||
if (nvec == 0) {
|
if (nvec == 0) {
|
||||||
xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
|
return ENOMEM; /* triggers a shutdown! */
|
||||||
goto shut_us_down;
|
|
||||||
} else if (nvec <= XFS_TRANS_LOGVEC_COUNT) {
|
} else if (nvec <= XFS_TRANS_LOGVEC_COUNT) {
|
||||||
log_vector = log_vector_fast;
|
log_vector = log_vector_fast;
|
||||||
} else {
|
} else {
|
||||||
|
@ -877,6 +906,9 @@ shut_us_down:
|
||||||
*/
|
*/
|
||||||
xfs_trans_fill_vecs(tp, log_vector);
|
xfs_trans_fill_vecs(tp, log_vector);
|
||||||
|
|
||||||
|
if (flags & XFS_TRANS_RELEASE_LOG_RES)
|
||||||
|
log_flags = XFS_LOG_REL_PERM_RESERV;
|
||||||
|
|
||||||
error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket, &(tp->t_lsn));
|
error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket, &(tp->t_lsn));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -884,18 +916,17 @@ shut_us_down:
|
||||||
* at any time after this call. However, all the items associated
|
* at any time after this call. However, all the items associated
|
||||||
* with the transaction are still locked and pinned in memory.
|
* with the transaction are still locked and pinned in memory.
|
||||||
*/
|
*/
|
||||||
commit_lsn = xfs_log_done(mp, tp->t_ticket, &commit_iclog, log_flags);
|
*commit_lsn = xfs_log_done(mp, tp->t_ticket, &commit_iclog, log_flags);
|
||||||
|
|
||||||
tp->t_commit_lsn = commit_lsn;
|
tp->t_commit_lsn = *commit_lsn;
|
||||||
if (nvec > XFS_TRANS_LOGVEC_COUNT) {
|
if (nvec > XFS_TRANS_LOGVEC_COUNT)
|
||||||
kmem_free(log_vector);
|
kmem_free(log_vector);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we got a log write error. Unpin the logitems that we
|
* If we got a log write error. Unpin the logitems that we
|
||||||
* had pinned, clean up, free trans structure, and return error.
|
* had pinned, clean up, free trans structure, and return error.
|
||||||
*/
|
*/
|
||||||
if (error || commit_lsn == -1) {
|
if (error || *commit_lsn == -1) {
|
||||||
current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
|
current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
|
||||||
xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT);
|
xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT);
|
||||||
return XFS_ERROR(EIO);
|
return XFS_ERROR(EIO);
|
||||||
|
@ -909,8 +940,6 @@ shut_us_down:
|
||||||
*/
|
*/
|
||||||
xfs_trans_unreserve_and_mod_sb(tp);
|
xfs_trans_unreserve_and_mod_sb(tp);
|
||||||
|
|
||||||
sync = tp->t_flags & XFS_TRANS_SYNC;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell the LM to call the transaction completion routine
|
* Tell the LM to call the transaction completion routine
|
||||||
* when the log write with LSN commit_lsn completes (e.g.
|
* when the log write with LSN commit_lsn completes (e.g.
|
||||||
|
@ -953,7 +982,7 @@ shut_us_down:
|
||||||
* the commit lsn of this transaction for dependency tracking
|
* the commit lsn of this transaction for dependency tracking
|
||||||
* purposes.
|
* purposes.
|
||||||
*/
|
*/
|
||||||
xfs_trans_unlock_items(tp, commit_lsn);
|
xfs_trans_unlock_items(tp, *commit_lsn);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we detected a log error earlier, finish committing
|
* If we detected a log error earlier, finish committing
|
||||||
|
@ -973,7 +1002,92 @@ shut_us_down:
|
||||||
* and the items are released we can finally allow the iclog to
|
* and the items are released we can finally allow the iclog to
|
||||||
* go to disk.
|
* go to disk.
|
||||||
*/
|
*/
|
||||||
error = xfs_log_release_iclog(mp, commit_iclog);
|
return xfs_log_release_iclog(mp, commit_iclog);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* xfs_trans_commit
|
||||||
|
*
|
||||||
|
* Commit the given transaction to the log a/synchronously.
|
||||||
|
*
|
||||||
|
* XFS disk error handling mechanism is not based on a typical
|
||||||
|
* transaction abort mechanism. Logically after the filesystem
|
||||||
|
* gets marked 'SHUTDOWN', we can't let any new transactions
|
||||||
|
* be durable - ie. committed to disk - because some metadata might
|
||||||
|
* be inconsistent. In such cases, this returns an error, and the
|
||||||
|
* caller may assume that all locked objects joined to the transaction
|
||||||
|
* have already been unlocked as if the commit had succeeded.
|
||||||
|
* Do not reference the transaction structure after this call.
|
||||||
|
*/
|
||||||
|
/*ARGSUSED*/
|
||||||
|
int
|
||||||
|
_xfs_trans_commit(
|
||||||
|
xfs_trans_t *tp,
|
||||||
|
uint flags,
|
||||||
|
int *log_flushed)
|
||||||
|
{
|
||||||
|
xfs_mount_t *mp = tp->t_mountp;
|
||||||
|
xfs_lsn_t commit_lsn = -1;
|
||||||
|
int error;
|
||||||
|
int log_flags = 0;
|
||||||
|
int sync = tp->t_flags & XFS_TRANS_SYNC;
|
||||||
|
int shutdown;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine whether this commit is releasing a permanent
|
||||||
|
* log reservation or not.
|
||||||
|
*/
|
||||||
|
if (flags & XFS_TRANS_RELEASE_LOG_RES) {
|
||||||
|
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
|
||||||
|
log_flags = XFS_LOG_REL_PERM_RESERV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is nothing to be logged by the transaction,
|
||||||
|
* then unlock all of the items associated with the
|
||||||
|
* transaction and free the transaction structure.
|
||||||
|
* Also make sure to return any reserved blocks to
|
||||||
|
* the free pool.
|
||||||
|
*/
|
||||||
|
shut_us_down:
|
||||||
|
shutdown = XFS_FORCED_SHUTDOWN(mp) ? EIO : 0;
|
||||||
|
if (!(tp->t_flags & XFS_TRANS_DIRTY) || shutdown) {
|
||||||
|
xfs_trans_unreserve_and_mod_sb(tp);
|
||||||
|
/*
|
||||||
|
* It is indeed possible for the transaction to be
|
||||||
|
* not dirty but the dqinfo portion to be. All that
|
||||||
|
* means is that we have some (non-persistent) quota
|
||||||
|
* reservations that need to be unreserved.
|
||||||
|
*/
|
||||||
|
xfs_trans_unreserve_and_mod_dquots(tp);
|
||||||
|
if (tp->t_ticket) {
|
||||||
|
commit_lsn = xfs_log_done(mp, tp->t_ticket,
|
||||||
|
NULL, log_flags);
|
||||||
|
if (commit_lsn == -1 && !shutdown)
|
||||||
|
shutdown = XFS_ERROR(EIO);
|
||||||
|
}
|
||||||
|
current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
|
||||||
|
xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0);
|
||||||
|
xfs_trans_free_busy(tp);
|
||||||
|
xfs_trans_free(tp);
|
||||||
|
XFS_STATS_INC(xs_trans_empty);
|
||||||
|
return (shutdown);
|
||||||
|
}
|
||||||
|
ASSERT(tp->t_ticket != NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we need to update the superblock, then do it now.
|
||||||
|
*/
|
||||||
|
if (tp->t_flags & XFS_TRANS_SB_DIRTY)
|
||||||
|
xfs_trans_apply_sb_deltas(tp);
|
||||||
|
xfs_trans_apply_dquot_deltas(tp);
|
||||||
|
|
||||||
|
error = xfs_trans_commit_iclog(mp, tp, &commit_lsn, flags);
|
||||||
|
if (error == ENOMEM) {
|
||||||
|
xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
|
||||||
|
goto shut_us_down;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the transaction needs to be synchronous, then force the
|
* If the transaction needs to be synchronous, then force the
|
||||||
|
@ -992,47 +1106,6 @@ shut_us_down:
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Total up the number of log iovecs needed to commit this
|
|
||||||
* transaction. The transaction itself needs one for the
|
|
||||||
* transaction header. Ask each dirty item in turn how many
|
|
||||||
* it needs to get the total.
|
|
||||||
*/
|
|
||||||
STATIC uint
|
|
||||||
xfs_trans_count_vecs(
|
|
||||||
xfs_trans_t *tp)
|
|
||||||
{
|
|
||||||
int nvecs;
|
|
||||||
xfs_log_item_desc_t *lidp;
|
|
||||||
|
|
||||||
nvecs = 1;
|
|
||||||
lidp = xfs_trans_first_item(tp);
|
|
||||||
ASSERT(lidp != NULL);
|
|
||||||
|
|
||||||
/* In the non-debug case we need to start bailing out if we
|
|
||||||
* didn't find a log_item here, return zero and let trans_commit
|
|
||||||
* deal with it.
|
|
||||||
*/
|
|
||||||
if (lidp == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
while (lidp != NULL) {
|
|
||||||
/*
|
|
||||||
* Skip items which aren't dirty in this transaction.
|
|
||||||
*/
|
|
||||||
if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
|
|
||||||
lidp = xfs_trans_next_item(tp, lidp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
lidp->lid_size = IOP_SIZE(lidp->lid_item);
|
|
||||||
nvecs += lidp->lid_size;
|
|
||||||
lidp = xfs_trans_next_item(tp, lidp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nvecs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called from the trans_commit code when we notice that
|
* Called from the trans_commit code when we notice that
|
||||||
* the filesystem is in the middle of a forced shutdown.
|
* the filesystem is in the middle of a forced shutdown.
|
||||||
|
@ -1062,68 +1135,6 @@ xfs_trans_uncommit(
|
||||||
xfs_trans_free(tp);
|
xfs_trans_free(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Fill in the vector with pointers to data to be logged
|
|
||||||
* by this transaction. The transaction header takes
|
|
||||||
* the first vector, and then each dirty item takes the
|
|
||||||
* number of vectors it indicated it needed in xfs_trans_count_vecs().
|
|
||||||
*
|
|
||||||
* As each item fills in the entries it needs, also pin the item
|
|
||||||
* so that it cannot be flushed out until the log write completes.
|
|
||||||
*/
|
|
||||||
STATIC void
|
|
||||||
xfs_trans_fill_vecs(
|
|
||||||
xfs_trans_t *tp,
|
|
||||||
xfs_log_iovec_t *log_vector)
|
|
||||||
{
|
|
||||||
xfs_log_item_desc_t *lidp;
|
|
||||||
xfs_log_iovec_t *vecp;
|
|
||||||
uint nitems;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Skip over the entry for the transaction header, we'll
|
|
||||||
* fill that in at the end.
|
|
||||||
*/
|
|
||||||
vecp = log_vector + 1; /* pointer arithmetic */
|
|
||||||
|
|
||||||
nitems = 0;
|
|
||||||
lidp = xfs_trans_first_item(tp);
|
|
||||||
ASSERT(lidp != NULL);
|
|
||||||
while (lidp != NULL) {
|
|
||||||
/*
|
|
||||||
* Skip items which aren't dirty in this transaction.
|
|
||||||
*/
|
|
||||||
if (!(lidp->lid_flags & XFS_LID_DIRTY)) {
|
|
||||||
lidp = xfs_trans_next_item(tp, lidp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* The item may be marked dirty but not log anything.
|
|
||||||
* This can be used to get called when a transaction
|
|
||||||
* is committed.
|
|
||||||
*/
|
|
||||||
if (lidp->lid_size) {
|
|
||||||
nitems++;
|
|
||||||
}
|
|
||||||
IOP_FORMAT(lidp->lid_item, vecp);
|
|
||||||
vecp += lidp->lid_size; /* pointer arithmetic */
|
|
||||||
IOP_PIN(lidp->lid_item);
|
|
||||||
lidp = xfs_trans_next_item(tp, lidp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now that we've counted the number of items in this
|
|
||||||
* transaction, fill in the transaction header.
|
|
||||||
*/
|
|
||||||
tp->t_header.th_magic = XFS_TRANS_HEADER_MAGIC;
|
|
||||||
tp->t_header.th_type = tp->t_type;
|
|
||||||
tp->t_header.th_num_items = nitems;
|
|
||||||
log_vector->i_addr = (xfs_caddr_t)&tp->t_header;
|
|
||||||
log_vector->i_len = sizeof(xfs_trans_header_t);
|
|
||||||
log_vector->i_type = XLOG_REG_TYPE_TRANSHDR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unlock all of the transaction's items and free the transaction.
|
* Unlock all of the transaction's items and free the transaction.
|
||||||
* The transaction must not have modified any of its items, because
|
* The transaction must not have modified any of its items, because
|
||||||
|
|
Загрузка…
Ссылка в новой задаче