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