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