|
@@ -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 */
|
|
|
|
|
- xfs_bmap_free_t *flist, /* i/o: list extents to free */
|
|
|
|
|
- int *committed) /* xact committed or not */
|
|
|
|
|
|
|
+ struct xfs_trans **tp, /* transaction pointer addr */
|
|
|
|
|
+ struct xfs_bmap_free *flist, /* i/o: list extents to free */
|
|
|
|
|
+ int *committed)/* xact committed or not */
|
|
|
{
|
|
{
|
|
|
- xfs_efd_log_item_t *efd; /* extent free data */
|
|
|
|
|
- xfs_efi_log_item_t *efi; /* extent free intention */
|
|
|
|
|
- int error; /* error return value */
|
|
|
|
|
- xfs_bmap_free_item_t *free; /* free extent item */
|
|
|
|
|
- xfs_mount_t *mp; /* filesystem mount structure */
|
|
|
|
|
- xfs_bmap_free_item_t *next; /* next item on free list */
|
|
|
|
|
|
|
+ struct xfs_efd_log_item *efd; /* extent free data */
|
|
|
|
|
+ struct xfs_efi_log_item *efi; /* extent free intention */
|
|
|
|
|
+ int error; /* error return value */
|
|
|
|
|
+ struct xfs_bmap_free_item *free; /* free extent item */
|
|
|
|
|
+ struct xfs_bmap_free_item *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,55 @@ 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);
|
|
|
|
|
- *committed = 1;
|
|
|
|
|
- /*
|
|
|
|
|
- * We have a new transaction, so we should return committed=1,
|
|
|
|
|
- * even though we're returning an error.
|
|
|
|
|
- */
|
|
|
|
|
- if (error)
|
|
|
|
|
|
|
+ error = __xfs_trans_roll(tp, NULL, committed);
|
|
|
|
|
+ if (error) {
|
|
|
|
|
+ /*
|
|
|
|
|
+ * If the transaction was committed, drop the EFD reference
|
|
|
|
|
+ * since we're bailing out of here. The other reference is
|
|
|
|
|
+ * dropped when the EFI hits the AIL.
|
|
|
|
|
+ *
|
|
|
|
|
+ * 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;
|
|
return 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))) {
|
|
|
|
|
- /*
|
|
|
|
|
- * The bmap free list will be cleaned up at a
|
|
|
|
|
- * 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;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * Free the extent and log the EFD to dirty the transaction
|
|
|
|
|
+ * before handling errors. This ensures that the transaction is
|
|
|
|
|
+ * aborted, which:
|
|
|
|
|
+ *
|
|
|
|
|
+ * 1.) releases the EFI and frees the EFD
|
|
|
|
|
+ * 2.) shuts down the filesystem
|
|
|
|
|
+ *
|
|
|
|
|
+ * The bmap free list is cleaned up at a higher level.
|
|
|
|
|
+ */
|
|
|
|
|
+ error = xfs_free_extent(*tp, free->xbfi_startblock,
|
|
|
|
|
+ free->xbfi_blockcount);
|
|
|
xfs_trans_log_efd_extent(*tp, efd, free->xbfi_startblock,
|
|
xfs_trans_log_efd_extent(*tp, efd, free->xbfi_startblock,
|
|
|
- free->xbfi_blockcount);
|
|
|
|
|
|
|
+ free->xbfi_blockcount);
|
|
|
|
|
+ if (error)
|
|
|
|
|
+ return error;
|
|
|
|
|
+
|
|
|
xfs_bmap_del_free(flist, NULL, free);
|
|
xfs_bmap_del_free(flist, NULL, free);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|