1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2014 Red Hat, Inc. 4f08c3bdfSopenharmony_ci * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Tests a shared mount: shared mount can be replicated to as many 11f08c3bdfSopenharmony_ci * mountpoints and all the replicas continue to be exactly same. 12f08c3bdfSopenharmony_ci * 13f08c3bdfSopenharmony_ci * [Algorithm] 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * - Creates directories DIR_A, DIR_B and files DIR_A/"A", DIR_B/"B" 16f08c3bdfSopenharmony_ci * - Unshares mount namespace and makes it private (so mounts/umounts have no 17f08c3bdfSopenharmony_ci * effect on a real system) 18f08c3bdfSopenharmony_ci * - Bind mounts directory DIR_A to DIR_A 19f08c3bdfSopenharmony_ci * - Makes directory DIR_A shared 20f08c3bdfSopenharmony_ci * - Clones a new child process with CLONE_NEWNS flag 21f08c3bdfSopenharmony_ci * - There are two test cases (where X is parent namespace and Y child namespace): 22f08c3bdfSopenharmony_ci * 1. First test case 23f08c3bdfSopenharmony_ci * .. X: bind mounts DIR_B to DIR_A 24f08c3bdfSopenharmony_ci * .. Y: must see DIR_A/"B" 25f08c3bdfSopenharmony_ci * .. X: umounts DIR_A 26f08c3bdfSopenharmony_ci * 2. Second test case 27f08c3bdfSopenharmony_ci * .. Y: bind mounts DIR_B to DIR_A 28f08c3bdfSopenharmony_ci * .. X: must see DIR_A/"B" 29f08c3bdfSopenharmony_ci * .. Y: umounts DIR_A 30f08c3bdfSopenharmony_ci */ 31f08c3bdfSopenharmony_ci 32f08c3bdfSopenharmony_ci#include <sys/wait.h> 33f08c3bdfSopenharmony_ci#include <sys/mount.h> 34f08c3bdfSopenharmony_ci#include "mountns.h" 35f08c3bdfSopenharmony_ci#include "tst_test.h" 36f08c3bdfSopenharmony_ci#include "lapi/sched.h" 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_cistatic void child_func(void) 39f08c3bdfSopenharmony_ci{ 40f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAIT(0); 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_ci if (access(DIRA "/B", F_OK) == 0) 43f08c3bdfSopenharmony_ci tst_res(TPASS, "shared mount in parent passed"); 44f08c3bdfSopenharmony_ci else 45f08c3bdfSopenharmony_ci tst_res(TFAIL, "shared mount in parent failed"); 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE_AND_WAIT(0); 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_ci /* bind mounts DIRB to DIRA making contents of DIRB visible in DIRA */ 50f08c3bdfSopenharmony_ci SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE_AND_WAIT(0); 53f08c3bdfSopenharmony_ci 54f08c3bdfSopenharmony_ci SAFE_UMOUNT(DIRA); 55f08c3bdfSopenharmony_ci} 56f08c3bdfSopenharmony_ci 57f08c3bdfSopenharmony_cistatic void run(void) 58f08c3bdfSopenharmony_ci{ 59f08c3bdfSopenharmony_ci const struct tst_clone_args args = { 60f08c3bdfSopenharmony_ci .flags = CLONE_NEWNS, 61f08c3bdfSopenharmony_ci .exit_signal = SIGCHLD, 62f08c3bdfSopenharmony_ci }; 63f08c3bdfSopenharmony_ci 64f08c3bdfSopenharmony_ci SAFE_UNSHARE(CLONE_NEWNS); 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci /* makes sure parent mounts/umounts have no effect on a real system */ 67f08c3bdfSopenharmony_ci SAFE_MOUNT("none", "/", "none", MS_REC | MS_PRIVATE, NULL); 68f08c3bdfSopenharmony_ci 69f08c3bdfSopenharmony_ci SAFE_MOUNT(DIRA, DIRA, "none", MS_BIND, NULL); 70f08c3bdfSopenharmony_ci SAFE_MOUNT("none", DIRA, "none", MS_SHARED, NULL); 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci if (!SAFE_CLONE(&args)) { 73f08c3bdfSopenharmony_ci child_func(); 74f08c3bdfSopenharmony_ci return; 75f08c3bdfSopenharmony_ci } 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ci SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE_AND_WAIT(0); 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci SAFE_UMOUNT(DIRA); 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE_AND_WAIT(0); 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_ci if (access(DIRA "/B", F_OK) == 0) 86f08c3bdfSopenharmony_ci tst_res(TPASS, "shared mount in child passed"); 87f08c3bdfSopenharmony_ci else 88f08c3bdfSopenharmony_ci tst_res(TFAIL, "shared mount in child failed"); 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE(0); 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci SAFE_WAIT(NULL); 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_ci SAFE_UMOUNT(DIRA); 95f08c3bdfSopenharmony_ci} 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_cistatic void setup(void) 98f08c3bdfSopenharmony_ci{ 99f08c3bdfSopenharmony_ci create_folders(); 100f08c3bdfSopenharmony_ci} 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_cistatic void cleanup(void) 103f08c3bdfSopenharmony_ci{ 104f08c3bdfSopenharmony_ci umount_folders(); 105f08c3bdfSopenharmony_ci} 106f08c3bdfSopenharmony_ci 107f08c3bdfSopenharmony_cistatic struct tst_test test = { 108f08c3bdfSopenharmony_ci .setup = setup, 109f08c3bdfSopenharmony_ci .cleanup = cleanup, 110f08c3bdfSopenharmony_ci .test_all = run, 111f08c3bdfSopenharmony_ci .needs_root = 1, 112f08c3bdfSopenharmony_ci .forks_child = 1, 113f08c3bdfSopenharmony_ci .needs_checkpoints = 1, 114f08c3bdfSopenharmony_ci .needs_kconfigs = (const char *[]) { 115f08c3bdfSopenharmony_ci "CONFIG_USER_NS", 116f08c3bdfSopenharmony_ci NULL, 117f08c3bdfSopenharmony_ci }, 118f08c3bdfSopenharmony_ci}; 119