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