Merge branch 'xfs-logging-fixes' into for-next

This commit is contained in:
Dave Chinner 2015-10-12 18:37:58 +11:00
Родитель 9e92054e8e 91f9f5fe1e
Коммит 316433beda
18 изменённых файлов: 210 добавлений и 26 удалений

Просмотреть файл

@ -482,7 +482,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
@ -2259,9 +2261,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)) &&

Просмотреть файл

@ -41,6 +41,7 @@
#include "xfs_buf_item.h"
#include "xfs_cksum.h"
#include "xfs_dir2.h"
#include "xfs_log.h"
/*
@ -266,6 +267,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;

Просмотреть файл

@ -948,14 +948,16 @@ xfs_bmap_local_to_extents(
bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
/*
* Initialise the block and copy the data
* Initialize the block, copy the data and log the remote buffer.
*
* Note: init_fn must set the buffer log item type correctly!
* The callout is responsible for logging because the remote format
* might differ from the local format and thus we don't know how much to
* log here. Note that init_fn must also set the buffer log item type
* correctly.
*/
init_fn(tp, bp, ip, ifp);
/* account for the change in fork size and log everything */
xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
/* account for the change in fork size */
xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
xfs_bmap_local_to_extents_empty(ip, whichfork);
flags |= XFS_ILOG_CORE;

Просмотреть файл

@ -32,6 +32,7 @@
#include "xfs_trace.h"
#include "xfs_cksum.h"
#include "xfs_alloc.h"
#include "xfs_log.h"
/*
* Cursor allocation zone.
@ -243,8 +244,14 @@ bool
xfs_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(&mp->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;
}
@ -275,8 +282,14 @@ bool
xfs_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(&mp->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;
}

Просмотреть файл

@ -39,6 +39,7 @@
#include "xfs_trace.h"
#include "xfs_cksum.h"
#include "xfs_buf_item.h"
#include "xfs_log.h"
/*
* xfs_da_btree.c
@ -150,6 +151,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;
@ -322,6 +325,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);

Просмотреть файл

@ -34,6 +34,7 @@
#include "xfs_error.h"
#include "xfs_trace.h"
#include "xfs_cksum.h"
#include "xfs_log.h"
/*
* Local function prototypes.
@ -71,6 +72,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;

Просмотреть файл

@ -31,6 +31,7 @@
#include "xfs_trans.h"
#include "xfs_buf_item.h"
#include "xfs_cksum.h"
#include "xfs_log.h"
/*
* Check the consistency of the data block.
@ -224,6 +225,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;

Просмотреть файл

@ -33,6 +33,7 @@
#include "xfs_trans.h"
#include "xfs_buf_item.h"
#include "xfs_cksum.h"
#include "xfs_log.h"
/*
* Local function declarations.
@ -164,6 +165,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;

Просмотреть файл

@ -33,6 +33,7 @@
#include "xfs_trans.h"
#include "xfs_buf_item.h"
#include "xfs_cksum.h"
#include "xfs_log.h"
/*
* Function declarations.
@ -97,6 +98,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;

Просмотреть файл

@ -38,6 +38,7 @@
#include "xfs_icreate_item.h"
#include "xfs_icache.h"
#include "xfs_trace.h"
#include "xfs_log.h"
/*
@ -2500,9 +2501,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.
*/

Просмотреть файл

