Merge branch 'xfs-efi-rework' into for-next

This commit is contained in:
Dave Chinner 2015-08-19 10:10:47 +10:00
commit 5be203ad11
21 changed files with 423 additions and 237 deletions

View File

@ -5945,6 +5945,7 @@ xfs_bmap_split_extent(
return xfs_trans_commit(tp); return xfs_trans_commit(tp);
out: out:
xfs_bmap_cancel(&free_list);
xfs_trans_cancel(tp); xfs_trans_cancel(tp);
return error; return error;
} }

View File

@ -2233,7 +2233,7 @@ xfs_imap_lookup(
} }
xfs_trans_brelse(tp, agbp); xfs_trans_brelse(tp, agbp);
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
if (error) if (error)
return error; return error;

View File

@ -67,16 +67,15 @@ xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
*/ */
int /* error */ int /* error */
xfs_bmap_finish( xfs_bmap_finish(
xfs_trans_t **tp, /* transaction pointer addr */ struct xfs_trans **tp, /* transaction pointer addr */
xfs_bmap_free_t *flist, /* i/o: list extents to free */ struct xfs_bmap_free *flist, /* i/o: list extents to free */
int *committed) /* xact committed or not */ int *committed)/* xact committed or not */
{ {
xfs_efd_log_item_t *efd; /* extent free data */ struct xfs_efd_log_item *efd; /* extent free data */
xfs_efi_log_item_t *efi; /* extent free intention */ struct xfs_efi_log_item *efi; /* extent free intention */
int error; /* error return value */ int error; /* error return value */
xfs_bmap_free_item_t *free; /* free extent item */ struct xfs_bmap_free_item *free; /* free extent item */
xfs_mount_t *mp; /* filesystem mount structure */ struct xfs_bmap_free_item *next; /* next item on free list */
xfs_bmap_free_item_t *next; /* next item on free list */
ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
if (flist->xbf_count == 0) { if (flist->xbf_count == 0) {
@ -88,40 +87,48 @@ xfs_bmap_finish(
xfs_trans_log_efi_extent(*tp, efi, free->xbfi_startblock, xfs_trans_log_efi_extent(*tp, efi, free->xbfi_startblock,
free->xbfi_blockcount); free->xbfi_blockcount);
error = xfs_trans_roll(tp, NULL); error = __xfs_trans_roll(tp, NULL, committed);
*committed = 1; if (error) {
/* /*
* We have a new transaction, so we should return committed=1, * If the transaction was committed, drop the EFD reference
* even though we're returning an error. * since we're bailing out of here. The other reference is
*/ * dropped when the EFI hits the AIL.
if (error) *
return error; * If the transaction was not committed, the EFI is freed by the
* EFI item unlock handler on abort. Also, we have a new
* transaction so we should return committed=1 even though we're
* returning an error.
*/
if (*committed) {
xfs_efi_release(efi);
xfs_force_shutdown((*tp)->t_mountp,
(error == -EFSCORRUPTED) ?
SHUTDOWN_CORRUPT_INCORE :
SHUTDOWN_META_IO_ERROR);
} else {
*committed = 1;
}
return error;
}
/*
* Get an EFD and free each extent in the list, logging to the EFD in
* the process. The remaining bmap free list is cleaned up by the caller
* on error.
*/
efd = xfs_trans_get_efd(*tp, efi, flist->xbf_count); efd = xfs_trans_get_efd(*tp, efi, flist->xbf_count);
for (free = flist->xbf_first; free != NULL; free = next) { for (free = flist->xbf_first; free != NULL; free = next) {
next = free->xbfi_next; next = free->xbfi_next;
if ((error = xfs_free_extent(*tp, free->xbfi_startblock,
free->xbfi_blockcount))) { error = xfs_trans_free_extent(*tp, efd, free->xbfi_startblock,
/* free->xbfi_blockcount);
* The bmap free list will be cleaned up at a if (error)
* higher level. The EFI will be canceled when
* this transaction is aborted.
* Need to force shutdown here to make sure it
* happens, since this transaction may not be
* dirty yet.
*/
mp = (*tp)->t_mountp;
if (!XFS_FORCED_SHUTDOWN(mp))
xfs_force_shutdown(mp,
(error == -EFSCORRUPTED) ?
SHUTDOWN_CORRUPT_INCORE :
SHUTDOWN_META_IO_ERROR);
return error; return error;
}
xfs_trans_log_efd_extent(*tp, efd, free->xbfi_startblock,
free->xbfi_blockcount);
xfs_bmap_del_free(flist, NULL, free); xfs_bmap_del_free(flist, NULL, free);
} }
return 0; return 0;
} }
@ -1467,7 +1474,7 @@ xfs_shift_file_space(
XFS_DIOSTRAT_SPACE_RES(mp, 0), 0, XFS_DIOSTRAT_SPACE_RES(mp, 0), 0,
XFS_QMOPT_RES_REGBLKS); XFS_QMOPT_RES_REGBLKS);
if (error) if (error)
goto out; goto out_trans_cancel;
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
@ -1481,18 +1488,20 @@ xfs_shift_file_space(
&done, stop_fsb, &first_block, &free_list, &done, stop_fsb, &first_block, &free_list,
direction, XFS_BMAP_MAX_SHIFT_EXTENTS); direction, XFS_BMAP_MAX_SHIFT_EXTENTS);
if (error) if (error)
goto out; goto out_bmap_cancel;
error = xfs_bmap_finish(&tp, &free_list, &committed); error = xfs_bmap_finish(&tp, &free_list, &committed);
if (error) if (error)
goto out; goto out_bmap_cancel;
error = xfs_trans_commit(tp); error = xfs_trans_commit(tp);
} }
return error; return error;
out: out_bmap_cancel:
xfs_bmap_cancel(&free_list);
out_trans_cancel:
xfs_trans_cancel(tp); xfs_trans_cancel(tp);
return error; return error;
} }

View File

