xref: /aosp_15_r20/external/ltp/lib/tst_fill_fs.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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