umount2_02.c revision 879d392fa9fe8883e81aac7407c6bb3b021a8905
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
41static void setup(void);
42static void test_umount2(int i);
43static void verify_failure(int i);
44static void verify_success(int i);
45static void cleanup(void);
46
47static const char *device;
48static const char *fs_type;
49
50static int mount_flag;
51
52static 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
70char *TCID = "umount2_02";
71int TST_TOTAL = ARRAY_SIZE(test_cases);
72
73int 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
102static 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
128static 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
144static 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
161static 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
173static 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