1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2015-2022 FUJITSU LIMITED. All rights reserved 4f08c3bdfSopenharmony_ci * Author: Guangwen Feng <fenggw-fnst@cn.fujitsu.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Test for feature MNT_EXPIRE of umount2(): 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * - EINVAL when flag is specified with either MNT_FORCE or MNT_DETACH 13f08c3bdfSopenharmony_ci * - EAGAIN when initial call to umount2(2) with MNT_EXPIRE 14f08c3bdfSopenharmony_ci * - EAGAIN when umount2(2) with MNT_EXPIRE after access(2) 15f08c3bdfSopenharmony_ci * - succeed when second call to umount2(2) with MNT_EXPIRE 16f08c3bdfSopenharmony_ci * 17f08c3bdfSopenharmony_ci * Test for feature UMOUNT_NOFOLLOW of umount2(): 18f08c3bdfSopenharmony_ci * 19f08c3bdfSopenharmony_ci * - EINVAL when target is a symbolic link 20f08c3bdfSopenharmony_ci * - succeed when target is a mount point 21f08c3bdfSopenharmony_ci */ 22f08c3bdfSopenharmony_ci 23f08c3bdfSopenharmony_ci#include "lapi/mount.h" 24f08c3bdfSopenharmony_ci#include "tst_test.h" 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_ci#define MNTPOINT "mntpoint" 27f08c3bdfSopenharmony_ci#define SYMLINK "symlink" 28f08c3bdfSopenharmony_ci 29f08c3bdfSopenharmony_ci#define FLAG_DESC(x, y) .flag = x, .exp_errno = 0, \ 30f08c3bdfSopenharmony_ci .desc = "umount2("y") with "#x" expected success" 31f08c3bdfSopenharmony_ci 32f08c3bdfSopenharmony_ci#define FLAG_EXP_ERRNO_DESC(x, y, z) .flag = x, .exp_errno = y, \ 33f08c3bdfSopenharmony_ci .desc = "umount2("z") with "#x" expected "#y 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_cistatic int mount_flag; 36f08c3bdfSopenharmony_ci 37f08c3bdfSopenharmony_cistatic struct tcase { 38f08c3bdfSopenharmony_ci int flag; 39f08c3bdfSopenharmony_ci int exp_errno; 40f08c3bdfSopenharmony_ci const char *desc; 41f08c3bdfSopenharmony_ci const char *mntpoint; 42f08c3bdfSopenharmony_ci int do_access; 43f08c3bdfSopenharmony_ci} tcases[] = { 44f08c3bdfSopenharmony_ci {FLAG_EXP_ERRNO_DESC(MNT_EXPIRE | MNT_FORCE, EINVAL, ""), MNTPOINT, 0}, 45f08c3bdfSopenharmony_ci {FLAG_EXP_ERRNO_DESC(MNT_EXPIRE | MNT_DETACH, EINVAL, ""), MNTPOINT, 0}, 46f08c3bdfSopenharmony_ci {FLAG_EXP_ERRNO_DESC(MNT_EXPIRE, EAGAIN, "initial call"), MNTPOINT, 0}, 47f08c3bdfSopenharmony_ci {FLAG_EXP_ERRNO_DESC(MNT_EXPIRE, EAGAIN, "after access"), MNTPOINT, 1}, 48f08c3bdfSopenharmony_ci {FLAG_DESC(MNT_EXPIRE, "second call"), MNTPOINT, 0}, 49f08c3bdfSopenharmony_ci {FLAG_EXP_ERRNO_DESC(UMOUNT_NOFOLLOW, EINVAL, "symlink"), SYMLINK, 0}, 50f08c3bdfSopenharmony_ci {FLAG_DESC(UMOUNT_NOFOLLOW, "mntpoint"), MNTPOINT, 0}, 51f08c3bdfSopenharmony_ci}; 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_cistatic int umount2_retry(const char *target, int flags) 54f08c3bdfSopenharmony_ci{ 55f08c3bdfSopenharmony_ci int i, ret; 56f08c3bdfSopenharmony_ci 57f08c3bdfSopenharmony_ci for (i = 0; i < 50; i++) { 58f08c3bdfSopenharmony_ci ret = umount2(target, flags); 59f08c3bdfSopenharmony_ci if (ret == 0 || errno != EBUSY) 60f08c3bdfSopenharmony_ci return ret; 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_ci tst_res(TINFO, "umount('%s', %i) failed with EBUSY, try %2i...", 63f08c3bdfSopenharmony_ci target, flags, i); 64f08c3bdfSopenharmony_ci 65f08c3bdfSopenharmony_ci usleep(100000); 66f08c3bdfSopenharmony_ci } 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci tst_res(TWARN, "Failed to umount('%s', %i) after 50 retries", 69f08c3bdfSopenharmony_ci target, flags); 70f08c3bdfSopenharmony_ci 71f08c3bdfSopenharmony_ci errno = EBUSY; 72f08c3bdfSopenharmony_ci return -1; 73f08c3bdfSopenharmony_ci} 74f08c3bdfSopenharmony_ci 75f08c3bdfSopenharmony_cistatic void test_umount2(unsigned int n) 76f08c3bdfSopenharmony_ci{ 77f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_ci if (!mount_flag) { 80f08c3bdfSopenharmony_ci SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); 81f08c3bdfSopenharmony_ci mount_flag = 1; 82f08c3bdfSopenharmony_ci } 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci tst_res(TINFO, "Testing %s", tc->desc); 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci if (tc->do_access) 87f08c3bdfSopenharmony_ci SAFE_ACCESS(MNTPOINT, F_OK); 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci if (tc->exp_errno) 90f08c3bdfSopenharmony_ci TST_EXP_FAIL(umount2_retry(tc->mntpoint, tc->flag), tc->exp_errno, 91f08c3bdfSopenharmony_ci "umount2_retry(%s, %d)", tc->mntpoint, tc->flag); 92f08c3bdfSopenharmony_ci else 93f08c3bdfSopenharmony_ci TST_EXP_PASS(umount2_retry(tc->mntpoint, tc->flag), 94f08c3bdfSopenharmony_ci "umount2_retry(%s, %d)", tc->mntpoint, tc->flag); 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci if (!!tc->exp_errno ^ !!TST_PASS) 97f08c3bdfSopenharmony_ci mount_flag = 0; 98f08c3bdfSopenharmony_ci} 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_cistatic void setup(void) 101f08c3bdfSopenharmony_ci{ 102f08c3bdfSopenharmony_ci SAFE_SYMLINK(MNTPOINT, SYMLINK); 103f08c3bdfSopenharmony_ci} 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_cistatic void cleanup(void) 106f08c3bdfSopenharmony_ci{ 107f08c3bdfSopenharmony_ci if (mount_flag) 108f08c3bdfSopenharmony_ci SAFE_UMOUNT(MNTPOINT); 109f08c3bdfSopenharmony_ci} 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_cistatic struct tst_test test = { 112f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 113f08c3bdfSopenharmony_ci .cleanup = cleanup, 114f08c3bdfSopenharmony_ci .setup = setup, 115f08c3bdfSopenharmony_ci .needs_root = 1, 116f08c3bdfSopenharmony_ci .format_device = 1, 117f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 118f08c3bdfSopenharmony_ci .test = test_umount2, 119f08c3bdfSopenharmony_ci}; 120