1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2014 Red Hat, Inc.
4 * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
5 */
6
7 /*\
8 * [Description]
9 *
10 * Tests a slave mount: slave mount is like a shared mount except that
11 * mount and umount events only propagate towards it.
12 *
13 * [Algorithm]
14 *
15 * - Creates directories DIRA, DIRB and files DIRA/"A", DIRB/"B"
16 * - Unshares mount namespace and makes it private (so mounts/umounts have no
17 * effect on a real system)
18 * - Bind mounts directory DIRA to itself
19 * - Makes directory DIRA shared
20 * - Clones a new child process with CLONE_NEWNS flag and makes "A" a slave
21 * mount
22 * - There are two testcases (where X is parent namespace and Y child
23 * namespace):
24 * 1. First test case
25 * .. X: bind mounts DIRB to DIRA
26 * .. Y: must see the file DIRA/"B"
27 * .. X: umounts DIRA
28 * 2. Second test case
29 * .. Y: bind mounts DIRB to DIRA
30 * .. X: must see only the DIRA/"A" and must not see DIRA/"B" (as slave mount does
31 * not forward propagation)
32 * .. Y: umounts DIRA
33 */
34
35 #include <sys/wait.h>
36 #include <sys/mount.h>
37 #include "mountns.h"
38 #include "tst_test.h"
39
child_func(LTP_ATTRIBUTE_UNUSED void * arg)40 static int child_func(LTP_ATTRIBUTE_UNUSED void *arg)
41 {
42 /*
43 * makes mount DIRA a slave of DIRA (all slave mounts have
44 * a master mount which is a shared mount)
45 */
46 SAFE_MOUNT("none", DIRA, "none", MS_SLAVE, NULL);
47
48 TST_CHECKPOINT_WAKE_AND_WAIT(0);
49
50 if (access(DIRA "/B", F_OK) == 0)
51 tst_res(TPASS, "propagation to slave mount passed");
52 else
53 tst_res(TFAIL, "propagation to slave mount failed");
54
55 TST_CHECKPOINT_WAKE_AND_WAIT(0);
56
57 SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL);
58
59 TST_CHECKPOINT_WAKE_AND_WAIT(0);
60
61 SAFE_UMOUNT(DIRA);
62
63 return 0;
64 }
65
run(void)66 static void run(void)
67 {
68 int ret;
69
70 SAFE_UNSHARE(CLONE_NEWNS);
71
72 /* makes sure parent mounts/umounts have no effect on a real system */
73 SAFE_MOUNT("none", "/", "none", MS_REC | MS_PRIVATE, NULL);
74
75 SAFE_MOUNT(DIRA, DIRA, "none", MS_BIND, NULL);
76
77 SAFE_MOUNT("none", DIRA, "none", MS_SHARED, NULL);
78
79 ret = ltp_clone_quick(CLONE_NEWNS | SIGCHLD, child_func, NULL);
80 if (ret < 0)
81 tst_brk(TBROK, "clone failed");
82
83 TST_CHECKPOINT_WAIT(0);
84
85 SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL);
86
87 TST_CHECKPOINT_WAKE_AND_WAIT(0);
88
89 SAFE_UMOUNT(DIRA);
90
91 TST_CHECKPOINT_WAKE_AND_WAIT(0);
92
93 if ((access(DIRA "/A", F_OK) == 0) && (access(DIRA "/B", F_OK) == -1))
94 tst_res(TPASS, "propagation from slave mount passed");
95 else
96 tst_res(TFAIL, "propagation form slave mount failed");
97
98 TST_CHECKPOINT_WAKE(0);
99
100 SAFE_WAIT(NULL);
101
102 SAFE_UMOUNT(DIRA);
103 }
104
setup(void)105 static void setup(void)
106 {
107 check_newns();
108 create_folders();
109 }
110
cleanup(void)111 static void cleanup(void)
112 {
113 umount_folders();
114 }
115
116 static struct tst_test test = {
117 .setup = setup,
118 .cleanup = cleanup,
119 .test_all = run,
120 .needs_root = 1,
121 .needs_checkpoints = 1,
122 };
123