• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015 Fujitsu Ltd.
3  * Author: Guangwen Feng <fenggw-fnst@cn.fujitsu.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * You should have received a copy of the GNU General Public License
14  * alone with this program.
15  */
16 
17 /*
18  * DESCRIPTION
19  *  Test for feature MNT_EXPIRE of umount2().
20  *  "Mark the mount point as expired.If a mount point is not currently
21  *   in use, then an initial call to umount2() with this flag fails with
22  *   the error EAGAIN, but marks the mount point as expired. The mount
23  *   point remains expired as long as it isn't accessed by any process.
24  *   A second umount2() call specifying MNT_EXPIRE unmounts an expired
25  *   mount point. This flag cannot be specified with either MNT_FORCE or
26  *   MNT_DETACH. (fails with the error EINVAL)"
27  */
28 
29 #include <errno.h>
30 #include <sys/mount.h>
31 
32 #include "test.h"
33 #include "safe_macros.h"
34 #include "lapi/mount.h"
35 
36 #include "umount2.h"
37 
38 #define DIR_MODE	(S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
39 #define MNTPOINT	"mntpoint"
40 
41 static void setup(void);
42 static void test_umount2(int i);
43 static void verify_failure(int i);
44 static void verify_success(int i);
45 static void cleanup(void);
46 
47 static const char *device;
48 static const char *fs_type;
49 
50 static int mount_flag;
51 
52 static struct test_case_t {
53 	int flag;
54 	int exp_errno;
55 	int do_access;
56 	const char *desc;
57 } test_cases[] = {
58 	{MNT_EXPIRE | MNT_FORCE, EINVAL, 0,
59 		"umount2(2) with MNT_EXPIRE | MNT_FORCE expected EINVAL"},
60 	{MNT_EXPIRE | MNT_DETACH, EINVAL, 0,
61 		"umount2(2) with MNT_EXPIRE | MNT_DETACH expected EINVAL"},
62 	{MNT_EXPIRE, EAGAIN, 0,
63 		"initial call to umount2(2) with MNT_EXPIRE expected EAGAIN"},
64 	{MNT_EXPIRE, EAGAIN, 1,
65 		"umount2(2) with MNT_EXPIRE after access(2) expected EAGAIN"},
66 	{MNT_EXPIRE, 0, 0,
67 		"second call to umount2(2) with MNT_EXPIRE expected success"},
68 };
69 
70 char *TCID = "umount2_02";
71 int TST_TOTAL = ARRAY_SIZE(test_cases);
72 
main(int ac,char ** av)73 int main(int ac, char **av)
74 {
75 	int lc;
76 	int tc;
77 
78 	tst_parse_opts(ac, av, NULL, NULL);
79 
80 	setup();
81 
82 	for (lc = 0; TEST_LOOPING(lc); lc++) {
83 		tst_count = 0;
84 
85 		SAFE_MOUNT(cleanup, device, MNTPOINT, fs_type, 0, NULL);
86 		mount_flag = 1;
87 
88 		for (tc = 0; tc < TST_TOTAL; tc++)
89 			test_umount2(tc);
90 
91 		if (mount_flag) {
92 			if (tst_umount(MNTPOINT))
93 				tst_brkm(TBROK, cleanup, "umount() failed");
94 			mount_flag = 0;
95 		}
96 	}
97 
98 	cleanup();
99 	tst_exit();
100 }
101 
setup(void)102 static void setup(void)
103 {
104 	tst_require_root();
105 
106 	if ((tst_kvercmp(2, 6, 8)) < 0) {
107 		tst_brkm(TCONF, NULL, "This test can only run on kernels "
108 			 "that are 2.6.8 or higher");
109 	}
110 
111 	tst_sig(NOFORK, DEF_HANDLER, NULL);
112 
113 	tst_tmpdir();
114 
115 	fs_type = tst_dev_fs_type();
116 	device = tst_acquire_device(cleanup);
117 
118 	if (!device)
119 		tst_brkm(TCONF, cleanup, "Failed to obtain block device");
120 
121 	tst_mkfs(cleanup, device, fs_type, NULL, NULL);
122 
123 	SAFE_MKDIR(cleanup, MNTPOINT, DIR_MODE);
124 
125 	TEST_PAUSE;
126 }
127 
test_umount2(int i)128 static void test_umount2(int i)
129 {
130 	/* a new access removes the expired mark of the mount point */
131 	if (test_cases[i].do_access) {
132 		if (access(MNTPOINT, F_OK) == -1)
133 			tst_brkm(TBROK | TERRNO, cleanup, "access(2) failed");
134 	}
135 
136 	TEST(umount2_retry(MNTPOINT, test_cases[i].flag));
137 
138 	if (test_cases[i].exp_errno != 0)
139 		verify_failure(i);
140 	else
141 		verify_success(i);
142 }
143 
verify_failure(int i)144 static void verify_failure(int i)
145 {
146 	if (TEST_RETURN == 0) {
147 		tst_resm(TFAIL, "%s passed unexpectedly", test_cases[i].desc);
148 		mount_flag = 0;
149 		return;
150 	}
151 
152 	if (TEST_ERRNO != test_cases[i].exp_errno) {
153 		tst_resm(TFAIL | TTERRNO, "%s failed unexpectedly",
154 			 test_cases[i].desc);
155 		return;
156 	}
157 
158 	tst_resm(TPASS | TTERRNO, "umount2(2) failed as expected");
159 }
160 
verify_success(int i)161 static void verify_success(int i)
162 {
163 	if (TEST_RETURN != 0) {
164 		tst_resm(TFAIL | TTERRNO, "%s failed unexpectedly",
165 			 test_cases[i].desc);
166 		return;
167 	}
168 
169 	tst_resm(TPASS, "umount2(2) succeeded as expected");
170 	mount_flag = 0;
171 }
172 
cleanup(void)173 static void cleanup(void)
174 {
175 	if (mount_flag && tst_umount(MNTPOINT))
176 		tst_resm(TWARN | TERRNO, "Failed to unmount");
177 
178 	if (device)
179 		tst_release_device(device);
180 
181 	tst_rmdir();
182 }
183