1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2014 SUSE Linux. All Rights Reserved. 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci * Started by Jan Kara <jack@suse.cz> 6f08c3bdfSopenharmony_ci */ 7f08c3bdfSopenharmony_ci 8f08c3bdfSopenharmony_ci/*\ 9f08c3bdfSopenharmony_ci * [Description] 10f08c3bdfSopenharmony_ci * Check that fanotify overflow event is properly generated. 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * [Algorithm] 13f08c3bdfSopenharmony_ci * Generate enough events without reading them and check that overflow 14f08c3bdfSopenharmony_ci * event is generated. 15f08c3bdfSopenharmony_ci */ 16f08c3bdfSopenharmony_ci 17f08c3bdfSopenharmony_ci#define _GNU_SOURCE 18f08c3bdfSopenharmony_ci#include "config.h" 19f08c3bdfSopenharmony_ci 20f08c3bdfSopenharmony_ci#include <stdio.h> 21f08c3bdfSopenharmony_ci#include <sys/stat.h> 22f08c3bdfSopenharmony_ci#include <sys/types.h> 23f08c3bdfSopenharmony_ci#include <errno.h> 24f08c3bdfSopenharmony_ci#include <libgen.h> 25f08c3bdfSopenharmony_ci#include <stdlib.h> 26f08c3bdfSopenharmony_ci#include <string.h> 27f08c3bdfSopenharmony_ci#include <sys/syscall.h> 28f08c3bdfSopenharmony_ci#include "tst_test.h" 29f08c3bdfSopenharmony_ci#include "tst_timer.h" 30f08c3bdfSopenharmony_ci 31f08c3bdfSopenharmony_ci#ifdef HAVE_SYS_FANOTIFY_H 32f08c3bdfSopenharmony_ci#include "fanotify.h" 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_ci#define MOUNT_PATH "fs_mnt" 35f08c3bdfSopenharmony_ci#define FNAME_PREFIX "fname_" 36f08c3bdfSopenharmony_ci#define FNAME_PREFIX_LEN 6 37f08c3bdfSopenharmony_ci#define PATH_PREFIX MOUNT_PATH "/" FNAME_PREFIX 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_ci#define SYSFS_MAX_EVENTS "/proc/sys/fs/fanotify/max_queued_events" 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_ci/* In older kernels this limit is fixed in kernel */ 42f08c3bdfSopenharmony_ci#define DEFAULT_MAX_EVENTS 16384 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_cistatic int max_events; 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_cistatic struct tcase { 47f08c3bdfSopenharmony_ci const char *tname; 48f08c3bdfSopenharmony_ci unsigned int init_flags; 49f08c3bdfSopenharmony_ci} tcases[] = { 50f08c3bdfSopenharmony_ci { 51f08c3bdfSopenharmony_ci "Limited queue", 52f08c3bdfSopenharmony_ci FAN_CLASS_NOTIF, 53f08c3bdfSopenharmony_ci }, 54f08c3bdfSopenharmony_ci { 55f08c3bdfSopenharmony_ci "Unlimited queue", 56f08c3bdfSopenharmony_ci FAN_CLASS_NOTIF | FAN_UNLIMITED_QUEUE, 57f08c3bdfSopenharmony_ci }, 58f08c3bdfSopenharmony_ci}; 59f08c3bdfSopenharmony_ci 60f08c3bdfSopenharmony_ci#define BUF_SIZE 256 61f08c3bdfSopenharmony_cistatic char fname[BUF_SIZE]; 62f08c3bdfSopenharmony_cistatic char symlnk[BUF_SIZE]; 63f08c3bdfSopenharmony_cistatic char fdpath[BUF_SIZE]; 64f08c3bdfSopenharmony_cistatic int fd, fd_notify; 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_cistatic struct fanotify_event_metadata event; 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_cistatic void event_res(struct fanotify_event_metadata *event, int i) 69f08c3bdfSopenharmony_ci{ 70f08c3bdfSopenharmony_ci int len = 0; 71f08c3bdfSopenharmony_ci const char *filename; 72f08c3bdfSopenharmony_ci 73f08c3bdfSopenharmony_ci sprintf(symlnk, "/proc/self/fd/%d", event->fd); 74f08c3bdfSopenharmony_ci len = readlink(symlnk, fdpath, sizeof(fdpath)); 75f08c3bdfSopenharmony_ci if (len < 0) 76f08c3bdfSopenharmony_ci len = 0; 77f08c3bdfSopenharmony_ci fdpath[len] = 0; 78f08c3bdfSopenharmony_ci filename = basename(fdpath); 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_ci if (len > FNAME_PREFIX_LEN && atoi(filename + FNAME_PREFIX_LEN) != i) 81f08c3bdfSopenharmony_ci tst_res(TFAIL, "Got event #%d out of order filename=%s", i, filename); 82f08c3bdfSopenharmony_ci else if (i == 0) 83f08c3bdfSopenharmony_ci tst_res(TINFO, "Got event #%d filename=%s", i, filename); 84f08c3bdfSopenharmony_ci} 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_cistatic void generate_events(int open_flags, int num_files) 87f08c3bdfSopenharmony_ci{ 88f08c3bdfSopenharmony_ci long long elapsed_ms; 89f08c3bdfSopenharmony_ci int i; 90f08c3bdfSopenharmony_ci 91f08c3bdfSopenharmony_ci tst_timer_start(CLOCK_MONOTONIC); 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_ci for (i = 0; i < num_files; i++) { 94f08c3bdfSopenharmony_ci sprintf(fname, PATH_PREFIX "%d", i); 95f08c3bdfSopenharmony_ci fd = SAFE_OPEN(fname, open_flags, 0644); 96f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 97f08c3bdfSopenharmony_ci } 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_ci tst_timer_stop(); 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci elapsed_ms = tst_timer_elapsed_ms(); 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci tst_res(TINFO, "%s %d files in %llims", 104f08c3bdfSopenharmony_ci (open_flags & O_CREAT) ? "Created" : "Opened", i, elapsed_ms); 105f08c3bdfSopenharmony_ci} 106f08c3bdfSopenharmony_ci 107f08c3bdfSopenharmony_cistatic void test_fanotify(unsigned int n) 108f08c3bdfSopenharmony_ci{ 109f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 110f08c3bdfSopenharmony_ci int len, nevents = 0, got_overflow = 0; 111f08c3bdfSopenharmony_ci int num_files = max_events + 1; 112f08c3bdfSopenharmony_ci int expect_overflow = !(tc->init_flags & FAN_UNLIMITED_QUEUE); 113f08c3bdfSopenharmony_ci 114f08c3bdfSopenharmony_ci tst_res(TINFO, "Test #%d: %s", n, tc->tname); 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_ci fd_notify = SAFE_FANOTIFY_INIT(tc->init_flags | FAN_NONBLOCK, O_RDONLY); 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_ci SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_MOUNT | FAN_MARK_ADD, FAN_OPEN, 119f08c3bdfSopenharmony_ci AT_FDCWD, MOUNT_PATH); 120f08c3bdfSopenharmony_ci 121f08c3bdfSopenharmony_ci /* 122f08c3bdfSopenharmony_ci * Generate events on unique files so they won't be merged 123f08c3bdfSopenharmony_ci */ 124f08c3bdfSopenharmony_ci generate_events(O_RDWR | O_CREAT, num_files); 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_ci /* 127f08c3bdfSopenharmony_ci * Generate more events on the same files that me be merged 128f08c3bdfSopenharmony_ci */ 129f08c3bdfSopenharmony_ci generate_events(O_RDONLY, num_files); 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci while (1) { 132f08c3bdfSopenharmony_ci /* 133f08c3bdfSopenharmony_ci * get list on events 134f08c3bdfSopenharmony_ci */ 135f08c3bdfSopenharmony_ci len = read(fd_notify, &event, sizeof(event)); 136f08c3bdfSopenharmony_ci if (len < 0) { 137f08c3bdfSopenharmony_ci if (errno != EAGAIN) { 138f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, 139f08c3bdfSopenharmony_ci "read of notification event failed"); 140f08c3bdfSopenharmony_ci } 141f08c3bdfSopenharmony_ci if (!got_overflow) 142f08c3bdfSopenharmony_ci tst_res(expect_overflow ? TFAIL : TPASS, "Overflow event not generated!\n"); 143f08c3bdfSopenharmony_ci break; 144f08c3bdfSopenharmony_ci } 145f08c3bdfSopenharmony_ci if (event.fd != FAN_NOFD) { 146f08c3bdfSopenharmony_ci /* 147f08c3bdfSopenharmony_ci * Verify that events generated on unique files 148f08c3bdfSopenharmony_ci * are received by the same order they were generated. 149f08c3bdfSopenharmony_ci */ 150f08c3bdfSopenharmony_ci if (nevents < num_files) 151f08c3bdfSopenharmony_ci event_res(&event, nevents); 152f08c3bdfSopenharmony_ci close(event.fd); 153f08c3bdfSopenharmony_ci } 154f08c3bdfSopenharmony_ci nevents++; 155f08c3bdfSopenharmony_ci 156f08c3bdfSopenharmony_ci /* 157f08c3bdfSopenharmony_ci * check events 158f08c3bdfSopenharmony_ci */ 159f08c3bdfSopenharmony_ci if (event.mask != FAN_OPEN && 160f08c3bdfSopenharmony_ci event.mask != FAN_Q_OVERFLOW) { 161f08c3bdfSopenharmony_ci tst_res(TFAIL, 162f08c3bdfSopenharmony_ci "got event: mask=%llx (expected %llx) pid=%u fd=%d", 163f08c3bdfSopenharmony_ci (unsigned long long)event.mask, 164f08c3bdfSopenharmony_ci (unsigned long long)FAN_OPEN, 165f08c3bdfSopenharmony_ci (unsigned int)event.pid, event.fd); 166f08c3bdfSopenharmony_ci break; 167f08c3bdfSopenharmony_ci } 168f08c3bdfSopenharmony_ci if (event.mask == FAN_Q_OVERFLOW) { 169f08c3bdfSopenharmony_ci if (got_overflow || event.fd != FAN_NOFD) { 170f08c3bdfSopenharmony_ci tst_res(TFAIL, 171f08c3bdfSopenharmony_ci "%s overflow event: mask=%llx pid=%u fd=%d", 172f08c3bdfSopenharmony_ci got_overflow ? "unexpected" : "invalid", 173f08c3bdfSopenharmony_ci (unsigned long long)event.mask, 174f08c3bdfSopenharmony_ci (unsigned int)event.pid, 175f08c3bdfSopenharmony_ci event.fd); 176f08c3bdfSopenharmony_ci break; 177f08c3bdfSopenharmony_ci } 178f08c3bdfSopenharmony_ci tst_res(expect_overflow ? TPASS : TFAIL, 179f08c3bdfSopenharmony_ci "Got an overflow event: pid=%u fd=%d", 180f08c3bdfSopenharmony_ci (unsigned int)event.pid, event.fd); 181f08c3bdfSopenharmony_ci got_overflow = 1; 182f08c3bdfSopenharmony_ci } 183f08c3bdfSopenharmony_ci } 184f08c3bdfSopenharmony_ci tst_res(TINFO, "Got %d events", nevents); 185f08c3bdfSopenharmony_ci SAFE_CLOSE(fd_notify); 186f08c3bdfSopenharmony_ci} 187f08c3bdfSopenharmony_ci 188f08c3bdfSopenharmony_cistatic void setup(void) 189f08c3bdfSopenharmony_ci{ 190f08c3bdfSopenharmony_ci int fd; 191f08c3bdfSopenharmony_ci 192f08c3bdfSopenharmony_ci /* Check for kernel fanotify support */ 193f08c3bdfSopenharmony_ci fd = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY); 194f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 195f08c3bdfSopenharmony_ci 196f08c3bdfSopenharmony_ci /* In older kernels this limit is fixed in kernel */ 197f08c3bdfSopenharmony_ci if (access(SYSFS_MAX_EVENTS, F_OK) && errno == ENOENT) 198f08c3bdfSopenharmony_ci max_events = DEFAULT_MAX_EVENTS; 199f08c3bdfSopenharmony_ci else 200f08c3bdfSopenharmony_ci SAFE_FILE_SCANF(SYSFS_MAX_EVENTS, "%d", &max_events); 201f08c3bdfSopenharmony_ci tst_res(TINFO, "max_queued_events=%d", max_events); 202f08c3bdfSopenharmony_ci} 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_cistatic void cleanup(void) 205f08c3bdfSopenharmony_ci{ 206f08c3bdfSopenharmony_ci if (fd_notify > 0) 207f08c3bdfSopenharmony_ci SAFE_CLOSE(fd_notify); 208f08c3bdfSopenharmony_ci} 209f08c3bdfSopenharmony_ci 210f08c3bdfSopenharmony_cistatic struct tst_test test = { 211f08c3bdfSopenharmony_ci .test = test_fanotify, 212f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 213f08c3bdfSopenharmony_ci .setup = setup, 214f08c3bdfSopenharmony_ci .cleanup = cleanup, 215f08c3bdfSopenharmony_ci .needs_root = 1, 216f08c3bdfSopenharmony_ci .mount_device = 1, 217f08c3bdfSopenharmony_ci .mntpoint = MOUNT_PATH, 218f08c3bdfSopenharmony_ci}; 219f08c3bdfSopenharmony_ci#else 220f08c3bdfSopenharmony_ci TST_TEST_TCONF("system doesn't have required fanotify support"); 221f08c3bdfSopenharmony_ci#endif 222