@ -35,6 +35,7 @@
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
#include "xfs_log.h"
/*
* Physical superblock buffer manipulations. Shared with libxfs in userspace.
@ -163,6 +164,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)) {

Просмотреть файл

@ -31,6 +31,7 @@
#include "xfs_cksum.h"
#include "xfs_trans.h"
#include "xfs_buf_item.h"
#include "xfs_log.h"
/*
@ -60,6 +61,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);
@ -116,6 +118,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;
}
@ -183,6 +187,7 @@ xfs_symlink_local_to_remote(
if (!xfs_sb_version_hascrc(&mp->m_sb)) {
bp->b_ops = NULL;
memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
return;
}
@ -198,4 +203,6 @@ xfs_symlink_local_to_remote(
buf = bp->b_addr;
buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
ifp->if_bytes - 1);
}

Просмотреть файл

@ -1027,7 +1027,7 @@ xfs_alloc_file_space(
xfs_bmap_init(&free_list, &firstfsb);
error = xfs_bmapi_write(tp, ip, startoffset_fsb,
allocatesize_fsb, alloc_type, &firstfsb,
0, imapp, &nimaps, &free_list);
resblks, imapp, &nimaps, &free_list);
if (error) {
goto error0;
}

Просмотреть файл

@ -202,8 +202,8 @@ xfs_iomap_write_direct(
xfs_bmap_init(&free_list, &firstfsb);
nimaps = 1;
error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
XFS_BMAPI_PREALLOC, &firstfsb, 0,
imap, &nimaps, &free_list);
XFS_BMAPI_PREALLOC, &firstfsb, resblks, imap,
&nimaps, &free_list);
if (error)
goto out_bmap_cancel;
@ -750,9 +750,9 @@ xfs_iomap_write_allocate(
* pointer that the caller gave to us.
*/
error = xfs_bmapi_write(tp, ip, map_start_fsb,
count_fsb, 0,
&first_block, 1,
imap, &nimaps, &free_list);
count_fsb, 0, &first_block,
nres, imap, &nimaps,
&free_list);
if (error)
goto trans_cancel;
@ -866,8 +866,8 @@ xfs_iomap_write_unwritten(
xfs_bmap_init(&free_list, &firstfsb);
nimaps = 1;
error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
XFS_BMAPI_CONVERT, &firstfsb,
1, &imap, &nimaps, &free_list);
XFS_BMAPI_CONVERT, &firstfsb, resblks,
&imap, &nimaps, &free_list);
if (error)
goto error_on_bmapi_transaction;

Просмотреть файл

@ -2422,11 +2422,20 @@ xlog_write(
&partial_copy_len);
xlog_verify_dest_ptr(log, ptr);
/* copy region */
/*
* Copy region.
*
* Unmount records just log an opheader, so can have
* empty payloads with no data region to copy. Hence we
* only copy the payload if the vector says it has data
* to copy.
*/
ASSERT(copy_len >= 0);
memcpy(ptr, reg->i_addr + copy_off, copy_len);
xlog_write_adv_cnt(&ptr, &len, &log_offset, copy_len);
if (copy_len > 0) {
memcpy(ptr, reg->i_addr + copy_off, copy_len);
xlog_write_adv_cnt(&ptr, &len, &log_offset,
copy_len);
}
copy_len += start_rec_copy + sizeof(xlog_op_header_t);
record_cnt++;
data_cnt += contwr ? copy_len : 0;
@ -3165,11 +3174,19 @@ xlog_state_switch_iclogs(
}
if (log->l_curr_block >= log->l_logBBsize) {
/*
* Rewind the current block before the cycle is bumped to make
* sure that the combined LSN never transiently moves forward
* when the log wraps to the next cycle. This is to support the
* unlocked sample of these fields from xlog_valid_lsn(). Most
* other cases should acquire l_icloglock.
*/
log->l_curr_block -= log->l_logBBsize;
ASSERT(log->l_curr_block >= 0);
smp_wmb();
log->l_curr_cycle++;
if (log->l_curr_cycle == XLOG_HEADER_MAGIC_NUM)
log->l_curr_cycle++;
log->l_curr_block -= log->l_logBBsize;
ASSERT(log->l_curr_block >= 0);
}
ASSERT(iclog == log->l_iclog);
log->l_iclog = iclog->ic_next;
@ -4023,3 +4040,45 @@ xlog_iclogs_empty(
return 1;
}
/*
* Verify that an LSN stamped into a piece of metadata is valid. This is
* intended for use in read verifiers on v5 superblocks.
*/
bool
xfs_log_check_lsn(
struct xfs_mount *mp,
xfs_lsn_t lsn)
{
struct xlog *log = mp->m_log;
bool valid;
/*
* norecovery mode skips mount-time log processing and unconditionally
* resets the in-core LSN. We can't validate in this mode, but
* modifications are not allowed anyways so just return true.
*/
if (mp->m_flags & XFS_MOUNT_NORECOVERY)
return true;
/*
* Some metadata LSNs are initialized to NULL (e.g., the agfl). This is
* handled by recovery and thus safe to ignore here.
*/
if (lsn == NULLCOMMITLSN)
return true;
valid = xlog_valid_lsn(mp->m_log, lsn);
/* warn the user about what's gone wrong before verifier failure */
if (!valid) {
spin_lock(&log->l_icloglock);
xfs_warn(mp,
"Corruption warning: Metadata has LSN (%d:%d) ahead of current LSN (%d:%d). "
"Please unmount and run xfs_repair (>= v4.3) to resolve.",
CYCLE_LSN(lsn), BLOCK_LSN(lsn),
log->l_curr_cycle, log->l_curr_block);
spin_unlock(&log->l_icloglock);
}
return valid;
}