@ -647,11 +647,7 @@ xfs_buf_item_unlock(
xfs_buf_item_relse(bp); xfs_buf_item_relse(bp);
else if (aborted) { else if (aborted) {
ASSERT(XFS_FORCED_SHUTDOWN(lip->li_mountp)); ASSERT(XFS_FORCED_SHUTDOWN(lip->li_mountp));
if (lip->li_flags & XFS_LI_IN_AIL) { xfs_trans_ail_remove(lip, SHUTDOWN_LOG_IO_ERROR);
spin_lock(&lip->li_ailp->xa_lock);
xfs_trans_ail_delete(lip->li_ailp, lip,
SHUTDOWN_LOG_IO_ERROR);
}
xfs_buf_item_relse(bp); xfs_buf_item_relse(bp);
} }
} }

View File

@ -954,12 +954,8 @@ xfs_qm_dqflush(
struct xfs_log_item *lip = &dqp->q_logitem.qli_item; struct xfs_log_item *lip = &dqp->q_logitem.qli_item;
dqp->dq_flags &= ~XFS_DQ_DIRTY; dqp->dq_flags &= ~XFS_DQ_DIRTY;
spin_lock(&mp->m_ail->xa_lock); xfs_trans_ail_remove(lip, SHUTDOWN_CORRUPT_INCORE);
if (lip->li_flags & XFS_LI_IN_AIL)
xfs_trans_ail_delete(mp->m_ail, lip,
SHUTDOWN_CORRUPT_INCORE);
else
spin_unlock(&mp->m_ail->xa_lock);
error = -EIO; error = -EIO;
goto out_unlock; goto out_unlock;
} }

View File

