1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2017 Cyril Hrubis <[email protected]>
4 */
5
6 #include <errno.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/statvfs.h>
10 #include <sys/uio.h>
11
12 #define TST_NO_DEFAULT_MAIN
13 #include "tst_test.h"
14 #include "lapi/fcntl.h"
15 #include "tst_fs.h"
16 #include "tst_rand_data.h"
17 #include "tst_safe_file_at.h"
18
fill_random(const char * path,int verbose)19 static void fill_random(const char *path, int verbose)
20 {
21 int i = 0;
22 char file[PATH_MAX];
23 size_t len;
24 ssize_t ret;
25 int fd;
26 struct statvfs fi;
27
28 statvfs(path, &fi);
29
30 for (;;) {
31 len = random() % (1024 * 102400);
32
33 snprintf(file, sizeof(file), "%s/file%i", path, i++);
34
35 if (verbose)
36 tst_res(TINFO, "Creating file %s size %zu", file, len);
37
38 fd = open(file, O_WRONLY | O_CREAT, 0700);
39 if (fd == -1) {
40 if (errno != ENOSPC)
41 tst_brk(TBROK | TERRNO, "open()");
42
43 tst_res(TINFO | TERRNO, "open()");
44 return;
45 }
46
47 while (len) {
48 ret = write(fd, tst_rand_data, MIN(len, tst_rand_data_len));
49
50 if (ret < 0) {
51 /* retry on ENOSPC to make sure filesystem is really full */
52 if (errno == ENOSPC && len >= fi.f_bsize/2) {
53 SAFE_FSYNC(fd);
54 len /= 2;
55 continue;
56 }
57
58 SAFE_CLOSE(fd);
59
60 if (errno != ENOSPC)
61 tst_brk(TBROK | TERRNO, "write()");
62
63 tst_res(TINFO | TERRNO, "write()");
64 return;
65 }
66
67 len -= ret;
68 }
69
70 SAFE_CLOSE(fd);
71 }
72 }
73
fill_flat_vec(const char * path,int verbose)74 static void fill_flat_vec(const char *path, int verbose)
75 {
76 int dir, fd;
77 struct iovec iov[512];
78 int iovcnt = ARRAY_SIZE(iov);
79 int retries = 3;
80
81 dir = open(path, O_PATH | O_DIRECTORY);
82 if (dir == -1) {
83 if (errno == ENOSPC) {
84 tst_res(TINFO | TERRNO, "open()");
85 return;
86 }
87 tst_brk(TBROK | TERRNO, "open(%s, %d) failed", path, O_PATH | O_DIRECTORY);
88 }
89
90 fd = openat(dir, "AOF", O_WRONLY | O_CREAT, 0600);
91 if (fd == -1) {
92 if (errno == ENOSPC) {
93 tst_res(TINFO | TERRNO, "openat()");
94 return;
95 }
96 tst_brk(TBROK | TERRNO, "openat(%d, %d, 0600) failed for path %s",
97 dir, O_PATH | O_DIRECTORY, path);
98 }
99
100 SAFE_CLOSE(dir);
101
102 for (int i = 0; i < iovcnt; i++) {
103 iov[i] = (struct iovec) {
104 (void *)tst_rand_data,
105 tst_rand_data_len
106 };
107 }
108
109 while (retries) {
110 const int ret = writev(fd, iov, iovcnt);
111
112 if (!ret)
113 tst_res(TWARN | TERRNO, "writev returned 0; not sure what this means");
114
115 if (ret > -1) {
116 if (verbose && retries < 3)
117 tst_res(TINFO, "writev(\"%s/AOF\", iov, %d) = %d", path, iovcnt, ret);
118
119 retries = 3;
120 continue;
121 }
122
123 if (errno != ENOSPC)
124 tst_brk(TBROK | TERRNO, "writev(\"%s/AOF\", iov, %d)", path, iovcnt);
125
126 if (verbose)
127 tst_res(TINFO, "writev(\"%s/AOF\", iov, %d): ENOSPC", path, iovcnt);
128
129 retries--;
130 }
131
132 SAFE_CLOSE(fd);
133 }
134
tst_fill_fs(const char * path,int verbose,enum tst_fill_access_pattern pattern)135 void tst_fill_fs(const char *path, int verbose, enum tst_fill_access_pattern pattern)
136 {
137
138 switch (pattern) {
139 case TST_FILL_BLOCKS:
140 return fill_flat_vec(path, verbose);
141 case TST_FILL_RANDOM:
142 return fill_random(path, verbose);
143 }
144 }
145