Просмотреть файл

@ -181,5 +181,6 @@ bool xfs_log_item_in_current_chkpt(struct xfs_log_item *lip);
void xfs_log_work_queue(struct xfs_mount *mp);
void xfs_log_worker(struct work_struct *work);
void xfs_log_quiesce(struct xfs_mount *mp);
bool xfs_log_check_lsn(struct xfs_mount *, xfs_lsn_t);
#endif /* __XFS_LOG_H__ */

Просмотреть файл

@ -560,4 +560,55 @@ static inline void xlog_wait(wait_queue_head_t *wq, spinlock_t *lock)
remove_wait_queue(wq, &wait);
}
/*
* The LSN is valid so long as it is behind the current LSN. If it isn't, this
* means that the next log record that includes this metadata could have a
* smaller LSN. In turn, this means that the modification in the log would not
* replay.
*/
static inline bool
xlog_valid_lsn(
struct xlog *log,
xfs_lsn_t lsn)
{
int cur_cycle;
int cur_block;
bool valid = true;
/*
* First, sample the current lsn without locking to avoid added
* contention from metadata I/O. The current cycle and block are updated
* (in xlog_state_switch_iclogs()) and read here in a particular order
* to avoid false negatives (e.g., thinking the metadata LSN is valid
* when it is not).
*
* The current block is always rewound before the cycle is bumped in
* xlog_state_switch_iclogs() to ensure the current LSN is never seen in
* a transiently forward state. Instead, we can see the LSN in a
* transiently behind state if we happen to race with a cycle wrap.
*/
cur_cycle = ACCESS_ONCE(log->l_curr_cycle);
smp_rmb();
cur_block = ACCESS_ONCE(log->l_curr_block);
if ((CYCLE_LSN(lsn) > cur_cycle) ||
(CYCLE_LSN(lsn) == cur_cycle && BLOCK_LSN(lsn) > cur_block)) {
/*
* If the metadata LSN appears invalid, it's possible the check
* above raced with a wrap to the next log cycle. Grab the lock
* to check for sure.
*/
spin_lock(&log->l_icloglock);
cur_cycle = log->l_curr_cycle;
cur_block = log->l_curr_block;
spin_unlock(&log->l_icloglock);
if ((CYCLE_LSN(lsn) > cur_cycle) ||
(CYCLE_LSN(lsn) == cur_cycle && BLOCK_LSN(lsn) > cur_block))
valid = false;
}
return valid;
}
#endif /* __XFS_LOG_PRIV_H__ */

Просмотреть файл

@ -4609,9 +4609,19 @@ xlog_recover(
int error;
/* find the tail of the log */
if ((error = xlog_find_tail(log, &head_blk, &tail_blk)))
error = xlog_find_tail(log, &head_blk, &tail_blk);
if (error)
return error;
/*
* The superblock was read before the log was available and thus the LSN
* could not be verified. Check the superblock LSN against the current
* LSN now that it's known.
*/
if (xfs_sb_version_hascrc(&log->l_mp->m_sb) &&
!xfs_log_check_lsn(log->l_mp, log->l_mp->m_sb.sb_lsn))
return -EINVAL;
if (tail_blk != head_blk) {
/* There used to be a comment here:
*