/* * 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.
*/ STATICvoid
xfs_efi_release( struct xfs_efi_log_item *efip)
{
ASSERT(atomic_read(&efip->efi_refcount) > 0); if (!atomic_dec_and_test(&efip->efi_refcount)) return;
/* * This is called to fill in the vector of log iovecs for the * given efi log item. We use only 1 iovec, and we point that * at the efi_log_format structure embedded in the efi item. * It is at this point that we assert that all of the extent * slots in the efi item have been filled.
*/ STATICvoid
xfs_efi_item_format( struct xfs_log_item *lip, struct xfs_log_vec *lv)
{ struct xfs_efi_log_item *efip = EFI_ITEM(lip); struct xfs_log_iovec *vecp = NULL;
/* * The unpin operation is the last place an EFI is manipulated in the log. It is * either inserted in the AIL or aborted in the event of a log I/O error. In * either case, the EFI transaction has been successfully committed to make it * this far. Therefore, we expect whoever committed the EFI to either construct * and commit the EFD or drop the EFD's reference in the event of error. Simply * drop the log's EFI reference now that the log is done with it.
*/ STATICvoid
xfs_efi_item_unpin( struct xfs_log_item *lip, int remove)
{ struct xfs_efi_log_item *efip = EFI_ITEM(lip);
xfs_efi_release(efip);
}
/* * 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.
*/ STATICvoid
xfs_efi_item_release( struct xfs_log_item *lip)
{
xfs_efi_release(EFI_ITEM(lip));
}
/* * Allocate and initialize an efi item with the given number of extents.
*/ STATICstruct xfs_efi_log_item *
xfs_efi_init( struct xfs_mount *mp, unsignedshort item_type,
uint nextents)
{ struct xfs_efi_log_item *efip;
/* * Copy an EFI format buffer from the given buf, and into the destination * EFI format structure. * The given buffer can be in 32 bit or 64 bit form (which has different padding), * one of which will be the native format for this kernel. * It will handle the conversion of formats if necessary.
*/ STATICint
xfs_efi_copy_format( struct kvec *buf, struct xfs_efi_log_format *dst_efi_fmt)
{ struct xfs_efi_log_format *src_efi_fmt = buf->iov_base;
uint len, len32, len64, i;
len = xfs_efi_log_format_sizeof(src_efi_fmt->efi_nextents);
len32 = xfs_efi_log_format32_sizeof(src_efi_fmt->efi_nextents);
len64 = xfs_efi_log_format64_sizeof(src_efi_fmt->efi_nextents);
if (buf->iov_len == len) {
memcpy(dst_efi_fmt, src_efi_fmt,
offsetof(struct xfs_efi_log_format, efi_extents)); for (i = 0; i < src_efi_fmt->efi_nextents; i++)
memcpy(&dst_efi_fmt->efi_extents[i],
&src_efi_fmt->efi_extents[i], sizeof(struct xfs_extent)); return 0;
} elseif (buf->iov_len == len32) {
xfs_efi_log_format_32_t *src_efi_fmt_32 = buf->iov_base;
/* * This is called to fill in the vector of log iovecs for the * given efd log item. We use only 1 iovec, and we point that * at the efd_log_format structure embedded in the efd item. * It is at this point that we assert that all of the extent * slots in the efd item have been filled.
*/ STATICvoid
xfs_efd_item_format( struct xfs_log_item *lip, struct xfs_log_vec *lv)
{ struct xfs_efd_log_item *efdp = EFD_ITEM(lip); struct xfs_log_iovec *vecp = NULL;
/* * 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.
*/ STATICvoid
xfs_efd_item_release( struct xfs_log_item *lip)
{ struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
/* * Fill the EFD with all extents from the EFI when we need to roll the * transaction and continue with a new EFI. * * This simply copies all the extents in the EFI to the EFD rather than make * assumptions about which extents in the EFI have already been processed. We * currently keep the xefi list in the same order as the EFI extent list, but * that may not always be the case. Copying everything avoids leaving a landmine * were we fail to cancel all the extents in an EFI if the xefi list is * processed in a different order to the extents in the EFI.
*/ staticvoid
xfs_efd_from_efi( struct xfs_efd_log_item *efdp)
{ struct xfs_efi_log_item *efip = efdp->efd_efip;
uint i;
/* Log a free extent to the intent item. */ STATICvoid
xfs_extent_free_log_item( struct xfs_trans *tp, struct xfs_efi_log_item *efip, struct xfs_extent_free_item *xefi)
{
uint next_extent; struct xfs_extent *extp;
/* * atomic_inc_return gives us the value after the increment; * we want to use it as an array index so we need to subtract 1 from * it.
*/
next_extent = atomic_inc_return(&efip->efi_next_extent) - 1;
ASSERT(next_extent < efip->efi_format.efi_nextents);
extp = &efip->efi_format.efi_extents[next_extent];
extp->ext_start = xefi->xefi_startblock;
extp->ext_len = xefi->xefi_blockcount;
}
/* Get an EFD so we can process all the free extents. */ staticstruct xfs_log_item *
xfs_extent_free_create_done( struct xfs_trans *tp, struct xfs_log_item *intent, unsignedint count)
{ struct xfs_efi_log_item *efip = EFI_ITEM(intent); struct xfs_efd_log_item *efdp;
oinfo.oi_owner = xefi->xefi_owner; if (xefi->xefi_flags & XFS_EFI_ATTR_FORK)
oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK; if (xefi->xefi_flags & XFS_EFI_BMBT_BLOCK)
oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
trace_xfs_extent_free_deferred(mp, xefi);
/* * If we need a new transaction to make progress, the caller will log a * new EFI with the current contents. It will also log an EFD to cancel * the existing EFI, and so we need to copy all the unprocessed extents * in this EFI to the EFD so this works correctly.
*/ if (!(xefi->xefi_flags & XFS_EFI_CANCELLED))
error = __xfs_free_extent(tp, to_perag(xefi->xefi_group), agbno,
xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv,
xefi->xefi_flags & XFS_EFI_SKIP_DISCARD); if (error == -EAGAIN) {
xfs_efd_from_efi(efdp); return error;
}
/* * Process an extent free intent item that was recovered from * the log. We need to free the extents that it describes.
*/ STATICint
xfs_extent_free_recover_work( struct xfs_defer_pending *dfp, struct list_head *capture_list)
{ struct xfs_trans_res resv; struct xfs_log_item *lip = dfp->dfp_intent; struct xfs_efi_log_item *efip = EFI_ITEM(lip); struct xfs_mount *mp = lip->li_log->l_mp; struct xfs_trans *tp; int i; int error = 0; bool isrt = xfs_efi_item_isrt(lip);
/* * First check the validity of the extents described by the EFI. If * any are bad, then assume that all are bad and just toss the EFI. * Mixing RT and non-RT extents in the same EFI item is not allowed.
*/ for (i = 0; i < efip->efi_format.efi_nextents; i++) { if (!xfs_efi_validate_ext(mp, isrt,
&efip->efi_format.efi_extents[i])) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
&efip->efi_format, sizeof(efip->efi_format)); return -EFSCORRUPTED;
}
/* * This routine is called to create an in-core extent free intent * item from the efi format structure which was logged on disk. * It allocates an in-core efi, copies the extents from the format * structure into it, and adds the efi to the AIL with the given * LSN.
*/ STATICint
xlog_recover_efi_commit_pass2( struct xlog *log, struct list_head *buffer_list, struct xlog_recover_item *item,
xfs_lsn_t lsn)
{ struct xfs_mount *mp = log->l_mp; struct xfs_efi_log_item *efip; struct xfs_efi_log_format *efi_formatp; int error;
/* * This routine is called when an EFD format structure is found in a committed * transaction in the log. Its purpose is to cancel the corresponding EFI if it * was still in the log. To do this it searches the AIL for the EFI with an id * equal to that in the EFD format structure. If we find it we drop the EFD * reference, which removes the EFI from the AIL and frees it.
*/ STATICint
xlog_recover_efd_commit_pass2( struct xlog *log, struct list_head *buffer_list, struct xlog_recover_item *item,
xfs_lsn_t lsn)
{ struct xfs_efd_log_format *efd_formatp; int buflen = item->ri_buf[0].iov_len;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.