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 slave mount: slave mount is like a shared mount except that 11f08c3bdfSopenharmony_ci * mount and umount events only propagate towards it. 12f08c3bdfSopenharmony_ci * 13f08c3bdfSopenharmony_ci * [Algorithm] 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * - Creates directories DIRA, DIRB and files DIRA/"A", DIRB/"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 DIRA to itself 19f08c3bdfSopenharmony_ci * - Makes directory DIRA shared 20f08c3bdfSopenharmony_ci * - Clones a new child process with CLONE_NEWNS flag and makes "A" a slave 21f08c3bdfSopenharmony_ci * mount 22f08c3bdfSopenharmony_ci * - There are two testcases (where X is parent namespace and Y child 23f08c3bdfSopenharmony_ci * namespace): 24f08c3bdfSopenharmony_ci * 1. First test case 25f08c3bdfSopenharmony_ci * .. X: bind mounts DIRB to DIRA 26f08c3bdfSopenharmony_ci * .. Y: must see the file DIRA/"B" 27f08c3bdfSopenharmony_ci * .. X: umounts DIRA 28f08c3bdfSopenharmony_ci * 2. Second test case 29f08c3bdfSopenharmony_ci * .. Y: bind mounts DIRB to DIRA 30f08c3bdfSopenharmony_ci * .. X: must see only the DIRA/"A" and must not see DIRA/"B" (as slave mount does 31f08c3bdfSopenharmony_ci * not forward propagation) 32f08c3bdfSopenharmony_ci * .. Y: umounts DIRA 33f08c3bdfSopenharmony_ci */ 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_ci#include <sys/wait.h> 36f08c3bdfSopenharmony_ci#include <sys/mount.h> 37f08c3bdfSopenharmony_ci#include "mountns.h" 38f08c3bdfSopenharmony_ci#include "tst_test.h" 39f08c3bdfSopenharmony_ci#include "lapi/sched.h" 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_cistatic void child_func(void) 42f08c3bdfSopenharmony_ci{ 43f08c3bdfSopenharmony_ci /* 44f08c3bdfSopenharmony_ci * makes mount DIRA a slave of DIRA (all slave mounts have 45f08c3bdfSopenharmony_ci * a master mount which is a shared mount) 46f08c3bdfSopenharmony_ci */ 47f08c3bdfSopenharmony_ci SAFE_MOUNT("none", DIRA, "none", MS_SLAVE, NULL); 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE_AND_WAIT(0); 50f08c3bdfSopenharmony_ci 51f08c3bdfSopenharmony_ci if (access(DIRA "/B", F_OK) == 0) 52f08c3bdfSopenharmony_ci tst_res(TPASS, "propagation to slave mount passed"); 53f08c3bdfSopenharmony_ci else 54f08c3bdfSopenharmony_ci tst_res(TFAIL, "propagation to slave mount failed"); 55f08c3bdfSopenharmony_ci 56f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE_AND_WAIT(0); 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_ci SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); 59f08c3bdfSopenharmony_ci 60f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE_AND_WAIT(0); 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_ci SAFE_UMOUNT(DIRA); 63f08c3bdfSopenharmony_ci} 64f08c3bdfSopenharmony_ci 65f08c3bdfSopenharmony_cistatic void run(void) 66f08c3bdfSopenharmony_ci{ 67f08c3bdfSopenharmony_ci const struct tst_clone_args args = { 68f08c3bdfSopenharmony_ci .flags = CLONE_NEWNS, 69f08c3bdfSopenharmony_ci .exit_signal = SIGCHLD, 70f08c3bdfSopenharmony_ci }; 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci SAFE_UNSHARE(CLONE_NEWNS); 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci /* makes sure parent mounts/umounts have no effect on a real system */ 75f08c3bdfSopenharmony_ci SAFE_MOUNT("none", "/", "none", MS_REC | MS_PRIVATE, NULL); 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ci SAFE_MOUNT(DIRA, DIRA, "none", MS_BIND, NULL); 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_ci SAFE_MOUNT("none", DIRA, "none", MS_SHARED, NULL); 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci if (!SAFE_CLONE(&args)) { 82f08c3bdfSopenharmony_ci child_func(); 83f08c3bdfSopenharmony_ci return; 84f08c3bdfSopenharmony_ci } 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAIT(0); 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE_AND_WAIT(0); 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci SAFE_UMOUNT(DIRA); 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE_AND_WAIT(0); 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci if ((access(DIRA "/A", F_OK) == 0) && (access(DIRA "/B", F_OK) == -1)) 97f08c3bdfSopenharmony_ci tst_res(TPASS, "propagation from slave mount passed"); 98f08c3bdfSopenharmony_ci else 99f08c3bdfSopenharmony_ci tst_res(TFAIL, "propagation form slave mount failed"); 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE(0); 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci SAFE_WAIT(NULL); 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci SAFE_UMOUNT(DIRA); 106f08c3bdfSopenharmony_ci} 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_cistatic void setup(void) 109f08c3bdfSopenharmony_ci{ 110f08c3bdfSopenharmony_ci create_folders(); 111f08c3bdfSopenharmony_ci} 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_cistatic void cleanup(void) 114f08c3bdfSopenharmony_ci{ 115f08c3bdfSopenharmony_ci umount_folders(); 116f08c3bdfSopenharmony_ci} 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_cistatic struct tst_test test = { 119f08c3bdfSopenharmony_ci .setup = setup, 120f08c3bdfSopenharmony_ci .cleanup = cleanup, 121f08c3bdfSopenharmony_ci .test_all = run, 122f08c3bdfSopenharmony_ci .needs_root = 1, 123f08c3bdfSopenharmony_ci .forks_child = 1, 124f08c3bdfSopenharmony_ci .needs_checkpoints = 1, 125f08c3bdfSopenharmony_ci .needs_kconfigs = (const char *[]) { 126f08c3bdfSopenharmony_ci "CONFIG_USER_NS", 127f08c3bdfSopenharmony_ci NULL, 128f08c3bdfSopenharmony_ci }, 129f08c3bdfSopenharmony_ci}; 130