18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/fs.h>
38c2ecf20Sopenharmony_ci#include <linux/random.h>
48c2ecf20Sopenharmony_ci#include <linux/buffer_head.h>
58c2ecf20Sopenharmony_ci#include <linux/utsname.h>
68c2ecf20Sopenharmony_ci#include <linux/kthread.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "ext4.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/* Checksumming functions */
118c2ecf20Sopenharmony_cistatic __le32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
148c2ecf20Sopenharmony_ci	int offset = offsetof(struct mmp_struct, mmp_checksum);
158c2ecf20Sopenharmony_ci	__u32 csum;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci	csum = ext4_chksum(sbi, sbi->s_csum_seed, (char *)mmp, offset);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	return cpu_to_le32(csum);
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic int ext4_mmp_csum_verify(struct super_block *sb, struct mmp_struct *mmp)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	if (!ext4_has_metadata_csum(sb))
258c2ecf20Sopenharmony_ci		return 1;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	return mmp->mmp_checksum == ext4_mmp_csum(sb, mmp);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic void ext4_mmp_csum_set(struct super_block *sb, struct mmp_struct *mmp)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	if (!ext4_has_metadata_csum(sb))
338c2ecf20Sopenharmony_ci		return;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	mmp->mmp_checksum = ext4_mmp_csum(sb, mmp);
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/*
398c2ecf20Sopenharmony_ci * Write the MMP block using REQ_SYNC to try to get the block on-disk
408c2ecf20Sopenharmony_ci * faster.
418c2ecf20Sopenharmony_ci */
428c2ecf20Sopenharmony_cistatic int write_mmp_block_thawed(struct super_block *sb,
438c2ecf20Sopenharmony_ci				  struct buffer_head *bh)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct mmp_struct *mmp = (struct mmp_struct *)(bh->b_data);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	ext4_mmp_csum_set(sb, mmp);
488c2ecf20Sopenharmony_ci	lock_buffer(bh);
498c2ecf20Sopenharmony_ci	bh->b_end_io = end_buffer_write_sync;
508c2ecf20Sopenharmony_ci	get_bh(bh);
518c2ecf20Sopenharmony_ci	submit_bh(REQ_OP_WRITE, REQ_SYNC | REQ_META | REQ_PRIO, bh);
528c2ecf20Sopenharmony_ci	wait_on_buffer(bh);
538c2ecf20Sopenharmony_ci	if (unlikely(!buffer_uptodate(bh)))
548c2ecf20Sopenharmony_ci		return -EIO;
558c2ecf20Sopenharmony_ci	return 0;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int write_mmp_block(struct super_block *sb, struct buffer_head *bh)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	int err;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/*
638c2ecf20Sopenharmony_ci	 * We protect against freezing so that we don't create dirty buffers
648c2ecf20Sopenharmony_ci	 * on frozen filesystem.
658c2ecf20Sopenharmony_ci	 */
668c2ecf20Sopenharmony_ci	sb_start_write(sb);
678c2ecf20Sopenharmony_ci	err = write_mmp_block_thawed(sb, bh);
688c2ecf20Sopenharmony_ci	sb_end_write(sb);
698c2ecf20Sopenharmony_ci	return err;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/*
738c2ecf20Sopenharmony_ci * Read the MMP block. It _must_ be read from disk and hence we clear the
748c2ecf20Sopenharmony_ci * uptodate flag on the buffer.
758c2ecf20Sopenharmony_ci */
768c2ecf20Sopenharmony_cistatic int read_mmp_block(struct super_block *sb, struct buffer_head **bh,
778c2ecf20Sopenharmony_ci			  ext4_fsblk_t mmp_block)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct mmp_struct *mmp;
808c2ecf20Sopenharmony_ci	int ret;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (*bh)
838c2ecf20Sopenharmony_ci		clear_buffer_uptodate(*bh);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* This would be sb_bread(sb, mmp_block), except we need to be sure
868c2ecf20Sopenharmony_ci	 * that the MD RAID device cache has been bypassed, and that the read
878c2ecf20Sopenharmony_ci	 * is not blocked in the elevator. */
888c2ecf20Sopenharmony_ci	if (!*bh) {
898c2ecf20Sopenharmony_ci		*bh = sb_getblk(sb, mmp_block);
908c2ecf20Sopenharmony_ci		if (!*bh) {
918c2ecf20Sopenharmony_ci			ret = -ENOMEM;
928c2ecf20Sopenharmony_ci			goto warn_exit;
938c2ecf20Sopenharmony_ci		}
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	lock_buffer(*bh);
978c2ecf20Sopenharmony_ci	ret = ext4_read_bh(*bh, REQ_META | REQ_PRIO, NULL);
988c2ecf20Sopenharmony_ci	if (ret)
998c2ecf20Sopenharmony_ci		goto warn_exit;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	mmp = (struct mmp_struct *)((*bh)->b_data);
1028c2ecf20Sopenharmony_ci	if (le32_to_cpu(mmp->mmp_magic) != EXT4_MMP_MAGIC) {
1038c2ecf20Sopenharmony_ci		ret = -EFSCORRUPTED;
1048c2ecf20Sopenharmony_ci		goto warn_exit;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci	if (!ext4_mmp_csum_verify(sb, mmp)) {
1078c2ecf20Sopenharmony_ci		ret = -EFSBADCRC;
1088c2ecf20Sopenharmony_ci		goto warn_exit;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ciwarn_exit:
1128c2ecf20Sopenharmony_ci	brelse(*bh);
1138c2ecf20Sopenharmony_ci	*bh = NULL;
1148c2ecf20Sopenharmony_ci	ext4_warning(sb, "Error %d while reading MMP block %llu",
1158c2ecf20Sopenharmony_ci		     ret, mmp_block);
1168c2ecf20Sopenharmony_ci	return ret;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/*
1208c2ecf20Sopenharmony_ci * Dump as much information as possible to help the admin.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_civoid __dump_mmp_msg(struct super_block *sb, struct mmp_struct *mmp,
1238c2ecf20Sopenharmony_ci		    const char *function, unsigned int line, const char *msg)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	__ext4_warning(sb, function, line, "%s", msg);
1268c2ecf20Sopenharmony_ci	__ext4_warning(sb, function, line,
1278c2ecf20Sopenharmony_ci		       "MMP failure info: last update time: %llu, last update node: %.*s, last update device: %.*s",
1288c2ecf20Sopenharmony_ci		       (unsigned long long)le64_to_cpu(mmp->mmp_time),
1298c2ecf20Sopenharmony_ci		       (int)sizeof(mmp->mmp_nodename), mmp->mmp_nodename,
1308c2ecf20Sopenharmony_ci		       (int)sizeof(mmp->mmp_bdevname), mmp->mmp_bdevname);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/*
1348c2ecf20Sopenharmony_ci * kmmpd will update the MMP sequence every s_mmp_update_interval seconds
1358c2ecf20Sopenharmony_ci */
1368c2ecf20Sopenharmony_cistatic int kmmpd(void *data)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct super_block *sb = (struct super_block *) data;
1398c2ecf20Sopenharmony_ci	struct ext4_super_block *es = EXT4_SB(sb)->s_es;
1408c2ecf20Sopenharmony_ci	struct buffer_head *bh = EXT4_SB(sb)->s_mmp_bh;
1418c2ecf20Sopenharmony_ci	struct mmp_struct *mmp;
1428c2ecf20Sopenharmony_ci	ext4_fsblk_t mmp_block;
1438c2ecf20Sopenharmony_ci	u32 seq = 0;
1448c2ecf20Sopenharmony_ci	unsigned long failed_writes = 0;
1458c2ecf20Sopenharmony_ci	int mmp_update_interval = le16_to_cpu(es->s_mmp_update_interval);
1468c2ecf20Sopenharmony_ci	unsigned mmp_check_interval;
1478c2ecf20Sopenharmony_ci	unsigned long last_update_time;
1488c2ecf20Sopenharmony_ci	unsigned long diff;
1498c2ecf20Sopenharmony_ci	int retval = 0;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	mmp_block = le64_to_cpu(es->s_mmp_block);
1528c2ecf20Sopenharmony_ci	mmp = (struct mmp_struct *)(bh->b_data);
1538c2ecf20Sopenharmony_ci	mmp->mmp_time = cpu_to_le64(ktime_get_real_seconds());
1548c2ecf20Sopenharmony_ci	/*
1558c2ecf20Sopenharmony_ci	 * Start with the higher mmp_check_interval and reduce it if
1568c2ecf20Sopenharmony_ci	 * the MMP block is being updated on time.
1578c2ecf20Sopenharmony_ci	 */
1588c2ecf20Sopenharmony_ci	mmp_check_interval = max(EXT4_MMP_CHECK_MULT * mmp_update_interval,
1598c2ecf20Sopenharmony_ci				 EXT4_MMP_MIN_CHECK_INTERVAL);
1608c2ecf20Sopenharmony_ci	mmp->mmp_check_interval = cpu_to_le16(mmp_check_interval);
1618c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(mmp->mmp_bdevname) < BDEVNAME_SIZE);
1628c2ecf20Sopenharmony_ci	bdevname(bh->b_bdev, mmp->mmp_bdevname);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	memcpy(mmp->mmp_nodename, init_utsname()->nodename,
1658c2ecf20Sopenharmony_ci	       sizeof(mmp->mmp_nodename));
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	while (!kthread_should_stop() && !sb_rdonly(sb)) {
1688c2ecf20Sopenharmony_ci		if (!ext4_has_feature_mmp(sb)) {
1698c2ecf20Sopenharmony_ci			ext4_warning(sb, "kmmpd being stopped since MMP feature"
1708c2ecf20Sopenharmony_ci				     " has been disabled.");
1718c2ecf20Sopenharmony_ci			goto wait_to_exit;
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci		if (++seq > EXT4_MMP_SEQ_MAX)
1748c2ecf20Sopenharmony_ci			seq = 1;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci		mmp->mmp_seq = cpu_to_le32(seq);
1778c2ecf20Sopenharmony_ci		mmp->mmp_time = cpu_to_le64(ktime_get_real_seconds());
1788c2ecf20Sopenharmony_ci		last_update_time = jiffies;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci		retval = write_mmp_block(sb, bh);
1818c2ecf20Sopenharmony_ci		/*
1828c2ecf20Sopenharmony_ci		 * Don't spew too many error messages. Print one every
1838c2ecf20Sopenharmony_ci		 * (s_mmp_update_interval * 60) seconds.
1848c2ecf20Sopenharmony_ci		 */
1858c2ecf20Sopenharmony_ci		if (retval) {
1868c2ecf20Sopenharmony_ci			if ((failed_writes % 60) == 0) {
1878c2ecf20Sopenharmony_ci				ext4_error_err(sb, -retval,
1888c2ecf20Sopenharmony_ci					       "Error writing to MMP block");
1898c2ecf20Sopenharmony_ci			}
1908c2ecf20Sopenharmony_ci			failed_writes++;
1918c2ecf20Sopenharmony_ci		}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci		diff = jiffies - last_update_time;
1948c2ecf20Sopenharmony_ci		if (diff < mmp_update_interval * HZ)
1958c2ecf20Sopenharmony_ci			schedule_timeout_interruptible(mmp_update_interval *
1968c2ecf20Sopenharmony_ci						       HZ - diff);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		/*
1998c2ecf20Sopenharmony_ci		 * We need to make sure that more than mmp_check_interval
2008c2ecf20Sopenharmony_ci		 * seconds have not passed since writing. If that has happened
2018c2ecf20Sopenharmony_ci		 * we need to check if the MMP block is as we left it.
2028c2ecf20Sopenharmony_ci		 */
2038c2ecf20Sopenharmony_ci		diff = jiffies - last_update_time;
2048c2ecf20Sopenharmony_ci		if (diff > mmp_check_interval * HZ) {
2058c2ecf20Sopenharmony_ci			struct buffer_head *bh_check = NULL;
2068c2ecf20Sopenharmony_ci			struct mmp_struct *mmp_check;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci			retval = read_mmp_block(sb, &bh_check, mmp_block);
2098c2ecf20Sopenharmony_ci			if (retval) {
2108c2ecf20Sopenharmony_ci				ext4_error_err(sb, -retval,
2118c2ecf20Sopenharmony_ci					       "error reading MMP data: %d",
2128c2ecf20Sopenharmony_ci					       retval);
2138c2ecf20Sopenharmony_ci				goto wait_to_exit;
2148c2ecf20Sopenharmony_ci			}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci			mmp_check = (struct mmp_struct *)(bh_check->b_data);
2178c2ecf20Sopenharmony_ci			if (mmp->mmp_seq != mmp_check->mmp_seq ||
2188c2ecf20Sopenharmony_ci			    memcmp(mmp->mmp_nodename, mmp_check->mmp_nodename,
2198c2ecf20Sopenharmony_ci				   sizeof(mmp->mmp_nodename))) {
2208c2ecf20Sopenharmony_ci				dump_mmp_msg(sb, mmp_check,
2218c2ecf20Sopenharmony_ci					     "Error while updating MMP info. "
2228c2ecf20Sopenharmony_ci					     "The filesystem seems to have been"
2238c2ecf20Sopenharmony_ci					     " multiply mounted.");
2248c2ecf20Sopenharmony_ci				ext4_error_err(sb, EBUSY, "abort");
2258c2ecf20Sopenharmony_ci				put_bh(bh_check);
2268c2ecf20Sopenharmony_ci				retval = -EBUSY;
2278c2ecf20Sopenharmony_ci				goto wait_to_exit;
2288c2ecf20Sopenharmony_ci			}
2298c2ecf20Sopenharmony_ci			put_bh(bh_check);
2308c2ecf20Sopenharmony_ci		}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci		 /*
2338c2ecf20Sopenharmony_ci		 * Adjust the mmp_check_interval depending on how much time
2348c2ecf20Sopenharmony_ci		 * it took for the MMP block to be written.
2358c2ecf20Sopenharmony_ci		 */
2368c2ecf20Sopenharmony_ci		mmp_check_interval = max(min(EXT4_MMP_CHECK_MULT * diff / HZ,
2378c2ecf20Sopenharmony_ci					     EXT4_MMP_MAX_CHECK_INTERVAL),
2388c2ecf20Sopenharmony_ci					 EXT4_MMP_MIN_CHECK_INTERVAL);
2398c2ecf20Sopenharmony_ci		mmp->mmp_check_interval = cpu_to_le16(mmp_check_interval);
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/*
2438c2ecf20Sopenharmony_ci	 * Unmount seems to be clean.
2448c2ecf20Sopenharmony_ci	 */
2458c2ecf20Sopenharmony_ci	mmp->mmp_seq = cpu_to_le32(EXT4_MMP_SEQ_CLEAN);
2468c2ecf20Sopenharmony_ci	mmp->mmp_time = cpu_to_le64(ktime_get_real_seconds());
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	retval = write_mmp_block(sb, bh);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ciwait_to_exit:
2518c2ecf20Sopenharmony_ci	while (!kthread_should_stop()) {
2528c2ecf20Sopenharmony_ci		set_current_state(TASK_INTERRUPTIBLE);
2538c2ecf20Sopenharmony_ci		if (!kthread_should_stop())
2548c2ecf20Sopenharmony_ci			schedule();
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci	set_current_state(TASK_RUNNING);
2578c2ecf20Sopenharmony_ci	return retval;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_civoid ext4_stop_mmpd(struct ext4_sb_info *sbi)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	if (sbi->s_mmp_tsk) {
2638c2ecf20Sopenharmony_ci		kthread_stop(sbi->s_mmp_tsk);
2648c2ecf20Sopenharmony_ci		brelse(sbi->s_mmp_bh);
2658c2ecf20Sopenharmony_ci		sbi->s_mmp_tsk = NULL;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci/*
2708c2ecf20Sopenharmony_ci * Get a random new sequence number but make sure it is not greater than
2718c2ecf20Sopenharmony_ci * EXT4_MMP_SEQ_MAX.
2728c2ecf20Sopenharmony_ci */
2738c2ecf20Sopenharmony_cistatic unsigned int mmp_new_seq(void)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	u32 new_seq;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	do {
2788c2ecf20Sopenharmony_ci		new_seq = prandom_u32();
2798c2ecf20Sopenharmony_ci	} while (new_seq > EXT4_MMP_SEQ_MAX);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	return new_seq;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci/*
2858c2ecf20Sopenharmony_ci * Protect the filesystem from being mounted more than once.
2868c2ecf20Sopenharmony_ci */
2878c2ecf20Sopenharmony_ciint ext4_multi_mount_protect(struct super_block *sb,
2888c2ecf20Sopenharmony_ci				    ext4_fsblk_t mmp_block)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct ext4_super_block *es = EXT4_SB(sb)->s_es;
2918c2ecf20Sopenharmony_ci	struct buffer_head *bh = NULL;
2928c2ecf20Sopenharmony_ci	struct mmp_struct *mmp = NULL;
2938c2ecf20Sopenharmony_ci	u32 seq;
2948c2ecf20Sopenharmony_ci	unsigned int mmp_check_interval = le16_to_cpu(es->s_mmp_update_interval);
2958c2ecf20Sopenharmony_ci	unsigned int wait_time = 0;
2968c2ecf20Sopenharmony_ci	int retval;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (mmp_block < le32_to_cpu(es->s_first_data_block) ||
2998c2ecf20Sopenharmony_ci	    mmp_block >= ext4_blocks_count(es)) {
3008c2ecf20Sopenharmony_ci		ext4_warning(sb, "Invalid MMP block in superblock");
3018c2ecf20Sopenharmony_ci		retval = -EINVAL;
3028c2ecf20Sopenharmony_ci		goto failed;
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	retval = read_mmp_block(sb, &bh, mmp_block);
3068c2ecf20Sopenharmony_ci	if (retval)
3078c2ecf20Sopenharmony_ci		goto failed;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	mmp = (struct mmp_struct *)(bh->b_data);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (mmp_check_interval < EXT4_MMP_MIN_CHECK_INTERVAL)
3128c2ecf20Sopenharmony_ci		mmp_check_interval = EXT4_MMP_MIN_CHECK_INTERVAL;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/*
3158c2ecf20Sopenharmony_ci	 * If check_interval in MMP block is larger, use that instead of
3168c2ecf20Sopenharmony_ci	 * update_interval from the superblock.
3178c2ecf20Sopenharmony_ci	 */
3188c2ecf20Sopenharmony_ci	if (le16_to_cpu(mmp->mmp_check_interval) > mmp_check_interval)
3198c2ecf20Sopenharmony_ci		mmp_check_interval = le16_to_cpu(mmp->mmp_check_interval);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	seq = le32_to_cpu(mmp->mmp_seq);
3228c2ecf20Sopenharmony_ci	if (seq == EXT4_MMP_SEQ_CLEAN)
3238c2ecf20Sopenharmony_ci		goto skip;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if (seq == EXT4_MMP_SEQ_FSCK) {
3268c2ecf20Sopenharmony_ci		dump_mmp_msg(sb, mmp, "fsck is running on the filesystem");
3278c2ecf20Sopenharmony_ci		retval = -EBUSY;
3288c2ecf20Sopenharmony_ci		goto failed;
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	wait_time = min(mmp_check_interval * 2 + 1,
3328c2ecf20Sopenharmony_ci			mmp_check_interval + 60);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	/* Print MMP interval if more than 20 secs. */
3358c2ecf20Sopenharmony_ci	if (wait_time > EXT4_MMP_MIN_CHECK_INTERVAL * 4)
3368c2ecf20Sopenharmony_ci		ext4_warning(sb, "MMP interval %u higher than expected, please"
3378c2ecf20Sopenharmony_ci			     " wait.\n", wait_time * 2);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (schedule_timeout_interruptible(HZ * wait_time) != 0) {
3408c2ecf20Sopenharmony_ci		ext4_warning(sb, "MMP startup interrupted, failing mount\n");
3418c2ecf20Sopenharmony_ci		retval = -ETIMEDOUT;
3428c2ecf20Sopenharmony_ci		goto failed;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	retval = read_mmp_block(sb, &bh, mmp_block);
3468c2ecf20Sopenharmony_ci	if (retval)
3478c2ecf20Sopenharmony_ci		goto failed;
3488c2ecf20Sopenharmony_ci	mmp = (struct mmp_struct *)(bh->b_data);
3498c2ecf20Sopenharmony_ci	if (seq != le32_to_cpu(mmp->mmp_seq)) {
3508c2ecf20Sopenharmony_ci		dump_mmp_msg(sb, mmp,
3518c2ecf20Sopenharmony_ci			     "Device is already active on another node.");
3528c2ecf20Sopenharmony_ci		retval = -EBUSY;
3538c2ecf20Sopenharmony_ci		goto failed;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ciskip:
3578c2ecf20Sopenharmony_ci	/*
3588c2ecf20Sopenharmony_ci	 * write a new random sequence number.
3598c2ecf20Sopenharmony_ci	 */
3608c2ecf20Sopenharmony_ci	seq = mmp_new_seq();
3618c2ecf20Sopenharmony_ci	mmp->mmp_seq = cpu_to_le32(seq);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/*
3648c2ecf20Sopenharmony_ci	 * On mount / remount we are protected against fs freezing (by s_umount
3658c2ecf20Sopenharmony_ci	 * semaphore) and grabbing freeze protection upsets lockdep
3668c2ecf20Sopenharmony_ci	 */
3678c2ecf20Sopenharmony_ci	retval = write_mmp_block_thawed(sb, bh);
3688c2ecf20Sopenharmony_ci	if (retval)
3698c2ecf20Sopenharmony_ci		goto failed;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	/*
3728c2ecf20Sopenharmony_ci	 * wait for MMP interval and check mmp_seq.
3738c2ecf20Sopenharmony_ci	 */
3748c2ecf20Sopenharmony_ci	if (schedule_timeout_interruptible(HZ * wait_time) != 0) {
3758c2ecf20Sopenharmony_ci		ext4_warning(sb, "MMP startup interrupted, failing mount");
3768c2ecf20Sopenharmony_ci		retval = -ETIMEDOUT;
3778c2ecf20Sopenharmony_ci		goto failed;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	retval = read_mmp_block(sb, &bh, mmp_block);
3818c2ecf20Sopenharmony_ci	if (retval)
3828c2ecf20Sopenharmony_ci		goto failed;
3838c2ecf20Sopenharmony_ci	mmp = (struct mmp_struct *)(bh->b_data);
3848c2ecf20Sopenharmony_ci	if (seq != le32_to_cpu(mmp->mmp_seq)) {
3858c2ecf20Sopenharmony_ci		dump_mmp_msg(sb, mmp,
3868c2ecf20Sopenharmony_ci			     "Device is already active on another node.");
3878c2ecf20Sopenharmony_ci		retval = -EBUSY;
3888c2ecf20Sopenharmony_ci		goto failed;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	EXT4_SB(sb)->s_mmp_bh = bh;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	/*
3948c2ecf20Sopenharmony_ci	 * Start a kernel thread to update the MMP block periodically.
3958c2ecf20Sopenharmony_ci	 */
3968c2ecf20Sopenharmony_ci	EXT4_SB(sb)->s_mmp_tsk = kthread_run(kmmpd, sb, "kmmpd-%.*s",
3978c2ecf20Sopenharmony_ci					     (int)sizeof(mmp->mmp_bdevname),
3988c2ecf20Sopenharmony_ci					     bdevname(bh->b_bdev,
3998c2ecf20Sopenharmony_ci						      mmp->mmp_bdevname));
4008c2ecf20Sopenharmony_ci	if (IS_ERR(EXT4_SB(sb)->s_mmp_tsk)) {
4018c2ecf20Sopenharmony_ci		EXT4_SB(sb)->s_mmp_tsk = NULL;
4028c2ecf20Sopenharmony_ci		ext4_warning(sb, "Unable to create kmmpd thread for %s.",
4038c2ecf20Sopenharmony_ci			     sb->s_id);
4048c2ecf20Sopenharmony_ci		retval = -ENOMEM;
4058c2ecf20Sopenharmony_ci		goto failed;
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	return 0;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cifailed:
4118c2ecf20Sopenharmony_ci	brelse(bh);
4128c2ecf20Sopenharmony_ci	return retval;
4138c2ecf20Sopenharmony_ci}
414