mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 22:51:42 +00:00
Merge branch 'xfs-efi-rework' into for-next
This commit is contained in:
commit
5be203ad11
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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__ */
|
||||||
|
@ -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",
|
||||||
|
@ -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;
|
||||||
/*
|
/*
|
||||||
|
@ -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;
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
/*
|
/*
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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 *);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 *);
|
||||||
|
Loading…
Reference in New Issue
Block a user