xfs: factor out log buffer writing from xlog_sync

Replace the not very useful xlog_bdstrat wrapper with a new version that
that takes care of all the common logic for writing log buffers.  Use
the opportunity to avoid overloading the buffer address with the log
relative address, and to shed the unused return value.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
Christoph Hellwig 2019-06-28 19:27:22 -07:00 committed by Darrick J. Wong
parent 1f9489be02
commit 94860a301b

View File

@ -45,10 +45,6 @@ STATIC int
xlog_space_left(
struct xlog *log,
atomic64_t *head);
STATIC int
xlog_sync(
struct xlog *log,
struct xlog_in_core *iclog);
STATIC void
xlog_dealloc_log(
struct xlog *log);
@ -1726,28 +1722,34 @@ xlog_cksum(
return xfs_end_cksum(crc);
}
/*
* The bdstrat callback function for log bufs. This gives us a central
* place to trap bufs in case we get hit by a log I/O error and need to
* shutdown. Actually, in practice, even when we didn't get a log error,
* we transition the iclogs to IOERROR state *after* flushing all existing
* iclogs to disk. This is because we don't want anymore new transactions to be
* started or completed afterwards.
*
* We lock the iclogbufs here so that we can serialise against IO completion
* during unmount. We might be processing a shutdown triggered during unmount,
* and that can occur asynchronously to the unmount thread, and hence we need to
* ensure that completes before tearing down the iclogbufs. Hence we need to
* hold the buffer lock across the log IO to acheive that.
*/
STATIC int
xlog_bdstrat(
struct xfs_buf *bp)
STATIC void
xlog_write_iclog(
struct xlog *log,
struct xlog_in_core *iclog,
struct xfs_buf *bp,
uint64_t bno,
bool need_flush)
{
struct xlog_in_core *iclog = bp->b_log_item;
ASSERT(bno < log->l_logBBsize);
ASSERT(bno + bp->b_io_length <= log->l_logBBsize);
bp->b_maps[0].bm_bn = log->l_logBBstart + bno;
bp->b_log_item = iclog;
bp->b_flags &= ~XBF_FLUSH;
bp->b_flags |= (XBF_ASYNC | XBF_SYNCIO | XBF_WRITE | XBF_FUA);
if (need_flush)
bp->b_flags |= XBF_FLUSH;
/*
* We lock the iclogbufs here so that we can serialise against I/O
* completion during unmount. We might be processing a shutdown
* triggered during unmount, and that can occur asynchronously to the
* unmount thread, and hence we need to ensure that completes before
* tearing down the iclogbufs. Hence we need to hold the buffer lock
* across the log IO to archieve that.
*/
xfs_buf_lock(bp);
if (iclog->ic_state & XLOG_STATE_IOERROR) {
if (unlikely(iclog->ic_state & XLOG_STATE_IOERROR)) {
xfs_buf_ioerror(bp, -EIO);
xfs_buf_stale(bp);
xfs_buf_ioend(bp);
@ -1757,11 +1759,10 @@ xlog_bdstrat(
* doing it here. Similarly, IO completion will unlock the
* buffer, so we don't do it here.
*/
return 0;
return;
}
xfs_buf_submit(bp);
return 0;
}
/*
@ -1784,25 +1785,23 @@ xlog_bdstrat(
* log will require grabbing the lock though.
*
* The entire log manager uses a logical block numbering scheme. Only
* log_sync (and then only bwrite()) know about the fact that the log may
* not start with block zero on a given device. The log block start offset
* is added immediately before calling bwrite().
* xlog_write_iclog knows about the fact that the log may not start with
* block zero on a given device.
*/
STATIC int
STATIC void
xlog_sync(
struct xlog *log,
struct xlog_in_core *iclog)
{
xfs_buf_t *bp;
int i;
uint count; /* byte count of bwrite */
uint count_init; /* initial count before roundup */
int roundoff; /* roundoff to BB or stripe */
int split = 0; /* split write into two regions */
int error;
int v2 = xfs_sb_version_haslogv2(&log->l_mp->m_sb);
uint64_t bno;
int size;
bool need_flush = true;
XFS_STATS_INC(log->l_mp, xs_log_writes);
ASSERT(atomic_read(&iclog->ic_refcnt) == 0);
@ -1838,17 +1837,16 @@ xlog_sync(
size += roundoff;
iclog->ic_header.h_len = cpu_to_be32(size);
bp = iclog->ic_bp;
XFS_BUF_SET_ADDR(bp, BLOCK_LSN(be64_to_cpu(iclog->ic_header.h_lsn)));
XFS_STATS_ADD(log->l_mp, xs_log_blocks, BTOBB(count));
bno = BLOCK_LSN(be64_to_cpu(iclog->ic_header.h_lsn));
/* Do we need to split this write into 2 parts? */
if (XFS_BUF_ADDR(bp) + BTOBB(count) > log->l_logBBsize) {
if (bno + BTOBB(count) > log->l_logBBsize) {
char *dptr;
split = count - (BBTOB(log->l_logBBsize - XFS_BUF_ADDR(bp)));
count = BBTOB(log->l_logBBsize - XFS_BUF_ADDR(bp));
split = count - (BBTOB(log->l_logBBsize - bno));
count = BBTOB(log->l_logBBsize - bno);
iclog->ic_bwritecnt = 2;
/*
@ -1891,11 +1889,6 @@ xlog_sync(
}
#endif
bp->b_io_length = BTOBB(count);
bp->b_log_item = iclog;
bp->b_flags &= ~XBF_FLUSH;
bp->b_flags |= (XBF_ASYNC | XBF_SYNCIO | XBF_WRITE | XBF_FUA);
/*
* Flush the data device before flushing the log to make sure all meta
* data written back from the AIL actually made it to disk before
@ -1904,50 +1897,22 @@ xlog_sync(
* synchronously here; for an internal log we can simply use the block
* layer state machine for preflushes.
*/
if (log->l_mp->m_logdev_targp != log->l_mp->m_ddev_targp || split)
if (log->l_mp->m_logdev_targp != log->l_mp->m_ddev_targp || split) {
xfs_blkdev_issue_flush(log->l_mp->m_ddev_targp);
else
bp->b_flags |= XBF_FLUSH;
need_flush = false;
}
ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1);
ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize);
iclog->ic_bp->b_io_length = BTOBB(count);
xlog_verify_iclog(log, iclog, count, true);
xlog_write_iclog(log, iclog, iclog->ic_bp, bno, need_flush);
/* account for log which doesn't start at block #0 */
XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart);
/*
* Don't call xfs_bwrite here. We do log-syncs even when the filesystem
* is shutting down.
*/
error = xlog_bdstrat(bp);
if (error) {
xfs_buf_ioerror_alert(bp, "xlog_sync");
return error;
}
if (split) {
bp = iclog->ic_log->l_xbuf;
XFS_BUF_SET_ADDR(bp, 0); /* logical 0 */
xfs_buf_associate_memory(bp,
xfs_buf_associate_memory(iclog->ic_log->l_xbuf,
(char *)&iclog->ic_header + count, split);
bp->b_log_item = iclog;
bp->b_flags &= ~XBF_FLUSH;
bp->b_flags |= (XBF_ASYNC | XBF_SYNCIO | XBF_WRITE | XBF_FUA);
ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1);
ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize);
/* account for internal log which doesn't start at block #0 */
XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart);
error = xlog_bdstrat(bp);
if (error) {
xfs_buf_ioerror_alert(bp, "xlog_sync (split)");
return error;
}
xlog_write_iclog(log, iclog, iclog->ic_log->l_xbuf, 0, false);
}
return 0;
} /* xlog_sync */
}
/*
* Deallocate a log structure
@ -3194,7 +3159,7 @@ xlog_state_release_iclog(
* flags after this point.
*/
if (sync)
return xlog_sync(log, iclog);
xlog_sync(log, iclog);
return 0;
} /* xlog_state_release_iclog */