xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/mmap/mmap16.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2015 Fujitsu Ltd. Xiaoguang Wang <[email protected]>
4*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (C) 2021 SUSE LLC Andrea Cervesato <[email protected]>
5*49cdfc7eSAndroid Build Coastguard Worker  */
6*49cdfc7eSAndroid Build Coastguard Worker 
7*49cdfc7eSAndroid Build Coastguard Worker /*\
8*49cdfc7eSAndroid Build Coastguard Worker  * [Description]
9*49cdfc7eSAndroid Build Coastguard Worker  *
10*49cdfc7eSAndroid Build Coastguard Worker  * This is a regression test for a silent data corruption for a mmaped file
11*49cdfc7eSAndroid Build Coastguard Worker  * when filesystem gets out of space.
12*49cdfc7eSAndroid Build Coastguard Worker  *
13*49cdfc7eSAndroid Build Coastguard Worker  * Fixed by commits:
14*49cdfc7eSAndroid Build Coastguard Worker  *
15*49cdfc7eSAndroid Build Coastguard Worker  *  commit 0572639ff66dcffe62d37adfe4c4576f9fc398f4
16*49cdfc7eSAndroid Build Coastguard Worker  *  Author: Xiaoguang Wang <[email protected]>
17*49cdfc7eSAndroid Build Coastguard Worker  *  Date:   Thu Feb 12 23:00:17 2015 -0500
18*49cdfc7eSAndroid Build Coastguard Worker  *
19*49cdfc7eSAndroid Build Coastguard Worker  *      ext4: fix mmap data corruption in nodelalloc mode when blocksize < pagesize
20*49cdfc7eSAndroid Build Coastguard Worker  *
21*49cdfc7eSAndroid Build Coastguard Worker  *  commit d6320cbfc92910a3e5f10c42d98c231c98db4f60
22*49cdfc7eSAndroid Build Coastguard Worker  *  Author: Jan Kara <[email protected]>
23*49cdfc7eSAndroid Build Coastguard Worker  *  Date:   Wed Oct 1 21:49:46 2014 -0400
24*49cdfc7eSAndroid Build Coastguard Worker  *
25*49cdfc7eSAndroid Build Coastguard Worker  *      ext4: fix mmap data corruption when blocksize < pagesize
26*49cdfc7eSAndroid Build Coastguard Worker  */
27*49cdfc7eSAndroid Build Coastguard Worker 
28*49cdfc7eSAndroid Build Coastguard Worker #define _GNU_SOURCE
29*49cdfc7eSAndroid Build Coastguard Worker 
30*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
31*49cdfc7eSAndroid Build Coastguard Worker #include <signal.h>
32*49cdfc7eSAndroid Build Coastguard Worker #include <time.h>
33*49cdfc7eSAndroid Build Coastguard Worker #include <sys/mman.h>
34*49cdfc7eSAndroid Build Coastguard Worker #include <sys/wait.h>
35*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
36*49cdfc7eSAndroid Build Coastguard Worker 
37*49cdfc7eSAndroid Build Coastguard Worker #define MNTPOINT "mntpoint"
38*49cdfc7eSAndroid Build Coastguard Worker #define FILE_PARENT "mntpoint/testfilep"
39*49cdfc7eSAndroid Build Coastguard Worker #define FILE_CHILD "mntpoint/testfilec"
40*49cdfc7eSAndroid Build Coastguard Worker #define FS_BLOCKSIZE 1024
41*49cdfc7eSAndroid Build Coastguard Worker #define LOOPS 10
42*49cdfc7eSAndroid Build Coastguard Worker 
43*49cdfc7eSAndroid Build Coastguard Worker static int parentfd = -1;
44*49cdfc7eSAndroid Build Coastguard Worker static int childfd = -1;
45*49cdfc7eSAndroid Build Coastguard Worker 
do_child(void)46*49cdfc7eSAndroid Build Coastguard Worker static void do_child(void)
47*49cdfc7eSAndroid Build Coastguard Worker {
48*49cdfc7eSAndroid Build Coastguard Worker 	int offset;
49*49cdfc7eSAndroid Build Coastguard Worker 	int page_size;
50*49cdfc7eSAndroid Build Coastguard Worker 	char buf[FS_BLOCKSIZE];
51*49cdfc7eSAndroid Build Coastguard Worker 	char *addr = NULL;
52*49cdfc7eSAndroid Build Coastguard Worker 
53*49cdfc7eSAndroid Build Coastguard Worker 	page_size = getpagesize();
54*49cdfc7eSAndroid Build Coastguard Worker 
55*49cdfc7eSAndroid Build Coastguard Worker 	childfd = SAFE_OPEN(FILE_CHILD, O_RDWR | O_CREAT, 0666);
56*49cdfc7eSAndroid Build Coastguard Worker 
57*49cdfc7eSAndroid Build Coastguard Worker 	memset(buf, 'a', FS_BLOCKSIZE);
58*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_WRITE(SAFE_WRITE_ALL, childfd, buf, FS_BLOCKSIZE);
59*49cdfc7eSAndroid Build Coastguard Worker 
60*49cdfc7eSAndroid Build Coastguard Worker 	/*
61*49cdfc7eSAndroid Build Coastguard Worker 	 * In case mremap() may fail because that memory area can not be
62*49cdfc7eSAndroid Build Coastguard Worker 	 * expanded at current virtual address(MREMAP_MAYMOVE is not set),
63*49cdfc7eSAndroid Build Coastguard Worker 	 * we first do a mmap(page_size * 2) operation to reserve some
64*49cdfc7eSAndroid Build Coastguard Worker 	 * free address space.
65*49cdfc7eSAndroid Build Coastguard Worker 	 */
66*49cdfc7eSAndroid Build Coastguard Worker 	addr = SAFE_MMAP(NULL, page_size * 2, PROT_WRITE | PROT_READ,
67*49cdfc7eSAndroid Build Coastguard Worker 			 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
68*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_MUNMAP(addr, page_size * 2);
69*49cdfc7eSAndroid Build Coastguard Worker 
70*49cdfc7eSAndroid Build Coastguard Worker 	addr = SAFE_MMAP(addr, FS_BLOCKSIZE, PROT_WRITE | PROT_READ, MAP_SHARED, childfd, 0);
71*49cdfc7eSAndroid Build Coastguard Worker 
72*49cdfc7eSAndroid Build Coastguard Worker 	addr[0] = 'a';
73*49cdfc7eSAndroid Build Coastguard Worker 
74*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FTRUNCATE(childfd, page_size * 2);
75*49cdfc7eSAndroid Build Coastguard Worker 
76*49cdfc7eSAndroid Build Coastguard Worker 	addr = mremap(addr, FS_BLOCKSIZE, 2 * page_size, 0);
77*49cdfc7eSAndroid Build Coastguard Worker 	if (addr == MAP_FAILED)
78*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TERRNO, "mremap failed unexpectedly");
79*49cdfc7eSAndroid Build Coastguard Worker 
80*49cdfc7eSAndroid Build Coastguard Worker 	/*
81*49cdfc7eSAndroid Build Coastguard Worker 	 * Let parent process consume FS free blocks as many as possible, then
82*49cdfc7eSAndroid Build Coastguard Worker 	 * there'll be no free blocks allocated for this new file mmaping for
83*49cdfc7eSAndroid Build Coastguard Worker 	 * offset starting at 1024, 2048, or 3072. If this above kernel bug
84*49cdfc7eSAndroid Build Coastguard Worker 	 * has been fixed, usually child process will killed by SIGBUS signal,
85*49cdfc7eSAndroid Build Coastguard Worker 	 * if not, the data 'A', 'B', 'C' will be silently discarded later when
86*49cdfc7eSAndroid Build Coastguard Worker 	 * kernel writepage is called, that means data corruption.
87*49cdfc7eSAndroid Build Coastguard Worker 	 */
88*49cdfc7eSAndroid Build Coastguard Worker 	TST_CHECKPOINT_WAKE_AND_WAIT(0);
89*49cdfc7eSAndroid Build Coastguard Worker 
90*49cdfc7eSAndroid Build Coastguard Worker 	for (offset = FS_BLOCKSIZE; offset < page_size; offset += FS_BLOCKSIZE)
91*49cdfc7eSAndroid Build Coastguard Worker 		addr[offset] = 'a';
92*49cdfc7eSAndroid Build Coastguard Worker 
93*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_MUNMAP(addr, 2 * page_size);
94*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_CLOSE(childfd);
95*49cdfc7eSAndroid Build Coastguard Worker 
96*49cdfc7eSAndroid Build Coastguard Worker 	exit(1);
97*49cdfc7eSAndroid Build Coastguard Worker }
98*49cdfc7eSAndroid Build Coastguard Worker 
run_single(void)99*49cdfc7eSAndroid Build Coastguard Worker static void run_single(void)
100*49cdfc7eSAndroid Build Coastguard Worker {
101*49cdfc7eSAndroid Build Coastguard Worker 	int ret, status;
102*49cdfc7eSAndroid Build Coastguard Worker 	pid_t child;
103*49cdfc7eSAndroid Build Coastguard Worker 	char buf[FS_BLOCKSIZE];
104*49cdfc7eSAndroid Build Coastguard Worker 	int bug_reproduced = 0;
105*49cdfc7eSAndroid Build Coastguard Worker 
106*49cdfc7eSAndroid Build Coastguard Worker 	child = SAFE_FORK();
107*49cdfc7eSAndroid Build Coastguard Worker 	if (!child) {
108*49cdfc7eSAndroid Build Coastguard Worker 		do_child();
109*49cdfc7eSAndroid Build Coastguard Worker 		return;
110*49cdfc7eSAndroid Build Coastguard Worker 	}
111*49cdfc7eSAndroid Build Coastguard Worker 
112*49cdfc7eSAndroid Build Coastguard Worker 	parentfd = SAFE_OPEN(FILE_PARENT, O_RDWR | O_CREAT, 0666);
113*49cdfc7eSAndroid Build Coastguard Worker 
114*49cdfc7eSAndroid Build Coastguard Worker 	memset(buf, 'a', FS_BLOCKSIZE);
115*49cdfc7eSAndroid Build Coastguard Worker 
116*49cdfc7eSAndroid Build Coastguard Worker 	TST_CHECKPOINT_WAIT(0);
117*49cdfc7eSAndroid Build Coastguard Worker 
118*49cdfc7eSAndroid Build Coastguard Worker 	while (1) {
119*49cdfc7eSAndroid Build Coastguard Worker 		ret = write(parentfd, buf, FS_BLOCKSIZE);
120*49cdfc7eSAndroid Build Coastguard Worker 		if (ret < 0) {
121*49cdfc7eSAndroid Build Coastguard Worker 			if (errno == ENOSPC)
122*49cdfc7eSAndroid Build Coastguard Worker 				break;
123*49cdfc7eSAndroid Build Coastguard Worker 
124*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK | TERRNO, "write failed unexpectedly");
125*49cdfc7eSAndroid Build Coastguard Worker 		}
126*49cdfc7eSAndroid Build Coastguard Worker 	}
127*49cdfc7eSAndroid Build Coastguard Worker 
128*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_CLOSE(parentfd);
129*49cdfc7eSAndroid Build Coastguard Worker 
130*49cdfc7eSAndroid Build Coastguard Worker 	TST_CHECKPOINT_WAKE(0);
131*49cdfc7eSAndroid Build Coastguard Worker 
132*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_WAITPID(child, &status, 0);
133*49cdfc7eSAndroid Build Coastguard Worker 	if (WIFEXITED(status) && WEXITSTATUS(status) == 1) {
134*49cdfc7eSAndroid Build Coastguard Worker 		bug_reproduced = 1;
135*49cdfc7eSAndroid Build Coastguard Worker 	} else {
136*49cdfc7eSAndroid Build Coastguard Worker 		/*
137*49cdfc7eSAndroid Build Coastguard Worker 		 * If child process was killed by SIGBUS, bug is not reproduced.
138*49cdfc7eSAndroid Build Coastguard Worker 		 */
139*49cdfc7eSAndroid Build Coastguard Worker 		if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGBUS) {
140*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK | TERRNO, "child process terminate unexpectedly with status %s",
141*49cdfc7eSAndroid Build Coastguard Worker 				tst_strstatus(status));
142*49cdfc7eSAndroid Build Coastguard Worker 		}
143*49cdfc7eSAndroid Build Coastguard Worker 	}
144*49cdfc7eSAndroid Build Coastguard Worker 
145*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_UNLINK(FILE_PARENT);
146*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_UNLINK(FILE_CHILD);
147*49cdfc7eSAndroid Build Coastguard Worker 
148*49cdfc7eSAndroid Build Coastguard Worker 	if (bug_reproduced)
149*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "bug is reproduced");
150*49cdfc7eSAndroid Build Coastguard Worker 	else
151*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TPASS, "bug is not reproduced");
152*49cdfc7eSAndroid Build Coastguard Worker }
153*49cdfc7eSAndroid Build Coastguard Worker 
run(void)154*49cdfc7eSAndroid Build Coastguard Worker static void run(void)
155*49cdfc7eSAndroid Build Coastguard Worker {
156*49cdfc7eSAndroid Build Coastguard Worker 	int i;
157*49cdfc7eSAndroid Build Coastguard Worker 
158*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < LOOPS; i++)
159*49cdfc7eSAndroid Build Coastguard Worker 		run_single();
160*49cdfc7eSAndroid Build Coastguard Worker }
161*49cdfc7eSAndroid Build Coastguard Worker 
cleanup(void)162*49cdfc7eSAndroid Build Coastguard Worker static void cleanup(void)
163*49cdfc7eSAndroid Build Coastguard Worker {
164*49cdfc7eSAndroid Build Coastguard Worker 	if (childfd >= 0)
165*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(childfd);
166*49cdfc7eSAndroid Build Coastguard Worker 
167*49cdfc7eSAndroid Build Coastguard Worker 	if (parentfd >= 0)
168*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(parentfd);
169*49cdfc7eSAndroid Build Coastguard Worker }
170*49cdfc7eSAndroid Build Coastguard Worker 
171*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
172*49cdfc7eSAndroid Build Coastguard Worker 	.test_all = run,
173*49cdfc7eSAndroid Build Coastguard Worker 	.cleanup = cleanup,
174*49cdfc7eSAndroid Build Coastguard Worker 	.forks_child = 1,
175*49cdfc7eSAndroid Build Coastguard Worker 	.needs_root = 1,
176*49cdfc7eSAndroid Build Coastguard Worker 	.needs_checkpoints = 1,
177*49cdfc7eSAndroid Build Coastguard Worker 	.mount_device = 1,
178*49cdfc7eSAndroid Build Coastguard Worker 	.mntpoint = MNTPOINT,
179*49cdfc7eSAndroid Build Coastguard Worker 	.dev_fs_type = "ext4",
180*49cdfc7eSAndroid Build Coastguard Worker 	.dev_fs_opts = (const char *const[]){
181*49cdfc7eSAndroid Build Coastguard Worker 		"-b",
182*49cdfc7eSAndroid Build Coastguard Worker 		"1024",
183*49cdfc7eSAndroid Build Coastguard Worker 		NULL,
184*49cdfc7eSAndroid Build Coastguard Worker 	},
185*49cdfc7eSAndroid Build Coastguard Worker 	.dev_extra_opts = (const char *const[]){
186*49cdfc7eSAndroid Build Coastguard Worker 		"10240",
187*49cdfc7eSAndroid Build Coastguard Worker 		NULL,
188*49cdfc7eSAndroid Build Coastguard Worker 	},
189*49cdfc7eSAndroid Build Coastguard Worker 	.needs_cmds = (const char *const[]){
190*49cdfc7eSAndroid Build Coastguard Worker 		"mkfs.ext4",
191*49cdfc7eSAndroid Build Coastguard Worker 		NULL,
192*49cdfc7eSAndroid Build Coastguard Worker 	},
193*49cdfc7eSAndroid Build Coastguard Worker 	.tags = (const struct tst_tag[]){
194*49cdfc7eSAndroid Build Coastguard Worker 		{"linux-git", "d6320cbfc929"},
195*49cdfc7eSAndroid Build Coastguard Worker 		{"linux-git", "0572639ff66d"},
196*49cdfc7eSAndroid Build Coastguard Worker 		{},
197*49cdfc7eSAndroid Build Coastguard Worker 	},
198*49cdfc7eSAndroid Build Coastguard Worker };
199