162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2006 Silicon Graphics, Inc.
462306a36Sopenharmony_ci * All Rights Reserved.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "xfs.h"
762306a36Sopenharmony_ci#include "xfs_fs.h"
862306a36Sopenharmony_ci#include "xfs_shared.h"
962306a36Sopenharmony_ci#include "xfs_format.h"
1062306a36Sopenharmony_ci#include "xfs_log_format.h"
1162306a36Sopenharmony_ci#include "xfs_trans_resv.h"
1262306a36Sopenharmony_ci#include "xfs_mount.h"
1362306a36Sopenharmony_ci#include "xfs_inode.h"
1462306a36Sopenharmony_ci#include "xfs_trans.h"
1562306a36Sopenharmony_ci#include "xfs_inode_item.h"
1662306a36Sopenharmony_ci#include "xfs_trace.h"
1762306a36Sopenharmony_ci#include "xfs_trans_priv.h"
1862306a36Sopenharmony_ci#include "xfs_buf_item.h"
1962306a36Sopenharmony_ci#include "xfs_log.h"
2062306a36Sopenharmony_ci#include "xfs_error.h"
2162306a36Sopenharmony_ci#include "xfs_log_priv.h"
2262306a36Sopenharmony_ci#include "xfs_log_recover.h"
2362306a36Sopenharmony_ci#include "xfs_icache.h"
2462306a36Sopenharmony_ci#include "xfs_bmap_btree.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciSTATIC void
2762306a36Sopenharmony_cixlog_recover_inode_ra_pass2(
2862306a36Sopenharmony_ci	struct xlog                     *log,
2962306a36Sopenharmony_ci	struct xlog_recover_item        *item)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) {
3262306a36Sopenharmony_ci		struct xfs_inode_log_format	*ilfp = item->ri_buf[0].i_addr;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci		xlog_buf_readahead(log, ilfp->ilf_blkno, ilfp->ilf_len,
3562306a36Sopenharmony_ci				   &xfs_inode_buf_ra_ops);
3662306a36Sopenharmony_ci	} else {
3762306a36Sopenharmony_ci		struct xfs_inode_log_format_32	*ilfp = item->ri_buf[0].i_addr;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci		xlog_buf_readahead(log, ilfp->ilf_blkno, ilfp->ilf_len,
4062306a36Sopenharmony_ci				   &xfs_inode_buf_ra_ops);
4162306a36Sopenharmony_ci	}
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/*
4562306a36Sopenharmony_ci * Inode fork owner changes
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * If we have been told that we have to reparent the inode fork, it's because an
4862306a36Sopenharmony_ci * extent swap operation on a CRC enabled filesystem has been done and we are
4962306a36Sopenharmony_ci * replaying it. We need to walk the BMBT of the appropriate fork and change the
5062306a36Sopenharmony_ci * owners of it.
5162306a36Sopenharmony_ci *
5262306a36Sopenharmony_ci * The complexity here is that we don't have an inode context to work with, so
5362306a36Sopenharmony_ci * after we've replayed the inode we need to instantiate one.  This is where the
5462306a36Sopenharmony_ci * fun begins.
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci * We are in the middle of log recovery, so we can't run transactions. That
5762306a36Sopenharmony_ci * means we cannot use cache coherent inode instantiation via xfs_iget(), as
5862306a36Sopenharmony_ci * that will result in the corresponding iput() running the inode through
5962306a36Sopenharmony_ci * xfs_inactive(). If we've just replayed an inode core that changes the link
6062306a36Sopenharmony_ci * count to zero (i.e. it's been unlinked), then xfs_inactive() will run
6162306a36Sopenharmony_ci * transactions (bad!).
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci * So, to avoid this, we instantiate an inode directly from the inode core we've
6462306a36Sopenharmony_ci * just recovered. We have the buffer still locked, and all we really need to
6562306a36Sopenharmony_ci * instantiate is the inode core and the forks being modified. We can do this
6662306a36Sopenharmony_ci * manually, then run the inode btree owner change, and then tear down the
6762306a36Sopenharmony_ci * xfs_inode without having to run any transactions at all.
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * Also, because we don't have a transaction context available here but need to
7062306a36Sopenharmony_ci * gather all the buffers we modify for writeback so we pass the buffer_list
7162306a36Sopenharmony_ci * instead for the operation to use.
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ciSTATIC int
7562306a36Sopenharmony_cixfs_recover_inode_owner_change(
7662306a36Sopenharmony_ci	struct xfs_mount	*mp,
7762306a36Sopenharmony_ci	struct xfs_dinode	*dip,
7862306a36Sopenharmony_ci	struct xfs_inode_log_format *in_f,
7962306a36Sopenharmony_ci	struct list_head	*buffer_list)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	struct xfs_inode	*ip;
8262306a36Sopenharmony_ci	int			error;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	ASSERT(in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER));
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	ip = xfs_inode_alloc(mp, in_f->ilf_ino);
8762306a36Sopenharmony_ci	if (!ip)
8862306a36Sopenharmony_ci		return -ENOMEM;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* instantiate the inode */
9162306a36Sopenharmony_ci	ASSERT(dip->di_version >= 3);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	error = xfs_inode_from_disk(ip, dip);
9462306a36Sopenharmony_ci	if (error)
9562306a36Sopenharmony_ci		goto out_free_ip;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (in_f->ilf_fields & XFS_ILOG_DOWNER) {
9862306a36Sopenharmony_ci		ASSERT(in_f->ilf_fields & XFS_ILOG_DBROOT);
9962306a36Sopenharmony_ci		error = xfs_bmbt_change_owner(NULL, ip, XFS_DATA_FORK,
10062306a36Sopenharmony_ci					      ip->i_ino, buffer_list);
10162306a36Sopenharmony_ci		if (error)
10262306a36Sopenharmony_ci			goto out_free_ip;
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (in_f->ilf_fields & XFS_ILOG_AOWNER) {
10662306a36Sopenharmony_ci		ASSERT(in_f->ilf_fields & XFS_ILOG_ABROOT);
10762306a36Sopenharmony_ci		error = xfs_bmbt_change_owner(NULL, ip, XFS_ATTR_FORK,
10862306a36Sopenharmony_ci					      ip->i_ino, buffer_list);
10962306a36Sopenharmony_ci		if (error)
11062306a36Sopenharmony_ci			goto out_free_ip;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ciout_free_ip:
11462306a36Sopenharmony_ci	xfs_inode_free(ip);
11562306a36Sopenharmony_ci	return error;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic inline bool xfs_log_dinode_has_bigtime(const struct xfs_log_dinode *ld)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	return ld->di_version >= 3 &&
12162306a36Sopenharmony_ci	       (ld->di_flags2 & XFS_DIFLAG2_BIGTIME);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/* Convert a log timestamp to an ondisk timestamp. */
12562306a36Sopenharmony_cistatic inline xfs_timestamp_t
12662306a36Sopenharmony_cixfs_log_dinode_to_disk_ts(
12762306a36Sopenharmony_ci	struct xfs_log_dinode		*from,
12862306a36Sopenharmony_ci	const xfs_log_timestamp_t	its)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct xfs_legacy_timestamp	*lts;
13162306a36Sopenharmony_ci	struct xfs_log_legacy_timestamp	*lits;
13262306a36Sopenharmony_ci	xfs_timestamp_t			ts;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (xfs_log_dinode_has_bigtime(from))
13562306a36Sopenharmony_ci		return cpu_to_be64(its);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	lts = (struct xfs_legacy_timestamp *)&ts;
13862306a36Sopenharmony_ci	lits = (struct xfs_log_legacy_timestamp *)&its;
13962306a36Sopenharmony_ci	lts->t_sec = cpu_to_be32(lits->t_sec);
14062306a36Sopenharmony_ci	lts->t_nsec = cpu_to_be32(lits->t_nsec);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	return ts;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic inline bool xfs_log_dinode_has_large_extent_counts(
14662306a36Sopenharmony_ci		const struct xfs_log_dinode *ld)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	return ld->di_version >= 3 &&
14962306a36Sopenharmony_ci	       (ld->di_flags2 & XFS_DIFLAG2_NREXT64);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic inline void
15362306a36Sopenharmony_cixfs_log_dinode_to_disk_iext_counters(
15462306a36Sopenharmony_ci	struct xfs_log_dinode	*from,
15562306a36Sopenharmony_ci	struct xfs_dinode	*to)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	if (xfs_log_dinode_has_large_extent_counts(from)) {
15862306a36Sopenharmony_ci		to->di_big_nextents = cpu_to_be64(from->di_big_nextents);
15962306a36Sopenharmony_ci		to->di_big_anextents = cpu_to_be32(from->di_big_anextents);
16062306a36Sopenharmony_ci		to->di_nrext64_pad = cpu_to_be16(from->di_nrext64_pad);
16162306a36Sopenharmony_ci	} else {
16262306a36Sopenharmony_ci		to->di_nextents = cpu_to_be32(from->di_nextents);
16362306a36Sopenharmony_ci		to->di_anextents = cpu_to_be16(from->di_anextents);
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ciSTATIC void
16962306a36Sopenharmony_cixfs_log_dinode_to_disk(
17062306a36Sopenharmony_ci	struct xfs_log_dinode	*from,
17162306a36Sopenharmony_ci	struct xfs_dinode	*to,
17262306a36Sopenharmony_ci	xfs_lsn_t		lsn)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	to->di_magic = cpu_to_be16(from->di_magic);
17562306a36Sopenharmony_ci	to->di_mode = cpu_to_be16(from->di_mode);
17662306a36Sopenharmony_ci	to->di_version = from->di_version;
17762306a36Sopenharmony_ci	to->di_format = from->di_format;
17862306a36Sopenharmony_ci	to->di_onlink = 0;
17962306a36Sopenharmony_ci	to->di_uid = cpu_to_be32(from->di_uid);
18062306a36Sopenharmony_ci	to->di_gid = cpu_to_be32(from->di_gid);
18162306a36Sopenharmony_ci	to->di_nlink = cpu_to_be32(from->di_nlink);
18262306a36Sopenharmony_ci	to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
18362306a36Sopenharmony_ci	to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	to->di_atime = xfs_log_dinode_to_disk_ts(from, from->di_atime);
18662306a36Sopenharmony_ci	to->di_mtime = xfs_log_dinode_to_disk_ts(from, from->di_mtime);
18762306a36Sopenharmony_ci	to->di_ctime = xfs_log_dinode_to_disk_ts(from, from->di_ctime);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	to->di_size = cpu_to_be64(from->di_size);
19062306a36Sopenharmony_ci	to->di_nblocks = cpu_to_be64(from->di_nblocks);
19162306a36Sopenharmony_ci	to->di_extsize = cpu_to_be32(from->di_extsize);
19262306a36Sopenharmony_ci	to->di_forkoff = from->di_forkoff;
19362306a36Sopenharmony_ci	to->di_aformat = from->di_aformat;
19462306a36Sopenharmony_ci	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
19562306a36Sopenharmony_ci	to->di_dmstate = cpu_to_be16(from->di_dmstate);
19662306a36Sopenharmony_ci	to->di_flags = cpu_to_be16(from->di_flags);
19762306a36Sopenharmony_ci	to->di_gen = cpu_to_be32(from->di_gen);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (from->di_version == 3) {
20062306a36Sopenharmony_ci		to->di_changecount = cpu_to_be64(from->di_changecount);
20162306a36Sopenharmony_ci		to->di_crtime = xfs_log_dinode_to_disk_ts(from,
20262306a36Sopenharmony_ci							  from->di_crtime);
20362306a36Sopenharmony_ci		to->di_flags2 = cpu_to_be64(from->di_flags2);
20462306a36Sopenharmony_ci		to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
20562306a36Sopenharmony_ci		to->di_ino = cpu_to_be64(from->di_ino);
20662306a36Sopenharmony_ci		to->di_lsn = cpu_to_be64(lsn);
20762306a36Sopenharmony_ci		memset(to->di_pad2, 0, sizeof(to->di_pad2));
20862306a36Sopenharmony_ci		uuid_copy(&to->di_uuid, &from->di_uuid);
20962306a36Sopenharmony_ci		to->di_v3_pad = 0;
21062306a36Sopenharmony_ci	} else {
21162306a36Sopenharmony_ci		to->di_flushiter = cpu_to_be16(from->di_flushiter);
21262306a36Sopenharmony_ci		memset(to->di_v2_pad, 0, sizeof(to->di_v2_pad));
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	xfs_log_dinode_to_disk_iext_counters(from, to);
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ciSTATIC int
21962306a36Sopenharmony_cixlog_dinode_verify_extent_counts(
22062306a36Sopenharmony_ci	struct xfs_mount	*mp,
22162306a36Sopenharmony_ci	struct xfs_log_dinode	*ldip)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	xfs_extnum_t		nextents;
22462306a36Sopenharmony_ci	xfs_aextnum_t		anextents;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (xfs_log_dinode_has_large_extent_counts(ldip)) {
22762306a36Sopenharmony_ci		if (!xfs_has_large_extent_counts(mp) ||
22862306a36Sopenharmony_ci		    (ldip->di_nrext64_pad != 0)) {
22962306a36Sopenharmony_ci			XFS_CORRUPTION_ERROR(
23062306a36Sopenharmony_ci				"Bad log dinode large extent count format",
23162306a36Sopenharmony_ci				XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
23262306a36Sopenharmony_ci			xfs_alert(mp,
23362306a36Sopenharmony_ci				"Bad inode 0x%llx, large extent counts %d, padding 0x%x",
23462306a36Sopenharmony_ci				ldip->di_ino, xfs_has_large_extent_counts(mp),
23562306a36Sopenharmony_ci				ldip->di_nrext64_pad);
23662306a36Sopenharmony_ci			return -EFSCORRUPTED;
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		nextents = ldip->di_big_nextents;
24062306a36Sopenharmony_ci		anextents = ldip->di_big_anextents;
24162306a36Sopenharmony_ci	} else {
24262306a36Sopenharmony_ci		if (ldip->di_version == 3 && ldip->di_v3_pad != 0) {
24362306a36Sopenharmony_ci			XFS_CORRUPTION_ERROR(
24462306a36Sopenharmony_ci				"Bad log dinode di_v3_pad",
24562306a36Sopenharmony_ci				XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
24662306a36Sopenharmony_ci			xfs_alert(mp,
24762306a36Sopenharmony_ci				"Bad inode 0x%llx, di_v3_pad 0x%llx",
24862306a36Sopenharmony_ci				ldip->di_ino, ldip->di_v3_pad);
24962306a36Sopenharmony_ci			return -EFSCORRUPTED;
25062306a36Sopenharmony_ci		}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		nextents = ldip->di_nextents;
25362306a36Sopenharmony_ci		anextents = ldip->di_anextents;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (unlikely(nextents + anextents > ldip->di_nblocks)) {
25762306a36Sopenharmony_ci		XFS_CORRUPTION_ERROR("Bad log dinode extent counts",
25862306a36Sopenharmony_ci				XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
25962306a36Sopenharmony_ci		xfs_alert(mp,
26062306a36Sopenharmony_ci			"Bad inode 0x%llx, large extent counts %d, nextents 0x%llx, anextents 0x%x, nblocks 0x%llx",
26162306a36Sopenharmony_ci			ldip->di_ino, xfs_has_large_extent_counts(mp), nextents,
26262306a36Sopenharmony_ci			anextents, ldip->di_nblocks);
26362306a36Sopenharmony_ci		return -EFSCORRUPTED;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return 0;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ciSTATIC int
27062306a36Sopenharmony_cixlog_recover_inode_commit_pass2(
27162306a36Sopenharmony_ci	struct xlog			*log,
27262306a36Sopenharmony_ci	struct list_head		*buffer_list,
27362306a36Sopenharmony_ci	struct xlog_recover_item	*item,
27462306a36Sopenharmony_ci	xfs_lsn_t			current_lsn)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	struct xfs_inode_log_format	*in_f;
27762306a36Sopenharmony_ci	struct xfs_mount		*mp = log->l_mp;
27862306a36Sopenharmony_ci	struct xfs_buf			*bp;
27962306a36Sopenharmony_ci	struct xfs_dinode		*dip;
28062306a36Sopenharmony_ci	int				len;
28162306a36Sopenharmony_ci	char				*src;
28262306a36Sopenharmony_ci	char				*dest;
28362306a36Sopenharmony_ci	int				error;
28462306a36Sopenharmony_ci	int				attr_index;
28562306a36Sopenharmony_ci	uint				fields;
28662306a36Sopenharmony_ci	struct xfs_log_dinode		*ldip;
28762306a36Sopenharmony_ci	uint				isize;
28862306a36Sopenharmony_ci	int				need_free = 0;
28962306a36Sopenharmony_ci	xfs_failaddr_t			fa;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) {
29262306a36Sopenharmony_ci		in_f = item->ri_buf[0].i_addr;
29362306a36Sopenharmony_ci	} else {
29462306a36Sopenharmony_ci		in_f = kmem_alloc(sizeof(struct xfs_inode_log_format), 0);
29562306a36Sopenharmony_ci		need_free = 1;
29662306a36Sopenharmony_ci		error = xfs_inode_item_format_convert(&item->ri_buf[0], in_f);
29762306a36Sopenharmony_ci		if (error)
29862306a36Sopenharmony_ci			goto error;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	/*
30262306a36Sopenharmony_ci	 * Inode buffers can be freed, look out for it,
30362306a36Sopenharmony_ci	 * and do not replay the inode.
30462306a36Sopenharmony_ci	 */
30562306a36Sopenharmony_ci	if (xlog_is_buffer_cancelled(log, in_f->ilf_blkno, in_f->ilf_len)) {
30662306a36Sopenharmony_ci		error = 0;
30762306a36Sopenharmony_ci		trace_xfs_log_recover_inode_cancel(log, in_f);
30862306a36Sopenharmony_ci		goto error;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci	trace_xfs_log_recover_inode_recover(log, in_f);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	error = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len,
31362306a36Sopenharmony_ci			0, &bp, &xfs_inode_buf_ops);
31462306a36Sopenharmony_ci	if (error)
31562306a36Sopenharmony_ci		goto error;
31662306a36Sopenharmony_ci	ASSERT(in_f->ilf_fields & XFS_ILOG_CORE);
31762306a36Sopenharmony_ci	dip = xfs_buf_offset(bp, in_f->ilf_boffset);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/*
32062306a36Sopenharmony_ci	 * Make sure the place we're flushing out to really looks
32162306a36Sopenharmony_ci	 * like an inode!
32262306a36Sopenharmony_ci	 */
32362306a36Sopenharmony_ci	if (XFS_IS_CORRUPT(mp, !xfs_verify_magic16(bp, dip->di_magic))) {
32462306a36Sopenharmony_ci		xfs_alert(mp,
32562306a36Sopenharmony_ci	"%s: Bad inode magic number, dip = "PTR_FMT", dino bp = "PTR_FMT", ino = %lld",
32662306a36Sopenharmony_ci			__func__, dip, bp, in_f->ilf_ino);
32762306a36Sopenharmony_ci		error = -EFSCORRUPTED;
32862306a36Sopenharmony_ci		goto out_release;
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci	ldip = item->ri_buf[1].i_addr;
33162306a36Sopenharmony_ci	if (XFS_IS_CORRUPT(mp, ldip->di_magic != XFS_DINODE_MAGIC)) {
33262306a36Sopenharmony_ci		xfs_alert(mp,
33362306a36Sopenharmony_ci			"%s: Bad inode log record, rec ptr "PTR_FMT", ino %lld",
33462306a36Sopenharmony_ci			__func__, item, in_f->ilf_ino);
33562306a36Sopenharmony_ci		error = -EFSCORRUPTED;
33662306a36Sopenharmony_ci		goto out_release;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/*
34062306a36Sopenharmony_ci	 * If the inode has an LSN in it, recover the inode only if the on-disk
34162306a36Sopenharmony_ci	 * inode's LSN is older than the lsn of the transaction we are
34262306a36Sopenharmony_ci	 * replaying. We can have multiple checkpoints with the same start LSN,
34362306a36Sopenharmony_ci	 * so the current LSN being equal to the on-disk LSN doesn't necessarily
34462306a36Sopenharmony_ci	 * mean that the on-disk inode is more recent than the change being
34562306a36Sopenharmony_ci	 * replayed.
34662306a36Sopenharmony_ci	 *
34762306a36Sopenharmony_ci	 * We must check the current_lsn against the on-disk inode
34862306a36Sopenharmony_ci	 * here because the we can't trust the log dinode to contain a valid LSN
34962306a36Sopenharmony_ci	 * (see comment below before replaying the log dinode for details).
35062306a36Sopenharmony_ci	 *
35162306a36Sopenharmony_ci	 * Note: we still need to replay an owner change even though the inode
35262306a36Sopenharmony_ci	 * is more recent than the transaction as there is no guarantee that all
35362306a36Sopenharmony_ci	 * the btree blocks are more recent than this transaction, too.
35462306a36Sopenharmony_ci	 */
35562306a36Sopenharmony_ci	if (dip->di_version >= 3) {
35662306a36Sopenharmony_ci		xfs_lsn_t	lsn = be64_to_cpu(dip->di_lsn);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci		if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) > 0) {
35962306a36Sopenharmony_ci			trace_xfs_log_recover_inode_skip(log, in_f);
36062306a36Sopenharmony_ci			error = 0;
36162306a36Sopenharmony_ci			goto out_owner_change;
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/*
36662306a36Sopenharmony_ci	 * di_flushiter is only valid for v1/2 inodes. All changes for v3 inodes
36762306a36Sopenharmony_ci	 * are transactional and if ordering is necessary we can determine that
36862306a36Sopenharmony_ci	 * more accurately by the LSN field in the V3 inode core. Don't trust
36962306a36Sopenharmony_ci	 * the inode versions we might be changing them here - use the
37062306a36Sopenharmony_ci	 * superblock flag to determine whether we need to look at di_flushiter
37162306a36Sopenharmony_ci	 * to skip replay when the on disk inode is newer than the log one
37262306a36Sopenharmony_ci	 */
37362306a36Sopenharmony_ci	if (!xfs_has_v3inodes(mp)) {
37462306a36Sopenharmony_ci		if (ldip->di_flushiter < be16_to_cpu(dip->di_flushiter)) {
37562306a36Sopenharmony_ci			/*
37662306a36Sopenharmony_ci			 * Deal with the wrap case, DI_MAX_FLUSH is less
37762306a36Sopenharmony_ci			 * than smaller numbers
37862306a36Sopenharmony_ci			 */
37962306a36Sopenharmony_ci			if (be16_to_cpu(dip->di_flushiter) == DI_MAX_FLUSH &&
38062306a36Sopenharmony_ci			    ldip->di_flushiter < (DI_MAX_FLUSH >> 1)) {
38162306a36Sopenharmony_ci				/* do nothing */
38262306a36Sopenharmony_ci			} else {
38362306a36Sopenharmony_ci				trace_xfs_log_recover_inode_skip(log, in_f);
38462306a36Sopenharmony_ci				error = 0;
38562306a36Sopenharmony_ci				goto out_release;
38662306a36Sopenharmony_ci			}
38762306a36Sopenharmony_ci		}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		/* Take the opportunity to reset the flush iteration count */
39062306a36Sopenharmony_ci		ldip->di_flushiter = 0;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (unlikely(S_ISREG(ldip->di_mode))) {
39562306a36Sopenharmony_ci		if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) &&
39662306a36Sopenharmony_ci		    (ldip->di_format != XFS_DINODE_FMT_BTREE)) {
39762306a36Sopenharmony_ci			XFS_CORRUPTION_ERROR(
39862306a36Sopenharmony_ci				"Bad log dinode data fork format for regular file",
39962306a36Sopenharmony_ci				XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
40062306a36Sopenharmony_ci			xfs_alert(mp,
40162306a36Sopenharmony_ci				"Bad inode 0x%llx, data fork format 0x%x",
40262306a36Sopenharmony_ci				in_f->ilf_ino, ldip->di_format);
40362306a36Sopenharmony_ci			error = -EFSCORRUPTED;
40462306a36Sopenharmony_ci			goto out_release;
40562306a36Sopenharmony_ci		}
40662306a36Sopenharmony_ci	} else if (unlikely(S_ISDIR(ldip->di_mode))) {
40762306a36Sopenharmony_ci		if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) &&
40862306a36Sopenharmony_ci		    (ldip->di_format != XFS_DINODE_FMT_BTREE) &&
40962306a36Sopenharmony_ci		    (ldip->di_format != XFS_DINODE_FMT_LOCAL)) {
41062306a36Sopenharmony_ci			XFS_CORRUPTION_ERROR(
41162306a36Sopenharmony_ci				"Bad log dinode data fork format for directory",
41262306a36Sopenharmony_ci				XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
41362306a36Sopenharmony_ci			xfs_alert(mp,
41462306a36Sopenharmony_ci				"Bad inode 0x%llx, data fork format 0x%x",
41562306a36Sopenharmony_ci				in_f->ilf_ino, ldip->di_format);
41662306a36Sopenharmony_ci			error = -EFSCORRUPTED;
41762306a36Sopenharmony_ci			goto out_release;
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	error = xlog_dinode_verify_extent_counts(mp, ldip);
42262306a36Sopenharmony_ci	if (error)
42362306a36Sopenharmony_ci		goto out_release;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	if (unlikely(ldip->di_forkoff > mp->m_sb.sb_inodesize)) {
42662306a36Sopenharmony_ci		XFS_CORRUPTION_ERROR("Bad log dinode fork offset",
42762306a36Sopenharmony_ci				XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
42862306a36Sopenharmony_ci		xfs_alert(mp,
42962306a36Sopenharmony_ci			"Bad inode 0x%llx, di_forkoff 0x%x",
43062306a36Sopenharmony_ci			in_f->ilf_ino, ldip->di_forkoff);
43162306a36Sopenharmony_ci		error = -EFSCORRUPTED;
43262306a36Sopenharmony_ci		goto out_release;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci	isize = xfs_log_dinode_size(mp);
43562306a36Sopenharmony_ci	if (unlikely(item->ri_buf[1].i_len > isize)) {
43662306a36Sopenharmony_ci		XFS_CORRUPTION_ERROR("Bad log dinode size", XFS_ERRLEVEL_LOW,
43762306a36Sopenharmony_ci				     mp, ldip, sizeof(*ldip));
43862306a36Sopenharmony_ci		xfs_alert(mp,
43962306a36Sopenharmony_ci			"Bad inode 0x%llx log dinode size 0x%x",
44062306a36Sopenharmony_ci			in_f->ilf_ino, item->ri_buf[1].i_len);
44162306a36Sopenharmony_ci		error = -EFSCORRUPTED;
44262306a36Sopenharmony_ci		goto out_release;
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/*
44662306a36Sopenharmony_ci	 * Recover the log dinode inode into the on disk inode.
44762306a36Sopenharmony_ci	 *
44862306a36Sopenharmony_ci	 * The LSN in the log dinode is garbage - it can be zero or reflect
44962306a36Sopenharmony_ci	 * stale in-memory runtime state that isn't coherent with the changes
45062306a36Sopenharmony_ci	 * logged in this transaction or the changes written to the on-disk
45162306a36Sopenharmony_ci	 * inode.  Hence we write the current lSN into the inode because that
45262306a36Sopenharmony_ci	 * matches what xfs_iflush() would write inode the inode when flushing
45362306a36Sopenharmony_ci	 * the changes in this transaction.
45462306a36Sopenharmony_ci	 */
45562306a36Sopenharmony_ci	xfs_log_dinode_to_disk(ldip, dip, current_lsn);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	fields = in_f->ilf_fields;
45862306a36Sopenharmony_ci	if (fields & XFS_ILOG_DEV)
45962306a36Sopenharmony_ci		xfs_dinode_put_rdev(dip, in_f->ilf_u.ilfu_rdev);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (in_f->ilf_size == 2)
46262306a36Sopenharmony_ci		goto out_owner_change;
46362306a36Sopenharmony_ci	len = item->ri_buf[2].i_len;
46462306a36Sopenharmony_ci	src = item->ri_buf[2].i_addr;
46562306a36Sopenharmony_ci	ASSERT(in_f->ilf_size <= 4);
46662306a36Sopenharmony_ci	ASSERT((in_f->ilf_size == 3) || (fields & XFS_ILOG_AFORK));
46762306a36Sopenharmony_ci	ASSERT(!(fields & XFS_ILOG_DFORK) ||
46862306a36Sopenharmony_ci	       (len == xlog_calc_iovec_len(in_f->ilf_dsize)));
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	switch (fields & XFS_ILOG_DFORK) {
47162306a36Sopenharmony_ci	case XFS_ILOG_DDATA:
47262306a36Sopenharmony_ci	case XFS_ILOG_DEXT:
47362306a36Sopenharmony_ci		memcpy(XFS_DFORK_DPTR(dip), src, len);
47462306a36Sopenharmony_ci		break;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	case XFS_ILOG_DBROOT:
47762306a36Sopenharmony_ci		xfs_bmbt_to_bmdr(mp, (struct xfs_btree_block *)src, len,
47862306a36Sopenharmony_ci				 (struct xfs_bmdr_block *)XFS_DFORK_DPTR(dip),
47962306a36Sopenharmony_ci				 XFS_DFORK_DSIZE(dip, mp));
48062306a36Sopenharmony_ci		break;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	default:
48362306a36Sopenharmony_ci		/*
48462306a36Sopenharmony_ci		 * There are no data fork flags set.
48562306a36Sopenharmony_ci		 */
48662306a36Sopenharmony_ci		ASSERT((fields & XFS_ILOG_DFORK) == 0);
48762306a36Sopenharmony_ci		break;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/*
49162306a36Sopenharmony_ci	 * If we logged any attribute data, recover it.  There may or
49262306a36Sopenharmony_ci	 * may not have been any other non-core data logged in this
49362306a36Sopenharmony_ci	 * transaction.
49462306a36Sopenharmony_ci	 */
49562306a36Sopenharmony_ci	if (in_f->ilf_fields & XFS_ILOG_AFORK) {
49662306a36Sopenharmony_ci		if (in_f->ilf_fields & XFS_ILOG_DFORK) {
49762306a36Sopenharmony_ci			attr_index = 3;
49862306a36Sopenharmony_ci		} else {
49962306a36Sopenharmony_ci			attr_index = 2;
50062306a36Sopenharmony_ci		}
50162306a36Sopenharmony_ci		len = item->ri_buf[attr_index].i_len;
50262306a36Sopenharmony_ci		src = item->ri_buf[attr_index].i_addr;
50362306a36Sopenharmony_ci		ASSERT(len == xlog_calc_iovec_len(in_f->ilf_asize));
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci		switch (in_f->ilf_fields & XFS_ILOG_AFORK) {
50662306a36Sopenharmony_ci		case XFS_ILOG_ADATA:
50762306a36Sopenharmony_ci		case XFS_ILOG_AEXT:
50862306a36Sopenharmony_ci			dest = XFS_DFORK_APTR(dip);
50962306a36Sopenharmony_ci			ASSERT(len <= XFS_DFORK_ASIZE(dip, mp));
51062306a36Sopenharmony_ci			memcpy(dest, src, len);
51162306a36Sopenharmony_ci			break;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		case XFS_ILOG_ABROOT:
51462306a36Sopenharmony_ci			dest = XFS_DFORK_APTR(dip);
51562306a36Sopenharmony_ci			xfs_bmbt_to_bmdr(mp, (struct xfs_btree_block *)src,
51662306a36Sopenharmony_ci					 len, (struct xfs_bmdr_block *)dest,
51762306a36Sopenharmony_ci					 XFS_DFORK_ASIZE(dip, mp));
51862306a36Sopenharmony_ci			break;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		default:
52162306a36Sopenharmony_ci			xfs_warn(log->l_mp, "%s: Invalid flag", __func__);
52262306a36Sopenharmony_ci			ASSERT(0);
52362306a36Sopenharmony_ci			error = -EFSCORRUPTED;
52462306a36Sopenharmony_ci			goto out_release;
52562306a36Sopenharmony_ci		}
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ciout_owner_change:
52962306a36Sopenharmony_ci	/* Recover the swapext owner change unless inode has been deleted */
53062306a36Sopenharmony_ci	if ((in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER)) &&
53162306a36Sopenharmony_ci	    (dip->di_mode != 0))
53262306a36Sopenharmony_ci		error = xfs_recover_inode_owner_change(mp, dip, in_f,
53362306a36Sopenharmony_ci						       buffer_list);
53462306a36Sopenharmony_ci	/* re-generate the checksum and validate the recovered inode. */
53562306a36Sopenharmony_ci	xfs_dinode_calc_crc(log->l_mp, dip);
53662306a36Sopenharmony_ci	fa = xfs_dinode_verify(log->l_mp, in_f->ilf_ino, dip);
53762306a36Sopenharmony_ci	if (fa) {
53862306a36Sopenharmony_ci		XFS_CORRUPTION_ERROR(
53962306a36Sopenharmony_ci			"Bad dinode after recovery",
54062306a36Sopenharmony_ci				XFS_ERRLEVEL_LOW, mp, dip, sizeof(*dip));
54162306a36Sopenharmony_ci		xfs_alert(mp,
54262306a36Sopenharmony_ci			"Metadata corruption detected at %pS, inode 0x%llx",
54362306a36Sopenharmony_ci			fa, in_f->ilf_ino);
54462306a36Sopenharmony_ci		error = -EFSCORRUPTED;
54562306a36Sopenharmony_ci		goto out_release;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	ASSERT(bp->b_mount == mp);
54962306a36Sopenharmony_ci	bp->b_flags |= _XBF_LOGRECOVERY;
55062306a36Sopenharmony_ci	xfs_buf_delwri_queue(bp, buffer_list);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ciout_release:
55362306a36Sopenharmony_ci	xfs_buf_relse(bp);
55462306a36Sopenharmony_cierror:
55562306a36Sopenharmony_ci	if (need_free)
55662306a36Sopenharmony_ci		kmem_free(in_f);
55762306a36Sopenharmony_ci	return error;
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ciconst struct xlog_recover_item_ops xlog_inode_item_ops = {
56162306a36Sopenharmony_ci	.item_type		= XFS_LI_INODE,
56262306a36Sopenharmony_ci	.ra_pass2		= xlog_recover_inode_ra_pass2,
56362306a36Sopenharmony_ci	.commit_pass2		= xlog_recover_inode_commit_pass2,
56462306a36Sopenharmony_ci};
565