Skip to content

Commit

Permalink
[XFS] Propagate errors from xfs_trans_commit().
Browse files Browse the repository at this point in the history
xfs_trans_commit() can return errors when there are problems in the
transaction subsystem. They are indicative that the entire transaction may
be incomplete, and hence the error should be propagated as there is a good
possibility that there is something fatally wrong in the filesystem. Catch
and propagate or warn about commit errors in the places where they are
currently ignored.

SGI-PV: 980084
SGI-Modid: xfs-linux-melb:xfs-kern:30795a

Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Niv Sardi <xaiki@sgi.com>
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
  • Loading branch information
David Chinner authored and Lachlan McIlroy committed Apr 18, 2008
1 parent 3c1e2bb commit e5720ee
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 88 deletions.
4 changes: 2 additions & 2 deletions fs/xfs/quota/xfs_qm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2392,9 +2392,9 @@ xfs_qm_write_sb_changes(
}

xfs_mod_sb(tp, flags);
(void) xfs_trans_commit(tp, 0);
error = xfs_trans_commit(tp, 0);

return 0;
return error;
}


Expand Down
4 changes: 2 additions & 2 deletions fs/xfs/quota/xfs_qm_syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -734,12 +734,12 @@ xfs_qm_scall_setqlim(
xfs_trans_log_dquot(tp, dqp);

xfs_dqtrace_entry(dqp, "Q_SETQLIM: COMMIT");
xfs_trans_commit(tp, 0);
error = xfs_trans_commit(tp, 0);
xfs_qm_dqprint(dqp);
xfs_qm_dqrele(dqp);
mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));

return (0);
return error;
}

STATIC int
Expand Down
52 changes: 22 additions & 30 deletions fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1699,53 +1699,33 @@ xfs_itruncate_finish(
* blocks in the file system, but oh well.
*/
xfs_bmap_cancel(&free_list);
if (committed) {
/*
* If the passed in transaction committed
* in xfs_bmap_finish(), then we want to
* add the inode to this one before returning.
* This keeps things simple for the higher
* level code, because it always knows that
* the inode is locked and held in the
* transaction that returns to it whether
* errors occur or not. We don't mark the
* inode dirty so that this transaction can
* be easily aborted if possible.
*/
xfs_trans_ijoin(ntp, ip,
XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_trans_ihold(ntp, ip);
}
if (committed)
goto error_join;
return error;
}

if (committed) {
/*
* The first xact was committed,
* so add the inode to the new one.
* Mark it dirty so it will be logged
* and moved forward in the log as
* part of every commit.
* The first xact was committed, so add the inode to
* the new one. Mark it dirty so it will be logged and
* moved forward in the log as part of every commit.
*/
xfs_trans_ijoin(ntp, ip,
XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_trans_ihold(ntp, ip);
xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
}
ntp = xfs_trans_dup(ntp);
(void) xfs_trans_commit(*tp, 0);
error = xfs_trans_commit(*tp, 0);
*tp = ntp;
if (error)
goto error_join;
error = xfs_trans_reserve(ntp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
XFS_TRANS_PERM_LOG_RES,
XFS_ITRUNCATE_LOG_COUNT);
/*
* Add the inode being truncated to the next chained
* transaction.
*/
xfs_trans_ijoin(ntp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_trans_ihold(ntp, ip);
if (error)
return (error);
goto error_join;

}
/*
* Only update the size in the case of the data fork, but
Expand Down Expand Up @@ -1777,6 +1757,18 @@ xfs_itruncate_finish(
(ip->i_d.di_nextents == 0));
xfs_itrunc_trace(XFS_ITRUNC_FINISH2, ip, 0, new_size, 0, 0);
return 0;

error_join:
/*
* Add the inode being truncated to the next chained transaction. This
* keeps things simple for the higher level code, because it always
* knows that the inode is locked and held in the transaction that
* returns to it whether errors occur or not. We don't mark the inode
* dirty so that this transaction can be easily aborted if possible.
*/
xfs_trans_ijoin(ntp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_trans_ihold(ntp, ip);
return error;
}


Expand Down
27 changes: 17 additions & 10 deletions fs/xfs/xfs_log_recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -3017,7 +3017,7 @@ xlog_recover_process_efi(
}

efip->efi_flags |= XFS_EFI_RECOVERED;
xfs_trans_commit(tp, 0);
error = xfs_trans_commit(tp, 0);
return error;
}

Expand Down Expand Up @@ -3131,24 +3131,31 @@ xlog_recover_clear_agi_bucket(
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
XFS_FSS_TO_BB(mp, 1), 0, &agibp);
if (error) {
xfs_trans_cancel(tp, XFS_TRANS_ABORT);
return;
}
if (error)
goto out_abort;

error = EINVAL;
agi = XFS_BUF_TO_AGI(agibp);
if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) {
xfs_trans_cancel(tp, XFS_TRANS_ABORT);
return;
}
if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC)
goto out_abort;

agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
offset = offsetof(xfs_agi_t, agi_unlinked) +
(sizeof(xfs_agino_t) * bucket);
xfs_trans_log_buf(tp, agibp, offset,
(offset + sizeof(xfs_agino_t) - 1));

(void) xfs_trans_commit(tp, 0);
error = xfs_trans_commit(tp, 0);
if (error)
goto out_error;
return;

out_abort:
xfs_trans_cancel(tp, XFS_TRANS_ABORT);
out_error:
xfs_fs_cmn_err(CE_WARN, mp, "xlog_recover_clear_agi_bucket: "
"failed to clear agi %d. Continuing.", agno);
return;
}

/*
Expand Down
35 changes: 22 additions & 13 deletions fs/xfs/xfs_mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
#include "xfs_fsops.h"
#include "xfs_utils.h"

STATIC void xfs_mount_log_sb(xfs_mount_t *, __int64_t);
STATIC int xfs_mount_log_sb(xfs_mount_t *, __int64_t);
STATIC int xfs_uuid_mount(xfs_mount_t *);
STATIC void xfs_uuid_unmount(xfs_mount_t *mp);
STATIC void xfs_unmountfs_wait(xfs_mount_t *);
Expand Down Expand Up @@ -1189,8 +1189,13 @@ xfs_mountfs(
/*
* If fs is not mounted readonly, then update the superblock changes.
*/
if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY))
xfs_mount_log_sb(mp, update_flags);
if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) {
error = xfs_mount_log_sb(mp, update_flags);
if (error) {
cmn_err(CE_WARN, "XFS: failed to write sb changes");
goto error4;
}
}

/*
* Initialise the XFS quota management subsystem for this mount
Expand Down Expand Up @@ -1320,8 +1325,10 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
cmn_err(CE_WARN, "XFS: Unable to free reserved block pool. "
"Freespace may not be correct on next mount.");


xfs_log_sbcount(mp, 1);
error = xfs_log_sbcount(mp, 1);
if (error)
cmn_err(CE_WARN, "XFS: Unable to update superblock counters. "
"Freespace may not be correct on next mount.");
xfs_unmountfs_writesb(mp);
xfs_unmountfs_wait(mp); /* wait for async bufs */
xfs_log_unmount(mp); /* Done! No more fs ops. */
Expand Down Expand Up @@ -1413,9 +1420,8 @@ xfs_log_sbcount(
xfs_mod_sb(tp, XFS_SB_IFREE | XFS_SB_ICOUNT | XFS_SB_FDBLOCKS);
if (sync)
xfs_trans_set_sync(tp);
xfs_trans_commit(tp, 0);

return 0;
error = xfs_trans_commit(tp, 0);
return error;
}

STATIC void
Expand Down Expand Up @@ -1913,24 +1919,27 @@ xfs_uuid_unmount(
* be altered by the mount options, as well as any potential sb_features2
* fixup. Only the first superblock is updated.
*/
STATIC void
STATIC int
xfs_mount_log_sb(
xfs_mount_t *mp,
__int64_t fields)
{
xfs_trans_t *tp;
int error;

ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID |
XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2));

tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT);
if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
XFS_DEFAULT_LOG_COUNT)) {
error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
XFS_DEFAULT_LOG_COUNT);
if (error) {
xfs_trans_cancel(tp, 0);
return;
return error;
}
xfs_mod_sb(tp, fields);
xfs_trans_commit(tp, 0);
error = xfs_trans_commit(tp, 0);
return error;
}


