1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2022 CTERA Networks. All Rights Reserved. 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci * Started by Amir Goldstein <amir73il@gmail.com> 6f08c3bdfSopenharmony_ci * based on reproducer from Ivan Delalande <colona@arista.com> 7f08c3bdfSopenharmony_ci */ 8f08c3bdfSopenharmony_ci 9f08c3bdfSopenharmony_ci/*\ 10f08c3bdfSopenharmony_ci * [Description] 11f08c3bdfSopenharmony_ci * Test opening files after receiving IN_DELETE. 12f08c3bdfSopenharmony_ci * 13f08c3bdfSopenharmony_ci * Kernel v5.13 has a regression allowing files to be open after IN_DELETE. 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * The problem has been fixed by commit: 16f08c3bdfSopenharmony_ci * a37d9a17f099 "fsnotify: invalidate dcache before IN_DELETE event". 17f08c3bdfSopenharmony_ci */ 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_ci#include "config.h" 20f08c3bdfSopenharmony_ci 21f08c3bdfSopenharmony_ci#include <stdio.h> 22f08c3bdfSopenharmony_ci#include <unistd.h> 23f08c3bdfSopenharmony_ci#include <fcntl.h> 24f08c3bdfSopenharmony_ci#include <signal.h> 25f08c3bdfSopenharmony_ci#include <sys/wait.h> 26f08c3bdfSopenharmony_ci 27f08c3bdfSopenharmony_ci#include "tst_test.h" 28f08c3bdfSopenharmony_ci#include "tst_safe_macros.h" 29f08c3bdfSopenharmony_ci#include "inotify.h" 30f08c3bdfSopenharmony_ci 31f08c3bdfSopenharmony_ci#if defined(HAVE_SYS_INOTIFY_H) 32f08c3bdfSopenharmony_ci#include <sys/inotify.h> 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_ci/* Number of files to test */ 35f08c3bdfSopenharmony_ci#define CHURN_FILES 9999 36f08c3bdfSopenharmony_ci 37f08c3bdfSopenharmony_ci#define EVENT_MAX 32 38f08c3bdfSopenharmony_ci/* Size of the event structure, not including the name */ 39f08c3bdfSopenharmony_ci#define EVENT_SIZE (sizeof(struct inotify_event)) 40f08c3bdfSopenharmony_ci#define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16)) 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_cistatic pid_t pid; 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_cistatic char event_buf[EVENT_BUF_LEN]; 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_cistatic void churn(void) 47f08c3bdfSopenharmony_ci{ 48f08c3bdfSopenharmony_ci char path[10]; 49f08c3bdfSopenharmony_ci int i; 50f08c3bdfSopenharmony_ci 51f08c3bdfSopenharmony_ci for (i = 0; i <= CHURN_FILES; ++i) { 52f08c3bdfSopenharmony_ci snprintf(path, sizeof(path), "%d", i); 53f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(path, "1"); 54f08c3bdfSopenharmony_ci SAFE_UNLINK(path); 55f08c3bdfSopenharmony_ci } 56f08c3bdfSopenharmony_ci} 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_cistatic void verify_inotify(void) 59f08c3bdfSopenharmony_ci{ 60f08c3bdfSopenharmony_ci int nevents = 0, opened = 0; 61f08c3bdfSopenharmony_ci struct inotify_event *event; 62f08c3bdfSopenharmony_ci int inotify_fd; 63f08c3bdfSopenharmony_ci 64f08c3bdfSopenharmony_ci inotify_fd = SAFE_MYINOTIFY_INIT(); 65f08c3bdfSopenharmony_ci SAFE_MYINOTIFY_ADD_WATCH(inotify_fd, ".", IN_DELETE); 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_ci pid = SAFE_FORK(); 68f08c3bdfSopenharmony_ci if (pid == 0) { 69f08c3bdfSopenharmony_ci SAFE_CLOSE(inotify_fd); 70f08c3bdfSopenharmony_ci churn(); 71f08c3bdfSopenharmony_ci return; 72f08c3bdfSopenharmony_ci } 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci while (!opened && nevents < CHURN_FILES) { 75f08c3bdfSopenharmony_ci int i, fd, len; 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ci len = SAFE_READ(0, inotify_fd, event_buf, EVENT_BUF_LEN); 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_ci for (i = 0; i < len; i += EVENT_SIZE + event->len) { 80f08c3bdfSopenharmony_ci event = (struct inotify_event *)&event_buf[i]; 81f08c3bdfSopenharmony_ci 82f08c3bdfSopenharmony_ci if (!(event->mask & IN_DELETE)) 83f08c3bdfSopenharmony_ci continue; 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_ci nevents++; 86f08c3bdfSopenharmony_ci 87f08c3bdfSopenharmony_ci /* Open file after IN_DELETE should fail */ 88f08c3bdfSopenharmony_ci fd = open(event->name, O_RDONLY); 89f08c3bdfSopenharmony_ci if (fd < 0) 90f08c3bdfSopenharmony_ci continue; 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci tst_res(TFAIL, "File %s opened after IN_DELETE", event->name); 93f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 94f08c3bdfSopenharmony_ci opened = 1; 95f08c3bdfSopenharmony_ci break; 96f08c3bdfSopenharmony_ci } 97f08c3bdfSopenharmony_ci } 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_ci SAFE_CLOSE(inotify_fd); 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci if (!nevents) 102f08c3bdfSopenharmony_ci tst_res(TFAIL, "Didn't get any IN_DELETE events"); 103f08c3bdfSopenharmony_ci else if (!opened) 104f08c3bdfSopenharmony_ci tst_res(TPASS, "Got %d IN_DELETE events", nevents); 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci /* Kill the child creating / deleting files and wait for it */ 107f08c3bdfSopenharmony_ci SAFE_KILL(pid, SIGKILL); 108f08c3bdfSopenharmony_ci pid = 0; 109f08c3bdfSopenharmony_ci SAFE_WAIT(NULL); 110f08c3bdfSopenharmony_ci} 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_cistatic void cleanup(void) 113f08c3bdfSopenharmony_ci{ 114f08c3bdfSopenharmony_ci if (pid) { 115f08c3bdfSopenharmony_ci SAFE_KILL(pid, SIGKILL); 116f08c3bdfSopenharmony_ci SAFE_WAIT(NULL); 117f08c3bdfSopenharmony_ci } 118f08c3bdfSopenharmony_ci} 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_cistatic struct tst_test test = { 121f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 122f08c3bdfSopenharmony_ci .forks_child = 1, 123f08c3bdfSopenharmony_ci .cleanup = cleanup, 124f08c3bdfSopenharmony_ci .test_all = verify_inotify, 125f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 126f08c3bdfSopenharmony_ci {"linux-git", "a37d9a17f099"}, 127f08c3bdfSopenharmony_ci {} 128f08c3bdfSopenharmony_ci } 129f08c3bdfSopenharmony_ci}; 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci#else 132f08c3bdfSopenharmony_ci TST_TEST_TCONF("system doesn't have required inotify support"); 133f08c3bdfSopenharmony_ci#endif 134