xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/umount2/umount2_02.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2015-2022 FUJITSU LIMITED. All rights reserved
4  * Author: Guangwen Feng <[email protected]>
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 
35 static int mount_flag;
36 
37 static 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 
umount2_retry(const char * target,int flags)53 static 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 
test_umount2(unsigned int n)75 static 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 
setup(void)100 static void setup(void)
101 {
102 	SAFE_SYMLINK(MNTPOINT, SYMLINK);
103 }
104 
cleanup(void)105 static void cleanup(void)
106 {
107 	if (mount_flag)
108 		SAFE_UMOUNT(MNTPOINT);
109 }
110 
111 static 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