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