unplugged-system/external/ltp/testcases/kernel/syscalls/inotify/inotify11.c

134 lines
2.7 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2022 CTERA Networks. All Rights Reserved.
*
* Started by Amir Goldstein <amir73il@gmail.com>
* based on reproducer from Ivan Delalande <colona@arista.com>
*/
/*\
* [Description]
* Test opening files after receiving IN_DELETE.
*
* Kernel v5.13 has a regression allowing files to be open after IN_DELETE.
*
* The problem has been fixed by commit:
* a37d9a17f099 "fsnotify: invalidate dcache before IN_DELETE event".
*/
#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include "tst_test.h"
#include "tst_safe_macros.h"
#include "inotify.h"
#if defined(HAVE_SYS_INOTIFY_H)
#include <sys/inotify.h>
/* Number of files to test */
#define CHURN_FILES 9999
#define EVENT_MAX 32
/* Size of the event structure, not including the name */
#define EVENT_SIZE (sizeof(struct inotify_event))
#define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16))
static pid_t pid;
static char event_buf[EVENT_BUF_LEN];
static void churn(void)
{
char path[10];
int i;
for (i = 0; i <= CHURN_FILES; ++i) {
snprintf(path, sizeof(path), "%d", i);
SAFE_FILE_PRINTF(path, "1");
SAFE_UNLINK(path);
}
}
static void verify_inotify(void)
{
int nevents = 0, opened = 0;
struct inotify_event *event;
int inotify_fd;
inotify_fd = SAFE_MYINOTIFY_INIT();
SAFE_MYINOTIFY_ADD_WATCH(inotify_fd, ".", IN_DELETE);
pid = SAFE_FORK();
if (pid == 0) {
SAFE_CLOSE(inotify_fd);
churn();
return;
}
while (!opened && nevents < CHURN_FILES) {
int i, fd, len;
len = SAFE_READ(0, inotify_fd, event_buf, EVENT_BUF_LEN);
for (i = 0; i < len; i += EVENT_SIZE + event->len) {
event = (struct inotify_event *)&event_buf[i];
if (!(event->mask & IN_DELETE))
continue;
nevents++;
/* Open file after IN_DELETE should fail */
fd = open(event->name, O_RDONLY);
if (fd < 0)
continue;
tst_res(TFAIL, "File %s opened after IN_DELETE", event->name);
SAFE_CLOSE(fd);
opened = 1;
break;
}
}
SAFE_CLOSE(inotify_fd);
if (!nevents)
tst_res(TFAIL, "Didn't get any IN_DELETE events");
else if (!opened)
tst_res(TPASS, "Got %d IN_DELETE events", nevents);
/* Kill the child creating / deleting files and wait for it */
SAFE_KILL(pid, SIGKILL);
pid = 0;
SAFE_WAIT(NULL);
}
static void cleanup(void)
{
if (pid) {
SAFE_KILL(pid, SIGKILL);
SAFE_WAIT(NULL);
}
}
static struct tst_test test = {
.needs_tmpdir = 1,
.forks_child = 1,
.cleanup = cleanup,
.test_all = verify_inotify,
.tags = (const struct tst_tag[]) {
{"linux-git", "a37d9a17f099"},
{}
}
};
#else
TST_TEST_TCONF("system doesn't have required inotify support");
#endif