@@ -22,12 +22,37 @@ FIXTURE(merge)
2222 struct procmap_fd procmap ;
2323};
2424
25+ static char * map_carveout (unsigned int page_size )
26+ {
27+ return mmap (NULL , 30 * page_size , PROT_NONE ,
28+ MAP_ANON | MAP_PRIVATE , -1 , 0 );
29+ }
30+
31+ static pid_t do_fork (struct procmap_fd * procmap )
32+ {
33+ pid_t pid = fork ();
34+
35+ if (pid == -1 )
36+ return -1 ;
37+ if (pid != 0 ) {
38+ wait (NULL );
39+ return pid ;
40+ }
41+
42+ /* Reopen for child. */
43+ if (close_procmap (procmap ))
44+ return -1 ;
45+ if (open_self_procmap (procmap ))
46+ return -1 ;
47+
48+ return 0 ;
49+ }
50+
2551FIXTURE_SETUP (merge )
2652{
2753 self -> page_size = psize ();
2854 /* Carve out PROT_NONE region to map over. */
29- self -> carveout = mmap (NULL , 30 * self -> page_size , PROT_NONE ,
30- MAP_ANON | MAP_PRIVATE , -1 , 0 );
55+ self -> carveout = map_carveout (self -> page_size );
3156 ASSERT_NE (self -> carveout , MAP_FAILED );
3257 /* Setup PROCMAP_QUERY interface. */
3358 ASSERT_EQ (open_self_procmap (& self -> procmap ), 0 );
@@ -36,14 +61,53 @@ FIXTURE_SETUP(merge)
3661FIXTURE_TEARDOWN (merge )
3762{
3863 ASSERT_EQ (munmap (self -> carveout , 30 * self -> page_size ), 0 );
39- ASSERT_EQ (close_procmap (& self -> procmap ), 0 );
64+ /* May fail for parent of forked process. */
65+ close_procmap (& self -> procmap );
4066 /*
4167 * Clear unconditionally, as some tests set this. It is no issue if this
4268 * fails (KSM may be disabled for instance).
4369 */
4470 prctl (PR_SET_MEMORY_MERGE , 0 , 0 , 0 , 0 );
4571}
4672
73+ FIXTURE (merge_with_fork )
74+ {
75+ unsigned int page_size ;
76+ char * carveout ;
77+ struct procmap_fd procmap ;
78+ };
79+
80+ FIXTURE_VARIANT (merge_with_fork )
81+ {
82+ bool forked ;
83+ };
84+
85+ FIXTURE_VARIANT_ADD (merge_with_fork , forked )
86+ {
87+ .forked = true,
88+ };
89+
90+ FIXTURE_VARIANT_ADD (merge_with_fork , unforked )
91+ {
92+ .forked = false,
93+ };
94+
95+ FIXTURE_SETUP (merge_with_fork )
96+ {
97+ self -> page_size = psize ();
98+ self -> carveout = map_carveout (self -> page_size );
99+ ASSERT_NE (self -> carveout , MAP_FAILED );
100+ ASSERT_EQ (open_self_procmap (& self -> procmap ), 0 );
101+ }
102+
103+ FIXTURE_TEARDOWN (merge_with_fork )
104+ {
105+ ASSERT_EQ (munmap (self -> carveout , 30 * self -> page_size ), 0 );
106+ ASSERT_EQ (close_procmap (& self -> procmap ), 0 );
107+ /* See above. */
108+ prctl (PR_SET_MEMORY_MERGE , 0 , 0 , 0 , 0 );
109+ }
110+
47111TEST_F (merge , mprotect_unfaulted_left )
48112{
49113 unsigned int page_size = self -> page_size ;
@@ -322,8 +386,8 @@ TEST_F(merge, forked_target_vma)
322386 unsigned int page_size = self -> page_size ;
323387 char * carveout = self -> carveout ;
324388 struct procmap_fd * procmap = & self -> procmap ;
325- pid_t pid ;
326389 char * ptr , * ptr2 ;
390+ pid_t pid ;
327391 int i ;
328392
329393 /*
@@ -344,19 +408,10 @@ TEST_F(merge, forked_target_vma)
344408 */
345409 ptr [0 ] = 'x' ;
346410
347- pid = fork ( );
411+ pid = do_fork ( & self -> procmap );
348412 ASSERT_NE (pid , -1 );
349-
350- if (pid != 0 ) {
351- wait (NULL );
413+ if (pid != 0 )
352414 return ;
353- }
354-
355- /* Child process below: */
356-
357- /* Reopen for child. */
358- ASSERT_EQ (close_procmap (& self -> procmap ), 0 );
359- ASSERT_EQ (open_self_procmap (& self -> procmap ), 0 );
360415
361416 /* unCOWing everything does not cause the AVC to go away. */
362417 for (i = 0 ; i < 5 * page_size ; i += page_size )
@@ -386,8 +441,8 @@ TEST_F(merge, forked_source_vma)
386441 unsigned int page_size = self -> page_size ;
387442 char * carveout = self -> carveout ;
388443 struct procmap_fd * procmap = & self -> procmap ;
389- pid_t pid ;
390444 char * ptr , * ptr2 ;
445+ pid_t pid ;
391446 int i ;
392447
393448 /*
@@ -408,19 +463,10 @@ TEST_F(merge, forked_source_vma)
408463 */
409464 ptr [0 ] = 'x' ;
410465
411- pid = fork ( );
466+ pid = do_fork ( & self -> procmap );
412467 ASSERT_NE (pid , -1 );
413-
414- if (pid != 0 ) {
415- wait (NULL );
468+ if (pid != 0 )
416469 return ;
417- }
418-
419- /* Child process below: */
420-
421- /* Reopen for child. */
422- ASSERT_EQ (close_procmap (& self -> procmap ), 0 );
423- ASSERT_EQ (open_self_procmap (& self -> procmap ), 0 );
424470
425471 /* unCOWing everything does not cause the AVC to go away. */
426472 for (i = 0 ; i < 5 * page_size ; i += page_size )
@@ -1171,10 +1217,11 @@ TEST_F(merge, mremap_correct_placed_faulted)
11711217 ASSERT_EQ (procmap -> query .vma_end , (unsigned long )ptr + 15 * page_size );
11721218}
11731219
1174- TEST_F (merge , mremap_faulted_to_unfaulted_prev )
1220+ TEST_F (merge_with_fork , mremap_faulted_to_unfaulted_prev )
11751221{
11761222 struct procmap_fd * procmap = & self -> procmap ;
11771223 unsigned int page_size = self -> page_size ;
1224+ unsigned long offset ;
11781225 char * ptr_a , * ptr_b ;
11791226
11801227 /*
@@ -1197,6 +1244,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev)
11971244 /* Fault it in. */
11981245 ptr_a [0 ] = 'x' ;
11991246
1247+ if (variant -> forked ) {
1248+ pid_t pid = do_fork (& self -> procmap );
1249+
1250+ ASSERT_NE (pid , -1 );
1251+ if (pid != 0 )
1252+ return ;
1253+ }
1254+
12001255 /*
12011256 * Now move it out of the way so we can place VMA B in position,
12021257 * unfaulted.
@@ -1220,16 +1275,19 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev)
12201275 & self -> carveout [page_size + 3 * page_size ]);
12211276 ASSERT_NE (ptr_a , MAP_FAILED );
12221277
1223- /* The VMAs should have merged. */
1278+ /* The VMAs should have merged, if not forked . */
12241279 ASSERT_TRUE (find_vma_procmap (procmap , ptr_b ));
12251280 ASSERT_EQ (procmap -> query .vma_start , (unsigned long )ptr_b );
1226- ASSERT_EQ (procmap -> query .vma_end , (unsigned long )ptr_b + 6 * page_size );
1281+
1282+ offset = variant -> forked ? 3 * page_size : 6 * page_size ;
1283+ ASSERT_EQ (procmap -> query .vma_end , (unsigned long )ptr_b + offset );
12271284}
12281285
1229- TEST_F (merge , mremap_faulted_to_unfaulted_next )
1286+ TEST_F (merge_with_fork , mremap_faulted_to_unfaulted_next )
12301287{
12311288 struct procmap_fd * procmap = & self -> procmap ;
12321289 unsigned int page_size = self -> page_size ;
1290+ unsigned long offset ;
12331291 char * ptr_a , * ptr_b ;
12341292
12351293 /*
@@ -1253,6 +1311,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_next)
12531311 /* Fault it in. */
12541312 ptr_a [0 ] = 'x' ;
12551313
1314+ if (variant -> forked ) {
1315+ pid_t pid = do_fork (& self -> procmap );
1316+
1317+ ASSERT_NE (pid , -1 );
1318+ if (pid != 0 )
1319+ return ;
1320+ }
1321+
12561322 /*
12571323 * Now move it out of the way so we can place VMA B in position,
12581324 * unfaulted.
@@ -1276,16 +1342,18 @@ TEST_F(merge, mremap_faulted_to_unfaulted_next)
12761342 & self -> carveout [page_size ]);
12771343 ASSERT_NE (ptr_a , MAP_FAILED );
12781344
1279- /* The VMAs should have merged. */
1345+ /* The VMAs should have merged, if not forked . */
12801346 ASSERT_TRUE (find_vma_procmap (procmap , ptr_a ));
12811347 ASSERT_EQ (procmap -> query .vma_start , (unsigned long )ptr_a );
1282- ASSERT_EQ (procmap -> query .vma_end , (unsigned long )ptr_a + 6 * page_size );
1348+ offset = variant -> forked ? 3 * page_size : 6 * page_size ;
1349+ ASSERT_EQ (procmap -> query .vma_end , (unsigned long )ptr_a + offset );
12831350}
12841351
1285- TEST_F (merge , mremap_faulted_to_unfaulted_prev_unfaulted_next )
1352+ TEST_F (merge_with_fork , mremap_faulted_to_unfaulted_prev_unfaulted_next )
12861353{
12871354 struct procmap_fd * procmap = & self -> procmap ;
12881355 unsigned int page_size = self -> page_size ;
1356+ unsigned long offset ;
12891357 char * ptr_a , * ptr_b , * ptr_c ;
12901358
12911359 /*
@@ -1307,6 +1375,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_unfaulted_next)
13071375 /* Fault it in. */
13081376 ptr_b [0 ] = 'x' ;
13091377
1378+ if (variant -> forked ) {
1379+ pid_t pid = do_fork (& self -> procmap );
1380+
1381+ ASSERT_NE (pid , -1 );
1382+ if (pid != 0 )
1383+ return ;
1384+ }
1385+
13101386 /*
13111387 * Now move it out of the way so we can place VMAs A, C in position,
13121388 * unfaulted.
@@ -1337,13 +1413,21 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_unfaulted_next)
13371413 & self -> carveout [page_size + 3 * page_size ]);
13381414 ASSERT_NE (ptr_b , MAP_FAILED );
13391415
1340- /* The VMAs should have merged. */
1416+ /* The VMAs should have merged, if not forked . */
13411417 ASSERT_TRUE (find_vma_procmap (procmap , ptr_a ));
13421418 ASSERT_EQ (procmap -> query .vma_start , (unsigned long )ptr_a );
1343- ASSERT_EQ (procmap -> query .vma_end , (unsigned long )ptr_a + 9 * page_size );
1419+ offset = variant -> forked ? 3 * page_size : 9 * page_size ;
1420+ ASSERT_EQ (procmap -> query .vma_end , (unsigned long )ptr_a + offset );
1421+
1422+ /* If forked, B and C should also not have merged. */
1423+ if (variant -> forked ) {
1424+ ASSERT_TRUE (find_vma_procmap (procmap , ptr_b ));
1425+ ASSERT_EQ (procmap -> query .vma_start , (unsigned long )ptr_b );
1426+ ASSERT_EQ (procmap -> query .vma_end , (unsigned long )ptr_b + 3 * page_size );
1427+ }
13441428}
13451429
1346- TEST_F (merge , mremap_faulted_to_unfaulted_prev_faulted_next )
1430+ TEST_F (merge_with_fork , mremap_faulted_to_unfaulted_prev_faulted_next )
13471431{
13481432 struct procmap_fd * procmap = & self -> procmap ;
13491433 unsigned int page_size = self -> page_size ;
@@ -1373,6 +1457,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_faulted_next)
13731457 /* Fault it in. */
13741458 ptr_bc [0 ] = 'x' ;
13751459
1460+ if (variant -> forked ) {
1461+ pid_t pid = do_fork (& self -> procmap );
1462+
1463+ ASSERT_NE (pid , -1 );
1464+ if (pid != 0 )
1465+ return ;
1466+ }
1467+
13761468 /*
13771469 * Now move VMA B out the way (splitting VMA BC) so we can place VMA A
13781470 * in position, unfaulted, and leave the remainder of the VMA we just
@@ -1397,10 +1489,16 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_faulted_next)
13971489 & self -> carveout [page_size + 3 * page_size ]);
13981490 ASSERT_NE (ptr_b , MAP_FAILED );
13991491
1400- /* The VMAs should have merged. */
1401- ASSERT_TRUE (find_vma_procmap (procmap , ptr_a ));
1402- ASSERT_EQ (procmap -> query .vma_start , (unsigned long )ptr_a );
1403- ASSERT_EQ (procmap -> query .vma_end , (unsigned long )ptr_a + 9 * page_size );
1492+ /* The VMAs should have merged. A,B,C if unforked, B, C if forked. */
1493+ if (variant -> forked ) {
1494+ ASSERT_TRUE (find_vma_procmap (procmap , ptr_b ));
1495+ ASSERT_EQ (procmap -> query .vma_start , (unsigned long )ptr_b );
1496+ ASSERT_EQ (procmap -> query .vma_end , (unsigned long )ptr_b + 6 * page_size );
1497+ } else {
1498+ ASSERT_TRUE (find_vma_procmap (procmap , ptr_a ));
1499+ ASSERT_EQ (procmap -> query .vma_start , (unsigned long )ptr_a );
1500+ ASSERT_EQ (procmap -> query .vma_end , (unsigned long )ptr_a + 9 * page_size );
1501+ }
14041502}
14051503
14061504TEST_HARNESS_MAIN
0 commit comments