diff options
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_log.c | 125 |
1 files changed, 45 insertions, 80 deletions
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 99509d23265f..979a688a61ba 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -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 */ |