@ -46,28 +46,6 @@ xfs_efi_item_free(
kmem_zone_free(xfs_efi_zone, efip); kmem_zone_free(xfs_efi_zone, efip);
} }
/*
* Freeing the efi requires that we remove it from the AIL if it has already
* been placed there. However, the EFI may not yet have been placed in the AIL
* when called by xfs_efi_release() from EFD processing due to the ordering of
* committed vs unpin operations in bulk insert operations. Hence the reference
* count to ensure only the last caller frees the EFI.
*/
STATIC void
__xfs_efi_release(
struct xfs_efi_log_item *efip)
{
struct xfs_ail *ailp = efip->efi_item.li_ailp;
if (atomic_dec_and_test(&efip->efi_refcount)) {
spin_lock(&ailp->xa_lock);
/* xfs_trans_ail_delete() drops the AIL lock. */
xfs_trans_ail_delete(ailp, &efip->efi_item,
SHUTDOWN_LOG_IO_ERROR);
xfs_efi_item_free(efip);
}
}
/* /*
* This returns the number of iovecs needed to log the given efi item. * This returns the number of iovecs needed to log the given efi item.
* We only need 1 iovec for an efi item. It just logs the efi_log_format * We only need 1 iovec for an efi item. It just logs the efi_log_format
@ -128,12 +106,12 @@ xfs_efi_item_pin(
} }
/* /*
* While EFIs cannot really be pinned, the unpin operation is the last place at * The unpin operation is the last place an EFI is manipulated in the log. It is
* which the EFI is manipulated during a transaction. If we are being asked to * either inserted in the AIL or aborted in the event of a log I/O error. In
* remove the EFI it's because the transaction has been cancelled and by * either case, the EFI transaction has been successfully committed to make it
* definition that means the EFI cannot be in the AIL so remove it from the * this far. Therefore, we expect whoever committed the EFI to either construct
* transaction and free it. Otherwise coordinate with xfs_efi_release() * and commit the EFD or drop the EFD's reference in the event of error. Simply
* to determine who gets to free the EFI. * drop the log's EFI reference now that the log is done with it.
*/ */
STATIC void STATIC void
xfs_efi_item_unpin( xfs_efi_item_unpin(
@ -141,15 +119,7 @@ xfs_efi_item_unpin(
int remove) int remove)
{ {
struct xfs_efi_log_item *efip = EFI_ITEM(lip); struct xfs_efi_log_item *efip = EFI_ITEM(lip);
xfs_efi_release(efip);
if (remove) {
ASSERT(!(lip->li_flags & XFS_LI_IN_AIL));
if (lip->li_desc)
xfs_trans_del_item(lip);
xfs_efi_item_free(efip);
return;
}
__xfs_efi_release(efip);
} }
/* /*
@ -167,6 +137,11 @@ xfs_efi_item_push(
return XFS_ITEM_PINNED; return XFS_ITEM_PINNED;
} }
/*
* The EFI has been either committed or aborted if the transaction has been
* cancelled. If the transaction was cancelled, an EFD isn't going to be
* constructed and thus we free the EFI here directly.
*/
STATIC void STATIC void
xfs_efi_item_unlock( xfs_efi_item_unlock(
struct xfs_log_item *lip) struct xfs_log_item *lip)
@ -301,23 +276,19 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
} }
/* /*
* This is called by the efd item code below to release references to the given * Freeing the efi requires that we remove it from the AIL if it has already
* efi item. Each efd calls this with the number of extents that it has * been placed there. However, the EFI may not yet have been placed in the AIL
* logged, and when the sum of these reaches the total number of extents logged * when called by xfs_efi_release() from EFD processing due to the ordering of
* by this efi item we can free the efi item. * committed vs unpin operations in bulk insert operations. Hence the reference
* count to ensure only the last caller frees the EFI.
*/ */
void void
xfs_efi_release(xfs_efi_log_item_t *efip, xfs_efi_release(
uint nextents) struct xfs_efi_log_item *efip)
{ {
ASSERT(atomic_read(&efip->efi_next_extent) >= nextents); if (atomic_dec_and_test(&efip->efi_refcount)) {
if (atomic_sub_and_test(nextents, &efip->efi_next_extent)) { xfs_trans_ail_remove(&efip->efi_item, SHUTDOWN_LOG_IO_ERROR);
/* recovery needs us to drop the EFI reference, too */ xfs_efi_item_free(efip);
if (test_bit(XFS_EFI_RECOVERED, &efip->efi_flags))
__xfs_efi_release(efip);
__xfs_efi_release(efip);
/* efip may now have been freed, do not reference it again. */
} }
} }
@ -415,20 +386,27 @@ xfs_efd_item_push(
return XFS_ITEM_PINNED; return XFS_ITEM_PINNED;
} }
/*
* The EFD is either committed or aborted if the transaction is cancelled. If
* the transaction is cancelled, drop our reference to the EFI and free the EFD.
*/
STATIC void STATIC void
xfs_efd_item_unlock( xfs_efd_item_unlock(
struct xfs_log_item *lip) struct xfs_log_item *lip)
{ {
if (lip->li_flags & XFS_LI_ABORTED) struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
xfs_efd_item_free(EFD_ITEM(lip));
if (lip->li_flags & XFS_LI_ABORTED) {
xfs_efi_release(efdp->efd_efip);
xfs_efd_item_free(efdp);
}
} }
/* /*
* When the efd item is committed to disk, all we need to do * When the efd item is committed to disk, all we need to do is delete our
* is delete our reference to our partner efi item and then * reference to our partner efi item and then free ourselves. Since we're
* free ourselves. Since we're freeing ourselves we must * freeing ourselves we must return -1 to keep the transaction code from further
* return -1 to keep the transaction code from further referencing * referencing this item.
* this item.
*/ */
STATIC xfs_lsn_t STATIC xfs_lsn_t
xfs_efd_item_committed( xfs_efd_item_committed(
@ -438,13 +416,14 @@ xfs_efd_item_committed(
struct xfs_efd_log_item *efdp = EFD_ITEM(lip); struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
/* /*
* If we got a log I/O error, it's always the case that the LR with the * Drop the EFI reference regardless of whether the EFD has been
* EFI got unpinned and freed before the EFD got aborted. * aborted. Once the EFD transaction is constructed, it is the sole
* responsibility of the EFD to release the EFI (even if the EFI is
* aborted due to log I/O error).
*/ */
if (!(lip->li_flags & XFS_LI_ABORTED)) xfs_efi_release(efdp->efd_efip);
xfs_efi_release(efdp->efd_efip, efdp->efd_format.efd_nextents);
xfs_efd_item_free(efdp); xfs_efd_item_free(efdp);
return (xfs_lsn_t)-1; return (xfs_lsn_t)-1;
} }

View File

@ -39,9 +39,28 @@ struct kmem_zone;
* "extent free done" log item described below. * "extent free done" log item described below.
* *
* The EFI is reference counted so that it is not freed prior to both the EFI * The EFI is reference counted so that it is not freed prior to both the EFI
* and EFD being committed and unpinned. This ensures that when the last * and EFD being committed and unpinned. This ensures the EFI is inserted into
* reference goes away the EFI will always be in the AIL as it has been * the AIL even in the event of out of order EFI/EFD processing. In other words,
* unpinned, regardless of whether the EFD is processed before or after the EFI. * an EFI is born with two references:
*
* 1.) an EFI held reference to track EFI AIL insertion
* 2.) an EFD held reference to track EFD commit
*
* On allocation, both references are the responsibility of the caller. Once the
* EFI is added to and dirtied in a transaction, ownership of reference one
* transfers to the transaction. The reference is dropped once the EFI is
* inserted to the AIL or in the event of failure along the way (e.g., commit
* failure, log I/O error, etc.). Note that the caller remains responsible for
* the EFD reference under all circumstances to this point. The caller has no
* means to detect failure once the transaction is committed, however.
* Therefore, an EFD is required after this point, even in the event of
* unrelated failure.
*
* Once an EFD is allocated and dirtied in a transaction, reference two
* transfers to the transaction. The EFD reference is dropped once it reaches
* the unpin handler. Similar to the EFI, the reference also drops in the event
* of commit failure or log I/O errors. Note that the EFD is not inserted in the
* AIL, so at this point both the EFI and EFD are freed.
*/ */
typedef struct xfs_efi_log_item { typedef struct xfs_efi_log_item {
xfs_log_item_t efi_item; xfs_log_item_t efi_item;
@ -77,5 +96,6 @@ xfs_efd_log_item_t *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *,
int xfs_efi_copy_format(xfs_log_iovec_t *buf, int xfs_efi_copy_format(xfs_log_iovec_t *buf,
xfs_efi_log_format_t *dst_efi_fmt); xfs_efi_log_format_t *dst_efi_fmt);
void xfs_efi_item_free(xfs_efi_log_item_t *); void xfs_efi_item_free(xfs_efi_log_item_t *);
void xfs_efi_release(struct xfs_efi_log_item *);
#endif /* __XFS_EXTFREE_ITEM_H__ */ #endif /* __XFS_EXTFREE_ITEM_H__ */

View File

@ -1785,14 +1785,15 @@ xfs_inactive_ifree(
xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1); xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
/* /*
* Just ignore errors at this point. There is nothing we can * Just ignore errors at this point. There is nothing we can do except
* do except to try to keep going. Make sure it's not a silent * to try to keep going. Make sure it's not a silent error.
* error.
*/ */
error = xfs_bmap_finish(&tp, &free_list, &committed); error = xfs_bmap_finish(&tp, &free_list, &committed);
if (error) if (error) {
xfs_notice(mp, "%s: xfs_bmap_finish returned error %d", xfs_notice(mp, "%s: xfs_bmap_finish returned error %d",
__func__, error); __func__, error);
xfs_bmap_cancel(&free_list);
}
error = xfs_trans_commit(tp); error = xfs_trans_commit(tp);
if (error) if (error)
xfs_notice(mp, "%s: xfs_trans_commit returned error %d", xfs_notice(mp, "%s: xfs_trans_commit returned error %d",

View File

@ -703,17 +703,10 @@ xfs_iflush_abort(
xfs_inode_log_item_t *iip = ip->i_itemp; xfs_inode_log_item_t *iip = ip->i_itemp;
if (iip) { if (iip) {
struct xfs_ail *ailp = iip->ili_item.li_ailp;
if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { if (iip->ili_item.li_flags & XFS_LI_IN_AIL) {
spin_lock(&ailp->xa_lock); xfs_trans_ail_remove(&iip->ili_item,
if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { stale ? SHUTDOWN_LOG_IO_ERROR :
/* xfs_trans_ail_delete() drops the AIL lock. */
xfs_trans_ail_delete(ailp, &iip->ili_item,
stale ?
SHUTDOWN_LOG_IO_ERROR :
SHUTDOWN_CORRUPT_INCORE); SHUTDOWN_CORRUPT_INCORE);
} else
spin_unlock(&ailp->xa_lock);
} }
iip->ili_logged = 0; iip->ili_logged = 0;
/* /*

View File

@ -473,7 +473,8 @@ xfs_bulkstat(
* pending error, then we are done. * pending error, then we are done.
*/ */
del_cursor: del_cursor:
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(cur, error ?
XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
xfs_buf_relse(agbp); xfs_buf_relse(agbp);
if (error) if (error)
break; break;

View File

@ -700,6 +700,7 @@ xfs_log_mount(
if (error) { if (error) {
xfs_warn(mp, "log mount/recovery failed: error %d", xfs_warn(mp, "log mount/recovery failed: error %d",
error); error);
xlog_recover_cancel(mp->m_log);
goto out_destroy_ail; goto out_destroy_ail;
} }
} }
@ -740,18 +741,35 @@ out:
* it. * it.
*/ */
int int
xfs_log_mount_finish(xfs_mount_t *mp) xfs_log_mount_finish(
struct xfs_mount *mp)
{ {
int error = 0; int error = 0;
if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) { if (mp->m_flags & XFS_MOUNT_NORECOVERY) {
error = xlog_recover_finish(mp->m_log);
if (!error)
xfs_log_work_queue(mp);
} else {
ASSERT(mp->m_flags & XFS_MOUNT_RDONLY); ASSERT(mp->m_flags & XFS_MOUNT_RDONLY);
return 0;
} }
error = xlog_recover_finish(mp->m_log);
if (!error)
xfs_log_work_queue(mp);
return error;
}
/*
* The mount has failed. Cancel the recovery if it hasn't completed and destroy
* the log.
*/
int
xfs_log_mount_cancel(
struct xfs_mount *mp)
{
int error;
error = xlog_recover_cancel(mp->m_log);
xfs_log_unmount(mp);
return error; return error;
} }
@ -1654,8 +1672,13 @@ xlog_cksum(
if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) {
union xlog_in_core2 *xhdr = (union xlog_in_core2 *)rhead; union xlog_in_core2 *xhdr = (union xlog_in_core2 *)rhead;
int i; int i;
int xheads;
for (i = 1; i < log->l_iclog_heads; i++) { xheads = size / XLOG_HEADER_CYCLE_SIZE;
if (size % XLOG_HEADER_CYCLE_SIZE)
xheads++;
for (i = 1; i < xheads; i++) {
crc = crc32c(crc, &xhdr[i].hic_xheader, crc = crc32c(crc, &xhdr[i].hic_xheader,
sizeof(struct xlog_rec_ext_header)); sizeof(struct xlog_rec_ext_header));
} }

View File

@ -147,6 +147,7 @@ int xfs_log_mount(struct xfs_mount *mp,
xfs_daddr_t start_block, xfs_daddr_t start_block,
int num_bblocks); int num_bblocks);
int xfs_log_mount_finish(struct xfs_mount *mp); int xfs_log_mount_finish(struct xfs_mount *mp);
int xfs_log_mount_cancel(struct xfs_mount *);
xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp); xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp);
xfs_lsn_t xlog_assign_tail_lsn_locked(struct xfs_mount *mp); xfs_lsn_t xlog_assign_tail_lsn_locked(struct xfs_mount *mp);
void xfs_log_space_wake(struct xfs_mount *mp); void xfs_log_space_wake(struct xfs_mount *mp);

View File

@ -426,6 +426,8 @@ xlog_recover(
extern int extern int
xlog_recover_finish( xlog_recover_finish(
struct xlog *log); struct xlog *log);
extern int
xlog_recover_cancel(struct xlog *);
extern __le32 xlog_cksum(struct xlog *log, struct xlog_rec_header *rhead, extern __le32 xlog_cksum(struct xlog *log, struct xlog_rec_header *rhead,
char *dp, int size); char *dp, int size);

View File

@ -2933,16 +2933,16 @@ xlog_recover_efi_pass2(
struct xlog_recover_item *item, struct xlog_recover_item *item,
xfs_lsn_t lsn) xfs_lsn_t lsn)
{ {
int error; int error;
xfs_mount_t *mp = log->l_mp; struct xfs_mount *mp = log->l_mp;
xfs_efi_log_item_t *efip; struct xfs_efi_log_item *efip;
xfs_efi_log_format_t *efi_formatp; struct xfs_efi_log_format *efi_formatp;
efi_formatp = item->ri_buf[0].i_addr; efi_formatp = item->ri_buf[0].i_addr;
efip = xfs_efi_init(mp, efi_formatp->efi_nextents); efip = xfs_efi_init(mp, efi_formatp->efi_nextents);
if ((error = xfs_efi_copy_format(&(item->ri_buf[0]), error = xfs_efi_copy_format(&item->ri_buf[0], &efip->efi_format);
&(efip->efi_format)))) { if (error) {
xfs_efi_item_free(efip); xfs_efi_item_free(efip);
return error; return error;
} }
@ -2950,20 +2950,23 @@ xlog_recover_efi_pass2(
spin_lock(&log->l_ailp->xa_lock); spin_lock(&log->l_ailp->xa_lock);
/* /*
* xfs_trans_ail_update() drops the AIL lock. * The EFI has two references. One for the EFD and one for EFI to ensure
* it makes it into the AIL. Insert the EFI into the AIL directly and
* drop the EFI reference. Note that xfs_trans_ail_update() drops the
* AIL lock.
*/ */
xfs_trans_ail_update(log->l_ailp, &efip->efi_item, lsn); xfs_trans_ail_update(log->l_ailp, &efip->efi_item, lsn);
xfs_efi_release(efip);
return 0; return 0;
} }
/* /*
* This routine is called when an efd format structure is found in * This routine is called when an EFD format structure is found in a committed
* a committed transaction in the log. It's purpose is to cancel * transaction in the log. Its purpose is to cancel the corresponding EFI if it
* the corresponding efi if it was still in the log. To do this * was still in the log. To do this it searches the AIL for the EFI with an id
* it searches the AIL for the efi with an id equal to that in the * equal to that in the EFD format structure. If we find it we drop the EFD
* efd format structure. If we find it, we remove the efi from the * reference, which removes the EFI from the AIL and frees it.
* AIL and free it.
*/ */
STATIC int STATIC int
xlog_recover_efd_pass2( xlog_recover_efd_pass2(
@ -2985,8 +2988,8 @@ xlog_recover_efd_pass2(
efi_id = efd_formatp->efd_efi_id; efi_id = efd_formatp->efd_efi_id;
/* /*
* Search for the efi with the id in the efd format structure * Search for the EFI with the id in the EFD format structure in the
* in the AIL. * AIL.
*/ */
spin_lock(&ailp->xa_lock); spin_lock(&ailp->xa_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
@ -2995,18 +2998,18 @@ xlog_recover_efd_pass2(
efip = (xfs_efi_log_item_t *)lip; efip = (xfs_efi_log_item_t *)lip;
if (efip->efi_format.efi_id == efi_id) { if (efip->efi_format.efi_id == efi_id) {
/* /*
* xfs_trans_ail_delete() drops the * Drop the EFD reference to the EFI. This
* AIL lock. * removes the EFI from the AIL and frees it.
*/ */
xfs_trans_ail_delete(ailp, lip, spin_unlock(&ailp->xa_lock);
SHUTDOWN_CORRUPT_INCORE); xfs_efi_release(efip);
xfs_efi_item_free(efip);
spin_lock(&ailp->xa_lock); spin_lock(&ailp->xa_lock);
break; break;
} }
} }
lip = xfs_trans_ail_cursor_next(ailp, &cur); lip = xfs_trans_ail_cursor_next(ailp, &cur);
} }
xfs_trans_ail_cursor_done(&cur); xfs_trans_ail_cursor_done(&cur);
spin_unlock(&ailp->xa_lock); spin_unlock(&ailp->xa_lock);
@ -3034,6 +3037,11 @@ xlog_recover_do_icreate_pass2(
unsigned int count; unsigned int count;
unsigned int isize; unsigned int isize;
xfs_agblock_t length; xfs_agblock_t length;
int blks_per_cluster;
int bb_per_cluster;
int cancel_count;
int nbufs;
int i;
icl = (struct xfs_icreate_log *)item->ri_buf[0].i_addr; icl = (struct xfs_icreate_log *)item->ri_buf[0].i_addr;
if (icl->icl_type != XFS_LI_ICREATE) { if (icl->icl_type != XFS_LI_ICREATE) {
@ -3092,22 +3100,45 @@ xlog_recover_do_icreate_pass2(
} }
/* /*
* Inode buffers can be freed. Do not replay the inode initialisation as * The icreate transaction can cover multiple cluster buffers and these
* we could be overwriting something written after this inode buffer was * buffers could have been freed and reused. Check the individual
* cancelled. * buffers for cancellation so we don't overwrite anything written after
* * a cancellation.
* XXX: we need to iterate all buffers and only init those that are not
* cancelled. I think that a more fine grained factoring of
* xfs_ialloc_inode_init may be appropriate here to enable this to be
* done easily.
*/ */
if (xlog_check_buffer_cancelled(log, blks_per_cluster = xfs_icluster_size_fsb(mp);
XFS_AGB_TO_DADDR(mp, agno, agbno), length, 0)) bb_per_cluster = XFS_FSB_TO_BB(mp, blks_per_cluster);
return 0; nbufs = length / blks_per_cluster;
for (i = 0, cancel_count = 0; i < nbufs; i++) {
xfs_daddr_t daddr;
xfs_ialloc_inode_init(mp, NULL, buffer_list, count, agno, agbno, length, daddr = XFS_AGB_TO_DADDR(mp, agno,
be32_to_cpu(icl->icl_gen)); agbno + i * blks_per_cluster);
return 0; if (xlog_check_buffer_cancelled(log, daddr, bb_per_cluster, 0))
cancel_count++;
}
/*
* We currently only use icreate for a single allocation at a time. This
* means we should expect either all or none of the buffers to be
* cancelled. Be conservative and skip replay if at least one buffer is
* cancelled, but warn the user that something is awry if the buffers
* are not consistent.
*
* XXX: This must be refined to only skip cancelled clusters once we use
* icreate for multiple chunk allocations.
*/
ASSERT(!cancel_count || cancel_count == nbufs);
if (cancel_count) {
if (cancel_count != nbufs)
xfs_warn(mp,
"WARNING: partial inode chunk cancellation, skipped icreate.");
trace_xfs_log_recover_icreate_cancel(log, icl);
return 0;
}
trace_xfs_log_recover_icreate_recover(log, icl);
return xfs_ialloc_inode_init(mp, NULL, buffer_list, count, agno, agbno,
length, be32_to_cpu(icl->icl_gen));
} }
STATIC void STATIC void
@ -3766,7 +3797,7 @@ xlog_recover_process_efi(
* free the memory associated with it. * free the memory associated with it.
*/ */
set_bit(XFS_EFI_RECOVERED, &efip->efi_flags); set_bit(XFS_EFI_RECOVERED, &efip->efi_flags);
xfs_efi_release(efip, efip->efi_format.efi_nextents); xfs_efi_release(efip);
return -EIO; return -EIO;
} }
} }
@ -3779,11 +3810,11 @@ xlog_recover_process_efi(
for (i = 0; i < efip->efi_format.efi_nextents; i++) { for (i = 0; i < efip->efi_format.efi_nextents; i++) {
extp = &(efip->efi_format.efi_extents[i]); extp = &(efip->efi_format.efi_extents[i]);
error = xfs_free_extent(tp, extp->ext_start, extp->ext_len); error = xfs_trans_free_extent(tp, efdp, extp->ext_start,
extp->ext_len);
if (error) if (error)
goto abort_error; goto abort_error;
xfs_trans_log_efd_extent(tp, efdp, extp->ext_start,
extp->ext_len);
} }
set_bit(XFS_EFI_RECOVERED, &efip->efi_flags); set_bit(XFS_EFI_RECOVERED, &efip->efi_flags);
@ -3815,10 +3846,10 @@ abort_error:
*/ */
STATIC int STATIC int
xlog_recover_process_efis( xlog_recover_process_efis(
struct xlog *log) struct xlog *log)
{ {
xfs_log_item_t *lip; struct xfs_log_item *lip;
xfs_efi_log_item_t *efip; struct xfs_efi_log_item *efip;
int error = 0; int error = 0;
struct xfs_ail_cursor cur; struct xfs_ail_cursor cur;
struct xfs_ail *ailp; struct xfs_ail *ailp;
@ -3842,7 +3873,7 @@ xlog_recover_process_efis(
/* /*
* Skip EFIs that we've already processed. * Skip EFIs that we've already processed.
*/ */
efip = (xfs_efi_log_item_t *)lip; efip = container_of(lip, struct xfs_efi_log_item, efi_item);
if (test_bit(XFS_EFI_RECOVERED, &efip->efi_flags)) { if (test_bit(XFS_EFI_RECOVERED, &efip->efi_flags)) {
lip = xfs_trans_ail_cursor_next(ailp, &cur); lip = xfs_trans_ail_cursor_next(ailp, &cur);
continue; continue;
@ -3861,6 +3892,50 @@ out:
return error; return error;
} }
/*
* A cancel occurs when the mount has failed and we're bailing out. Release all
* pending EFIs so they don't pin the AIL.
*/
STATIC int
xlog_recover_cancel_efis(
struct xlog *log)
{
struct xfs_log_item *lip;
struct xfs_efi_log_item *efip;
int error = 0;
struct xfs_ail_cursor cur;
struct xfs_ail *ailp;
ailp = log->l_ailp;
spin_lock(&ailp->xa_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
while (lip != NULL) {
/*
* We're done when we see something other than an EFI.
* There should be no EFIs left in the AIL now.
*/
if (lip->li_type != XFS_LI_EFI) {
#ifdef DEBUG
for (; lip; lip = xfs_trans_ail_cursor_next(ailp, &cur))
ASSERT(lip->li_type != XFS_LI_EFI);
#endif
break;
}
efip = container_of(lip, struct xfs_efi_log_item, efi_item);
spin_unlock(&ailp->xa_lock);
xfs_efi_release(efip);
spin_lock(&ailp->xa_lock);
lip = xfs_trans_ail_cursor_next(ailp, &cur);
}
xfs_trans_ail_cursor_done(&cur);
spin_unlock(&ailp->xa_lock);
return error;
}
/* /*
* This routine performs a transaction to null out a bad inode pointer * This routine performs a transaction to null out a bad inode pointer
* in an agi unlinked inode hash bucket. * in an agi unlinked inode hash bucket.
@ -4636,6 +4711,17 @@ xlog_recover_finish(
return 0; return 0;
} }
int
xlog_recover_cancel(
struct xlog *log)
{
int error = 0;
if (log->l_flags & XLOG_RECOVERY_NEEDED)
error = xlog_recover_cancel_efis(log);
return error;
}
#if defined(DEBUG) #if defined(DEBUG)
/* /*

View File

@ -615,14 +615,14 @@ xfs_default_resblks(xfs_mount_t *mp)
*/ */
int int
xfs_mountfs( xfs_mountfs(
xfs_mount_t *mp) struct xfs_mount *mp)
{ {
xfs_sb_t *sbp = &(mp->m_sb); struct xfs_sb *sbp = &(mp->m_sb);
xfs_inode_t *rip; struct xfs_inode *rip;
__uint64_t resblks; __uint64_t resblks;
uint quotamount = 0; uint quotamount = 0;
uint quotaflags = 0; uint quotaflags = 0;
int error = 0; int error = 0;
xfs_sb_mount_common(mp, sbp); xfs_sb_mount_common(mp, sbp);
@ -799,7 +799,9 @@ xfs_mountfs(
} }
/* /*
* log's mount-time initialization. Perform 1st part recovery if needed * Log's mount-time initialization. The first part of recovery can place
* some items on the AIL, to be handled when recovery is finished or
* cancelled.
*/ */
error = xfs_log_mount(mp, mp->m_logdev_targp, error = xfs_log_mount(mp, mp->m_logdev_targp,
XFS_FSB_TO_DADDR(mp, sbp->sb_logstart), XFS_FSB_TO_DADDR(mp, sbp->sb_logstart),
@ -910,9 +912,9 @@ xfs_mountfs(
} }
/* /*
* Finish recovering the file system. This part needed to be * Finish recovering the file system. This part needed to be delayed
* delayed until after the root and real-time bitmap inodes * until after the root and real-time bitmap inodes were consistently
* were consistently read in. * read in.
*/ */
error = xfs_log_mount_finish(mp); error = xfs_log_mount_finish(mp);
if (error) { if (error) {
@ -955,8 +957,10 @@ xfs_mountfs(
xfs_rtunmount_inodes(mp); xfs_rtunmount_inodes(mp);
out_rele_rip: out_rele_rip:
IRELE(rip); IRELE(rip);
cancel_delayed_work_sync(&mp->m_reclaim_work);
xfs_reclaim_inodes(mp, SYNC_WAIT);
out_log_dealloc: out_log_dealloc:
xfs_log_unmount(mp); xfs_log_mount_cancel(mp);
out_fail_wait: out_fail_wait:
if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
xfs_wait_buftarg(mp->m_logdev_targp); xfs_wait_buftarg(mp->m_logdev_targp);

View File

@ -757,31 +757,30 @@ xfs_rtallocate_extent_size(
/* /*
* Allocate space to the bitmap or summary file, and zero it, for growfs. * Allocate space to the bitmap or summary file, and zero it, for growfs.
*/ */
STATIC int /* error */ STATIC int
xfs_growfs_rt_alloc( xfs_growfs_rt_alloc(
xfs_mount_t *mp, /* file system mount point */ struct xfs_mount *mp, /* file system mount point */
xfs_extlen_t oblocks, /* old count of blocks */ xfs_extlen_t oblocks, /* old count of blocks */
xfs_extlen_t nblocks, /* new count of blocks */ xfs_extlen_t nblocks, /* new count of blocks */
xfs_inode_t *ip) /* inode (bitmap/summary) */ struct xfs_inode *ip) /* inode (bitmap/summary) */
{ {
xfs_fileoff_t bno; /* block number in file */ xfs_fileoff_t bno; /* block number in file */
xfs_buf_t *bp; /* temporary buffer for zeroing */ struct xfs_buf *bp; /* temporary buffer for zeroing */
int committed; /* transaction committed flag */ int committed; /* transaction committed flag */
xfs_daddr_t d; /* disk block address */ xfs_daddr_t d; /* disk block address */
int error; /* error return value */ int error; /* error return value */
xfs_fsblock_t firstblock; /* first block allocated in xaction */ xfs_fsblock_t firstblock;/* first block allocated in xaction */
xfs_bmap_free_t flist; /* list of freed blocks */ struct xfs_bmap_free flist; /* list of freed blocks */
xfs_fsblock_t fsbno; /* filesystem block for bno */ xfs_fsblock_t fsbno; /* filesystem block for bno */
xfs_bmbt_irec_t map; /* block map output */ struct xfs_bmbt_irec map; /* block map output */
int nmap; /* number of block maps */ int nmap; /* number of block maps */
int resblks; /* space reservation */ int resblks; /* space reservation */
struct xfs_trans *tp;
/* /*
* Allocate space to the file, as necessary. * Allocate space to the file, as necessary.
*/ */
while (oblocks < nblocks) { while (oblocks < nblocks) {
xfs_trans_t *tp;
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ALLOC); tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ALLOC);
resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks); resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks);
/* /*
@ -790,7 +789,7 @@ xfs_growfs_rt_alloc(
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growrtalloc, error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growrtalloc,
resblks, 0); resblks, 0);
if (error) if (error)
goto error_cancel; goto out_trans_cancel;
/* /*
* Lock the inode. * Lock the inode.
*/ */
@ -808,16 +807,16 @@ xfs_growfs_rt_alloc(
if (!error && nmap < 1) if (!error && nmap < 1)
error = -ENOSPC; error = -ENOSPC;
if (error) if (error)
goto error_cancel; goto out_bmap_cancel;
/* /*
* Free any blocks freed up in the transaction, then commit. * Free any blocks freed up in the transaction, then commit.
*/ */
error = xfs_bmap_finish(&tp, &flist, &committed); error = xfs_bmap_finish(&tp, &flist, &committed);
if (error) if (error)
goto error_cancel; goto out_bmap_cancel;
error = xfs_trans_commit(tp); error = xfs_trans_commit(tp);
if (error) if (error)
goto error; return error;
/* /*
* Now we need to clear the allocated blocks. * Now we need to clear the allocated blocks.
* Do this one block per transaction, to keep it simple. * Do this one block per transaction, to keep it simple.
@ -832,7 +831,7 @@ xfs_growfs_rt_alloc(
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growrtzero, error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growrtzero,
0, 0); 0, 0);
if (error) if (error)
goto error_cancel; goto out_trans_cancel;
/* /*
* Lock the bitmap inode. * Lock the bitmap inode.
*/ */
@ -846,9 +845,7 @@ xfs_growfs_rt_alloc(
mp->m_bsize, 0); mp->m_bsize, 0);
if (bp == NULL) { if (bp == NULL) {
error = -EIO; error = -EIO;
error_cancel: goto out_trans_cancel;
xfs_trans_cancel(tp);
goto error;
} }
memset(bp->b_addr, 0, mp->m_sb.sb_blocksize); memset(bp->b_addr, 0, mp->m_sb.sb_blocksize);
xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1); xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
@ -857,16 +854,20 @@ error_cancel:
*/ */
error = xfs_trans_commit(tp); error = xfs_trans_commit(tp);
if (error) if (error)
goto error; return error;
} }
/* /*
* Go on to the next extent, if any. * Go on to the next extent, if any.
*/ */
oblocks = map.br_startoff + map.br_blockcount; oblocks = map.br_startoff + map.br_blockcount;
} }
return 0; return 0;
error: out_bmap_cancel:
xfs_bmap_cancel(&flist);
out_trans_cancel:
xfs_trans_cancel(tp);
return error; return error;
} }

View File

@ -2089,6 +2089,40 @@ DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_recover);
DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_cancel); DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_cancel);
DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_skip); DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_skip);
DECLARE_EVENT_CLASS(xfs_log_recover_icreate_item_class,
TP_PROTO(struct xlog *log, struct xfs_icreate_log *in_f),
TP_ARGS(log, in_f),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_agnumber_t, agno)
__field(xfs_agblock_t, agbno)
__field(unsigned int, count)
__field(unsigned int, isize)
__field(xfs_agblock_t, length)
__field(unsigned int, gen)
),
TP_fast_assign(
__entry->dev = log->l_mp->m_super->s_dev;
__entry->agno = be32_to_cpu(in_f->icl_ag);
__entry->agbno = be32_to_cpu(in_f->icl_agbno);
__entry->count = be32_to_cpu(in_f->icl_count);
__entry->isize = be32_to_cpu(in_f->icl_isize);
__entry->length = be32_to_cpu(in_f->icl_length);
__entry->gen = be32_to_cpu(in_f->icl_gen);
),
TP_printk("dev %d:%d agno %u agbno %u count %u isize %u length %u "
"gen %u", MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->agno, __entry->agbno, __entry->count, __entry->isize,
__entry->length, __entry->gen)
)
#define DEFINE_LOG_RECOVER_ICREATE_ITEM(name) \
DEFINE_EVENT(xfs_log_recover_icreate_item_class, name, \
TP_PROTO(struct xlog *log, struct xfs_icreate_log *in_f), \
TP_ARGS(log, in_f))
DEFINE_LOG_RECOVER_ICREATE_ITEM(xfs_log_recover_icreate_cancel);
DEFINE_LOG_RECOVER_ICREATE_ITEM(xfs_log_recover_icreate_recover);
DECLARE_EVENT_CLASS(xfs_discard_class, DECLARE_EVENT_CLASS(xfs_discard_class,
TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
xfs_agblock_t agbno, xfs_extlen_t len), xfs_agblock_t agbno, xfs_extlen_t len),

