From: Brian Foster Date: Tue, 13 Oct 2015 23:58:25 +0000 (+1100) Subject: db/metadump: bump lsn when log is cleared on v5 supers X-Git-Tag: v4.3.0-rc1~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1c12a8148b6873f1939f84c3915e6af3cbb382f8;p=thirdparty%2Fxfsprogs-dev.git db/metadump: bump lsn when log is cleared on v5 supers xfs_metadump handles the log in different ways depending on the mode of operation. If the log is dirty or obfuscation and stale data zeroing are disabled, the log is copied as is. In all other scenarios, the log is explicitly zeroed. This is incorrect for version 5 superblocks where the current LSN is always expected to be ahead of all fs metadata. Update metadump to use libxfs_log_clear() to format the log with an elevated LSN rather than zero the log and reset the current the LSN. Metadump does not use buffers for the dump target, instead using a cursor implementation to access the log via a single memory buffer. Therefore, update libxfs_log_clear() to receive an optional (but exclusive to the buftarg parameter) memory buffer pointer for the log. If the pointer is provided, the log format is written out to this buffer. Otherwise, fall back to the original behavior and access the log through buftarg buffers. Signed-off-by: Brian Foster Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- diff --git a/db/metadump.c b/db/metadump.c index 129670ebd..56b733ef0 100644 --- a/db/metadump.c +++ b/db/metadump.c @@ -2514,6 +2514,10 @@ copy_log(void) { struct xlog log; int dirty; + xfs_daddr_t logstart; + int logblocks; + int logversion; + int cycle = XLOG_INIT_CYCLE; if (show_progress) print_progress("Copying log"); @@ -2538,8 +2542,16 @@ copy_log(void) /* clear out a clean log */ if (show_progress) print_progress("Zeroing clean log"); - memset(iocur_top->data, 0, - mp->m_sb.sb_logblocks * mp->m_sb.sb_blocksize); + + logstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart); + logblocks = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); + logversion = xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1; + if (xfs_sb_version_hascrc(&mp->m_sb)) + cycle = log.l_curr_cycle + 1; + + libxfs_log_clear(NULL, iocur_top->data, logstart, logblocks, + &mp->m_sb.sb_uuid, logversion, + mp->m_sb.sb_logsunit, XLOG_FMT, cycle); break; case 1: /* keep the dirty log */ diff --git a/db/sb.c b/db/sb.c index 30c622dcd..17d446cec 100644 --- a/db/sb.c +++ b/db/sb.c @@ -283,7 +283,7 @@ sb_logzero(uuid_t *uuidp) dbprintf(_("Clearing log and setting UUID\n")); - error = libxfs_log_clear(mp->m_logdev_targp, + error = libxfs_log_clear(mp->m_logdev_targp, NULL, XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), uuidp, diff --git a/include/libxfs.h b/include/libxfs.h index 6c8793433..f733c36d9 100644 --- a/include/libxfs.h +++ b/include/libxfs.h @@ -153,8 +153,8 @@ typedef char *(libxfs_get_block_t)(char *, int, void *); * Helpers to clear the log to a particular log cycle. */ #define XLOG_INIT_CYCLE 1 -extern int libxfs_log_clear(struct xfs_buftarg *, xfs_daddr_t, uint, - uuid_t *, int, int, int, int); +extern int libxfs_log_clear(struct xfs_buftarg *, char *, xfs_daddr_t, + uint, uuid_t *, int, int, int, int); extern int libxfs_log_header(char *, uuid_t *, int, int, int, xfs_lsn_t, xfs_lsn_t, libxfs_get_block_t *, void *); diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c index 93f6eb754..c19070fb6 100644 --- a/libxfs/rdwr.c +++ b/libxfs/rdwr.c @@ -133,38 +133,54 @@ static void unmount_record(void *p) memcpy((char *)p + sizeof(xlog_op_header_t), &magic, sizeof(magic)); } -static char *next(char *ptr, int offset, void *private) +static char *next( + char *ptr, + int offset, + void *private) { - xfs_buf_t *buf = (xfs_buf_t *)private; + struct xfs_buf *buf = (struct xfs_buf *)private; - if (XFS_BUF_COUNT(buf) < (int)(ptr - XFS_BUF_PTR(buf)) + offset) + if (buf && + (XFS_BUF_COUNT(buf) < (int)(ptr - XFS_BUF_PTR(buf)) + offset)) abort(); + return ptr + offset; } +/* + * Format the log. The caller provides either a buftarg which is used to access + * the log via buffers or a direct pointer to a buffer that encapsulates the + * entire log. + */ int libxfs_log_clear( struct xfs_buftarg *btp, + char *dptr, xfs_daddr_t start, - uint length, + uint length, /* basic blocks */ uuid_t *fs_uuid, int version, - int sunit, + int sunit, /* bytes */ int fmt, int cycle) { - xfs_buf_t *bp; + struct xfs_buf *bp = NULL; int len; xfs_lsn_t lsn; xfs_lsn_t tail_lsn; xfs_daddr_t blk; xfs_daddr_t end_blk; + char *ptr; - if (!btp->dev || !fs_uuid) + if (((btp && dptr) || (!btp && !dptr)) || + (btp && !btp->dev) || !fs_uuid) return -EINVAL; /* first zero the log */ - libxfs_device_zero(btp, start, length); + if (btp) + libxfs_device_zero(btp, start, length); + else + memset(dptr, 0, BBTOB(length)); /* * Initialize the log record length and LSNs. XLOG_INIT_CYCLE is a @@ -182,11 +198,17 @@ libxfs_log_clear( tail_lsn = xlog_assign_lsn(cycle - 1, length - len); /* write out the first log record */ - bp = libxfs_getbufr(btp, start, len); - libxfs_log_header(XFS_BUF_PTR(bp), fs_uuid, version, sunit, fmt, - lsn, tail_lsn, next, bp); - bp->b_flags |= LIBXFS_B_DIRTY; - libxfs_putbufr(bp); + ptr = dptr; + if (btp) { + bp = libxfs_getbufr(btp, start, len); + ptr = XFS_BUF_PTR(bp); + } + libxfs_log_header(ptr, fs_uuid, version, sunit, fmt, lsn, tail_lsn, + next, bp); + if (bp) { + bp->b_flags |= LIBXFS_B_DIRTY; + libxfs_putbufr(bp); + } /* * There's nothing else to do if this is a log reset. The kernel detects @@ -207,6 +229,8 @@ libxfs_log_clear( */ cycle--; blk = start + len; + if (dptr) + dptr += BBTOB(len); end_blk = start + length; len = min(end_blk - blk, BTOBB(BDSTRAT_SIZE)); @@ -214,18 +238,26 @@ libxfs_log_clear( lsn = xlog_assign_lsn(cycle, blk - start); tail_lsn = xlog_assign_lsn(cycle, blk - start - len); - bp = libxfs_getbufr(btp, blk, len); + ptr = dptr; + if (btp) { + bp = libxfs_getbufr(btp, blk, len); + ptr = XFS_BUF_PTR(bp); + } /* * Note: pass the full buffer length as the sunit to initialize * the entire buffer. */ - libxfs_log_header(XFS_BUF_PTR(bp), fs_uuid, version, BBTOB(len), - fmt, lsn, tail_lsn, next, bp); - bp->b_flags |= LIBXFS_B_DIRTY; - libxfs_putbufr(bp); + libxfs_log_header(ptr, fs_uuid, version, BBTOB(len), fmt, lsn, + tail_lsn, next, bp); + if (bp) { + bp->b_flags |= LIBXFS_B_DIRTY; + libxfs_putbufr(bp); + } - len = min(end_blk - blk, BTOBB(BDSTRAT_SIZE)); blk += len; + if (dptr) + dptr += BBTOB(len); + len = min(end_blk - blk, BTOBB(BDSTRAT_SIZE)); } return 0; diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 9fb811e0d..7cba41a69 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -2710,7 +2710,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"), /* * Zero the log.... */ - libxfs_log_clear(mp->m_logdev_targp, + libxfs_log_clear(mp->m_logdev_targp, NULL, XFS_FSB_TO_DADDR(mp, logstart), (xfs_extlen_t)XFS_FSB_TO_BB(mp, logblocks), &sbp->sb_uuid, logversion, lsunit, XLOG_FMT, XLOG_INIT_CYCLE); diff --git a/repair/phase2.c b/repair/phase2.c index f9d0e2266..cb24711d2 100644 --- a/repair/phase2.c +++ b/repair/phase2.c @@ -114,7 +114,7 @@ zero_log( * filesystems. */ if (!no_modify && zap_log) { - libxfs_log_clear(log->l_dev, + libxfs_log_clear(log->l_dev, NULL, XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), &mp->m_sb.sb_uuid, diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c index 8285d9d1c..bed2ff5a8 100644 --- a/repair/xfs_repair.c +++ b/repair/xfs_repair.c @@ -584,8 +584,9 @@ format_log_max_lsn( } do_warn(_("Format log to cycle %d.\n"), new_cycle); - libxfs_log_clear(log->l_dev, logstart, logblocks, &mp->m_sb.sb_uuid, - logversion, mp->m_sb.sb_logsunit, XLOG_FMT, new_cycle); + libxfs_log_clear(log->l_dev, NULL, logstart, logblocks, + &mp->m_sb.sb_uuid, logversion, mp->m_sb.sb_logsunit, + XLOG_FMT, new_cycle); } int