fstests: convert remaining tests to SPDX license tags
[xfstests-dev.git] / src / t_encrypted_d_revalidate.c
1 /*
2  * t_encrypted_d_revalidate
3  *
4  * Test that ->d_revalidate() for encrypted dentries doesn't oops the
5  * kernel by incorrectly not dropping out of RCU mode.  To do this, try
6  * to look up a negative dentry while another thread deletes its parent
7  * directory.  Fixed by commit 03a8bb0e53d9 ("ext4/fscrypto: avoid RCU
8  * lookup in d_revalidate").
9  *
10  * This doesn't always reproduce reliably, but we give it a few seconds.
11  *
12  * ----------------------------------------------------------------------------
13  *
14  * Copyright (c) 2017 Google, Inc.  All Rights Reserved.
15  *
16  * Author: Eric Biggers <ebiggers@google.com>
17  *
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public Licence as published by
20  * the Free Software Foundation; either version 2 of the Licence, or (at
21  * your option) any later version.
22  *
23  * This program is distributed in the hope that it would be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26  * General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, see <http://www.gnu.org/licenses/>.
30  */
31
32 #include <errno.h>
33 #include <pthread.h>
34 #include <signal.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40
41 #define TIMEOUT         10
42 #define DIR_NAME        "dir"
43 #define FILE_NAME       DIR_NAME "/file"
44
45 static volatile sig_atomic_t timed_out = 0;
46
47 static void alarm_handler(int sig)
48 {
49         timed_out = 1;
50 }
51
52 static void __attribute__((noreturn))
53 die(int err, const char *msg)
54 {
55         fprintf(stderr, "ERROR: %s", msg);
56         if (err)
57                 fprintf(stderr, ": %s", strerror(err));
58         fputc('\n', stderr);
59         exit(1);
60 }
61
62 static void *stat_thread(void *_arg)
63 {
64         struct stat stbuf;
65
66         for (;;) {
67                 if (stat(FILE_NAME, &stbuf) == 0)
68                         die(0, "stat should have failed");
69                 if (errno != ENOENT)
70                         die(errno, "stat");
71         }
72 }
73
74 int main(int argc, char *argv[])
75 {
76         long ncpus;
77         long num_stat_threads;
78         long i;
79         struct stat stbuf;
80
81         if (argc != 2) {
82                 fprintf(stderr, "Usage: %s DIR\n", argv[0]);
83                 return 2;
84         }
85
86         if (chdir(argv[1]) != 0)
87                 die(errno, "chdir");
88
89         ncpus = sysconf(_SC_NPROCESSORS_ONLN);
90         if (ncpus > 1)
91                 num_stat_threads = ncpus - 1;
92         else
93                 num_stat_threads = 1;
94
95         for (i = 0; i < num_stat_threads; i++) {
96                 pthread_t thread;
97                 int err;
98
99                 err = pthread_create(&thread, NULL, stat_thread, NULL);
100                 if (err)
101                         die(err, "pthread_create");
102         }
103
104         if (signal(SIGALRM, alarm_handler) == SIG_ERR)
105                 die(errno, "signal");
106
107         alarm(TIMEOUT);
108
109         while (!timed_out) {
110                 if (mkdir(DIR_NAME, 0777) != 0)
111                         die(errno, "mkdir");
112                 if (stat(FILE_NAME, &stbuf) == 0)
113                         die(0, "stat should have failed");
114                 if (errno != ENOENT)
115                         die(errno, "stat");
116                 if (rmdir(DIR_NAME) != 0)
117                         die(errno, "rmdir");
118         }
119
120         printf("t_encrypted_d_revalidate finished\n");
121         return 0;
122 }