void libxfs_trans_cancel( xfs_trans_t *tp) { #ifdef XACT_DEBUG xfs_trans_t *otp = tp; #endif if (tp != NULL) { xfs_trans_free_items(tp); free(tp); tp = NULL; } #ifdef XACT_DEBUG fprintf(stderr, "## cancelled transaction %p\n", otp); #endif }
/* * Called from the trans_commit code when we notice that * the filesystem is in the middle of a forced shutdown. */ STATIC void xfs_trans_uncommit( xfs_trans_t *tp, uint flags) { xfs_log_item_desc_t *lidp; for (lidp = xfs_trans_first_item(tp); lidp != NULL; lidp = xfs_trans_next_item(tp, lidp)) { /* * Unpin all but those that aren't dirty. */ if (lidp->lid_flags & XFS_LID_DIRTY) IOP_UNPIN_REMOVE(lidp->lid_item, tp); } xfs_trans_unreserve_and_mod_sb(tp); XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(tp->t_mountp, tp); xfs_trans_free_items(tp, flags); xfs_trans_free_busy(tp); xfs_trans_free(tp); }
/*ARGSUSED*/ int _xfs_trans_commit( xfs_trans_t *tp, uint flags, xfs_lsn_t *commit_lsn_p, int *log_flushed) { 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]; void *commit_iclog; int shutdown; 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(mp, 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); } PFLAGS_RESTORE_FSTRANS(&tp->t_pflags); 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); if (commit_lsn_p) *commit_lsn_p = commit_lsn; 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(mp, tp); /* * Ask each log item how many log_vector entries it will * need so we can figure out how many to allocate. * Try to avoid the kmem_alloc() call in the common case * by using a vector from the stack when it fits. */ nvec = xfs_trans_count_vecs(tp); if (nvec == 0) { xfs_force_shutdown(mp, XFS_LOG_IO_ERROR); goto shut_us_down; } else if (nvec <= XFS_TRANS_LOGVEC_COUNT) { log_vector = log_vector_fast; } else { log_vector = (xfs_log_iovec_t *)kmem_alloc(nvec * sizeof(xfs_log_iovec_t), KM_SLEEP); } /* * Fill in the log_vector and pin the logged items, and * then write the transaction to the log. */ xfs_trans_fill_vecs(tp, log_vector); error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket, &(tp->t_lsn)); /* * The transaction is committed incore here, and can go out to disk * at any time after this call. However, all the items associated * with the transaction are still locked and pinned in memory. */ commit_lsn = xfs_log_done(mp, tp->t_ticket, &commit_iclog, log_flags); tp->t_commit_lsn = commit_lsn; if (nvec > XFS_TRANS_LOGVEC_COUNT) { kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t)); } if (commit_lsn_p) *commit_lsn_p = commit_lsn; /* * If we got a log write error. Unpin the logitems that we * had pinned, clean up, free trans structure, and return error. */ if (error || commit_lsn == -1) { PFLAGS_RESTORE_FSTRANS(&tp->t_pflags); xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT); return XFS_ERROR(EIO); } /* * Once the transaction has committed, unused * reservations need to be released and changes to * the superblock need to be reflected in the in-core * version. Do that now. */ xfs_trans_unreserve_and_mod_sb(tp); sync = tp->t_flags & XFS_TRANS_SYNC; /* * Tell the LM to call the transaction completion routine * when the log write with LSN commit_lsn completes (e.g. * when the transaction commit really hits the on-disk log). * After this call we cannot reference tp, because the call * can happen at any time and the call will free the transaction * structure pointed to by tp. The only case where we call * the completion routine (xfs_trans_committed) directly is * if the log is turned off on a debug kernel or we're * running in simulation mode (the log is explicitly turned * off). */ tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed; tp->t_logcb.cb_arg = tp; /* * We need to pass the iclog buffer which was used for the * transaction commit record into this function, and attach * the callback to it. The callback must be attached before * the items are unlocked to avoid racing with other threads * waiting for an item to unlock. */ shutdown = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb)); /* * Mark this thread as no longer being in a transaction */ PFLAGS_RESTORE_FSTRANS(&tp->t_pflags); /* * Once all the items of the transaction have been copied * to the in core log and the callback is attached, the * items can be unlocked. * * This will free descriptors pointing to items which were * not logged since there is nothing more to do with them. * For items which were logged, we will keep pointers to them * so they can be unpinned after the transaction commits to disk. * This will also stamp each modified meta-data item with * the commit lsn of this transaction for dependency tracking * purposes. */ xfs_trans_unlock_items(tp, commit_lsn); /* * If we detected a log error earlier, finish committing * the transaction now (unpin log items, etc). * * Order is critical here, to avoid using the transaction * pointer after its been freed (by xfs_trans_committed * either here now, or as a callback). We cannot do this * step inside xfs_log_notify as was done earlier because * of this issue. */ if (shutdown) xfs_trans_committed(tp, XFS_LI_ABORTED); /* * Now that the xfs_trans_committed callback has been attached, * and the items are released we can finally allow the iclog to * go to disk. */ error = xfs_log_release_iclog(mp, commit_iclog); /* * If the transaction needs to be synchronous, then force the * log out now and wait for it. */ if (sync) { if (!error) { error = _xfs_log_force(mp, commit_lsn, XFS_LOG_FORCE | XFS_LOG_SYNC, log_flushed); } XFS_STATS_INC(xs_trans_sync); } else { XFS_STATS_INC(xs_trans_async); } return (error); }
/* * Unlock all of the transaction's items and free the transaction. * The transaction must not have modified any of its items, because * there is no way to restore them to their previous state. * * If the transaction has made a log reservation, make sure to release * it as well. */ void xfs_trans_cancel( xfs_trans_t *tp, int flags) { int log_flags; #ifdef DEBUG xfs_log_item_chunk_t *licp; xfs_log_item_desc_t *lidp; xfs_log_item_t *lip; int i; #endif xfs_mount_t *mp = tp->t_mountp; /* * See if the caller is being too lazy to figure out if * the transaction really needs an abort. */ if ((flags & XFS_TRANS_ABORT) && !(tp->t_flags & XFS_TRANS_DIRTY)) flags &= ~XFS_TRANS_ABORT; /* * See if the caller is relying on us to shut down the * filesystem. This happens in paths where we detect * corruption and decide to give up. */ if ((tp->t_flags & XFS_TRANS_DIRTY) && !XFS_FORCED_SHUTDOWN(mp)) { XFS_ERROR_REPORT("xfs_trans_cancel", XFS_ERRLEVEL_LOW, mp); xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); } #ifdef DEBUG if (!(flags & XFS_TRANS_ABORT)) { licp = &(tp->t_items); while (licp != NULL) { lidp = licp->lic_descs; for (i = 0; i < licp->lic_unused; i++, lidp++) { if (XFS_LIC_ISFREE(licp, i)) { continue; } lip = lidp->lid_item; if (!XFS_FORCED_SHUTDOWN(mp)) ASSERT(!(lip->li_type == XFS_LI_EFD)); } licp = licp->lic_next; } } #endif xfs_trans_unreserve_and_mod_sb(tp); XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp); if (tp->t_ticket) { 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; } xfs_log_done(mp, tp->t_ticket, NULL, log_flags); } /* mark this thread as no longer being in a transaction */ PFLAGS_RESTORE_FSTRANS(&tp->t_pflags); xfs_trans_free_items(tp, flags); xfs_trans_free_busy(tp); xfs_trans_free(tp); }