xfsprogs: format the log correctly on v5 supers
v3 cover xfsprogs: format the log correctly on v5 supers
Hi all,
Here is v3 of the userspace v5 log formatting fixes. This version is based on the latest variant of the kernel metadata LSN verification patch:
http://oss.sgi.com/pipermail/xfs/2015-September/043846.html
The updates are relatively minor with the exception of added support for xfs_copy. Patches 1-6 update libxfs/libxlog to support max. metadata LSN tracking, cycle-specific log formatting and otherwise prepare for subsequent fixes. Patches 7-11 update xfs_repair to no longer zero the log by default and format v5 logs correctly based on the maximum seen metadata LSN. Patches 12-13 update the xfs_db uuid and metadump commands to bump the cycle number when formatting v5 logs. Patch 14 is an independent bug fix to enable xfs_copy to detect and warn about a dirty log in the source filesystem. Patches 15-18 refactor and fix xfs_copy to also bump the cycle number when formatting v5 logs.
Thoughts, reviews, flames appreciated.
Brian
v3:
- Rebased on latest LSN validation kernel patch.
- Added comment for dummy log clearing tid.
- Seed max lsn value from initial log state in xfs_repair.
- Added xfs_copy fixes (non-dup. dirty log fix + v5 log format fixes).
v2: http://oss.sgi.com/pipermail/xfs/2015-September/043630.html
- Rebase to latest kernel variant of invalid metadata LSN detection.
- Added support for xfs_db's uuid command and xfs_metadump.
v1: http://oss.sgi.com/pipermail/xfs/2015-August/043397.html
Brian Foster (18):
libxfs: validate metadata LSNs against log on v5 superblocks
libxfs: track largest metadata LSN in use via verifiers
libxfs: don't hardcode cycle 1 into unmount op header
libxfs: pass lsn param to log clear and record header logging helpers
libxfs: add ability to clear log to arbitrary log cycle
libxlog: pull struct xlog out of xlog_is_dirty()
xfs_repair: track log state throughout all recovery phases
xfs_repair: process the log in no_modify mode
xfs_repair: format the log with forward cycle number on v5 supers
xfs_repair: don't clear the log by default
xfs_repair: seed the max lsn from log state in phase 2
xfs_db: do not reset current lsn from uuid command on v5 supers db/metadump: bump lsn when log is cleared on v5 supers
xfs_copy: check for dirty log on non-duplicate copies
xfs_copy: genericize write helper to facilitate separate log buf
xfs_copy: store data buf alignment in buf data structure
xfs_copy: refactor log format code into new helper
xfs_copy: format v5 sb logs correctly
Makefile | 2 +- copy/Makefile | 4 +- copy/xfs_copy.c | 196 +++++++++++++++++++++++++++++++++++--------- copy/xfs_copy.h | 1 + db/init.c | 25 +++--- db/metadump.c | 21 ++++- db/sb.c | 18 +++- include/libxfs.h | 13 ++- include/libxlog.h | 3 +- include/xfs_mount.h | 6 ++ libxfs/libxfs_priv.h | 2 + libxfs/rdwr.c | 160 ++++++++++++++++++++++++++++++------ libxfs/util.c | 41 +++++++++ libxfs/xfs_alloc.c | 12 ++- libxfs/xfs_attr_leaf.c | 2 + libxfs/xfs_btree.c | 16 +++- libxfs/xfs_da_btree.c | 3 + libxfs/xfs_dir2_block.c | 2 + libxfs/xfs_dir2_data.c | 2 + libxfs/xfs_dir2_leaf.c | 2 + libxfs/xfs_dir2_node.c | 2 + libxfs/xfs_ialloc.c | 9 +- libxfs/xfs_sb.c | 9 ++ libxfs/xfs_symlink_remote.c | 3 + libxlog/util.c | 37 +++++---- mkfs/xfs_mkfs.c | 4 +- repair/phase2.c | 90 +++++++++++++------- repair/xfs_repair.c | 79 +++++++++++++++++- 28 files changed, 614 insertions(+), 150 deletions(-)
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 1/18 libxfs: validate metadata LSNs against log on v5 superblocks
Backport the associated kernel commit. Replace the xfs_log_check_lsn() helper with a stub.
--- libxfs/libxfs_priv.h | 2 ++ libxfs/util.c | 8 ++++++++ libxfs/xfs_alloc.c | 12 +++++++++--- libxfs/xfs_attr_leaf.c | 2 ++ libxfs/xfs_btree.c | 16 ++++++++++++++-- libxfs/xfs_da_btree.c | 3 +++ libxfs/xfs_dir2_block.c | 2 ++ libxfs/xfs_dir2_data.c | 2 ++ libxfs/xfs_dir2_leaf.c | 2 ++ libxfs/xfs_dir2_node.c | 2 ++ libxfs/xfs_ialloc.c | 9 +++++++-- libxfs/xfs_sb.c | 9 +++++++++ libxfs/xfs_symlink_remote.c | 3 +++ 13 files changed, 65 insertions(+), 7 deletions(-)
libxfs/libxfs_priv.h +2 -0
@@ -505,4 +505,6 @@ void xfs_verifier_error(struct xfs_buf *bp);/* xfs_rtalloc.c */ int libxfs_rtfree_extent (struct xfs_trans *,xfs_rtblock_t ,xfs_extlen_t ); +bool xfs_log_check_lsn (struct xfs_mount *,xfs_lsn_t ); +#endif /* __LIBXFS_INTERNAL_XFS_H__ */
libxfs/util.c +8 -0
@@ -729,3 +729,11 @@ xfs_verifier_error( bp->b_error == -EFSBADCRC ?"CRC error" :"corruption" , bp->b_bn, BBTOB(bp->b_length)); } + +bool +xfs_log_check_lsn ( +struct xfs_mount *mp, +xfs_lsn_t lsn) +{ +return true; +}
libxfs/xfs_alloc.c +9 -3
@@ -478,7 +478,9 @@ xfs_agfl_verify( be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks)return false; } -return true; + +return xfs_log_check_lsn (mp, +be64_to_cpu (XFS_BUF_TO_AGFL (bp)->agfl_lsn)); } static void
@@ -2255,9 +2257,13 @@ xfs_agf_verify( {struct xfs_agf *agf =XFS_BUF_TO_AGF (bp); -if (xfs_sb_version_hascrc (&mp->m_sb) && - !uuid_equal (&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) +if (xfs_sb_version_hascrc (&mp->m_sb)) { +if (!uuid_equal (&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))return false; +if (!xfs_log_check_lsn (mp, +be64_to_cpu (XFS_BUF_TO_AGF (bp)->agf_lsn))) +return false; + } if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) && XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
libxfs/xfs_attr_leaf.c +2 -0
@@ -262,6 +262,8 @@ xfs_attr3_leaf_verify(return false;if (be64_to_cpu (hdr3->info.blkno) != bp->b_bn)return false; +if (!xfs_log_check_lsn (mp,be64_to_cpu (hdr3->info.lsn))) +return false; }else {if (ichdr.magic !=XFS_ATTR_LEAF_MAGIC )return false;
libxfs/xfs_btree.c +14 -2
@@ -240,8 +240,14 @@ boolxfs_btree_lblock_verify_crc ( struct xfs_buf *bp) { -if (xfs_sb_version_hascrc (&bp->b_target->bt_mount->m_sb)) +struct xfs_btree_block *block =XFS_BUF_TO_BLOCK (bp); +struct xfs_mount *mp = bp->b_target->bt_mount; + +if (xfs_sb_version_hascrc (&bp->b_target->bt_mount->m_sb)) { +if (!xfs_log_check_lsn (mp,be64_to_cpu (block->bb_u.l.bb_lsn))) +return false;return xfs_buf_verify_cksum (bp,XFS_BTREE_LBLOCK_CRC_OFF ); + }return true; }
@@ -272,8 +278,14 @@ boolxfs_btree_sblock_verify_crc ( struct xfs_buf *bp) { -if (xfs_sb_version_hascrc (&bp->b_target->bt_mount->m_sb)) +struct xfs_btree_block *block =XFS_BUF_TO_BLOCK (bp); +struct xfs_mount *mp = bp->b_target->bt_mount; + +if (xfs_sb_version_hascrc (&bp->b_target->bt_mount->m_sb)) { +if (!xfs_log_check_lsn (mp,be64_to_cpu (block->bb_u.s.bb_lsn))) +return false;return xfs_buf_verify_cksum (bp,XFS_BTREE_SBLOCK_CRC_OFF ); + }return true; }
libxfs/xfs_da_btree.c +3 -0
@@ -146,6 +146,8 @@ xfs_da3_node_verify(return false;if (be64_to_cpu (hdr3->info.blkno) != bp->b_bn)return false; +if (!xfs_log_check_lsn (mp,be64_to_cpu (hdr3->info.lsn))) +return false; }else {if (ichdr.magic !=XFS_DA_NODE_MAGIC )return false;
@@ -318,6 +320,7 @@ xfs_da3_node_create(if (xfs_sb_version_hascrc (&mp->m_sb)) {struct xfs_da3_node_hdr *hdr3 = bp->b_addr; +memset (hdr3,0 ,sizeof (struct xfs_da3_node_hdr )); ichdr.magic =XFS_DA3_NODE_MAGIC ; hdr3->info.blkno =cpu_to_be64 (bp->b_bn); hdr3->info.owner =cpu_to_be64 (args->dp->i_ino);
libxfs/xfs_dir2_block.c +2 -0
@@ -68,6 +68,8 @@ xfs_dir3_block_verify(return false;if (be64_to_cpu (hdr3->blkno) != bp->b_bn)return false; +if (!xfs_log_check_lsn (mp,be64_to_cpu (hdr3->lsn))) +return false; }else {if (hdr3->magic !=cpu_to_be32 (XFS_DIR2_BLOCK_MAGIC ))return false;
libxfs/xfs_dir2_data.c +2 -0
@@ -222,6 +222,8 @@ xfs_dir3_data_verify(return false;if (be64_to_cpu (hdr3->blkno) != bp->b_bn)return false; +if (!xfs_log_check_lsn (mp,be64_to_cpu (hdr3->lsn))) +return false; }else {if (hdr3->magic !=cpu_to_be32 (XFS_DIR2_DATA_MAGIC ))return false;
libxfs/xfs_dir2_leaf.c +2 -0
@@ -162,6 +162,8 @@ xfs_dir3_leaf_verify(return false;if (be64_to_cpu (leaf3->info.blkno) != bp->b_bn)return false; +if (!xfs_log_check_lsn (mp,be64_to_cpu (leaf3->info.lsn))) +return false; }else {if (leaf->hdr.info.magic !=cpu_to_be16 (magic))return false;
libxfs/xfs_dir2_node.c +2 -0
@@ -95,6 +95,8 @@ xfs_dir3_free_verify(return false;if (be64_to_cpu (hdr3->blkno) != bp->b_bn)return false; +if (!xfs_log_check_lsn (mp,be64_to_cpu (hdr3->lsn))) +return false; }else {if (hdr->magic !=cpu_to_be32 (XFS_DIR2_FREE_MAGIC ))return false;
libxfs/xfs_ialloc.c +7 -2
@@ -2495,9 +2495,14 @@ xfs_agi_verify(struct xfs_mount *mp = bp->b_target->bt_mount;struct xfs_agi *agi =XFS_BUF_TO_AGI (bp); -if (xfs_sb_version_hascrc (&mp->m_sb) && - !uuid_equal (&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) +if (xfs_sb_version_hascrc (&mp->m_sb)) { +if (!uuid_equal (&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) +return false; +if (!xfs_log_check_lsn (mp, +be64_to_cpu (XFS_BUF_TO_AGI (bp)->agi_lsn)))return false; + } +/* * Validate the magic number of the agi block. */
libxfs/xfs_sb.c +9 -0
@@ -161,6 +161,15 @@ xfs_mount_validate_sb( "Filesystem can not be safely mounted by this kernel.");return -EINVAL ; } + }else if (xfs_sb_version_hascrc (sbp)) { +/* +* We can't read verify the sb LSN because the read verifier is +* called before the log is allocated and processed. We know the +* log is set up before write verifier (!check_version) calls, +* so just check it here. +*/ +if (!xfs_log_check_lsn (mp, sbp->sb_lsn)) +return -EFSCORRUPTED ; }if (xfs_sb_version_has_pquotino (sbp)) {
libxfs/xfs_symlink_remote.c +3 -0
@@ -57,6 +57,7 @@ xfs_symlink_hdr_set(if (!xfs_sb_version_hascrc (&mp->m_sb))return 0 ; +memset (dsl,0 ,sizeof (struct xfs_dsymlink_hdr )); dsl->sl_magic =cpu_to_be32 (XFS_SYMLINK_MAGIC ); dsl->sl_offset =cpu_to_be32 (offset); dsl->sl_bytes =cpu_to_be32 (size);
@@ -113,6 +114,8 @@ xfs_symlink_verify(return false;if (dsl->sl_owner ==0 )return false; +if (!xfs_log_check_lsn (mp,be64_to_cpu (dsl->sl_lsn))) +return false;return true; }
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 2/18 libxfs: track largest metadata LSN in use via verifiers
In reply to Brian FosterThe LSN validation helper is called in the I/O verifier codepath for metadata that embed a last-modification LSN. While the codepath exists, this is not used in userspace as in the kernel because the former doesn't have an active log.
xfs_repair does need to check the validity of the LSN metadata with respect to the on-disk log, however. Use the LSN validation mechanism to track the largest LSN that has been seen. Export the value so repair can use it once it has processed the entire filesystem. Note that the helper continues to always return true to preserve existing behavior.
--- include/libxfs.h | 1 + libxfs/util.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+)
include/libxfs.h +1 -0
@@ -134,6 +134,7 @@ typedef struct {#define LIBXFS_DIRECT 0x0020/* can use direct I/O, not buffered */ extern char *progname; +extern xfs_lsn_t libxfs_max_lsn;extern int libxfs_init (libxfs_init_t *);extern void libxfs_destroy (void );extern int libxfs_device_to_fd (dev_t );
libxfs/util.c +33 -0
@@ -730,10 +730,43 @@ xfs_verifier_error( bp->b_bn, BBTOB(bp->b_length)); } +/* +* This is called from I/O verifiers on v5 superblock filesystems. In the +* kernel, it validates the metadata LSN parameter against the current LSN of +* the active log. We don't have an active log in userspace so this kind of +* validation is not required. Therefore, this function always returns true in +* userspace. +* +* xfs_repair piggybacks off this mechanism to help track the largest metadata +* LSN in use on a filesystem. Keep a record of the largest LSN seen such that +* repair can validate it against the state of the log. +*/ +xfs_lsn_t libxfs_max_lsn =0 ; +pthread_mutex_t libxfs_max_lsn_lock =PTHREAD_MUTEX_INITIALIZER ; +bool xfs_log_check_lsn (struct xfs_mount *mp,xfs_lsn_t lsn) { +int cycle =CYCLE_LSN (lsn); +int block =BLOCK_LSN (lsn); +int max_cycle; +int max_block; + +if (lsn ==NULLCOMMITLSN ) +return true; + +pthread_mutex_lock (&libxfs_max_lsn_lock); + + max_cycle =CYCLE_LSN (libxfs_max_lsn); + max_block =BLOCK_LSN (libxfs_max_lsn); + +if ((cycle > max_cycle) || + (cycle == max_cycle && block > max_block)) + libxfs_max_lsn = lsn; + +pthread_mutex_unlock (&libxfs_max_lsn_lock); +return true; }
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 3/18 libxfs: don't hardcode cycle 1 into unmount op header
In reply to Brian FosterThe libxfs helper to write a log record after zeroing the log fills much of the record header and unmount record with dummy data. It also hardcodes the cycle number into the transaction oh_tid field as the kernel expects to find the cycle stamped at the top of each block and the original oh_tid value packed into h_cycle_data of the record header.
The log clearing code requires the ability to format the log to an arbitrary cycle number to fix v5 superblock log recovery ordering problems. As a result, the unmount record helper must not hardcode a cycle of 1.
Fix up libxfs_log_header() to pack the unmount record appropriately, as is already done for extra blocks that might exist beyond the record. Use h_cycle_data for the original 32-bit word of the log record data block and stamp the cycle number in its place. This allows unmount_record() to work for arbitrary cycle numbers and libxfs_log_header() to pack a cycle value that matches the lsn used in the record header. Note that this patch does not change behavior as the lsn is still hardcoded to (1:0).
--- libxfs/rdwr.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-)
libxfs/rdwr.c +17 -7
@@ -122,7 +122,8 @@ static void unmount_record(void *p) } magic = { XLOG_UNMOUNT_TYPE, 0, 0 };memset (p,0 ,BBSIZE ); - op->oh_tid =cpu_to_be32 (1 ); +/* dummy tid to mark this as written from userspace */ + op->oh_tid =cpu_to_be32 (0xb0c0d0d0 ); op->oh_len =cpu_to_be32 (sizeof (magic)); op->oh_clientid =XFS_LOG ; op->oh_flags =XLOG_UNMOUNT_TRANS ;
@@ -188,10 +189,6 @@ libxfs_log_header( len = ((version ==2 ) && sunit) ?BTOBB (sunit) :1 ; -/* note that oh_tid actually contains the cycle number -* and the tid is stored in h_cycle_data[0] - that's the -* way things end up on disk. -*/ memset (p,0 ,BBSIZE ); head->h_magicno =cpu_to_be32 (XLOG_HEADER_MAGIC_NUM ); head->h_cycle =cpu_to_be32 (1 );
@@ -203,7 +200,6 @@ libxfs_log_header( head->h_crc =cpu_to_le32 (0 ); head->h_prev_block =cpu_to_be32 (-1 ); head->h_num_logops =cpu_to_be32 (1 ); - head->h_cycle_data[0 ] =cpu_to_be32 (0xb0c0d0d0 ); head->h_fmt =cpu_to_be32 (fmt); head->h_size =cpu_to_be32 (XLOG_HEADER_CYCLE_SIZE );
@@ -212,11 +208,25 @@ libxfs_log_header(memcpy (&head->h_fs_uuid, fs_uuid,sizeof (uuid_t)); - len =MAX (len,2 ); p =nextfunc (p,BBSIZE , private);unmount_record (p); +/* +* The kernel expects to see either a log record header magic or the LSN +* cycle at the top of every log block (for example, see +* xlog_[un]pack_data() and xlog_get_cycle()). Pack the unmount record +* block appropriately here. +*/ cycle_lsn =CYCLE_LSN_DISK (head->h_lsn); + head->h_cycle_data[0 ] = *(__be32 *)p; + *(__be32 *)p = cycle_lsn; + +/* +* Now zero any remaining blocks in the record and stamp with the cycle. +* Note that we don't need to swap into h_cycle_data because it has +* already been initialized to zero. +*/ + len =MAX (len,2 );for (i =2 ; i < len; i++) { p =nextfunc (p,BBSIZE , private);memset (p,0 ,BBSIZE );
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 4/18 libxfs: pass lsn param to log clear and record header logging helpers
In reply to Brian FosterIn preparation to support the ability to format the log with an arbitrary cycle number, the log clear and record logging helpers must be updated to receive the desired cycle and LSN values as parameters.
Update libxfs_log_clear() to receive the desired cycle number to format the log with. Define a preprocessor directive to represent the currently hardcoded case of cycle 1. Update libxfs_log_header() to receive the lsn and tail_lsn of the record to write. Use a NULL value LSN to represent the currently hardcoded behavior.
All callers are updated to use the current default values. As such, this patch does not change behavior in any way.
--- copy/xfs_copy.c | 4 ++-- db/sb.c | 2 +- include/libxfs.h | 12 ++++++++---- libxfs/rdwr.c | 26 ++++++++++++++++++++------ mkfs/xfs_mkfs.c | 2 +- repair/phase2.c | 2 +- 6 files changed, 33 insertions(+), 15 deletions(-)
copy/xfs_copy.c +2 -2
@@ -1212,8 +1212,8 @@ write_log_header(int fd, wbuf *buf, xfs_mount_t *mp) offset =libxfs_log_header (p, &buf->owner->uuid,xfs_sb_version_haslogv2 (&mp->m_sb) ?2 :1 , - mp->m_sb.sb_logsunit,XLOG_FMT , - next_log_chunk, buf); + mp->m_sb.sb_logsunit,XLOG_FMT ,NULLCOMMITLSN , +NULLCOMMITLSN , next_log_chunk, buf);do_write (buf->owner);return roundup (logstart + offset, buf->length);
db/sb.c +1 -1
@@ -278,7 +278,7 @@ sb_logzero(uuid_t *uuidp) (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), uuidp, xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1, - mp->m_sb.sb_logsunit, XLOG_FMT)) { + mp->m_sb.sb_logsunit, XLOG_FMT, XLOG_INIT_CYCLE)) {dbprintf (_ ("ERROR: cannot clear the log\n" ));return 0 ; }
include/libxfs.h +8 -4
@@ -149,10 +149,14 @@ extern int platform_nproc(void);/* check or write log footer: specify device, log size in blocks & uuid */ typedef char *(libxfs_get_block_t )(char *,int ,void *); -extern int libxfs_log_clear (struct xfs_buftarg *,xfs_daddr_t ,uint , -uuid_t *,int ,int ,int ); -extern int libxfs_log_header (char *,uuid_t *,int ,int ,int , -libxfs_get_block_t *,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_header (char *,uuid_t *,int ,int ,int ,xfs_lsn_t , +xfs_lsn_t ,libxfs_get_block_t *,void *);/* Shared utility routines */
libxfs/rdwr.c +20 -6
@@ -150,14 +150,21 @@ libxfs_log_clear(uuid_t *fs_uuid, int version, int sunit, - int fmt) + int fmt, + int cycle) { xfs_buf_t *bp;int len; +xfs_lsn_t lsn;if (!btp->dev || !fs_uuid)return -EINVAL ; +if (cycle !=XLOG_INIT_CYCLE ) +return -EINVAL ; + + lsn =xlog_assign_lsn (cycle,0 ); +/* first zero the log */ libxfs_device_zero (btp, start, length);
@@ -165,8 +172,8 @@ libxfs_log_clear( len = ((version ==2 ) && sunit) ?BTOBB (sunit) :2 ; len =MAX (len,2 ); bp =libxfs_getbufr (btp, start, len); -libxfs_log_header (XFS_BUF_PTR (bp), - fs_uuid, version, sunit, fmt, next, bp); +libxfs_log_header (XFS_BUF_PTR (bp), fs_uuid, version, sunit, fmt, lsn, + lsn, next, bp); bp->b_flags |=LIBXFS_B_DIRTY ;libxfs_putbufr (bp);return 0 ;
@@ -179,6 +186,8 @@ libxfs_log_header(int version, int sunit, int fmt, + xfs_lsn_t lsn, + xfs_lsn_t tail_lsn, libxfs_get_block_t *nextfunc, void *private) {
@@ -187,11 +196,16 @@ libxfs_log_header(__be32 cycle_lsn;int i, len; +if (lsn ==NULLCOMMITLSN ) + lsn =xlog_assign_lsn (XLOG_INIT_CYCLE ,0 ); +if (tail_lsn ==NULLCOMMITLSN ) + tail_lsn = lsn; + len = ((version ==2 ) && sunit) ?BTOBB (sunit) :1 ;memset (p,0 ,BBSIZE ); head->h_magicno =cpu_to_be32 (XLOG_HEADER_MAGIC_NUM ); - head->h_cycle =cpu_to_be32 (1 ); + head->h_cycle =cpu_to_be32 (CYCLE_LSN (lsn)); head->h_version =cpu_to_be32 (version);if (len !=1 ) head->h_len =cpu_to_be32 (sunit -BBSIZE );
@@ -203,8 +217,8 @@ libxfs_log_header( head->h_fmt =cpu_to_be32 (fmt); head->h_size =cpu_to_be32 (XLOG_HEADER_CYCLE_SIZE ); - head->h_lsn =cpu_to_be64 (xlog_assign_lsn (1 ,0 )); - head->h_tail_lsn =cpu_to_be64 (xlog_assign_lsn (1 ,0 )); + head->h_lsn =cpu_to_be64 (lsn); + head->h_tail_lsn =cpu_to_be64 (tail_lsn);memcpy (&head->h_fs_uuid, fs_uuid,sizeof (uuid_t));
mkfs/xfs_mkfs.c +1 -1
@@ -2670,7 +2670,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),libxfs_log_clear (mp->m_logdev_targp,XFS_FSB_TO_DADDR (mp, logstart), (xfs_extlen_t )XFS_FSB_TO_BB (mp, logblocks), - &sbp->sb_uuid, logversion, lsunit,XLOG_FMT ); + &sbp->sb_uuid, logversion, lsunit,XLOG_FMT ,XLOG_INIT_CYCLE ); mp =libxfs_mount (mp, sbp, xi.ddev, xi.logdev, xi.rtdev,0 );if (mp ==NULL ) {
repair/phase2.c +1 -1
@@ -98,7 +98,7 @@ zero_log(xfs_mount_t *mp) (xfs_extlen_t )XFS_FSB_TO_BB (mp, mp->m_sb.sb_logblocks), &mp->m_sb.sb_uuid,xfs_sb_version_haslogv2 (&mp->m_sb) ?2 :1 , - mp->m_sb.sb_logsunit, XLOG_FMT); + mp->m_sb.sb_logsunit, XLOG_FMT, XLOG_INIT_CYCLE); }/*
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 5/18 libxfs: add ability to clear log to arbitrary log cycle
In reply to Brian FosterThe libxfs_log_clear() helper currently zeroes the log and writes a single log record such that the kernel code detects the log has been zeroed and mounts successfully. This is not sufficient for v5 filesystems, which must have the log cleared to an LSN that is guaranteed to be ahead of any LSN that has been previously stamped into on-disk metadata.
Update libxfs_log_clear() to support the ability to format the log to an arbitrary cycle number. First, the log is physically zeroed. A log record is written to the first block of the log with the desired lsn and refers to the tail_lsn as the last record of the previous cycle. The rest of the log is filled with log records of the previous cycle. This causes the kernel to set the current LSN to start of the desired cycle number at mount time.
--- libxfs/rdwr.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 8 deletions(-)
libxfs/rdwr.c +60 -8
@@ -156,26 +156,78 @@ libxfs_log_clear(xfs_buf_t *bp;int len;xfs_lsn_t lsn; +xfs_lsn_t tail_lsn; +xfs_daddr_t blk; +xfs_daddr_t end_blk;if (!btp->dev || !fs_uuid)return -EINVAL ; -if (cycle !=XLOG_INIT_CYCLE ) -return -EINVAL ; - - lsn =xlog_assign_lsn (cycle,0 ); -/* first zero the log */ libxfs_device_zero (btp, start, length); -/* then write a log record header */ +/* +* Initialize the log record length and LSNs. XLOG_INIT_CYCLE is a +* special reset case where we only write a single record where the lsn +* and tail_lsn match. Otherwise, the record lsn starts at block 0 of +* the specified cycle and points tail_lsn at the last record of the +* previous cycle. +*/ len = ((version ==2 ) && sunit) ?BTOBB (sunit) :2 ; len =MAX (len,2 ); + lsn =xlog_assign_lsn (cycle,0 ); +if (cycle ==XLOG_INIT_CYCLE ) + tail_lsn = lsn; +else + 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, - lsn, next, bp); +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); + +/* +* There's nothing else to do if this is a log reset. The kernel detects +* the rest of the log is zeroed and starts at cycle 1. +*/ +if (cycle ==XLOG_INIT_CYCLE ) +return 0 ; + +/* +* Otherwise, fill everything beyond the initial record with records of +* the previous cycle so the kernel head/tail detection works correctly. +* +* We don't particularly care about the record size or content here. +* It's only important that the headers are in place such that the +* kernel finds 1.) a clean log and 2.) the correct current cycle value. +* Therefore, bump up the record size to the max to use larger I/Os and +* improve performance. +*/ + cycle--; + blk = start + len; + end_blk = start + length; + + len =min (end_blk - blk,BTOBB (BDSTRAT_SIZE )); +while (blk < end_blk) { + lsn =xlog_assign_lsn (cycle, blk - start); + tail_lsn =xlog_assign_lsn (cycle, blk - start - len); + + bp =libxfs_getbufr (btp, blk, len); +/* +* 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); + + len =min (end_blk - blk,BTOBB (BDSTRAT_SIZE )); + blk += len; + } +return 0 ; }
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 6/18 libxlog: pull struct xlog out of xlog_is_dirty()
In reply to Brian FosterThe xlog_is_dirty() helper is called in various places to acquire the current log head, tail and to determine whether the log is dirty. Some callers will require additional information to deal with formatting the log, such as the current LSN. xlog_is_dirty() already acquires this information through existing sub-helpers, but it is not available to callers as the xlog structure is allocated on the local stack.
Update xlog_is_dirty() to receive the xlog structure as a parameter and pass it along such that additional information about the log is available to callers. Update the existing callers to allocate the xlog structure on the stack.
--- db/metadump.c | 5 +++-- db/sb.c | 3 ++- include/libxlog.h | 3 ++- libxlog/util.c | 37 +++++++++++++++++++------------------ 4 files changed, 26 insertions(+), 22 deletions(-)
db/metadump.c +3 -2
@@ -2512,7 +2512,8 @@ copy_sb_inodes(void)static int copy_log (void ) { -int dirty; +struct xlog log; +int dirty;if (show_progress)print_progress ("Copying log" );
@@ -2530,7 +2531,7 @@ copy_log(void)if (!obfuscate && !zero_stale_data) goto done; - dirty =xlog_is_dirty (mp, &x,0 ); + dirty =xlog_is_dirty (mp, &log, &x,0 );switch (dirty) {case 0 :
db/sb.c +2 -1
@@ -229,6 +229,7 @@ int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p)int sb_logcheck (void ) { +struct xlog log;int dirty;if (mp->m_sb.sb_logstart) {
@@ -247,7 +248,7 @@ sb_logcheck(void)libxfs_buftarg_init (mp, x.ddev, x.logdev, x.rtdev); - dirty =xlog_is_dirty (mp, &x,0 ); + dirty =xlog_is_dirty (mp, &log, &x,0 );if (dirty ==-1 ) {dbprintf (_ ("ERROR: cannot find log head/tail, run xfs_repair\n" ));return 0 ;
include/libxlog.h +2 -1
@@ -84,7 +84,8 @@ extern int print_record_header;extern libxfs_init_t x; -extern int xlog_is_dirty (xfs_mount_t *mp,libxfs_init_t *x,int verbose); +extern int xlog_is_dirty (struct xfs_mount *,struct xlog *,libxfs_init_t *, +int );extern struct xfs_buf *xlog_get_bp (struct xlog *,int );extern void xlog_put_bp (struct xfs_buf *); extern int xlog_bread(struct xlog *log, xfs_daddr_t blk_no, int nbblks,
libxlog/util.c +19 -18
@@ -29,15 +29,15 @@ libxfs_init_t x;*/ int xlog_is_dirty ( -xfs_mount_t *mp, -libxfs_init_t *x, -int verbose) +struct xfs_mount *mp, +struct xlog *log, +libxfs_init_t *x, +int verbose) { -int error; -struct xlog log; -xfs_daddr_t head_blk, tail_blk; +int error; +xfs_daddr_t head_blk, tail_blk; -memset (&log,0 ,sizeof (log)); +memset (log,0 ,sizeof (*log));/* We (re-)init members of libxfs_init_t here? really? */ x->logBBsize =XFS_FSB_TO_BB (mp, mp->m_sb.sb_logblocks);
@@ -46,23 +46,24 @@ xlog_is_dirty(if (xfs_sb_version_hassector (&mp->m_sb)) x->lbsize <<= (mp->m_sb.sb_logsectlog -BBSHIFT ); - log.l_dev = mp->m_logdev_targp; - log.l_logBBsize = x->logBBsize; - log.l_logBBstart = x->logBBstart; - log.l_sectBBsize =BTOBB (x->lbsize); - log.l_mp = mp; + log->l_dev = mp->m_logdev_targp; + log->l_logBBsize = x->logBBsize; + log->l_logBBstart = x->logBBstart; + log->l_sectBBsize =BTOBB (x->lbsize); + log->l_mp = mp;if (xfs_sb_version_hassector (&mp->m_sb)) { - log.l_sectbb_log = mp->m_sb.sb_logsectlog -BBSHIFT ; -ASSERT (log.l_sectbb_log <= mp->m_sectbb_log); + log->l_sectbb_log = mp->m_sb.sb_logsectlog -BBSHIFT ; +ASSERT (log->l_sectbb_log <= mp->m_sectbb_log);/* for larger sector sizes, must have v2 or external log */ -ASSERT (log.l_sectbb_log ==0 || - log.l_logBBstart ==0 || +ASSERT (log->l_sectbb_log ==0 || + log->l_logBBstart ==0 ||xfs_sb_version_haslogv2 (&mp->m_sb));ASSERT (mp->m_sb.sb_logsectlog >=BBSHIFT ); } - log.l_sectbb_mask = (1 << log.l_sectbb_log) -1 ; + log->l_sectbb_mask = (1 << log->l_sectbb_log) -1 ; -if ((error =xlog_find_tail (&log, &head_blk, &tail_blk))) { + error =xlog_find_tail (log, &head_blk, &tail_blk); +if (error) {xlog_warn (_ ("%s: cannot find log head/tail " "(xlog_find_tail=%d)\n" ), __func__, error);
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 7/18 xfs_repair: track log state throughout all recovery phases
In reply to Brian Fosterxfs_repair examines and clears the log in phase 2. Phase 2 acquires the log state in local data structures that are lost upon phase exit. v5 filesystems require that the log is formatted with a higher cycle number after the fs is repaired. This requires assessment of the log state to determine whether a reformat is necessary.
Rather than duplicate the log processing code, update phase 2 to populate a globally available log data structure. Add a log pointer to xfs_mount, as exists in kernel space, that repair uses to store a reference to the log that is available to various phases. Note that this patch simply plumbs through the global log data structure and does not change behavior in any way.
--- include/xfs_mount.h | 6 ++++++ repair/phase2.c | 34 +++++++++++++++++++--------------- repair/xfs_repair.c | 8 +++++++- 3 files changed, 32 insertions(+), 16 deletions(-)
include/xfs_mount.h +6 -0
@@ -98,6 +98,12 @@ typedef struct xfs_mount {int qi_dqperchunk; } *m_quotainfo; +/* +* xlog is defined in libxlog and thus is not intialized by libxfs. This +* allows an application to initialize and store a reference to the log +* if warranted. +*/ +struct xlog *m_log; } xfs_mount_t;/*
repair/phase2.c +19 -15
@@ -39,33 +39,33 @@ static void zero_log(xfs_mount_t *mp) {int error; -struct xlog log;xfs_daddr_t head_blk, tail_blk; +struct xlog *log = mp->m_log; -memset (&log,0 ,sizeof (log)); +memset (log,0 ,sizeof (struct xlog )); x.logBBsize =XFS_FSB_TO_BB (mp, mp->m_sb.sb_logblocks); x.logBBstart =XFS_FSB_TO_DADDR (mp, mp->m_sb.sb_logstart); x.lbsize =BBSIZE ;if (xfs_sb_version_hassector (&mp->m_sb)) x.lbsize <<= (mp->m_sb.sb_logsectlog -BBSHIFT ); - log.l_dev = mp->m_logdev_targp; - log.l_logBBsize = x.logBBsize; - log.l_logBBstart = x.logBBstart; - log.l_sectBBsize =BTOBB (x.lbsize); - log.l_mp = mp; + log->l_dev = mp->m_logdev_targp; + log->l_logBBsize = x.logBBsize; + log->l_logBBstart = x.logBBstart; + log->l_sectBBsize =BTOBB (x.lbsize); + log->l_mp = mp;if (xfs_sb_version_hassector (&mp->m_sb)) { - log.l_sectbb_log = mp->m_sb.sb_logsectlog -BBSHIFT ; -ASSERT (log.l_sectbb_log <= mp->m_sectbb_log); + log->l_sectbb_log = mp->m_sb.sb_logsectlog -BBSHIFT ; +ASSERT (log->l_sectbb_log <= mp->m_sectbb_log);/* for larger sector sizes, must have v2 or external log */ -ASSERT (log.l_sectbb_log ==0 || - log.l_logBBstart ==0 || +ASSERT (log->l_sectbb_log ==0 || + log->l_logBBstart ==0 ||xfs_sb_version_haslogv2 (&mp->m_sb));ASSERT (mp->m_sb.sb_logsectlog >=BBSHIFT ); } - log.l_sectbb_mask = (1 << log.l_sectbb_log) -1 ; + log->l_sectbb_mask = (1 << log->l_sectbb_log) -1 ; -if ((error =xlog_find_tail (&log, &head_blk, &tail_blk))) { +if ((error =xlog_find_tail (log, &head_blk, &tail_blk))) {do_warn (_ ("zero_log: cannot find log head/tail " "(xlog_find_tail=%d), zeroing it anyway\n" ), error);
@@ -93,12 +93,16 @@ zero_log(xfs_mount_t *mp) } } -libxfs_log_clear (log.l_dev, -XFS_FSB_TO_DADDR (mp, mp->m_sb.sb_logstart), +libxfs_log_clear (log->l_dev,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,xfs_sb_version_haslogv2 (&mp->m_sb) ?2 :1 , mp->m_sb.sb_logsunit,XLOG_FMT ,XLOG_INIT_CYCLE ); + +/* update the log data structure with new state */ + error =xlog_find_tail (log, &head_blk, &tail_blk); +if (error || head_blk != tail_blk) +do_error (_ ("failed to clear log" )); }/*
repair/xfs_repair.c +7 -1
@@ -539,6 +539,7 @@ main(int argc, char **argv)xfs_dsb_t *dsb;xfs_buf_t *sbp;xfs_mount_t xfs_m; +struct xlog log = {0 };char *msgbuf;struct xfs_sb psb;int rval;
@@ -620,7 +621,11 @@ main(int argc, char **argv) } } -/* prepare the mount structure */ +/* +* Prepare the mount structure. Point the log reference to our local +* copy so it's available to the various phases. The log bits are +* initialized in phase 2. +*/ memset (&xfs_m,0 ,sizeof (xfs_mount_t)); mp =libxfs_mount (&xfs_m, &psb, x.ddev, x.logdev, x.rtdev,0 );
@@ -630,6 +635,7 @@ main(int argc, char **argv) progname);exit (1 ); } + mp->m_log = &log;/* * set XFS-independent status vars from the mount/sb structure
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 8/18 xfs_repair: process the log in no_modify mode
In reply to Brian Fosterxfs_repair does not zero the log in no_modify mode. In doing so, it also skips the function that scans the log, locates the head/tail blocks and sets the current LSN. Now that the log state is used beyond phase 2, the log scan must occur regardless of whether no_modify mode is enabled or not.
Update phase 2 to always execute the log scanning code. Push down the no_modify checks into the log clearing helper such that the log is still not modified in no_modify mode.
--- repair/phase2.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
repair/phase2.c +6 -5
@@ -75,7 +75,7 @@ zero_log(xfs_mount_t *mp)_ ("zero_log: head block %" PRId64" tail block %" PRId64"\n" ), head_blk, tail_blk); } -if (head_blk != tail_blk) { +if (!no_modify && head_blk != tail_blk) {if (zap_log) { do_warn(_( "ALERT: The filesystem has valuable metadata changes in a log which is being\n"
@@ -93,6 +93,9 @@ zero_log(xfs_mount_t *mp) } } +if (no_modify) +return ; + libxfs_log_clear(log->l_dev, 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,
@@ -136,10 +139,8 @@ phase2(do_log (_ ("Phase 2 - using internal log\n" ));/* Zero log if applicable */ -if (!no_modify) { -do_log (_ (" - zero log...\n" )); -zero_log (mp); - } +do_log (_ (" - zero log...\n" )); +zero_log (mp);do_log (_ (" - scan filesystem freespace and inode maps...\n" ));
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 9/18 xfs_repair: format the log with forward cycle number on v5 supers
In reply to Brian Fosterv5 filesystems use the current LSN and the last modified LSN stored within fs metadata to provide correct log recovery ordering. xfs_repair historically clears the log in phase 2. This resets to the current LSN of the filesystem to the initial cycle, as if the fs was just created.
This is problematic because the filesystem LSN is now behind many pre-existing metadata structures on-disk until either the current filesystem LSN catches up or those particular data structures are modified and written out. If a filesystem crash occurs in the meantime, log recovery can incorrectly skip log items and cause filesystem corruption.
Update xfs_repair to check the maximum metadata LSN value against the current log state once the filesystem has been processed. If the maximum LSN exceeds the current LSN with respect to the log, reformat the log with a cycle number that exceeds that of the maximum LSN.
--- repair/xfs_repair.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-)
repair/xfs_repair.c +68 -2
@@ -531,6 +531,63 @@ _("sb realtime summary inode %" PRIu64 " %sinconsistent with calculated value %u } +/* +* v5 superblock metadata track the LSN of last modification and thus require +* that the current LSN is always moving forward. The current LSN is reset if +* the log has been cleared, which puts the log behind parts of the filesystem +* on-disk and can disrupt log recovery. +* +* We have tracked the maximum LSN of every piece of metadata that has been read +* in via the read verifiers. Compare the max LSN with the log and if the log is +* behind, bump the cycle number and reformat the log. +*/ +static void +format_log_max_lsn ( +struct xfs_mount *mp) +{ +struct xlog *log = mp->m_log; +int max_cycle; +int max_block; +int new_cycle; +xfs_daddr_t logstart; +xfs_daddr_t logblocks; +int logversion; + +if (!xfs_sb_version_hascrc (&mp->m_sb)) +return ; + +/* +* If the log is ahead of the highest metadata LSN we've seen, we're +* safe and there's nothing to do. +*/ + max_cycle =CYCLE_LSN (libxfs_max_lsn); + max_block =BLOCK_LSN (libxfs_max_lsn); +if (max_cycle < log->l_curr_cycle || + (max_cycle == log->l_curr_cycle && max_block < log->l_curr_block)) +return ; + +/* +* Going to the next cycle should be sufficient but we bump by a few +* counts to help cover any metadata LSNs we could have missed. +*/ + new_cycle = max_cycle +3 ; + 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 ; + +do_warn (_ ("Maximum metadata LSN (%d:%d) is ahead of log (%d:%d).\n" ), + max_cycle, max_block, log->l_curr_cycle, log->l_curr_block); + +if (no_modify) { +do_warn (_ ("Would format log to cycle %d.\n" ), new_cycle); +return ; + } + +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); +} +int main (int argc,char **argv) {
@@ -896,6 +953,12 @@ _("Warning: project quota information would be cleared.\n"stop_progress_rpt ();if (no_modify) { +/* +* Warn if the current LSN is problematic and the log requires a +* reformat. +*/ +format_log_max_lsn (mp); +do_log (_ ("No modify flag set, skipping filesystem flush and exiting.\n" ));if (verbose)
@@ -931,11 +994,14 @@ _("Note - stripe unit (%d) and width (%d) were copied from a backup superblock.\libxfs_writebuf (sbp,0 );/* -* Done, flush all cached buffers and inodes. +* Done. Flush all cached buffers and inodes first to ensure all +* verifiers are run (where we discover the max metadata LSN), reformat +* the log if necessary and unmount. */ libxfs_bcache_flush (); - +format_log_max_lsn (mp);libxfs_umount (mp); +if (x.rtdev)libxfs_device_close (x.rtdev);if (x.logdev && x.logdev != x.ddev)
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 10/18 xfs_repair: don't clear the log by default
In reply to Brian Fosterxfs_repair currently clears the log regardless of whether it is corrupted, clean or contains data. This is traditionally harmless but now causes log recovery problems on v5 filesystems. v5 filesystems expect a clean log to always have an LSN out ahead of the maximum last modification LSN stamped on any bit of metadata throughout the fs. If this is not the case, repair must reformat the log with a larger cycle number after fs processing is complete.
Given that unconditional log clearing actually introduces a filesystem inconsistency on v5 superblocks (that repair must subsequently recover from) and provides no tangible benefit for v4 filesystems that otherwise have a clean and covered log, it is more appropriate behavior to not clear the log by default.
Update xfs_repair to always and only clear the log when the -L parameter is specified. Retain the existing logic to require -L or otherwise exit if the log appears to contain data. Adopt similar behavior if the log appears to be corrupted.
--- repair/phase2.c | 60 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 20 deletions(-)
repair/phase2.c +40 -20
@@ -36,11 +36,13 @@ int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p) }static void -zero_log (xfs_mount_t *mp) +zero_log ( +struct xfs_mount *mp) { -int error; -xfs_daddr_t head_blk, tail_blk; -struct xlog *log = mp->m_log; +int error; +xfs_daddr_t head_blk; +xfs_daddr_t tail_blk; +struct xlog *log = mp->m_log;memset (log,0 ,sizeof (struct xlog )); x.logBBsize =XFS_FSB_TO_BB (mp, mp->m_sb.sb_logblocks);
@@ -65,10 +67,22 @@ zero_log(xfs_mount_t *mp) } log->l_sectbb_mask = (1 << log->l_sectbb_log) -1 ; -if ((error =xlog_find_tail (log, &head_blk, &tail_blk))) { -do_warn (_ ("zero_log: cannot find log head/tail " -"(xlog_find_tail=%d), zeroing it anyway\n" ), +/* +* Find the log head and tail and alert the user to the situation if the +* log appears corrupted or contains data. In either case, we do not +* proceed past this point unless the user explicitly requests to zap +* the log. +*/ + error =xlog_find_tail (log, &head_blk, &tail_blk); +if (error) { +do_warn ( +_ ("zero_log: cannot find log head/tail (xlog_find_tail=%d)\n" ), error); +if (!no_modify && !zap_log) +do_error (_ ( +"ERROR: The log head and/or tail cannot be discovered. Attempt to mount the\n" +"filesystem to replay the log or use the -L option to destroy the log and\n" +"attempt a repair.\n" )); }else {if (verbose) { do_warn(
@@ -93,19 +107,25 @@ zero_log(xfs_mount_t *mp) } } -if (no_modify) -return ; - -libxfs_log_clear (log->l_dev,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, -xfs_sb_version_haslogv2 (&mp->m_sb) ?2 :1 , - mp->m_sb.sb_logsunit,XLOG_FMT ,XLOG_INIT_CYCLE ); - -/* update the log data structure with new state */ - error =xlog_find_tail (log, &head_blk, &tail_blk); -if (error || head_blk != tail_blk) -do_error (_ ("failed to clear log" )); +/* +* Only clear the log when explicitly requested. Doing so is unnecessary +* unless something is wrong. Further, this resets the current LSN of +* the filesystem and creates more work for repair of v5 superblock +* filesystems. +*/ +if (!no_modify && zap_log) { +libxfs_log_clear (log->l_dev, +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, +xfs_sb_version_haslogv2 (&mp->m_sb) ?2 :1 , + mp->m_sb.sb_logsunit,XLOG_FMT ,XLOG_INIT_CYCLE ); + +/* update the log data structure with new state */ + error =xlog_find_tail (log, &head_blk, &tail_blk); +if (error || head_blk != tail_blk) +do_error (_ ("failed to clear log" )); + } }/*
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 11/18 xfs_repair: seed the max lsn from log state in phase 2
In reply to Brian FosterAt this point, the log state is always available once repair has progressed through phase 2 and the log is only ever zeroed when absolutely necessary. This means that in the common case, repair runs with the log in a non-initialized state. The libxfs max metadata LSN tracking initializes the max LSN to zero, however, which will require updates throughout the repair process even if all metadata LSNs are behind the current LSN.
Since all metadata LSNs that are behind the current LSN are valid, seed the libxfs maximum seen LSN value with the log state from phase 2. This is a minor optimization to minimize global variable updates in the common case where all (or most) metadata LSNs are valid.
--- repair/phase2.c | 7 +++++++ 1 file changed, 7 insertions(+)
repair/phase2.c +7 -0
@@ -126,6 +126,13 @@ zero_log(if (error || head_blk != tail_blk)do_error (_ ("failed to clear log" )); } + +/* +* Finally, seed the max LSN from the current state of the log if this +* is a v5 filesystem. +*/ +if (xfs_sb_version_hascrc (&mp->m_sb)) + libxfs_max_lsn = log->l_last_sync_lsn; }/*
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 12/18 xfs_db: do not reset current lsn from uuid command on v5 supers
In reply to Brian FosterThe xfs_db uuid command modifes the uuid of the filesystem. As part of this process, it is required to clear the log and format it with records that use the new uuid. It currently resets the log to cycle 1, which is not safe for v5 superblocks.
Update the uuid log clearing implementation to bump the current cycle when the log is formatted on v5 superblock filesystems. This ensures that the current LSN remains ahead of metadata LSNs on the subsequent mount. Since the log is checked and cleared across a couple different functions, also add a new global xlog structure, associate it with the preexisting global mount structure and reference it to get and use the current log cycle.
--- db/init.c | 25 ++++++++++++++----------- db/sb.c | 19 +++++++++++++++---- 2 files changed, 29 insertions(+), 15 deletions(-)
db/init.c +14 -11
@@ -17,6 +17,7 @@*/ #include "libxfs.h" +#include "libxlog.h" #include <signal.h> #include "command.h" #include "init.h"
@@ -28,17 +29,18 @@#include "malloc.h" #include "type.h" -static char **cmdline; -static int ncmdline; -char *fsdevice; -int blkbb; -int exitcode; -int expert_mode; -int force; -xfs_mount_t xmount; -xfs_mount_t *mp; -libxfs_init_t x; -xfs_agnumber_t cur_agno =NULLAGNUMBER ; +static char **cmdline; +static int ncmdline; +char *fsdevice; +int blkbb; +int exitcode; +int expert_mode; +int force; +struct xfs_mount xmount; +struct xfs_mount *mp; +struct xlog xlog; +libxfs_init_t x; +xfs_agnumber_t cur_agno =NULLAGNUMBER ;static void usage (void )
@@ -154,6 +156,7 @@ init( progname, fsdevice);exit (1 ); } + mp->m_log = &xlog; blkbb =1 << mp->m_blkbb_log;/*
db/sb.c +15 -4
@@ -229,7 +229,6 @@ int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p)int sb_logcheck (void ) { -struct xlog log;int dirty;if (mp->m_sb.sb_logstart) {
@@ -248,7 +247,7 @@ sb_logcheck(void)libxfs_buftarg_init (mp, x.ddev, x.logdev, x.rtdev); - dirty =xlog_is_dirty (mp, &log, &x,0 ); + dirty =xlog_is_dirty (mp, mp->m_log, &x,0 );if (dirty ==-1 ) {dbprintf (_ ("ERROR: cannot find log head/tail, run xfs_repair\n" ));return 0 ;
@@ -269,20 +268,32 @@ sb_logcheck(void)static int sb_logzero (uuid_t *uuidp) { +int cycle =XLOG_INIT_CYCLE ; +int error; +if (!sb_logcheck ())return 0 ; +/* +* The log must always move forward on v5 superblocks. Bump it to the +* next cycle. +*/ +if (xfs_sb_version_hascrc (&mp->m_sb)) + cycle = mp->m_log->l_curr_cycle +1 ; +dbprintf (_ ("Clearing log and setting UUID\n" )); -if (libxfs_log_clear (mp->m_logdev_targp, + error =libxfs_log_clear (mp->m_logdev_targp,XFS_FSB_TO_DADDR (mp, mp->m_sb.sb_logstart), (xfs_extlen_t )XFS_FSB_TO_BB (mp, mp->m_sb.sb_logblocks), uuidp,xfs_sb_version_haslogv2 (&mp->m_sb) ?2 :1 , - mp->m_sb.sb_logsunit,XLOG_FMT ,XLOG_INIT_CYCLE )) { + mp->m_sb.sb_logsunit,XLOG_FMT , cycle); +if (error) {dbprintf (_ ("ERROR: cannot clear the log\n" ));return 0 ; } +return 1 ; }
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 13/18 db/metadump: bump lsn when log is cleared on v5 supers
In reply to Brian Fosterxfs_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.
--- db/metadump.c | 16 +++++++++++-- db/sb.c | 2 +- include/libxfs.h | 4 ++-- libxfs/rdwr.c | 68 +++++++++++++++++++++++++++++++++++++++-------------- mkfs/xfs_mkfs.c | 2 +- repair/phase2.c | 2 +- repair/xfs_repair.c | 5 ++-- 7 files changed, 72 insertions(+), 27 deletions(-)
db/metadump.c +14 -2
@@ -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 */
db/sb.c +1 -1
@@ -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,
include/libxfs.h +2 -2
@@ -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 *);
libxfs/rdwr.c +50 -18
123 lines not on this page · raw message
mkfs/xfs_mkfs.c +1 -1
@@ -2667,7 +2667,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 );
repair/phase2.c +1 -1
@@ -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,
repair/xfs_repair.c +3 -2
@@ -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
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 14/18 xfs_copy: check for dirty log on non-duplicate copies
In reply to Brian Fosterxfs_copy either copies the log as-is or formats the log of the target(s) based on whether duplicate copy mode is enabled. The target log is formatted when non-duplicate mode is enabled because copies gain a new fs UUID and the new UUID must be stamped into the log.
When non-duplicate mode is enabled, however, xfs_copy does not check whether the source filesystem log is actually clean. If the source log is dirty, the target filesystem is silently created with a clean log and thus ends up in a potentially corrupted state.
Update xfs_copy to check the source log state and fail the copy if in non-duplicate mode and the log is dirty. Encourage the user to mount the filesystem or run xfs_repair to clear the log. Note that the log is scanned unconditionally as opposed to only in non-duplicate mode because v5 superblock log format support requires the current cycle number to format the log correctly.
--- Makefile | 2 +- copy/Makefile | 4 ++-- copy/xfs_copy.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-)
Makefile +1 -1
@@ -81,7 +81,7 @@ growfs: libxcmd io: libxcmd libhandle quota: libxcmd repair: libxlog - +copy: libxlog ifeq ($(HAVE_BUILDDEFS), yes) include $(BUILDRULES)
copy/Makefile +2 -2
@@ -9,8 +9,8 @@ LTCOMMAND = xfs_copy CFILES = xfs_copy.c HFILES = xfs_copy.h -LLDLIBS = $(LIBXFS) $(LIBUUID) $(LIBPTHREAD) $(LIBRT) -LTDEPENDENCIES = $(LIBXFS) +LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBPTHREAD) $(LIBRT) +LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG) LLDFLAGS = -static-libtool-libs default: depend $(LTCOMMAND)
copy/xfs_copy.c +33 -0
@@ -23,6 +23,7 @@#include <signal.h> #include <stdarg.h> #include "xfs_copy.h" +#include "libxlog.h" #define rounddown (x, y) (((x)/(y))*(y))#define uuid_equal (s,d) (platform_uuid_compare((s),(d)) == 0)
@@ -128,6 +129,12 @@ do_message(int flags, int code, const char *fmt, ...)exit (1 ); \ }while (0 ) +/* workaround craziness in the xlog routines */ +int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p) +{ + return 0; +} +void check_errors (void ) {
@@ -522,6 +529,7 @@ main(int argc, char **argv)ag_header_t ag_hdr;xfs_mount_t *mp;xfs_mount_t mbuf; +struct xlog xlog;xfs_buf_t *sbp;xfs_sb_t *sb;xfs_agnumber_t num_ags, agno;
@@ -717,6 +725,31 @@ main(int argc, char **argv)exit (1 ); } + +/* +* Set up the mount pointer to access the log and check whether the log +* is clean. Fail on a dirty or corrupt log in non-duplicate mode +* because the log is formatted as part of the copy and we don't want to +* destroy data. We also need the current log cycle to format v5 +* superblock logs correctly. +*/ +memset (&xlog,0 ,sizeof (struct xlog )); + mp->m_log = &xlog; + c =xlog_is_dirty (mp, mp->m_log, &xargs,0 ); +if (!duplicate) { +if (c ==1 ) { +do_log (_ ( +"Error: source filesystem log is dirty. Mount the filesystem to replay the\n" +"log, unmount and retry xfs_copy.\n" )); +exit (1 ); + }else if (c <0 ) { +do_log (_ ( +"Error: could not determine the log head or tail of the source filesystem.\n" +"Mount the filesystem to replay the log or run xfs_repair.\n" )); +exit (1 ); + } + } + source_blocksize = mp->m_sb.sb_blocksize; source_sectorsize = mp->m_sb.sb_sectsize;
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 15/18 xfs_copy: genericize write helper to facilitate separate log buf
In reply to Brian Fosterxfs_copy uses a fixed write buffer throughout the code for the various targets. This is a global buffer and is assumed to be the write source in the do_write() helper used by the log clearing code.
v5 superblock log formatting will require a larger, independent buffer to format the log. Therefore, update do_write() to accept a write buffer parameter to optionally override the global write buffer. This patch does not change current behavior.
--- copy/xfs_copy.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-)
copy/xfs_copy.c +20 -14
@@ -170,20 +170,26 @@ check_errors(void)* are taken care of when the buffer's read in */ int -do_write (thread_args *args) +do_write ( +thread_args *args, +wbuf *buf) { -int res, error =0 ; +int res; +int error =0 ; -if (target[args->id].position != w_buf.position) { -if (lseek64 (args->fd, w_buf.position,SEEK_SET ) <0 ) { +if (!buf) + buf = &w_buf; + +if (target[args->id].position != buf->position) { +if (lseek64 (args->fd, buf->position,SEEK_SET ) <0 ) { error = target[args->id].err_type =1 ; }else { - target[args->id].position = w_buf.position; + target[args->id].position = buf->position; } } -if ((res =write (target[args->id].fd, w_buf.data, - w_buf.length)) == w_buf.length) { +if ((res =write (target[args->id].fd, buf->data, + buf->length)) == buf->length) { target[args->id].position += res; }else { error =2 ;
@@ -191,7 +197,7 @@ do_write(thread_args *args)if (error) { target[args->id].error = errno; - target[args->id].position = w_buf.position; + target[args->id].position = buf->position; }return error; }
@@ -203,7 +209,7 @@ begin_reader(void *arg)for (;;) {pthread_mutex_lock (&args->wait); -if (do_write (args)) +if (do_write (args,NULL )) goto handle_error;pthread_mutex_lock (&glob_masks.mutex);if (--glob_masks.num_working ==0 )
@@ -1168,7 +1174,7 @@ main(int argc, char **argv)memset (w_buf.data,0 , w_buf.length);while (w_buf.position < end_pos) { -do_write (tcarg); +do_write (tcarg,NULL ); w_buf.position += w_buf.length; } tcarg++;
@@ -1190,7 +1196,7 @@ main(int argc, char **argv)for (j =0 , tcarg = targ; j < num_targets; j++) {sb_update_uuid (sb, &ag_hdr, tcarg); -do_write (tcarg); +do_write (tcarg,NULL ); tcarg++; } }
@@ -1212,7 +1218,7 @@ next_log_chunk(char *p, int offset, void *private)if (buf->length < (int )(p - buf->data) + offset) {/* need to flush this one, then start afresh */ -do_write (buf->owner); +do_write (buf->owner,NULL );memset (buf->data,0 , buf->length);return buf->data; }
@@ -1247,7 +1253,7 @@ write_log_header(int fd, wbuf *buf, xfs_mount_t *mp)xfs_sb_version_haslogv2 (&mp->m_sb) ?2 :1 , mp->m_sb.sb_logsunit,XLOG_FMT ,NULLCOMMITLSN , NULLCOMMITLSN, next_log_chunk, buf); -do_write (buf->owner); +do_write (buf->owner,NULL );return roundup (logstart + offset, buf->length); }
@@ -1272,7 +1278,7 @@ write_log_trailer(int fd, wbuf *buf, xfs_mount_t *mp)read_wbuf (fd, buf, mp); offset = (int )(logend - buf->position);memset (buf->data,0 , offset); -do_write (buf->owner); +do_write (buf->owner,NULL ); }return buf->position;
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 16/18 xfs_copy: store data buf alignment in buf data structure
In reply to Brian FosterThe write buffer data structure stores various characteristics of the write buffer, such as I/O alignment requirements, etc., but does not include the required data buffer alignment.
Data buffer alignment is a required buffer initialization parameter and the v5 log format support code would like to initialize an independent log buffer based on the predetermined alignment constraints encoded into the global write buffer. Update the write buffer data structure to store the provided data alignment value such that it can be accessed throughout the codebase. This patch does not change existing behavior.
--- copy/xfs_copy.c | 1 + copy/xfs_copy.h | 1 + 2 files changed, 2 insertions(+)
copy/xfs_copy.c +1 -0
@@ -352,6 +352,7 @@ wbuf_init(wbuf *buf, int data_size, int data_align, int min_io_size, int id)return NULL ; }ASSERT (min_io_size %BBSIZE ==0 ); + buf->data_align = data_align; buf->min_io_size = min_io_size; buf->size = data_size; buf->id = id;
copy/xfs_copy.h +1 -0
@@ -54,6 +54,7 @@ typedef struct {int id;/* buffer ID */ size_t size;/* size of buffer -- fixed */ size_t min_io_size;/* for direct I/O */ +int data_align;/* data buffer alignment */ xfs_off_t position;/* requested position (bytes) */ size_t length;/* requested length (bytes) */ char *data;/* pointer to data buffer */
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 17/18 xfs_copy: refactor log format code into new helper
In reply to Brian FosterThe xfs_copy log format code is mostly open-coded into the main() function of the application. Support for v5 superblock log formatting will require an alternate mechanism than that utilized for v4 superblocks and older.
As such, refactor the log formatting code into new helper functions. The top-level helper iterates the copy target devices and another helper implements the log format magic. This patch does not change existing behavior.
--- copy/xfs_copy.c | 69 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 24 deletions(-)
copy/xfs_copy.c +45 -24
@@ -62,8 +62,9 @@ pthread_mutex_t mainwait;#define ACTIVE 1#define INACTIVE 2 -xfs_off_t write_log_trailer (int fd,wbuf *w,xfs_mount_t *mp); -xfs_off_t write_log_header (int fd,wbuf *w,xfs_mount_t *mp); +xfs_off_t write_log_trailer (int fd,wbuf *w,xfs_mount_t *mp); +xfs_off_t write_log_header (int fd,wbuf *w,xfs_mount_t *mp); +static void format_logs (struct xfs_mount *);/* general purpose message reporting routine */
@@ -518,7 +519,7 @@ main(int argc, char **argv)int i, j;int howfar =0 ;int open_flags; -xfs_off_t pos, end_pos; +xfs_off_t pos;size_t length;int c;__uint64_t size, sizeb;
@@ -1160,29 +1161,11 @@ main(int argc, char **argv) }if (kids >0 ) { -if (!duplicate) { - +if (!duplicate)/* write a clean log using the specified UUID */ -for (j =0 , tcarg = targ; j < num_targets; j++) { - w_buf.owner = tcarg; - w_buf.length =rounddown (w_buf.size, - w_buf.min_io_size); - pos =write_log_header ( - source_fd, &w_buf, mp); - end_pos =write_log_trailer ( - source_fd, &w_buf, mp); - w_buf.position = pos; -memset (w_buf.data,0 , w_buf.length); - -while (w_buf.position < end_pos) { -do_write (tcarg,NULL ); - w_buf.position += w_buf.length; - } - tcarg++; - } - }else { +format_logs (mp); +else num_ags =1 ; - }/* reread and rewrite superblocks (UUID and in-progress) */ /* [backwards, so inprogress bit only updated when done] */
@@ -1284,3 +1267,41 @@ write_log_trailer(int fd, wbuf *buf, xfs_mount_t *mp)return buf->position; } + +/* +* Clear a log by writing a record at the head, the tail and zeroing everything +* in between. +*/ +static void +clear_log ( +struct xfs_mount *mp, +thread_args *tcarg) +{ +xfs_off_t pos; +xfs_off_t end_pos; + + w_buf.owner = tcarg; + w_buf.length =rounddown (w_buf.size, w_buf.min_io_size); + pos =write_log_header (source_fd, &w_buf, mp); + end_pos =write_log_trailer (source_fd, &w_buf, mp); + w_buf.position = pos; +memset (w_buf.data,0 , w_buf.length); + +while (w_buf.position < end_pos) { +do_write (tcarg,NULL ); + w_buf.position += w_buf.length; + } +} + +static void +format_logs ( +struct xfs_mount *mp) +{ +thread_args *tcarg; +int i; + +for (i =0 , tcarg = targ; i < num_targets; i++) { +clear_log (mp, tcarg); + tcarg++; + } +}
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v3 18/18 xfs_copy: format v5 sb logs correctly
In reply to Brian Fosterxfs_copy formats the target filesystem log in non-duplicate copy mode to stamp the new fs UUID into the log. The current format mechanism resets the current LSN of the target filesystem to cycle 1, which is invalid for v5 superblocks. The current LSN of v5 superblocks must always move forward and remain ahead of metadata LSNs stored in filesystem metadata.
Update the log format helper to detect and use an alternate format mechanism for v5 superblock logs. Allocate an independent log format buffer based on the size of the log and format the buffer with an incremented cycle count using the libxfs log format mechanism.
Note that the new libxfs log format mechanism could be used for both v5 and older superblock formats. The new mechanism requires a new, full log sized buffer allocation as well as doing I/O to the entire log whereas the pre-v5 sb mechanism only writes to the log head and tail. This is due to how xfs_copy uses its own internal buffer data structure rather than libxfs buftarg structures. As such, keep the original mechanism around to avoid potential disruption for non-v5 users. The old mechanism can be removed at some point in the future when the new mechanism is shaken out and v5 filesystems tend to outnumber v4.
--- copy/xfs_copy.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-)
copy/xfs_copy.c +59 -2
@@ -64,7 +64,7 @@ pthread_mutex_t mainwait;xfs_off_t write_log_trailer (int fd,wbuf *w,xfs_mount_t *mp);xfs_off_t write_log_header (int fd,wbuf *w,xfs_mount_t *mp); -static void format_logs (struct xfs_mount *); +static int format_logs (struct xfs_mount *);/* general purpose message reporting routine */
@@ -1293,15 +1293,72 @@ clear_log( } } +/* +* Format the log to a particular cycle number. This is required for version 5 +* superblock filesystems to provide metadata LSN validity guarantees. +*/ static void +format_log ( +struct xfs_mount *mp, +thread_args *tcarg, +wbuf *buf) +{ +int logstart; +int length; +int cycle =XLOG_INIT_CYCLE ; + + buf->owner = tcarg; + buf->length = buf->size; + buf->position =XFS_FSB_TO_DADDR (mp, mp->m_sb.sb_logstart) <<BBSHIFT ; + + logstart =XFS_FSB_TO_BB (mp, mp->m_sb.sb_logstart); + length =XFS_FSB_TO_BB (mp, mp->m_sb.sb_logblocks); + +/* +* Bump the cycle number on v5 superblock filesystems to guarantee that +* all existing metadata LSNs are valid (behind the current LSN) on the +* target fs. +*/ +if (xfs_sb_version_hascrc (&mp->m_sb)) + cycle = mp->m_log->l_curr_cycle +1 ; + +/* +* Format the entire log into the memory buffer and write it out. If the +* write fails, mark the target inactive so the failure is reported. +*/ +libxfs_log_clear (NULL , buf->data, logstart, length, &buf->owner->uuid, +xfs_sb_version_haslogv2 (&mp->m_sb) ?2 :1 , + mp->m_sb.sb_logsunit,XLOG_FMT , cycle); +if (do_write (buf->owner, buf)) + target[tcarg->id].state =INACTIVE ; +} + +static int format_logs (struct xfs_mount *mp) {thread_args *tcarg;int i; +wbuf logbuf; +int logsize; + +if (xfs_sb_version_hascrc (&mp->m_sb)) { + logsize =XFS_FSB_TO_B (mp, mp->m_sb.sb_logblocks); +if (!wbuf_init (&logbuf, logsize, w_buf.data_align, + w_buf.min_io_size, w_buf.id)) +return -ENOMEM ; + }for (i =0 , tcarg = targ; i < num_targets; i++) { -clear_log (mp, tcarg); +if (xfs_sb_version_hascrc (&mp->m_sb)) +format_log (mp, tcarg, &logbuf); +else +clear_log (mp, tcarg); tcarg++; } + +if (xfs_sb_version_hascrc (&mp->m_sb)) +free (logbuf.data); + +return 0 ; }
Signature · 6 lines
2.1.0 _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs