xref: /openbmc/linux/fs/ext4/mmp.c (revision ecc23d0a422a3118fcf6e4f0a46e17a6c2047b02)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2c5e06d10SJohann Lombardi #include <linux/fs.h>
3c5e06d10SJohann Lombardi #include <linux/random.h>
4c5e06d10SJohann Lombardi #include <linux/buffer_head.h>
5c5e06d10SJohann Lombardi #include <linux/utsname.h>
6c5e06d10SJohann Lombardi #include <linux/kthread.h>
7c5e06d10SJohann Lombardi 
8c5e06d10SJohann Lombardi #include "ext4.h"
9c5e06d10SJohann Lombardi 
105c359a47SDarrick J. Wong /* Checksumming functions */
ext4_mmp_csum(struct super_block * sb,struct mmp_struct * mmp)11171a7f21SDmitry Monakhov static __le32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp)
125c359a47SDarrick J. Wong {
135c359a47SDarrick J. Wong 	struct ext4_sb_info *sbi = EXT4_SB(sb);
145c359a47SDarrick J. Wong 	int offset = offsetof(struct mmp_struct, mmp_checksum);
155c359a47SDarrick J. Wong 	__u32 csum;
165c359a47SDarrick J. Wong 
175c359a47SDarrick J. Wong 	csum = ext4_chksum(sbi, sbi->s_csum_seed, (char *)mmp, offset);
185c359a47SDarrick J. Wong 
195c359a47SDarrick J. Wong 	return cpu_to_le32(csum);
205c359a47SDarrick J. Wong }
215c359a47SDarrick J. Wong 
ext4_mmp_csum_verify(struct super_block * sb,struct mmp_struct * mmp)22c197855eSStephen Hemminger static int ext4_mmp_csum_verify(struct super_block *sb, struct mmp_struct *mmp)
235c359a47SDarrick J. Wong {
249aa5d32bSDmitry Monakhov 	if (!ext4_has_metadata_csum(sb))
255c359a47SDarrick J. Wong 		return 1;
265c359a47SDarrick J. Wong 
275c359a47SDarrick J. Wong 	return mmp->mmp_checksum == ext4_mmp_csum(sb, mmp);
285c359a47SDarrick J. Wong }
295c359a47SDarrick J. Wong 
ext4_mmp_csum_set(struct super_block * sb,struct mmp_struct * mmp)30c197855eSStephen Hemminger static void ext4_mmp_csum_set(struct super_block *sb, struct mmp_struct *mmp)
315c359a47SDarrick J. Wong {
329aa5d32bSDmitry Monakhov 	if (!ext4_has_metadata_csum(sb))
335c359a47SDarrick J. Wong 		return;
345c359a47SDarrick J. Wong 
355c359a47SDarrick J. Wong 	mmp->mmp_checksum = ext4_mmp_csum(sb, mmp);
365c359a47SDarrick J. Wong }
375c359a47SDarrick J. Wong 
38c5e06d10SJohann Lombardi /*
3970fd7614SChristoph Hellwig  * Write the MMP block using REQ_SYNC to try to get the block on-disk
40c5e06d10SJohann Lombardi  * faster.
41c5e06d10SJohann Lombardi  */
write_mmp_block_thawed(struct super_block * sb,struct buffer_head * bh)42949f95ffSJan Kara static int write_mmp_block_thawed(struct super_block *sb,
43949f95ffSJan Kara 				  struct buffer_head *bh)
44c5e06d10SJohann Lombardi {
455c359a47SDarrick J. Wong 	struct mmp_struct *mmp = (struct mmp_struct *)(bh->b_data);
465c359a47SDarrick J. Wong 
475c359a47SDarrick J. Wong 	ext4_mmp_csum_set(sb, mmp);
48c5e06d10SJohann Lombardi 	lock_buffer(bh);
49c5e06d10SJohann Lombardi 	bh->b_end_io = end_buffer_write_sync;
50c5e06d10SJohann Lombardi 	get_bh(bh);
511420c4a5SBart Van Assche 	submit_bh(REQ_OP_WRITE | REQ_SYNC | REQ_META | REQ_PRIO, bh);
52c5e06d10SJohann Lombardi 	wait_on_buffer(bh);
53c5e06d10SJohann Lombardi 	if (unlikely(!buffer_uptodate(bh)))
546810fad9SYe Bin 		return -EIO;
55c5e06d10SJohann Lombardi 	return 0;
56c5e06d10SJohann Lombardi }
57c5e06d10SJohann Lombardi 
write_mmp_block(struct super_block * sb,struct buffer_head * bh)58949f95ffSJan Kara static int write_mmp_block(struct super_block *sb, struct buffer_head *bh)
59949f95ffSJan Kara {
60949f95ffSJan Kara 	int err;
61949f95ffSJan Kara 
62949f95ffSJan Kara 	/*
63949f95ffSJan Kara 	 * We protect against freezing so that we don't create dirty buffers
64949f95ffSJan Kara 	 * on frozen filesystem.
65949f95ffSJan Kara 	 */
66949f95ffSJan Kara 	sb_start_write(sb);
67949f95ffSJan Kara 	err = write_mmp_block_thawed(sb, bh);
68949f95ffSJan Kara 	sb_end_write(sb);
69949f95ffSJan Kara 	return err;
70949f95ffSJan Kara }
71949f95ffSJan Kara 
72c5e06d10SJohann Lombardi /*
73c5e06d10SJohann Lombardi  * Read the MMP block. It _must_ be read from disk and hence we clear the
74c5e06d10SJohann Lombardi  * uptodate flag on the buffer.
75c5e06d10SJohann Lombardi  */
read_mmp_block(struct super_block * sb,struct buffer_head ** bh,ext4_fsblk_t mmp_block)76c5e06d10SJohann Lombardi static int read_mmp_block(struct super_block *sb, struct buffer_head **bh,
77c5e06d10SJohann Lombardi 			  ext4_fsblk_t mmp_block)
78c5e06d10SJohann Lombardi {
79c5e06d10SJohann Lombardi 	struct mmp_struct *mmp;
8098104468SDan Carpenter 	int ret;
81c5e06d10SJohann Lombardi 
82c5e06d10SJohann Lombardi 	if (*bh)
83c5e06d10SJohann Lombardi 		clear_buffer_uptodate(*bh);
84c5e06d10SJohann Lombardi 
85c5e06d10SJohann Lombardi 	/* This would be sb_bread(sb, mmp_block), except we need to be sure
86c5e06d10SJohann Lombardi 	 * that the MD RAID device cache has been bypassed, and that the read
87c5e06d10SJohann Lombardi 	 * is not blocked in the elevator. */
8898104468SDan Carpenter 	if (!*bh) {
89c5e06d10SJohann Lombardi 		*bh = sb_getblk(sb, mmp_block);
9098104468SDan Carpenter 		if (!*bh) {
9198104468SDan Carpenter 			ret = -ENOMEM;
9298104468SDan Carpenter 			goto warn_exit;
9398104468SDan Carpenter 		}
9498104468SDan Carpenter 	}
9598104468SDan Carpenter 
96c5e06d10SJohann Lombardi 	lock_buffer(*bh);
97*77035e4dSLong Li 	ret = ext4_read_bh(*bh, REQ_META | REQ_PRIO, NULL, false);
982d069c08Szhangyi (F) 	if (ret)
9998104468SDan Carpenter 		goto warn_exit;
1002d069c08Szhangyi (F) 
101c5e06d10SJohann Lombardi 	mmp = (struct mmp_struct *)((*bh)->b_data);
10203046886Svikram.jadhav07 	if (le32_to_cpu(mmp->mmp_magic) != EXT4_MMP_MAGIC) {
1036a797d27SDarrick J. Wong 		ret = -EFSCORRUPTED;
10403046886Svikram.jadhav07 		goto warn_exit;
10503046886Svikram.jadhav07 	}
10603046886Svikram.jadhav07 	if (!ext4_mmp_csum_verify(sb, mmp)) {
1076a797d27SDarrick J. Wong 		ret = -EFSBADCRC;
10803046886Svikram.jadhav07 		goto warn_exit;
10903046886Svikram.jadhav07 	}
110c5e06d10SJohann Lombardi 	return 0;
11198104468SDan Carpenter warn_exit:
11203046886Svikram.jadhav07 	brelse(*bh);
11303046886Svikram.jadhav07 	*bh = NULL;
11498104468SDan Carpenter 	ext4_warning(sb, "Error %d while reading MMP block %llu",
11598104468SDan Carpenter 		     ret, mmp_block);
11698104468SDan Carpenter 	return ret;
117c5e06d10SJohann Lombardi }
118c5e06d10SJohann Lombardi 
119c5e06d10SJohann Lombardi /*
120c5e06d10SJohann Lombardi  * Dump as much information as possible to help the admin.
121c5e06d10SJohann Lombardi  */
__dump_mmp_msg(struct super_block * sb,struct mmp_struct * mmp,const char * function,unsigned int line,const char * msg)122c5e06d10SJohann Lombardi void __dump_mmp_msg(struct super_block *sb, struct mmp_struct *mmp,
123c5e06d10SJohann Lombardi 		    const char *function, unsigned int line, const char *msg)
124c5e06d10SJohann Lombardi {
125da0b5e40SDan Carpenter 	__ext4_warning(sb, function, line, "%s", msg);
126c5e06d10SJohann Lombardi 	__ext4_warning(sb, function, line,
12714c9ca05SAndreas Dilger 		       "MMP failure info: last update time: %llu, last update node: %.*s, last update device: %.*s",
12814c9ca05SAndreas Dilger 		       (unsigned long long)le64_to_cpu(mmp->mmp_time),
12914c9ca05SAndreas Dilger 		       (int)sizeof(mmp->mmp_nodename), mmp->mmp_nodename,
13014c9ca05SAndreas Dilger 		       (int)sizeof(mmp->mmp_bdevname), mmp->mmp_bdevname);
131c5e06d10SJohann Lombardi }
132c5e06d10SJohann Lombardi 
133c5e06d10SJohann Lombardi /*
134c5e06d10SJohann Lombardi  * kmmpd will update the MMP sequence every s_mmp_update_interval seconds
135c5e06d10SJohann Lombardi  */
kmmpd(void * data)136c5e06d10SJohann Lombardi static int kmmpd(void *data)
137c5e06d10SJohann Lombardi {
138c30365b9SYu Zhe 	struct super_block *sb = data;
139c5e06d10SJohann Lombardi 	struct ext4_super_block *es = EXT4_SB(sb)->s_es;
140618f0031SPavel Skripkin 	struct buffer_head *bh = EXT4_SB(sb)->s_mmp_bh;
141c5e06d10SJohann Lombardi 	struct mmp_struct *mmp;
142c5e06d10SJohann Lombardi 	ext4_fsblk_t mmp_block;
143c5e06d10SJohann Lombardi 	u32 seq = 0;
144c5e06d10SJohann Lombardi 	unsigned long failed_writes = 0;
145c5e06d10SJohann Lombardi 	int mmp_update_interval = le16_to_cpu(es->s_mmp_update_interval);
146c5e06d10SJohann Lombardi 	unsigned mmp_check_interval;
147c5e06d10SJohann Lombardi 	unsigned long last_update_time;
148c5e06d10SJohann Lombardi 	unsigned long diff;
149b6654142SYe Bin 	int retval = 0;
150c5e06d10SJohann Lombardi 
151c5e06d10SJohann Lombardi 	mmp_block = le64_to_cpu(es->s_mmp_block);
152c5e06d10SJohann Lombardi 	mmp = (struct mmp_struct *)(bh->b_data);
153af123b37SArnd Bergmann 	mmp->mmp_time = cpu_to_le64(ktime_get_real_seconds());
154c5e06d10SJohann Lombardi 	/*
155c5e06d10SJohann Lombardi 	 * Start with the higher mmp_check_interval and reduce it if
156c5e06d10SJohann Lombardi 	 * the MMP block is being updated on time.
157c5e06d10SJohann Lombardi 	 */
158c5e06d10SJohann Lombardi 	mmp_check_interval = max(EXT4_MMP_CHECK_MULT * mmp_update_interval,
159c5e06d10SJohann Lombardi 				 EXT4_MMP_MIN_CHECK_INTERVAL);
160c5e06d10SJohann Lombardi 	mmp->mmp_check_interval = cpu_to_le16(mmp_check_interval);
161c5e06d10SJohann Lombardi 
162215fc6afSNikitas Angelinas 	memcpy(mmp->mmp_nodename, init_utsname()->nodename,
163c5e06d10SJohann Lombardi 	       sizeof(mmp->mmp_nodename));
164c5e06d10SJohann Lombardi 
1651e1566b9SJan Kara 	while (!kthread_should_stop() && !ext4_forced_shutdown(sb)) {
16661bb4a1cSTheodore Ts'o 		if (!ext4_has_feature_mmp(sb)) {
16761bb4a1cSTheodore Ts'o 			ext4_warning(sb, "kmmpd being stopped since MMP feature"
16861bb4a1cSTheodore Ts'o 				     " has been disabled.");
16961bb4a1cSTheodore Ts'o 			goto wait_to_exit;
17061bb4a1cSTheodore Ts'o 		}
171c5e06d10SJohann Lombardi 		if (++seq > EXT4_MMP_SEQ_MAX)
172c5e06d10SJohann Lombardi 			seq = 1;
173c5e06d10SJohann Lombardi 
174c5e06d10SJohann Lombardi 		mmp->mmp_seq = cpu_to_le32(seq);
175af123b37SArnd Bergmann 		mmp->mmp_time = cpu_to_le64(ktime_get_real_seconds());
176c5e06d10SJohann Lombardi 		last_update_time = jiffies;
177c5e06d10SJohann Lombardi 
1785c359a47SDarrick J. Wong 		retval = write_mmp_block(sb, bh);
179c5e06d10SJohann Lombardi 		/*
180c5e06d10SJohann Lombardi 		 * Don't spew too many error messages. Print one every
181c5e06d10SJohann Lombardi 		 * (s_mmp_update_interval * 60) seconds.
182c5e06d10SJohann Lombardi 		 */
183bdfc230fSNikitas Angelinas 		if (retval) {
184878520acSTheodore Ts'o 			if ((failed_writes % 60) == 0) {
18554d3adbcSTheodore Ts'o 				ext4_error_err(sb, -retval,
18654d3adbcSTheodore Ts'o 					       "Error writing to MMP block");
187878520acSTheodore Ts'o 			}
188c5e06d10SJohann Lombardi 			failed_writes++;
189c5e06d10SJohann Lombardi 		}
190c5e06d10SJohann Lombardi 
191c5e06d10SJohann Lombardi 		diff = jiffies - last_update_time;
192c5e06d10SJohann Lombardi 		if (diff < mmp_update_interval * HZ)
193c5e06d10SJohann Lombardi 			schedule_timeout_interruptible(mmp_update_interval *
194c5e06d10SJohann Lombardi 						       HZ - diff);
195c5e06d10SJohann Lombardi 
196c5e06d10SJohann Lombardi 		/*
197c5e06d10SJohann Lombardi 		 * We need to make sure that more than mmp_check_interval
198c5e06d10SJohann Lombardi 		 * seconds have not passed since writing. If that has happened
199c5e06d10SJohann Lombardi 		 * we need to check if the MMP block is as we left it.
200c5e06d10SJohann Lombardi 		 */
201c5e06d10SJohann Lombardi 		diff = jiffies - last_update_time;
202c5e06d10SJohann Lombardi 		if (diff > mmp_check_interval * HZ) {
203c5e06d10SJohann Lombardi 			struct buffer_head *bh_check = NULL;
204c5e06d10SJohann Lombardi 			struct mmp_struct *mmp_check;
205c5e06d10SJohann Lombardi 
206c5e06d10SJohann Lombardi 			retval = read_mmp_block(sb, &bh_check, mmp_block);
207c5e06d10SJohann Lombardi 			if (retval) {
20854d3adbcSTheodore Ts'o 				ext4_error_err(sb, -retval,
20954d3adbcSTheodore Ts'o 					       "error reading MMP data: %d",
210c5e06d10SJohann Lombardi 					       retval);
21161bb4a1cSTheodore Ts'o 				goto wait_to_exit;
212c5e06d10SJohann Lombardi 			}
213c5e06d10SJohann Lombardi 
214c5e06d10SJohann Lombardi 			mmp_check = (struct mmp_struct *)(bh_check->b_data);
215c5e06d10SJohann Lombardi 			if (mmp->mmp_seq != mmp_check->mmp_seq ||
216c5e06d10SJohann Lombardi 			    memcmp(mmp->mmp_nodename, mmp_check->mmp_nodename,
217c5e06d10SJohann Lombardi 				   sizeof(mmp->mmp_nodename))) {
218c5e06d10SJohann Lombardi 				dump_mmp_msg(sb, mmp_check,
219c5e06d10SJohann Lombardi 					     "Error while updating MMP info. "
220c5e06d10SJohann Lombardi 					     "The filesystem seems to have been"
221c5e06d10SJohann Lombardi 					     " multiply mounted.");
22254d3adbcSTheodore Ts'o 				ext4_error_err(sb, EBUSY, "abort");
22303046886Svikram.jadhav07 				put_bh(bh_check);
22403046886Svikram.jadhav07 				retval = -EBUSY;
22561bb4a1cSTheodore Ts'o 				goto wait_to_exit;
226c5e06d10SJohann Lombardi 			}
227c5e06d10SJohann Lombardi 			put_bh(bh_check);
228c5e06d10SJohann Lombardi 		}
229c5e06d10SJohann Lombardi 
230c5e06d10SJohann Lombardi 		 /*
231c5e06d10SJohann Lombardi 		 * Adjust the mmp_check_interval depending on how much time
232c5e06d10SJohann Lombardi 		 * it took for the MMP block to be written.
233c5e06d10SJohann Lombardi 		 */
234c5e06d10SJohann Lombardi 		mmp_check_interval = max(min(EXT4_MMP_CHECK_MULT * diff / HZ,
235c5e06d10SJohann Lombardi 					     EXT4_MMP_MAX_CHECK_INTERVAL),
236c5e06d10SJohann Lombardi 					 EXT4_MMP_MIN_CHECK_INTERVAL);
237c5e06d10SJohann Lombardi 		mmp->mmp_check_interval = cpu_to_le16(mmp_check_interval);
238c5e06d10SJohann Lombardi 	}
239c5e06d10SJohann Lombardi 
240c5e06d10SJohann Lombardi 	/*
241c5e06d10SJohann Lombardi 	 * Unmount seems to be clean.
242c5e06d10SJohann Lombardi 	 */
243c5e06d10SJohann Lombardi 	mmp->mmp_seq = cpu_to_le32(EXT4_MMP_SEQ_CLEAN);
244af123b37SArnd Bergmann 	mmp->mmp_time = cpu_to_le64(ktime_get_real_seconds());
245c5e06d10SJohann Lombardi 
2465c359a47SDarrick J. Wong 	retval = write_mmp_block(sb, bh);
247c5e06d10SJohann Lombardi 
24861bb4a1cSTheodore Ts'o wait_to_exit:
24961bb4a1cSTheodore Ts'o 	while (!kthread_should_stop()) {
25061bb4a1cSTheodore Ts'o 		set_current_state(TASK_INTERRUPTIBLE);
25161bb4a1cSTheodore Ts'o 		if (!kthread_should_stop())
25261bb4a1cSTheodore Ts'o 			schedule();
25361bb4a1cSTheodore Ts'o 	}
25461bb4a1cSTheodore Ts'o 	set_current_state(TASK_RUNNING);
255c5e06d10SJohann Lombardi 	return retval;
256c5e06d10SJohann Lombardi }
257c5e06d10SJohann Lombardi 
ext4_stop_mmpd(struct ext4_sb_info * sbi)258618f0031SPavel Skripkin void ext4_stop_mmpd(struct ext4_sb_info *sbi)
259618f0031SPavel Skripkin {
260618f0031SPavel Skripkin 	if (sbi->s_mmp_tsk) {
261618f0031SPavel Skripkin 		kthread_stop(sbi->s_mmp_tsk);
262618f0031SPavel Skripkin 		brelse(sbi->s_mmp_bh);
263618f0031SPavel Skripkin 		sbi->s_mmp_tsk = NULL;
264618f0031SPavel Skripkin 	}
265618f0031SPavel Skripkin }
266618f0031SPavel Skripkin 
267c5e06d10SJohann Lombardi /*
268c5e06d10SJohann Lombardi  * Get a random new sequence number but make sure it is not greater than
269c5e06d10SJohann Lombardi  * EXT4_MMP_SEQ_MAX.
270c5e06d10SJohann Lombardi  */
mmp_new_seq(void)271c5e06d10SJohann Lombardi static unsigned int mmp_new_seq(void)
272c5e06d10SJohann Lombardi {
273d247aabdSJason A. Donenfeld 	return get_random_u32_below(EXT4_MMP_SEQ_MAX + 1);
274c5e06d10SJohann Lombardi }
275c5e06d10SJohann Lombardi 
276c5e06d10SJohann Lombardi /*
277c5e06d10SJohann Lombardi  * Protect the filesystem from being mounted more than once.
278c5e06d10SJohann Lombardi  */
ext4_multi_mount_protect(struct super_block * sb,ext4_fsblk_t mmp_block)279c5e06d10SJohann Lombardi int ext4_multi_mount_protect(struct super_block *sb,
280c5e06d10SJohann Lombardi 				    ext4_fsblk_t mmp_block)
281c5e06d10SJohann Lombardi {
282c5e06d10SJohann Lombardi 	struct ext4_super_block *es = EXT4_SB(sb)->s_es;
283c5e06d10SJohann Lombardi 	struct buffer_head *bh = NULL;
284c5e06d10SJohann Lombardi 	struct mmp_struct *mmp = NULL;
285c5e06d10SJohann Lombardi 	u32 seq;
286c5e06d10SJohann Lombardi 	unsigned int mmp_check_interval = le16_to_cpu(es->s_mmp_update_interval);
287c5e06d10SJohann Lombardi 	unsigned int wait_time = 0;
288c5e06d10SJohann Lombardi 	int retval;
289c5e06d10SJohann Lombardi 
290c5e06d10SJohann Lombardi 	if (mmp_block < le32_to_cpu(es->s_first_data_block) ||
291c5e06d10SJohann Lombardi 	    mmp_block >= ext4_blocks_count(es)) {
292c5e06d10SJohann Lombardi 		ext4_warning(sb, "Invalid MMP block in superblock");
2933b50d501STheodore Ts'o 		retval = -EINVAL;
294c5e06d10SJohann Lombardi 		goto failed;
295c5e06d10SJohann Lombardi 	}
296c5e06d10SJohann Lombardi 
297c5e06d10SJohann Lombardi 	retval = read_mmp_block(sb, &bh, mmp_block);
298c5e06d10SJohann Lombardi 	if (retval)
299c5e06d10SJohann Lombardi 		goto failed;
300c5e06d10SJohann Lombardi 
301c5e06d10SJohann Lombardi 	mmp = (struct mmp_struct *)(bh->b_data);
302c5e06d10SJohann Lombardi 
303c5e06d10SJohann Lombardi 	if (mmp_check_interval < EXT4_MMP_MIN_CHECK_INTERVAL)
304c5e06d10SJohann Lombardi 		mmp_check_interval = EXT4_MMP_MIN_CHECK_INTERVAL;
305c5e06d10SJohann Lombardi 
306c5e06d10SJohann Lombardi 	/*
307c5e06d10SJohann Lombardi 	 * If check_interval in MMP block is larger, use that instead of
308c5e06d10SJohann Lombardi 	 * update_interval from the superblock.
309c5e06d10SJohann Lombardi 	 */
31085d21650SSantosh Nayak 	if (le16_to_cpu(mmp->mmp_check_interval) > mmp_check_interval)
31185d21650SSantosh Nayak 		mmp_check_interval = le16_to_cpu(mmp->mmp_check_interval);
312c5e06d10SJohann Lombardi 
313c5e06d10SJohann Lombardi 	seq = le32_to_cpu(mmp->mmp_seq);
314c5e06d10SJohann Lombardi 	if (seq == EXT4_MMP_SEQ_CLEAN)
315c5e06d10SJohann Lombardi 		goto skip;
316c5e06d10SJohann Lombardi 
317c5e06d10SJohann Lombardi 	if (seq == EXT4_MMP_SEQ_FSCK) {
318c5e06d10SJohann Lombardi 		dump_mmp_msg(sb, mmp, "fsck is running on the filesystem");
3193b50d501STheodore Ts'o 		retval = -EBUSY;
320c5e06d10SJohann Lombardi 		goto failed;
321c5e06d10SJohann Lombardi 	}
322c5e06d10SJohann Lombardi 
323c5e06d10SJohann Lombardi 	wait_time = min(mmp_check_interval * 2 + 1,
324c5e06d10SJohann Lombardi 			mmp_check_interval + 60);
325c5e06d10SJohann Lombardi 
326c5e06d10SJohann Lombardi 	/* Print MMP interval if more than 20 secs. */
327c5e06d10SJohann Lombardi 	if (wait_time > EXT4_MMP_MIN_CHECK_INTERVAL * 4)
328c5e06d10SJohann Lombardi 		ext4_warning(sb, "MMP interval %u higher than expected, please"
329c5e06d10SJohann Lombardi 			     " wait.\n", wait_time * 2);
330c5e06d10SJohann Lombardi 
331c5e06d10SJohann Lombardi 	if (schedule_timeout_interruptible(HZ * wait_time) != 0) {
332c5e06d10SJohann Lombardi 		ext4_warning(sb, "MMP startup interrupted, failing mount\n");
3333b50d501STheodore Ts'o 		retval = -ETIMEDOUT;
334c5e06d10SJohann Lombardi 		goto failed;
335c5e06d10SJohann Lombardi 	}
336c5e06d10SJohann Lombardi 
337c5e06d10SJohann Lombardi 	retval = read_mmp_block(sb, &bh, mmp_block);
338c5e06d10SJohann Lombardi 	if (retval)
339c5e06d10SJohann Lombardi 		goto failed;
340c5e06d10SJohann Lombardi 	mmp = (struct mmp_struct *)(bh->b_data);
341c5e06d10SJohann Lombardi 	if (seq != le32_to_cpu(mmp->mmp_seq)) {
342c5e06d10SJohann Lombardi 		dump_mmp_msg(sb, mmp,
343c5e06d10SJohann Lombardi 			     "Device is already active on another node.");
3443b50d501STheodore Ts'o 		retval = -EBUSY;
345c5e06d10SJohann Lombardi 		goto failed;
346c5e06d10SJohann Lombardi 	}
347c5e06d10SJohann Lombardi 
348c5e06d10SJohann Lombardi skip:
349c5e06d10SJohann Lombardi 	/*
350c5e06d10SJohann Lombardi 	 * write a new random sequence number.
351c5e06d10SJohann Lombardi 	 */
352f6f96fdbSDarrick J. Wong 	seq = mmp_new_seq();
353f6f96fdbSDarrick J. Wong 	mmp->mmp_seq = cpu_to_le32(seq);
354c5e06d10SJohann Lombardi 
355949f95ffSJan Kara 	/*
356949f95ffSJan Kara 	 * On mount / remount we are protected against fs freezing (by s_umount
357949f95ffSJan Kara 	 * semaphore) and grabbing freeze protection upsets lockdep
358949f95ffSJan Kara 	 */
359949f95ffSJan Kara 	retval = write_mmp_block_thawed(sb, bh);
360c5e06d10SJohann Lombardi 	if (retval)
361c5e06d10SJohann Lombardi 		goto failed;
362c5e06d10SJohann Lombardi 
363c5e06d10SJohann Lombardi 	/*
364c5e06d10SJohann Lombardi 	 * wait for MMP interval and check mmp_seq.
365c5e06d10SJohann Lombardi 	 */
366c5e06d10SJohann Lombardi 	if (schedule_timeout_interruptible(HZ * wait_time) != 0) {
3678d2ae1cbSJakub Wilk 		ext4_warning(sb, "MMP startup interrupted, failing mount");
3683b50d501STheodore Ts'o 		retval = -ETIMEDOUT;
369c5e06d10SJohann Lombardi 		goto failed;
370c5e06d10SJohann Lombardi 	}
371c5e06d10SJohann Lombardi 
372c5e06d10SJohann Lombardi 	retval = read_mmp_block(sb, &bh, mmp_block);
373c5e06d10SJohann Lombardi 	if (retval)
374c5e06d10SJohann Lombardi 		goto failed;
375c5e06d10SJohann Lombardi 	mmp = (struct mmp_struct *)(bh->b_data);
376c5e06d10SJohann Lombardi 	if (seq != le32_to_cpu(mmp->mmp_seq)) {
377c5e06d10SJohann Lombardi 		dump_mmp_msg(sb, mmp,
378c5e06d10SJohann Lombardi 			     "Device is already active on another node.");
3793b50d501STheodore Ts'o 		retval = -EBUSY;
380c5e06d10SJohann Lombardi 		goto failed;
381c5e06d10SJohann Lombardi 	}
382c5e06d10SJohann Lombardi 
383618f0031SPavel Skripkin 	EXT4_SB(sb)->s_mmp_bh = bh;
384c5e06d10SJohann Lombardi 
385c5b045b9SChristoph Hellwig 	BUILD_BUG_ON(sizeof(mmp->mmp_bdevname) < BDEVNAME_SIZE);
386900d156bSChristoph Hellwig 	snprintf(mmp->mmp_bdevname, sizeof(mmp->mmp_bdevname),
387900d156bSChristoph Hellwig 		 "%pg", bh->b_bdev);
388c5b045b9SChristoph Hellwig 
389c5e06d10SJohann Lombardi 	/*
390c5e06d10SJohann Lombardi 	 * Start a kernel thread to update the MMP block periodically.
391c5e06d10SJohann Lombardi 	 */
392618f0031SPavel Skripkin 	EXT4_SB(sb)->s_mmp_tsk = kthread_run(kmmpd, sb, "kmmpd-%.*s",
39314c9ca05SAndreas Dilger 					     (int)sizeof(mmp->mmp_bdevname),
394c5b045b9SChristoph Hellwig 					     mmp->mmp_bdevname);
395c5e06d10SJohann Lombardi 	if (IS_ERR(EXT4_SB(sb)->s_mmp_tsk)) {
396c5e06d10SJohann Lombardi 		EXT4_SB(sb)->s_mmp_tsk = NULL;
397c5e06d10SJohann Lombardi 		ext4_warning(sb, "Unable to create kmmpd thread for %s.",
398c5e06d10SJohann Lombardi 			     sb->s_id);
3993b50d501STheodore Ts'o 		retval = -ENOMEM;
400c5e06d10SJohann Lombardi 		goto failed;
401c5e06d10SJohann Lombardi 	}
402c5e06d10SJohann Lombardi 
403c5e06d10SJohann Lombardi 	return 0;
404c5e06d10SJohann Lombardi 
405c5e06d10SJohann Lombardi failed:
406c5e06d10SJohann Lombardi 	brelse(bh);
4073b50d501STheodore Ts'o 	return retval;
408c5e06d10SJohann Lombardi }
409