xref: /aosp_15_r20/external/e2fsprogs/lib/ext2fs/mmp.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker  * Helper functions for multiple mount protection (MMP).
3*6a54128fSAndroid Build Coastguard Worker  *
4*6a54128fSAndroid Build Coastguard Worker  * Copyright (C) 2011 Whamcloud, Inc.
5*6a54128fSAndroid Build Coastguard Worker  *
6*6a54128fSAndroid Build Coastguard Worker  * %Begin-Header%
7*6a54128fSAndroid Build Coastguard Worker  * This file may be redistributed under the terms of the GNU Library
8*6a54128fSAndroid Build Coastguard Worker  * General Public License, version 2.
9*6a54128fSAndroid Build Coastguard Worker  * %End-Header%
10*6a54128fSAndroid Build Coastguard Worker  */
11*6a54128fSAndroid Build Coastguard Worker 
12*6a54128fSAndroid Build Coastguard Worker #ifndef _GNU_SOURCE
13*6a54128fSAndroid Build Coastguard Worker #define _GNU_SOURCE
14*6a54128fSAndroid Build Coastguard Worker #endif
15*6a54128fSAndroid Build Coastguard Worker #ifndef _DEFAULT_SOURCE
16*6a54128fSAndroid Build Coastguard Worker #define _DEFAULT_SOURCE	/* since glibc 2.20 _SVID_SOURCE is deprecated */
17*6a54128fSAndroid Build Coastguard Worker #endif
18*6a54128fSAndroid Build Coastguard Worker 
19*6a54128fSAndroid Build Coastguard Worker #include "config.h"
20*6a54128fSAndroid Build Coastguard Worker 
21*6a54128fSAndroid Build Coastguard Worker #if HAVE_UNISTD_H
22*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
23*6a54128fSAndroid Build Coastguard Worker #endif
24*6a54128fSAndroid Build Coastguard Worker #include <sys/time.h>
25*6a54128fSAndroid Build Coastguard Worker 
26*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
27*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
28*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
29*6a54128fSAndroid Build Coastguard Worker 
30*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2_fs.h"
31*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2fs.h"
32*6a54128fSAndroid Build Coastguard Worker 
33*6a54128fSAndroid Build Coastguard Worker #ifndef O_DIRECT
34*6a54128fSAndroid Build Coastguard Worker #define O_DIRECT 0
35*6a54128fSAndroid Build Coastguard Worker #endif
36*6a54128fSAndroid Build Coastguard Worker 
37*6a54128fSAndroid Build Coastguard Worker #if __GNUC_PREREQ (4, 6)
38*6a54128fSAndroid Build Coastguard Worker #pragma GCC diagnostic push
39*6a54128fSAndroid Build Coastguard Worker #ifndef CONFIG_MMP
40*6a54128fSAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wunused-parameter"
41*6a54128fSAndroid Build Coastguard Worker #endif
42*6a54128fSAndroid Build Coastguard Worker #endif
43*6a54128fSAndroid Build Coastguard Worker 
ext2fs_mmp_read(ext2_filsys fs,blk64_t mmp_blk,void * buf)44*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf)
45*6a54128fSAndroid Build Coastguard Worker {
46*6a54128fSAndroid Build Coastguard Worker #ifdef CONFIG_MMP
47*6a54128fSAndroid Build Coastguard Worker 	struct mmp_struct *mmp_cmp;
48*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval = 0;
49*6a54128fSAndroid Build Coastguard Worker 
50*6a54128fSAndroid Build Coastguard Worker 	if ((mmp_blk <= fs->super->s_first_data_block) ||
51*6a54128fSAndroid Build Coastguard Worker 	    (mmp_blk >= ext2fs_blocks_count(fs->super)))
52*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_MMP_BAD_BLOCK;
53*6a54128fSAndroid Build Coastguard Worker 
54*6a54128fSAndroid Build Coastguard Worker 	/* ext2fs_open() reserves fd0,1,2 to avoid stdio collision, so checking
55*6a54128fSAndroid Build Coastguard Worker 	 * mmp_fd <= 0 is OK to validate that the fd is valid.  This opens its
56*6a54128fSAndroid Build Coastguard Worker 	 * own fd to read the MMP block to ensure that it is using O_DIRECT,
57*6a54128fSAndroid Build Coastguard Worker 	 * regardless of how the io_manager is doing reads, to avoid caching of
58*6a54128fSAndroid Build Coastguard Worker 	 * the MMP block by the io_manager or the VM.  It needs to be fresh. */
59*6a54128fSAndroid Build Coastguard Worker 	if (fs->mmp_fd <= 0) {
60*6a54128fSAndroid Build Coastguard Worker 		struct stat st;
61*6a54128fSAndroid Build Coastguard Worker 		int flags = O_RDONLY | O_DIRECT;
62*6a54128fSAndroid Build Coastguard Worker 
63*6a54128fSAndroid Build Coastguard Worker 		/*
64*6a54128fSAndroid Build Coastguard Worker 		 * There is no reason for using O_DIRECT if we're working with
65*6a54128fSAndroid Build Coastguard Worker 		 * regular file. Disabling it also avoids problems with
66*6a54128fSAndroid Build Coastguard Worker 		 * alignment when the device of the host file system has sector
67*6a54128fSAndroid Build Coastguard Worker 		 * size larger than blocksize of the fs we're working with.
68*6a54128fSAndroid Build Coastguard Worker 		 */
69*6a54128fSAndroid Build Coastguard Worker 		if (stat(fs->device_name, &st) == 0 &&
70*6a54128fSAndroid Build Coastguard Worker 		    S_ISREG(st.st_mode))
71*6a54128fSAndroid Build Coastguard Worker 			flags &= ~O_DIRECT;
72*6a54128fSAndroid Build Coastguard Worker 
73*6a54128fSAndroid Build Coastguard Worker 		fs->mmp_fd = open(fs->device_name, flags);
74*6a54128fSAndroid Build Coastguard Worker 		if (fs->mmp_fd < 0) {
75*6a54128fSAndroid Build Coastguard Worker 			retval = EXT2_ET_MMP_OPEN_DIRECT;
76*6a54128fSAndroid Build Coastguard Worker 			goto out;
77*6a54128fSAndroid Build Coastguard Worker 		}
78*6a54128fSAndroid Build Coastguard Worker 	}
79*6a54128fSAndroid Build Coastguard Worker 
80*6a54128fSAndroid Build Coastguard Worker 	if (fs->mmp_cmp == NULL) {
81*6a54128fSAndroid Build Coastguard Worker 		int align = ext2fs_get_dio_alignment(fs->mmp_fd);
82*6a54128fSAndroid Build Coastguard Worker 
83*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_get_memalign(fs->blocksize, align,
84*6a54128fSAndroid Build Coastguard Worker 					     &fs->mmp_cmp);
85*6a54128fSAndroid Build Coastguard Worker 		if (retval)
86*6a54128fSAndroid Build Coastguard Worker 			return retval;
87*6a54128fSAndroid Build Coastguard Worker 	}
88*6a54128fSAndroid Build Coastguard Worker 
89*6a54128fSAndroid Build Coastguard Worker 	if ((blk64_t) ext2fs_llseek(fs->mmp_fd, mmp_blk * fs->blocksize,
90*6a54128fSAndroid Build Coastguard Worker 				    SEEK_SET) !=
91*6a54128fSAndroid Build Coastguard Worker 	    mmp_blk * fs->blocksize) {
92*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_LLSEEK_FAILED;
93*6a54128fSAndroid Build Coastguard Worker 		goto out;
94*6a54128fSAndroid Build Coastguard Worker 	}
95*6a54128fSAndroid Build Coastguard Worker 
96*6a54128fSAndroid Build Coastguard Worker 	if (read(fs->mmp_fd, fs->mmp_cmp, fs->blocksize) != fs->blocksize) {
97*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_SHORT_READ;
98*6a54128fSAndroid Build Coastguard Worker 		goto out;
99*6a54128fSAndroid Build Coastguard Worker 	}
100*6a54128fSAndroid Build Coastguard Worker 
101*6a54128fSAndroid Build Coastguard Worker 	mmp_cmp = fs->mmp_cmp;
102*6a54128fSAndroid Build Coastguard Worker 
103*6a54128fSAndroid Build Coastguard Worker 	if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
104*6a54128fSAndroid Build Coastguard Worker 	    !ext2fs_mmp_csum_verify(fs, mmp_cmp))
105*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_MMP_CSUM_INVALID;
106*6a54128fSAndroid Build Coastguard Worker 
107*6a54128fSAndroid Build Coastguard Worker #ifdef WORDS_BIGENDIAN
108*6a54128fSAndroid Build Coastguard Worker 	ext2fs_swap_mmp(mmp_cmp);
109*6a54128fSAndroid Build Coastguard Worker #endif
110*6a54128fSAndroid Build Coastguard Worker 
111*6a54128fSAndroid Build Coastguard Worker 	if (buf != NULL && buf != fs->mmp_cmp)
112*6a54128fSAndroid Build Coastguard Worker 		memcpy(buf, fs->mmp_cmp, fs->blocksize);
113*6a54128fSAndroid Build Coastguard Worker 
114*6a54128fSAndroid Build Coastguard Worker 	if (mmp_cmp->mmp_magic != EXT4_MMP_MAGIC) {
115*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_MMP_MAGIC_INVALID;
116*6a54128fSAndroid Build Coastguard Worker 		goto out;
117*6a54128fSAndroid Build Coastguard Worker 	}
118*6a54128fSAndroid Build Coastguard Worker 
119*6a54128fSAndroid Build Coastguard Worker out:
120*6a54128fSAndroid Build Coastguard Worker 	return retval;
121*6a54128fSAndroid Build Coastguard Worker #else
122*6a54128fSAndroid Build Coastguard Worker 	return EXT2_ET_OP_NOT_SUPPORTED;
123*6a54128fSAndroid Build Coastguard Worker #endif
124*6a54128fSAndroid Build Coastguard Worker }
125*6a54128fSAndroid Build Coastguard Worker 
ext2fs_mmp_write(ext2_filsys fs,blk64_t mmp_blk,void * buf)126*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf)
127*6a54128fSAndroid Build Coastguard Worker {
128*6a54128fSAndroid Build Coastguard Worker #ifdef CONFIG_MMP
129*6a54128fSAndroid Build Coastguard Worker 	struct mmp_struct *mmp_s = buf;
130*6a54128fSAndroid Build Coastguard Worker 	struct timeval tv;
131*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval = 0;
132*6a54128fSAndroid Build Coastguard Worker 
133*6a54128fSAndroid Build Coastguard Worker 	gettimeofday(&tv, 0);
134*6a54128fSAndroid Build Coastguard Worker 	mmp_s->mmp_time = tv.tv_sec;
135*6a54128fSAndroid Build Coastguard Worker 	fs->mmp_last_written = tv.tv_sec;
136*6a54128fSAndroid Build Coastguard Worker 
137*6a54128fSAndroid Build Coastguard Worker 	if (fs->super->s_mmp_block < fs->super->s_first_data_block ||
138*6a54128fSAndroid Build Coastguard Worker 	    fs->super->s_mmp_block > ext2fs_blocks_count(fs->super))
139*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_MMP_BAD_BLOCK;
140*6a54128fSAndroid Build Coastguard Worker 
141*6a54128fSAndroid Build Coastguard Worker #ifdef WORDS_BIGENDIAN
142*6a54128fSAndroid Build Coastguard Worker 	ext2fs_swap_mmp(mmp_s);
143*6a54128fSAndroid Build Coastguard Worker #endif
144*6a54128fSAndroid Build Coastguard Worker 
145*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_csum_set(fs, mmp_s);
146*6a54128fSAndroid Build Coastguard Worker 	if (retval)
147*6a54128fSAndroid Build Coastguard Worker 		return retval;
148*6a54128fSAndroid Build Coastguard Worker 
149*6a54128fSAndroid Build Coastguard Worker 	/* I was tempted to make this use O_DIRECT and the mmp_fd, but
150*6a54128fSAndroid Build Coastguard Worker 	 * this caused no end of grief, while leaving it as-is works. */
151*6a54128fSAndroid Build Coastguard Worker 	retval = io_channel_write_blk64(fs->io, mmp_blk, -(int)sizeof(struct mmp_struct), buf);
152*6a54128fSAndroid Build Coastguard Worker 
153*6a54128fSAndroid Build Coastguard Worker #ifdef WORDS_BIGENDIAN
154*6a54128fSAndroid Build Coastguard Worker 	ext2fs_swap_mmp(mmp_s);
155*6a54128fSAndroid Build Coastguard Worker #endif
156*6a54128fSAndroid Build Coastguard Worker 
157*6a54128fSAndroid Build Coastguard Worker 	/* Make sure the block gets to disk quickly */
158*6a54128fSAndroid Build Coastguard Worker 	io_channel_flush(fs->io);
159*6a54128fSAndroid Build Coastguard Worker 	return retval;
160*6a54128fSAndroid Build Coastguard Worker #else
161*6a54128fSAndroid Build Coastguard Worker 	return EXT2_ET_OP_NOT_SUPPORTED;
162*6a54128fSAndroid Build Coastguard Worker #endif
163*6a54128fSAndroid Build Coastguard Worker }
164*6a54128fSAndroid Build Coastguard Worker 
165*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_SRANDOM
166*6a54128fSAndroid Build Coastguard Worker #define srand(x)	srandom(x)
167*6a54128fSAndroid Build Coastguard Worker #define rand()		random()
168*6a54128fSAndroid Build Coastguard Worker #endif
169*6a54128fSAndroid Build Coastguard Worker 
ext2fs_mmp_new_seq(void)170*6a54128fSAndroid Build Coastguard Worker unsigned ext2fs_mmp_new_seq(void)
171*6a54128fSAndroid Build Coastguard Worker {
172*6a54128fSAndroid Build Coastguard Worker #ifdef CONFIG_MMP
173*6a54128fSAndroid Build Coastguard Worker 	unsigned new_seq;
174*6a54128fSAndroid Build Coastguard Worker 	struct timeval tv;
175*6a54128fSAndroid Build Coastguard Worker 	unsigned long pid = getpid();
176*6a54128fSAndroid Build Coastguard Worker 
177*6a54128fSAndroid Build Coastguard Worker 	gettimeofday(&tv, 0);
178*6a54128fSAndroid Build Coastguard Worker 	pid = (pid >> 16) | ((pid & 0xFFFF) << 16);
179*6a54128fSAndroid Build Coastguard Worker 	srand(pid ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
180*6a54128fSAndroid Build Coastguard Worker 
181*6a54128fSAndroid Build Coastguard Worker 	gettimeofday(&tv, 0);
182*6a54128fSAndroid Build Coastguard Worker 	/* Crank the random number generator a few times */
183*6a54128fSAndroid Build Coastguard Worker 	for (new_seq = (tv.tv_sec ^ tv.tv_usec) & 0x1F; new_seq > 0; new_seq--)
184*6a54128fSAndroid Build Coastguard Worker 		rand();
185*6a54128fSAndroid Build Coastguard Worker 
186*6a54128fSAndroid Build Coastguard Worker 	do {
187*6a54128fSAndroid Build Coastguard Worker 		new_seq = rand();
188*6a54128fSAndroid Build Coastguard Worker 	} while (new_seq > EXT4_MMP_SEQ_MAX);
189*6a54128fSAndroid Build Coastguard Worker 
190*6a54128fSAndroid Build Coastguard Worker 	return new_seq;
191*6a54128fSAndroid Build Coastguard Worker #else
192*6a54128fSAndroid Build Coastguard Worker 	return EXT2_ET_OP_NOT_SUPPORTED;
193*6a54128fSAndroid Build Coastguard Worker #endif
194*6a54128fSAndroid Build Coastguard Worker }
195*6a54128fSAndroid Build Coastguard Worker 
196*6a54128fSAndroid Build Coastguard Worker #ifdef CONFIG_MMP
ext2fs_mmp_reset(ext2_filsys fs)197*6a54128fSAndroid Build Coastguard Worker static errcode_t ext2fs_mmp_reset(ext2_filsys fs)
198*6a54128fSAndroid Build Coastguard Worker {
199*6a54128fSAndroid Build Coastguard Worker 	struct mmp_struct *mmp_s = NULL;
200*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval = 0;
201*6a54128fSAndroid Build Coastguard Worker 
202*6a54128fSAndroid Build Coastguard Worker 	if (fs->mmp_buf == NULL) {
203*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf);
204*6a54128fSAndroid Build Coastguard Worker 		if (retval)
205*6a54128fSAndroid Build Coastguard Worker 			goto out;
206*6a54128fSAndroid Build Coastguard Worker 	}
207*6a54128fSAndroid Build Coastguard Worker 
208*6a54128fSAndroid Build Coastguard Worker 	memset(fs->mmp_buf, 0, fs->blocksize);
209*6a54128fSAndroid Build Coastguard Worker 	mmp_s = fs->mmp_buf;
210*6a54128fSAndroid Build Coastguard Worker 
211*6a54128fSAndroid Build Coastguard Worker 	mmp_s->mmp_magic = EXT4_MMP_MAGIC;
212*6a54128fSAndroid Build Coastguard Worker 	mmp_s->mmp_seq = EXT4_MMP_SEQ_CLEAN;
213*6a54128fSAndroid Build Coastguard Worker 	mmp_s->mmp_time = 0;
214*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_GETHOSTNAME
215*6a54128fSAndroid Build Coastguard Worker 	gethostname((char *) mmp_s->mmp_nodename, sizeof(mmp_s->mmp_nodename));
216*6a54128fSAndroid Build Coastguard Worker #else
217*6a54128fSAndroid Build Coastguard Worker 	mmp_s->mmp_nodename[0] = '\0';
218*6a54128fSAndroid Build Coastguard Worker #endif
219*6a54128fSAndroid Build Coastguard Worker 	strncpy((char *) mmp_s->mmp_bdevname, fs->device_name,
220*6a54128fSAndroid Build Coastguard Worker 		sizeof(mmp_s->mmp_bdevname));
221*6a54128fSAndroid Build Coastguard Worker 
222*6a54128fSAndroid Build Coastguard Worker 	mmp_s->mmp_check_interval = fs->super->s_mmp_update_interval;
223*6a54128fSAndroid Build Coastguard Worker 	if (mmp_s->mmp_check_interval < EXT4_MMP_MIN_CHECK_INTERVAL)
224*6a54128fSAndroid Build Coastguard Worker 		mmp_s->mmp_check_interval = EXT4_MMP_MIN_CHECK_INTERVAL;
225*6a54128fSAndroid Build Coastguard Worker 
226*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf);
227*6a54128fSAndroid Build Coastguard Worker out:
228*6a54128fSAndroid Build Coastguard Worker 	return retval;
229*6a54128fSAndroid Build Coastguard Worker }
230*6a54128fSAndroid Build Coastguard Worker #endif
231*6a54128fSAndroid Build Coastguard Worker 
ext2fs_mmp_update(ext2_filsys fs)232*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_mmp_update(ext2_filsys fs)
233*6a54128fSAndroid Build Coastguard Worker {
234*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_mmp_update2(fs, 0);
235*6a54128fSAndroid Build Coastguard Worker }
236*6a54128fSAndroid Build Coastguard Worker 
ext2fs_mmp_clear(ext2_filsys fs)237*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_mmp_clear(ext2_filsys fs)
238*6a54128fSAndroid Build Coastguard Worker {
239*6a54128fSAndroid Build Coastguard Worker #ifdef CONFIG_MMP
240*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval = 0;
241*6a54128fSAndroid Build Coastguard Worker 
242*6a54128fSAndroid Build Coastguard Worker 	if (!(fs->flags & EXT2_FLAG_RW))
243*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_RO_FILSYS;
244*6a54128fSAndroid Build Coastguard Worker 
245*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_reset(fs);
246*6a54128fSAndroid Build Coastguard Worker 
247*6a54128fSAndroid Build Coastguard Worker 	return retval;
248*6a54128fSAndroid Build Coastguard Worker #else
249*6a54128fSAndroid Build Coastguard Worker 	return EXT2_ET_OP_NOT_SUPPORTED;
250*6a54128fSAndroid Build Coastguard Worker #endif
251*6a54128fSAndroid Build Coastguard Worker }
252*6a54128fSAndroid Build Coastguard Worker 
ext2fs_mmp_init(ext2_filsys fs)253*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_mmp_init(ext2_filsys fs)
254*6a54128fSAndroid Build Coastguard Worker {
255*6a54128fSAndroid Build Coastguard Worker #ifdef CONFIG_MMP
256*6a54128fSAndroid Build Coastguard Worker 	struct ext2_super_block *sb = fs->super;
257*6a54128fSAndroid Build Coastguard Worker 	blk64_t mmp_block;
258*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval;
259*6a54128fSAndroid Build Coastguard Worker 
260*6a54128fSAndroid Build Coastguard Worker 	if (sb->s_mmp_update_interval == 0)
261*6a54128fSAndroid Build Coastguard Worker 		sb->s_mmp_update_interval = EXT4_MMP_UPDATE_INTERVAL;
262*6a54128fSAndroid Build Coastguard Worker 	/* This is probably excessively large, but who knows? */
263*6a54128fSAndroid Build Coastguard Worker 	else if (sb->s_mmp_update_interval > EXT4_MMP_MAX_UPDATE_INTERVAL)
264*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_INVALID_ARGUMENT;
265*6a54128fSAndroid Build Coastguard Worker 
266*6a54128fSAndroid Build Coastguard Worker 	if (fs->mmp_buf == NULL) {
267*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf);
268*6a54128fSAndroid Build Coastguard Worker 		if (retval)
269*6a54128fSAndroid Build Coastguard Worker 			goto out;
270*6a54128fSAndroid Build Coastguard Worker 	}
271*6a54128fSAndroid Build Coastguard Worker 
272*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_alloc_block2(fs, 0, fs->mmp_buf, &mmp_block);
273*6a54128fSAndroid Build Coastguard Worker 	if (retval)
274*6a54128fSAndroid Build Coastguard Worker 		goto out;
275*6a54128fSAndroid Build Coastguard Worker 
276*6a54128fSAndroid Build Coastguard Worker 	sb->s_mmp_block = mmp_block;
277*6a54128fSAndroid Build Coastguard Worker 
278*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_reset(fs);
279*6a54128fSAndroid Build Coastguard Worker 	if (retval)
280*6a54128fSAndroid Build Coastguard Worker 		goto out;
281*6a54128fSAndroid Build Coastguard Worker 
282*6a54128fSAndroid Build Coastguard Worker out:
283*6a54128fSAndroid Build Coastguard Worker 	return retval;
284*6a54128fSAndroid Build Coastguard Worker #else
285*6a54128fSAndroid Build Coastguard Worker 	return EXT2_ET_OP_NOT_SUPPORTED;
286*6a54128fSAndroid Build Coastguard Worker #endif
287*6a54128fSAndroid Build Coastguard Worker }
288*6a54128fSAndroid Build Coastguard Worker 
289*6a54128fSAndroid Build Coastguard Worker #ifndef min
290*6a54128fSAndroid Build Coastguard Worker #define min(x, y) ((x) < (y) ? (x) : (y))
291*6a54128fSAndroid Build Coastguard Worker #endif
292*6a54128fSAndroid Build Coastguard Worker 
293*6a54128fSAndroid Build Coastguard Worker /*
294*6a54128fSAndroid Build Coastguard Worker  * Make sure that the fs is not mounted or being fsck'ed while opening the fs.
295*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_mmp_start(ext2_filsys fs)296*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_mmp_start(ext2_filsys fs)
297*6a54128fSAndroid Build Coastguard Worker {
298*6a54128fSAndroid Build Coastguard Worker #ifdef CONFIG_MMP
299*6a54128fSAndroid Build Coastguard Worker 	struct mmp_struct *mmp_s;
300*6a54128fSAndroid Build Coastguard Worker 	unsigned seq;
301*6a54128fSAndroid Build Coastguard Worker 	unsigned int mmp_check_interval;
302*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval = 0;
303*6a54128fSAndroid Build Coastguard Worker 
304*6a54128fSAndroid Build Coastguard Worker 	if (fs->mmp_buf == NULL) {
305*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf);
306*6a54128fSAndroid Build Coastguard Worker 		if (retval)
307*6a54128fSAndroid Build Coastguard Worker 			goto mmp_error;
308*6a54128fSAndroid Build Coastguard Worker 	}
309*6a54128fSAndroid Build Coastguard Worker 
310*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf);
311*6a54128fSAndroid Build Coastguard Worker 	if (retval)
312*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
313*6a54128fSAndroid Build Coastguard Worker 
314*6a54128fSAndroid Build Coastguard Worker 	mmp_s = fs->mmp_buf;
315*6a54128fSAndroid Build Coastguard Worker 
316*6a54128fSAndroid Build Coastguard Worker 	mmp_check_interval = fs->super->s_mmp_update_interval;
317*6a54128fSAndroid Build Coastguard Worker 	if (mmp_check_interval < EXT4_MMP_MIN_CHECK_INTERVAL)
318*6a54128fSAndroid Build Coastguard Worker 		mmp_check_interval = EXT4_MMP_MIN_CHECK_INTERVAL;
319*6a54128fSAndroid Build Coastguard Worker 
320*6a54128fSAndroid Build Coastguard Worker 	seq = mmp_s->mmp_seq;
321*6a54128fSAndroid Build Coastguard Worker 	if (seq == EXT4_MMP_SEQ_CLEAN)
322*6a54128fSAndroid Build Coastguard Worker 		goto clean_seq;
323*6a54128fSAndroid Build Coastguard Worker 	if (seq == EXT4_MMP_SEQ_FSCK) {
324*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_MMP_FSCK_ON;
325*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
326*6a54128fSAndroid Build Coastguard Worker 	}
327*6a54128fSAndroid Build Coastguard Worker 
328*6a54128fSAndroid Build Coastguard Worker 	if (seq > EXT4_MMP_SEQ_FSCK) {
329*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_MMP_UNKNOWN_SEQ;
330*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
331*6a54128fSAndroid Build Coastguard Worker 	}
332*6a54128fSAndroid Build Coastguard Worker 
333*6a54128fSAndroid Build Coastguard Worker 	/*
334*6a54128fSAndroid Build Coastguard Worker 	 * If check_interval in MMP block is larger, use that instead of
335*6a54128fSAndroid Build Coastguard Worker 	 * check_interval from the superblock.
336*6a54128fSAndroid Build Coastguard Worker 	 */
337*6a54128fSAndroid Build Coastguard Worker 	if (mmp_s->mmp_check_interval > mmp_check_interval)
338*6a54128fSAndroid Build Coastguard Worker 		mmp_check_interval = mmp_s->mmp_check_interval;
339*6a54128fSAndroid Build Coastguard Worker 
340*6a54128fSAndroid Build Coastguard Worker 	sleep(min(mmp_check_interval * 2 + 1, mmp_check_interval + 60));
341*6a54128fSAndroid Build Coastguard Worker 
342*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf);
343*6a54128fSAndroid Build Coastguard Worker 	if (retval)
344*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
345*6a54128fSAndroid Build Coastguard Worker 
346*6a54128fSAndroid Build Coastguard Worker 	if (seq != mmp_s->mmp_seq) {
347*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_MMP_FAILED;
348*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
349*6a54128fSAndroid Build Coastguard Worker 	}
350*6a54128fSAndroid Build Coastguard Worker 
351*6a54128fSAndroid Build Coastguard Worker clean_seq:
352*6a54128fSAndroid Build Coastguard Worker 	if (!(fs->flags & EXT2_FLAG_RW))
353*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
354*6a54128fSAndroid Build Coastguard Worker 
355*6a54128fSAndroid Build Coastguard Worker 	mmp_s->mmp_seq = seq = ext2fs_mmp_new_seq();
356*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_GETHOSTNAME
357*6a54128fSAndroid Build Coastguard Worker 	gethostname((char *) mmp_s->mmp_nodename, sizeof(mmp_s->mmp_nodename));
358*6a54128fSAndroid Build Coastguard Worker #else
359*6a54128fSAndroid Build Coastguard Worker 	strcpy((char *) mmp_s->mmp_nodename, "unknown host");
360*6a54128fSAndroid Build Coastguard Worker #endif
361*6a54128fSAndroid Build Coastguard Worker 	strncpy((char *) mmp_s->mmp_bdevname, fs->device_name,
362*6a54128fSAndroid Build Coastguard Worker 		sizeof(mmp_s->mmp_bdevname));
363*6a54128fSAndroid Build Coastguard Worker 
364*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf);
365*6a54128fSAndroid Build Coastguard Worker 	if (retval)
366*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
367*6a54128fSAndroid Build Coastguard Worker 
368*6a54128fSAndroid Build Coastguard Worker 	sleep(min(2 * mmp_check_interval + 1, mmp_check_interval + 60));
369*6a54128fSAndroid Build Coastguard Worker 
370*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf);
371*6a54128fSAndroid Build Coastguard Worker 	if (retval)
372*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
373*6a54128fSAndroid Build Coastguard Worker 
374*6a54128fSAndroid Build Coastguard Worker 	if (seq != mmp_s->mmp_seq) {
375*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_MMP_FAILED;
376*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
377*6a54128fSAndroid Build Coastguard Worker 	}
378*6a54128fSAndroid Build Coastguard Worker 
379*6a54128fSAndroid Build Coastguard Worker 	mmp_s->mmp_seq = EXT4_MMP_SEQ_FSCK;
380*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf);
381*6a54128fSAndroid Build Coastguard Worker 	if (retval)
382*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
383*6a54128fSAndroid Build Coastguard Worker 
384*6a54128fSAndroid Build Coastguard Worker 	return 0;
385*6a54128fSAndroid Build Coastguard Worker 
386*6a54128fSAndroid Build Coastguard Worker mmp_error:
387*6a54128fSAndroid Build Coastguard Worker 	return retval;
388*6a54128fSAndroid Build Coastguard Worker #else
389*6a54128fSAndroid Build Coastguard Worker 	return EXT2_ET_OP_NOT_SUPPORTED;
390*6a54128fSAndroid Build Coastguard Worker #endif
391*6a54128fSAndroid Build Coastguard Worker }
392*6a54128fSAndroid Build Coastguard Worker 
393*6a54128fSAndroid Build Coastguard Worker /*
394*6a54128fSAndroid Build Coastguard Worker  * Clear the MMP usage in the filesystem.  If this function returns an
395*6a54128fSAndroid Build Coastguard Worker  * error EXT2_ET_MMP_CHANGE_ABORT it means the filesystem was modified
396*6a54128fSAndroid Build Coastguard Worker  * by some other process while in use, and changes should be dropped, or
397*6a54128fSAndroid Build Coastguard Worker  * risk filesystem corruption.
398*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_mmp_stop(ext2_filsys fs)399*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_mmp_stop(ext2_filsys fs)
400*6a54128fSAndroid Build Coastguard Worker {
401*6a54128fSAndroid Build Coastguard Worker #ifdef CONFIG_MMP
402*6a54128fSAndroid Build Coastguard Worker 	struct mmp_struct *mmp, *mmp_cmp;
403*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval = 0;
404*6a54128fSAndroid Build Coastguard Worker 
405*6a54128fSAndroid Build Coastguard Worker 	if (!ext2fs_has_feature_mmp(fs->super) ||
406*6a54128fSAndroid Build Coastguard Worker 	    !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP) ||
407*6a54128fSAndroid Build Coastguard Worker 	    (fs->mmp_buf == NULL) || (fs->mmp_cmp == NULL))
408*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
409*6a54128fSAndroid Build Coastguard Worker 
410*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, NULL);
411*6a54128fSAndroid Build Coastguard Worker 	if (retval)
412*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
413*6a54128fSAndroid Build Coastguard Worker 
414*6a54128fSAndroid Build Coastguard Worker 	/* Check if the MMP block is not changed. */
415*6a54128fSAndroid Build Coastguard Worker 	mmp = fs->mmp_buf;
416*6a54128fSAndroid Build Coastguard Worker 	mmp_cmp = fs->mmp_cmp;
417*6a54128fSAndroid Build Coastguard Worker 	if (memcmp(mmp, mmp_cmp, sizeof(*mmp_cmp))) {
418*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_MMP_CHANGE_ABORT;
419*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
420*6a54128fSAndroid Build Coastguard Worker 	}
421*6a54128fSAndroid Build Coastguard Worker 
422*6a54128fSAndroid Build Coastguard Worker 	mmp_cmp->mmp_seq = EXT4_MMP_SEQ_CLEAN;
423*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_cmp);
424*6a54128fSAndroid Build Coastguard Worker 
425*6a54128fSAndroid Build Coastguard Worker mmp_error:
426*6a54128fSAndroid Build Coastguard Worker 	if (fs->mmp_fd > 0) {
427*6a54128fSAndroid Build Coastguard Worker 		close(fs->mmp_fd);
428*6a54128fSAndroid Build Coastguard Worker 		fs->mmp_fd = -1;
429*6a54128fSAndroid Build Coastguard Worker 	}
430*6a54128fSAndroid Build Coastguard Worker 
431*6a54128fSAndroid Build Coastguard Worker 	return retval;
432*6a54128fSAndroid Build Coastguard Worker #else
433*6a54128fSAndroid Build Coastguard Worker 	if (!ext2fs_has_feature_mmp(fs->super) ||
434*6a54128fSAndroid Build Coastguard Worker 	    !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP))
435*6a54128fSAndroid Build Coastguard Worker 		return 0;
436*6a54128fSAndroid Build Coastguard Worker 
437*6a54128fSAndroid Build Coastguard Worker 	return EXT2_ET_OP_NOT_SUPPORTED;
438*6a54128fSAndroid Build Coastguard Worker #endif
439*6a54128fSAndroid Build Coastguard Worker }
440*6a54128fSAndroid Build Coastguard Worker 
441*6a54128fSAndroid Build Coastguard Worker #define EXT2_MIN_MMP_UPDATE_INTERVAL 60
442*6a54128fSAndroid Build Coastguard Worker 
443*6a54128fSAndroid Build Coastguard Worker /*
444*6a54128fSAndroid Build Coastguard Worker  * Update the on-disk mmp buffer, after checking that it hasn't been changed.
445*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_mmp_update2(ext2_filsys fs,int immediately)446*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_mmp_update2(ext2_filsys fs, int immediately)
447*6a54128fSAndroid Build Coastguard Worker {
448*6a54128fSAndroid Build Coastguard Worker #ifdef CONFIG_MMP
449*6a54128fSAndroid Build Coastguard Worker 	struct mmp_struct *mmp, *mmp_cmp;
450*6a54128fSAndroid Build Coastguard Worker 	struct timeval tv;
451*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval = 0;
452*6a54128fSAndroid Build Coastguard Worker 
453*6a54128fSAndroid Build Coastguard Worker 	if (!ext2fs_has_feature_mmp(fs->super) ||
454*6a54128fSAndroid Build Coastguard Worker 	    !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP))
455*6a54128fSAndroid Build Coastguard Worker 		return 0;
456*6a54128fSAndroid Build Coastguard Worker 
457*6a54128fSAndroid Build Coastguard Worker 	gettimeofday(&tv, 0);
458*6a54128fSAndroid Build Coastguard Worker 	if (!immediately &&
459*6a54128fSAndroid Build Coastguard Worker 	    tv.tv_sec - fs->mmp_last_written < EXT2_MIN_MMP_UPDATE_INTERVAL)
460*6a54128fSAndroid Build Coastguard Worker 		return 0;
461*6a54128fSAndroid Build Coastguard Worker 
462*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, NULL);
463*6a54128fSAndroid Build Coastguard Worker 	if (retval)
464*6a54128fSAndroid Build Coastguard Worker 		goto mmp_error;
465*6a54128fSAndroid Build Coastguard Worker 
466*6a54128fSAndroid Build Coastguard Worker 	mmp = fs->mmp_buf;
467*6a54128fSAndroid Build Coastguard Worker 	mmp_cmp = fs->mmp_cmp;
468*6a54128fSAndroid Build Coastguard Worker 
469*6a54128fSAndroid Build Coastguard Worker 	if (memcmp(mmp, mmp_cmp, sizeof(*mmp_cmp)))
470*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_MMP_CHANGE_ABORT;
471*6a54128fSAndroid Build Coastguard Worker 
472*6a54128fSAndroid Build Coastguard Worker 	mmp->mmp_time = tv.tv_sec;
473*6a54128fSAndroid Build Coastguard Worker 	mmp->mmp_seq = EXT4_MMP_SEQ_FSCK;
474*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf);
475*6a54128fSAndroid Build Coastguard Worker 
476*6a54128fSAndroid Build Coastguard Worker mmp_error:
477*6a54128fSAndroid Build Coastguard Worker 	return retval;
478*6a54128fSAndroid Build Coastguard Worker #else
479*6a54128fSAndroid Build Coastguard Worker 	if (!ext2fs_has_feature_mmp(fs->super) ||
480*6a54128fSAndroid Build Coastguard Worker 	    !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP))
481*6a54128fSAndroid Build Coastguard Worker 		return 0;
482*6a54128fSAndroid Build Coastguard Worker 
483*6a54128fSAndroid Build Coastguard Worker 	return EXT2_ET_OP_NOT_SUPPORTED;
484*6a54128fSAndroid Build Coastguard Worker #endif
485*6a54128fSAndroid Build Coastguard Worker }
486*6a54128fSAndroid Build Coastguard Worker #if __GNUC_PREREQ (4, 6)
487*6a54128fSAndroid Build Coastguard Worker #pragma GCC diagnostic pop
488*6a54128fSAndroid Build Coastguard Worker #endif
489