Expand Down
38 changes: 23 additions & 15 deletions fs/xfs/xfs_rtalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,14 @@ xfs_growfs_rt_alloc(
XFS_GROWRTALLOC_LOG_RES(mp), 0,
XFS_TRANS_PERM_LOG_RES,
XFS_DEFAULT_PERM_LOG_COUNT)))
goto error_exit;
goto error_cancel;
cancelflags = XFS_TRANS_RELEASE_LOG_RES;
/*
* Lock the inode.
*/
if ((error = xfs_trans_iget(mp, tp, ino, 0,
XFS_ILOCK_EXCL, &ip)))
goto error_exit;
goto error_cancel;
XFS_BMAP_INIT(&flist, &firstblock);
/*
* Allocate blocks to the bitmap file.
Expand All @@ -144,14 +144,16 @@ xfs_growfs_rt_alloc(
if (!error && nmap < 1)
error = XFS_ERROR(ENOSPC);
if (error)
goto error_exit;
goto error_cancel;
/*
* Free any blocks freed up in the transaction, then commit.
*/
error = xfs_bmap_finish(&tp, &flist, &committed);
if (error)
goto error_exit;
xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
goto error_cancel;
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error)
goto error;
/*
* Now we need to clear the allocated blocks.
* Do this one block per transaction, to keep it simple.
Expand All @@ -166,13 +168,13 @@ xfs_growfs_rt_alloc(
*/
if ((error = xfs_trans_reserve(tp, 0,
XFS_GROWRTZERO_LOG_RES(mp), 0, 0, 0)))
goto error_exit;
goto error_cancel;
/*
* Lock the bitmap inode.
*/
if ((error = xfs_trans_iget(mp, tp, ino, 0,
XFS_ILOCK_EXCL, &ip)))
goto error_exit;
goto error_cancel;
/*
* Get a buffer for the block.
*/
Expand All @@ -181,23 +183,26 @@ xfs_growfs_rt_alloc(
mp->m_bsize, 0);
if (bp == NULL) {
error = XFS_ERROR(EIO);
goto error_exit;
goto error_cancel;
}
memset(XFS_BUF_PTR(bp), 0, mp->m_sb.sb_blocksize);
xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
/*
* Commit the transaction.
*/
xfs_trans_commit(tp, 0);
error = xfs_trans_commit(tp, 0);
if (error)
goto error;
}
/*
* Go on to the next extent, if any.
*/
oblocks = map.br_startoff + map.br_blockcount;
}
return 0;
error_exit:
error_cancel:
xfs_trans_cancel(tp, cancelflags);
error:
return error;
}

Expand Down Expand Up @@ -1876,6 +1881,7 @@ xfs_growfs_rt(
xfs_trans_t *tp; /* transaction pointer */

sbp = &mp->m_sb;
cancelflags = 0;
/*
* Initial error checking.
*/
Expand Down Expand Up @@ -2042,13 +2048,15 @@ xfs_growfs_rt(
*/
mp->m_rsumlevels = nrsumlevels;
mp->m_rsumsize = nrsumsize;
/*
* Commit the transaction.
*/
xfs_trans_commit(tp, 0);

error = xfs_trans_commit(tp, 0);
if (error) {
tp = NULL;
break;
}
}

if (error)
if (error && tp)
xfs_trans_cancel(tp, cancelflags);

/*
Expand Down
15 changes: 12 additions & 3 deletions fs/xfs/xfs_vfsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,8 @@ void
xfs_attr_quiesce(
xfs_mount_t *mp)
{
int error = 0;

/* wait for all modifications to complete */
while (atomic_read(&mp->m_active_trans) > 0)
delay(100);
Expand All @@ -682,7 +684,11 @@ xfs_attr_quiesce(
ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0);

/* Push the superblock and write an unmount record */
xfs_log_sbcount(mp, 1);
error = xfs_log_sbcount(mp, 1);
if (error)
xfs_fs_cmn_err(CE_WARN, mp,
"xfs_attr_quiesce: failed to log sb changes. "
"Frozen image may not be consistent.");
xfs_log_unmount_write(mp);
xfs_unmountfs_writesb(mp);
}
Expand Down Expand Up @@ -1316,8 +1322,11 @@ xfs_syncsub(
* of sync if we crash or get a forced shutdown. We don't want to force
* this to disk, just get a transaction into the iclogs....
*/
if (flags & SYNC_SUPER)
xfs_log_sbcount(mp, 0);
if (flags & SYNC_SUPER) {
error = xfs_log_sbcount(mp, 0);
if (error)
last_error = error;
}

/*
* Now check to see if the log needs a "dummy" transaction.
Expand Down
Loading

0 comments on commit e5720ee

Please sign in to comment.