xfs: quotas on idmapped mounts
[xfstests-dev.git] / src / t_enospc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 IBM.
4  * All Rights Reserved.
5  *
6  * simple mmap write multithreaded test for testing enospc
7  */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdbool.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <string.h>
14 #include <assert.h>
15 #include <sys/mman.h>
16 #include <pthread.h>
17 #include <signal.h>
18
19 #define pr_debug(fmt, ...) do { \
20     if (verbose) { \
21         printf (fmt, ##__VA_ARGS__); \
22     } \
23 } while (0)
24
25 struct thread_s {
26         int id;
27 };
28
29 static float file_ratio[2] = {0.5, 0.5};
30 static unsigned long fsize = 0;
31 static char *base_dir = ".";
32 static char *ratio = "1";
33
34 static bool use_fallocate = false;
35 static bool verbose = false;
36
37 pthread_barrier_t bar;
38
39 void handle_sigbus(int sig)
40 {
41         pr_debug("Enospc test failed with SIGBUS\n");
42         exit(7);
43 }
44
45 void enospc_test(int id)
46 {
47         int i;
48         int fd;
49         char fpath[255] = {0};
50         char *addr;
51         unsigned long size = 0;
52
53         /*
54          * Comma separated values against -r option indicates that the file
55          * should be divided into two small files.
56          * The file_ratio specifies the proportion in which the file sizes must
57          * be divided into.
58          *
59          * Half of the files will be divided into size of the first ratio and the
60          * rest of the following ratio
61          */
62
63         if (id % 2 == 0)
64                 size = fsize * file_ratio[0];
65         else
66                 size = fsize * file_ratio[1];
67
68         pthread_barrier_wait(&bar);
69
70         sprintf(fpath, "%s/mmap-file-%d", base_dir, id);
71         pr_debug("Test write phase starting file %s fsize %lu, id %d\n", fpath, size, id);
72
73         signal(SIGBUS, handle_sigbus);
74
75         fd = open(fpath, O_RDWR | O_CREAT, 0644);
76         if (fd < 0) {
77                 pr_debug("Open failed\n");
78                 exit(1);
79         }
80
81         if (use_fallocate)
82                 assert(fallocate(fd, 0, 0, size) == 0);
83         else
84                 assert(ftruncate(fd, size) == 0);
85
86         addr = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
87         assert(addr != MAP_FAILED);
88
89         for (i = 0; i < size; i++) {
90                 addr[i] = 0xAB;
91         }
92
93         assert(munmap(addr, size) != -1);
94         close(fd);
95         pr_debug("Test write phase completed...file %s, fsize %lu, id %d\n", fpath, size, id);
96 }
97
98 void *spawn_test_thread(void *arg)
99 {
100         struct thread_s *thread_info = (struct thread_s *)arg;
101
102         enospc_test(thread_info->id);
103         return NULL;
104 }
105
106 void _run_test(int threads)
107 {
108         int i;
109         pthread_t tid[threads];
110
111         pthread_barrier_init(&bar, NULL, threads+1);
112         for (i = 0; i < threads; i++) {
113                 struct thread_s *thread_info = (struct thread_s *) malloc(sizeof(struct thread_s));
114                 thread_info->id = i;
115                 assert(pthread_create(&tid[i], NULL, spawn_test_thread, thread_info) == 0);
116         }
117
118         pthread_barrier_wait(&bar);
119
120         for (i = 0; i < threads; i++) {
121                 assert(pthread_join(tid[i], NULL) == 0);
122         }
123
124         pthread_barrier_destroy(&bar);
125         return;
126 }
127
128 static void usage(void)
129 {
130         printf("\nUsage: t_enospc [options]\n\n"
131                " -t                    thread count\n"
132                " -s size               file size\n"
133                " -p path               set base path\n"
134                " -f fallocate          use fallocate instead of ftruncate\n"
135                " -v verbose            print debug information\n"
136                " -r ratio              ratio of file sizes, ',' separated values (def: 0.5,0.5)\n");
137 }
138
139 int main(int argc, char *argv[])
140 {
141         int opt;
142         int threads = 0;
143         char *ratio_ptr;
144
145         while ((opt = getopt(argc, argv, ":r:p:t:s:vf")) != -1) {
146                 switch(opt) {
147                 case 't':
148                         threads = atoi(optarg);
149                         pr_debug("Testing with (%d) threads\n", threads);
150                         break;
151                 case 's':
152                         fsize = atoi(optarg);
153                         pr_debug("size: %lu Bytes\n", fsize);
154                         break;
155                 case 'p':
156                         base_dir = optarg;
157                         break;
158                 case 'r':
159                         ratio = optarg;
160                         ratio_ptr = strtok(ratio, ",");
161                         if (ratio_ptr[0] == '1') {
162                                 file_ratio[0] = 1;
163                                 file_ratio[1] = 1;
164                                 break;
165                         }
166                         if (ratio_ptr != NULL)
167                                 file_ratio[0] = strtod(ratio_ptr, NULL);
168                         ratio_ptr = strtok(NULL, ",");
169                         if (ratio_ptr != NULL)
170                                 file_ratio[1] = strtod(ratio_ptr, NULL);
171                         break;
172                 case 'f':
173                         use_fallocate = true;
174                         break;
175                 case 'v':
176                         verbose = true;
177                         break;
178                 case '?':
179                         usage();
180                         exit(1);
181                 }
182         }
183
184         /* Sanity test of parameters */
185         assert(threads);
186         assert(fsize);
187         assert(file_ratio[0]);
188         assert(file_ratio[1]);
189
190         pr_debug("Testing with (%d) threads\n", threads);
191         pr_debug("size: %lu Bytes\n", fsize);
192
193         _run_test(threads);
194         return 0;
195 }