View File

@ -1019,9 +1019,10 @@ xfs_trans_cancel(
* chunk we've been working on and get a new transaction to continue. * chunk we've been working on and get a new transaction to continue.
*/ */
int int
xfs_trans_roll( __xfs_trans_roll(
struct xfs_trans **tpp, struct xfs_trans **tpp,
struct xfs_inode *dp) struct xfs_inode *dp,
int *committed)
{ {
struct xfs_trans *trans; struct xfs_trans *trans;
struct xfs_trans_res tres; struct xfs_trans_res tres;
@ -1052,6 +1053,7 @@ xfs_trans_roll(
if (error) if (error)
return error; return error;
*committed = 1;
trans = *tpp; trans = *tpp;
/* /*
@ -1074,3 +1076,12 @@ xfs_trans_roll(
xfs_trans_ijoin(trans, dp, 0); xfs_trans_ijoin(trans, dp, 0);
return 0; return 0;
} }
int
xfs_trans_roll(
struct xfs_trans **tpp,
struct xfs_inode *dp)
{
int committed = 0;
return __xfs_trans_roll(tpp, dp, &committed);
}

View File

@ -213,7 +213,6 @@ void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);
void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint);
void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint); void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint); struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint);
void xfs_efi_release(struct xfs_efi_log_item *, uint);
void xfs_trans_log_efi_extent(xfs_trans_t *, void xfs_trans_log_efi_extent(xfs_trans_t *,
struct xfs_efi_log_item *, struct xfs_efi_log_item *,
xfs_fsblock_t, xfs_fsblock_t,
@ -221,11 +220,11 @@ void xfs_trans_log_efi_extent(xfs_trans_t *,
struct xfs_efd_log_item *xfs_trans_get_efd(xfs_trans_t *, struct xfs_efd_log_item *xfs_trans_get_efd(xfs_trans_t *,
struct xfs_efi_log_item *, struct xfs_efi_log_item *,
uint); uint);
void xfs_trans_log_efd_extent(xfs_trans_t *, int xfs_trans_free_extent(struct xfs_trans *,
struct xfs_efd_log_item *, struct xfs_efd_log_item *, xfs_fsblock_t,
xfs_fsblock_t, xfs_extlen_t);
xfs_extlen_t);
int xfs_trans_commit(struct xfs_trans *); int xfs_trans_commit(struct xfs_trans *);
int __xfs_trans_roll(struct xfs_trans **, struct xfs_inode *, int *);
int xfs_trans_roll(struct xfs_trans **, struct xfs_inode *); int xfs_trans_roll(struct xfs_trans **, struct xfs_inode *);
void xfs_trans_cancel(xfs_trans_t *); void xfs_trans_cancel(xfs_trans_t *);
int xfs_trans_ail_init(struct xfs_mount *); int xfs_trans_ail_init(struct xfs_mount *);

View File

@ -25,6 +25,7 @@
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_trans_priv.h" #include "xfs_trans_priv.h"
#include "xfs_extfree_item.h" #include "xfs_extfree_item.h"
#include "xfs_alloc.h"
/* /*
* This routine is called to allocate an "extent free intention" * This routine is called to allocate an "extent free intention"
@ -108,19 +109,30 @@ xfs_trans_get_efd(xfs_trans_t *tp,
} }
/* /*
* This routine is called to indicate that the described * Free an extent and log it to the EFD. Note that the transaction is marked
* extent is to be logged as having been freed. It should * dirty regardless of whether the extent free succeeds or fails to support the
* be called once for each extent freed. * EFI/EFD lifecycle rules.
*/ */
void int
xfs_trans_log_efd_extent(xfs_trans_t *tp, xfs_trans_free_extent(
xfs_efd_log_item_t *efdp, struct xfs_trans *tp,
xfs_fsblock_t start_block, struct xfs_efd_log_item *efdp,
xfs_extlen_t ext_len) xfs_fsblock_t start_block,
xfs_extlen_t ext_len)
{ {
uint next_extent; uint next_extent;
xfs_extent_t *extp; struct xfs_extent *extp;
int error;
error = xfs_free_extent(tp, start_block, ext_len);
/*
* Mark the transaction dirty, even on error. This ensures the
* transaction is aborted, which:
*
* 1.) releases the EFI and frees the EFD
* 2.) shuts down the filesystem
*/
tp->t_flags |= XFS_TRANS_DIRTY; tp->t_flags |= XFS_TRANS_DIRTY;
efdp->efd_item.li_desc->lid_flags |= XFS_LID_DIRTY; efdp->efd_item.li_desc->lid_flags |= XFS_LID_DIRTY;
@ -130,4 +142,6 @@ xfs_trans_log_efd_extent(xfs_trans_t *tp,
extp->ext_start = start_block; extp->ext_start = start_block;
extp->ext_len = ext_len; extp->ext_len = ext_len;
efdp->efd_next_extent++; efdp->efd_next_extent++;
return error;
} }

View File

@ -119,6 +119,21 @@ xfs_trans_ail_delete(
xfs_trans_ail_delete_bulk(ailp, &lip, 1, shutdown_type); xfs_trans_ail_delete_bulk(ailp, &lip, 1, shutdown_type);
} }
static inline void
xfs_trans_ail_remove(
struct xfs_log_item *lip,
int shutdown_type)
{
struct xfs_ail *ailp = lip->li_ailp;
spin_lock(&ailp->xa_lock);
/* xfs_trans_ail_delete() drops the AIL lock */
if (lip->li_flags & XFS_LI_IN_AIL)
xfs_trans_ail_delete(ailp, lip, shutdown_type);
else
spin_unlock(&ailp->xa_lock);
}
void xfs_ail_push(struct xfs_ail *, xfs_lsn_t); void xfs_ail_push(struct xfs_ail *, xfs_lsn_t);
void xfs_ail_push_all(struct xfs_ail *); void xfs_ail_push_all(struct xfs_ail *);
void xfs_ail_push_all_sync(struct xfs_ail *); void xfs_ail_push_all_sync(struct xfs_ail *);