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