umount2_02.c revision 2df37ec39d153598ae7f4262c8422d50a2e3359b
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#define DIR_MODE	(S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
37#define MNTPOINT	"mntpoint"
38
39static void setup(void);
40static void test_umount2(int i);
41static void verify_failure(int i);
42static void verify_success(int i);
43static void cleanup(void);
44
45static const char *device;
46static const char *fs_type;
47
48static int mount_flag;
49
50static struct test_case_t {
51	int flag;
52	int exp_errno;
53	int do_access;
54	const char *desc;
55} test_cases[] = {
56	{MNT_EXPIRE | MNT_FORCE, EINVAL, 0,
57		"umount2(2) with MNT_EXPIRE | MNT_FORCE expected EINVAL"},
58	{MNT_EXPIRE | MNT_DETACH, EINVAL, 0,
59		"umount2(2) with MNT_EXPIRE | MNT_DETACH expected EINVAL"},
60	{MNT_EXPIRE, EAGAIN, 0,
61		"initial call to umount2(2) with MNT_EXPIRE expected EAGAIN"},
62	{MNT_EXPIRE, EAGAIN, 1,
63		"umount2(2) with MNT_EXPIRE after access(2) expected EAGAIN"},
64	{MNT_EXPIRE, 0, 0,
65		"second call to umount2(2) with MNT_EXPIRE expected success"},
66};
67
68char *TCID = "umount2_02";
69int TST_TOTAL = ARRAY_SIZE(test_cases);
70
71int main(int ac, char **av)
72{
73	int lc;
74	int tc;
75
76	tst_parse_opts(ac, av, NULL, NULL);
77
78	setup();
79
80	for (lc = 0; TEST_LOOPING(lc); lc++) {
81		tst_count = 0;
82
83		SAFE_MOUNT(cleanup, device, MNTPOINT, fs_type, 0, NULL);
84		mount_flag = 1;
85
86		for (tc = 0; tc < TST_TOTAL; tc++)
87			test_umount2(tc);
88
89		if (mount_flag) {
90			SAFE_UMOUNT(cleanup, MNTPOINT);
91			mount_flag = 0;
92		}
93	}
94
95	cleanup();
96	tst_exit();
97}
98
99static void setup(void)
100{
101	tst_require_root();
102
103	if ((tst_kvercmp(2, 6, 8)) < 0) {
104		tst_brkm(TCONF, NULL, "This test can only run on kernels "
105			 "that are 2.6.8 or higher");
106	}
107
108	tst_sig(NOFORK, DEF_HANDLER, NULL);
109
110	tst_tmpdir();
111
112	fs_type = tst_dev_fs_type();
113	device = tst_acquire_device(cleanup);
114
115	if (!device)
116		tst_brkm(TCONF, cleanup, "Failed to obtain block device");
117
118	tst_mkfs(cleanup, device, fs_type, NULL);
119
120	SAFE_MKDIR(cleanup, MNTPOINT, DIR_MODE);
121
122	TEST_PAUSE;
123}
124
125static void test_umount2(int i)
126{
127	/* a new access removes the expired mark of the mount point */
128	if (test_cases[i].do_access) {
129		if (access(MNTPOINT, F_OK) == -1)
130			tst_brkm(TBROK | TERRNO, cleanup, "access(2) failed");
131	}
132
133	TEST(umount2(MNTPOINT, test_cases[i].flag));
134
135	if (test_cases[i].exp_errno != 0)
136		verify_failure(i);
137	else
138		verify_success(i);
139}
140
141static void verify_failure(int i)
142{
143	if (TEST_RETURN == 0) {
144		tst_resm(TFAIL, "%s passed unexpectedly", test_cases[i].desc);
145		mount_flag = 0;
146		return;
147	}
148
149	if (TEST_ERRNO != test_cases[i].exp_errno) {
150		tst_resm(TFAIL | TTERRNO, "%s failed unexpectedly",
151			 test_cases[i].desc);
152		return;
153	}
154
155	tst_resm(TPASS | TTERRNO, "umount2(2) failed as expected");
156}
157
158static void verify_success(int i)
159{
160	if (TEST_RETURN != 0) {
161		tst_resm(TFAIL | TTERRNO, "%s failed unexpectedly",
162			 test_cases[i].desc);
163		return;
164	}
165
166	tst_resm(TPASS, "umount2(2) succeeded as expected");
167	mount_flag = 0;
168}
169
170static void cleanup(void)
171{
172	if (mount_flag && tst_umount(MNTPOINT))
173		tst_resm(TWARN | TERRNO, "Failed to unmount");
174
175	if (device)
176		tst_release_device(NULL, device);
177
178	tst_rmdir();
179}
180