xfs/098: adapt to external log devices
[xfstests-dev.git] / src / t_encrypted_d_revalidate.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2017 Google, Inc.  All Rights Reserved.
4  * Author: Eric Biggers <ebiggers@google.com>
5  *
6  * t_encrypted_d_revalidate
7  *
8  * Test that ->d_revalidate() for encrypted dentries doesn't oops the
9  * kernel by incorrectly not dropping out of RCU mode.  To do this, try
10  * to look up a negative dentry while another thread deletes its parent
11  * directory.  Fixed by commit 03a8bb0e53d9 ("ext4/fscrypto: avoid RCU
12  * lookup in d_revalidate").
13  *
14  * This doesn't always reproduce reliably, but we give it a few seconds.
15  */
16
17 #include <errno.h>
18 #include <pthread.h>
19 #include <signal.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25
26 #define TIMEOUT         10
27 #define DIR_NAME        "dir"
28 #define FILE_NAME       DIR_NAME "/file"
29
30 static volatile sig_atomic_t timed_out = 0;
31
32 static void alarm_handler(int sig)
33 {
34         timed_out = 1;
35 }
36
37 static void __attribute__((noreturn))
38 die(int err, const char *msg)
39 {
40         fprintf(stderr, "ERROR: %s", msg);
41         if (err)
42                 fprintf(stderr, ": %s", strerror(err));
43         fputc('\n', stderr);
44         exit(1);
45 }
46
47 static void *stat_thread(void *_arg)
48 {
49         struct stat stbuf;
50
51         for (;;) {
52                 if (stat(FILE_NAME, &stbuf) == 0)
53                         die(0, "stat should have failed");
54                 if (errno != ENOENT)
55                         die(errno, "stat");
56         }
57 }
58
59 int main(int argc, char *argv[])
60 {
61         long ncpus;
62         long num_stat_threads;
63         long i;
64         struct stat stbuf;
65
66         if (argc != 2) {
67                 fprintf(stderr, "Usage: %s DIR\n", argv[0]);
68                 return 2;
69         }
70
71         if (chdir(argv[1]) != 0)
72                 die(errno, "chdir");
73
74         ncpus = sysconf(_SC_NPROCESSORS_ONLN);
75         if (ncpus > 1)
76                 num_stat_threads = ncpus - 1;
77         else
78                 num_stat_threads = 1;
79
80         for (i = 0; i < num_stat_threads; i++) {
81                 pthread_t thread;
82                 int err;
83
84                 err = pthread_create(&thread, NULL, stat_thread, NULL);
85                 if (err)
86                         die(err, "pthread_create");
87         }
88
89         if (signal(SIGALRM, alarm_handler) == SIG_ERR)
90                 die(errno, "signal");
91
92         alarm(TIMEOUT);
93
94         while (!timed_out) {
95                 if (mkdir(DIR_NAME, 0777) != 0)
96                         die(errno, "mkdir");
97                 if (stat(FILE_NAME, &stbuf) == 0)
98                         die(0, "stat should have failed");
99                 if (errno != ENOENT)
100                         die(errno, "stat");
101                 if (rmdir(DIR_NAME) != 0)
102                         die(errno, "rmdir");
103         }
104
105         printf("t_encrypted_d_revalidate finished\n");
106         return 0;
107 }