1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2008 Parallels. All Rights Reserved.
4 * Author: Andrew Vagin <[email protected]>
5 */
6
7 /*\
8 * [Description]
9 *
10 * Check that inotify get IN_UNMOUNT event and don't block the umount command.
11 */
12
13 #include "config.h"
14
15 #include <stdio.h>
16 #include <sys/mount.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <sys/syscall.h>
23 #include <signal.h>
24 #include "tst_test.h"
25 #include "inotify.h"
26
27 #if defined(HAVE_SYS_INOTIFY_H)
28 #include <sys/inotify.h>
29
30 #define EVENT_MAX 1024
31 /* size of the event structure, not counting name */
32 #define EVENT_SIZE (sizeof(struct inotify_event))
33 /* reasonable guess as to size of 1024 events */
34 #define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16))
35
36 #define BUF_SIZE 1024
37 static char fname[BUF_SIZE];
38 static int fd, fd_notify;
39 static int wd;
40
41 static unsigned int event_set[EVENT_MAX];
42
43 static char event_buf[EVENT_BUF_LEN];
44
45 #define DIR_MODE (S_IRWXU | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP)
46
47 static char *mntpoint = "mntpoint";
48 static int mount_flag;
49
verify_inotify(void)50 void verify_inotify(void)
51 {
52 int ret;
53 int len, i, test_num;
54
55 int test_cnt = 0;
56
57 SAFE_MOUNT(tst_device->dev, mntpoint, tst_device->fs_type, 0, NULL);
58 mount_flag = 1;
59
60 wd = SAFE_MYINOTIFY_ADD_WATCH(fd_notify, fname, IN_ALL_EVENTS);
61
62 event_set[test_cnt] = IN_UNMOUNT;
63 test_cnt++;
64 event_set[test_cnt] = IN_IGNORED;
65 test_cnt++;
66
67 /*check exit code from inotify_rm_watch */
68 test_cnt++;
69
70 tst_res(TINFO, "umount %s", tst_device->dev);
71 TEST(tst_umount(mntpoint));
72 if (TST_RET != 0) {
73 tst_brk(TBROK, "umount(2) Failed "
74 "while unmounting errno = %d : %s",
75 TST_ERR, strerror(TST_ERR));
76 }
77 mount_flag = 0;
78
79 len = read(fd_notify, event_buf, EVENT_BUF_LEN);
80 if (len < 0) {
81 tst_brk(TBROK | TERRNO,
82 "read(%d, buf, %zu) failed", fd_notify, EVENT_BUF_LEN);
83 }
84
85 /* check events */
86 test_num = 0;
87 i = 0;
88 while (i < len) {
89 struct inotify_event *event;
90 event = (struct inotify_event *)&event_buf[i];
91 if (test_num >= (test_cnt - 1)) {
92 tst_res(TFAIL,
93 "get unnecessary event: wd=%d mask=%x "
94 "cookie=%u len=%u",
95 event->wd, event->mask,
96 event->cookie, event->len);
97 } else if (event_set[test_num] == event->mask) {
98 tst_res(TPASS, "get event: wd=%d mask=%x"
99 " cookie=%u len=%u",
100 event->wd, event->mask,
101 event->cookie, event->len);
102
103 } else {
104 tst_res(TFAIL, "get event: wd=%d mask=%x "
105 "(expected %x) cookie=%u len=%u",
106 event->wd, event->mask,
107 event_set[test_num],
108 event->cookie, event->len);
109 }
110 test_num++;
111 i += EVENT_SIZE + event->len;
112 }
113 for (; test_num < test_cnt - 1; test_num++) {
114 tst_res(TFAIL, "don't get event: mask=%x ",
115 event_set[test_num]);
116
117 }
118 ret = myinotify_rm_watch(fd_notify, wd);
119 if (ret != -1 || errno != EINVAL)
120 tst_res(TFAIL | TERRNO,
121 "inotify_rm_watch (%d, %d) didn't return EINVAL",
122 fd_notify, wd);
123 else
124 tst_res(TPASS, "inotify_rm_watch (%d, %d) returned EINVAL",
125 fd_notify, wd);
126 }
127
setup(void)128 static void setup(void)
129 {
130 int ret;
131
132 SAFE_MKDIR(mntpoint, DIR_MODE);
133
134 SAFE_MOUNT(tst_device->dev, mntpoint, tst_device->fs_type, 0, NULL);
135 mount_flag = 1;
136
137 sprintf(fname, "%s/tfile_%d", mntpoint, getpid());
138 fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700);
139
140 ret = write(fd, fname, 1);
141 if (ret == -1) {
142 tst_brk(TBROK | TERRNO,
143 "write(%d, %s, 1) failed", fd, fname);
144 }
145
146 /* close the file we have open */
147 SAFE_CLOSE(fd);
148
149 fd_notify = SAFE_MYINOTIFY_INIT();
150
151 tst_umount(mntpoint);
152 mount_flag = 0;
153 }
154
cleanup(void)155 static void cleanup(void)
156 {
157 if (fd_notify > 0)
158 SAFE_CLOSE(fd_notify);
159
160 if (mount_flag) {
161 TEST(tst_umount(mntpoint));
162 if (TST_RET != 0)
163 tst_res(TWARN | TTERRNO, "umount(%s) failed",
164 mntpoint);
165 }
166 }
167
168 static struct tst_test test = {
169 .needs_root = 1,
170 .format_device = 1,
171 .setup = setup,
172 .cleanup = cleanup,
173 .test_all = verify_inotify,
174 };
175
176 #else
177 TST_TEST_TCONF("system doesn't have required inotify support");
178 #endif
179