4 * Hard disk write workload: write random (or zeroed) data at random
5 * locations in a file, and optionally validate by re-reading some
6 * blocks after a while.
9 * gcc -O2 -Wall -o test-ssd-write test-ssd-write.c
11 * Hard disk setups known to stop responding with this program (requires a
12 * warm machine reboot to get the drive to respond, as soft reset is not
15 * Vendor Model Firmware Controller # drives tested HW BIOS
16 * Intel (Lenovo) SSDSC2BW180A3L LE1i SandForce 2281 1 (3.5 Debian kernel) Lenovo x230 G2ET90WW (2.50) 2012-20-12
17 * Intel (Lenovo) SSDSC2BW180A3L LF1i SandForce 2281 2 (3.2 Debian kernel) Lenovo x230 G2ET90WW (2.50) 2012-20-12
18 * Intel (Lenovo) SSDSC2BW180A3L LF1i SandForce 2281 1 (3.7.9 Arch kernel) Lenovo x230 G2ET86WW (2.06) 2012-11-13
19 * Intel (Lenovo) SSDSC2BW180A3L LF1i SandForce 2281 1 (3.2 Debian kernel) Lenovo x200
21 * In order to narrow down the problem, we ran this test on a number of
22 * other hardware configurations which don't show this problem:
24 * Vendor Model Firmware Controller # drives tested HW BIOS
25 * Intel SSDSA2M160G2GC 2CV102HD Intel 1
26 * Intel SSDSA2CW300G310 ??????? Intel 1 (over USB on 3.8 kernel)
27 * Intel SSDSA2CT040G3 4PC10302 Intel 1 (3.2 kernel)
28 * Intel SSDSA2CT040G3 4PC10362 Intel 1 (3.2 kernel)
29 * Intel SSDSC2CT120A3K5 ??????? SandForce 2281 1 (on HP SmartArray P212 with 3.2 kernel)
30 * OCZ OCZ-VERTEX3 2.25 SF-2281 1 (3.7.9 Arch kernel)
31 * OCZ OCZSSD2-2VTXE180G 1.37 SF-1200 1 (3.7.6 Arch kernel)
33 * Under Linux (Debian, Ubuntu, various kernels), after about 5 minutes,
36 * ata1.00: exception Emask 0x0 SAct 0x1 SErr 0x0 action 0x6 frozen
37 * ata1.00: failed command: WRITE FPDMA QUEUED
38 * ata1.00: cmd 61/28:00:a8:a9:7f/00:00:02:00:00/40 tag 0 ncq 20480 out
39 * res 40/00:00:00:4f:c2/00:00:00:00:00/00 Emask 0x4 (timeout)
40 * ata1.00: status: { DRDY }
41 * ata1.00: COMRESET failed (errno=-16)
42 * ata1.00: COMRESET failed (errno=-16)
44 * This happens with random data, zeroed data (-z), and has been tested
45 * with file sizes of 1MB, 200MB, 3.1GB and 21GB. The error happens with
46 * and without the validation (-v) option.
48 * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
50 * Permission is hereby granted, free of charge, to any person obtaining
51 * a copy of this software and associated documentation files (the
52 * "Software"), to deal in the Software without restriction, including
53 * without limitation the rights to use, copy, modify, merge, publish,
54 * distribute, sublicense, and/or sell copies of the Software, and to
55 * permit persons to whom the Software is furnished to do so, subject to
56 * the following conditions:
58 * The above copyright notice and this permission notice shall be
59 * included in all copies or substantial portions of the Software.
61 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
64 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
65 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
66 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
71 #include <sys/types.h>
86 static enum write_mode write_mode
;
87 static int verify_mode
;
89 #define PRINT_FREQ 100000
90 #define VALIDATE_FREQ 10000
93 static void rand_buf(char *buf
, size_t buflen
)
97 for (i
= 0; i
< buflen
; i
+= sizeof(int)) {
103 memcpy(&buf
[i
], u
.c
, sizeof(int));
107 static uint64_t validate(int fd
, const char *validate_buf
, off_t offset
)
113 uint64_t diffcnt
= 0;
118 pos
= lseek(fd
, offset
, SEEK_SET
);
123 rret
= read(fd
, buf
, BUFLEN
);
124 if (rret
!= BUFLEN
) {
125 fprintf(stderr
, "Error at read from offset: %zu\n",
130 for (i
= 0; i
< BUFLEN
; i
++) {
131 if (buf
[i
] != validate_buf
[i
]) {
138 static int rand_write(int fd
, size_t len
)
141 uint64_t write_nr
= 0;
144 char validate_buf
[BUFLEN
];
145 off_t validate_offset
= 0;
150 fprintf(stderr
, "Error: File size needs to be at least %u\n", BUFLEN
);
154 memset(buf
, 0, BUFLEN
);
157 if (len
> UINT32_MAX
) {
158 offset
= (((size_t) rand() << 32) + (size_t) rand()) % (len
- BUFLEN
);
160 offset
= rand() % (len
- BUFLEN
);
163 if ((offset
>= validate_offset
&&
164 offset
< validate_offset
+ BUFLEN
)
165 || (validate_offset
>= offset
&&
166 validate_offset
< offset
+ BUFLEN
)) {
167 /* Don't overwrite the range we want to validate. */
170 if (write_mode
== WRITE_RANDOM
)
171 rand_buf(buf
, BUFLEN
);
172 /* Save validation buffer and position */
173 if (write_nr
% VALIDATE_FREQ
== 0 && verify_mode
) {
174 memcpy(validate_buf
, buf
, BUFLEN
);
175 validate_offset
= offset
;
177 pos
= lseek(fd
, offset
, SEEK_SET
);
182 wret
= write(fd
, buf
, BUFLEN
);
183 if (wret
!= BUFLEN
) {
184 fprintf(stderr
, "Error at write to offset: %zu\n",
191 * Advise that we won't be re-reading the blocks. This
192 * will ask the kernel to drop pages related to this
193 * file quickly from its page cache, thus forcing a read
201 ret
= posix_fadvise(fd
, offset
, BUFLEN
, POSIX_FADV_DONTNEED
);
203 perror("posix_fadvise");
208 if (write_nr
% PRINT_FREQ
== 0) {
209 printf("Status: %" PRIu64
" writes.\n", write_nr
);
213 * Use the validation buffer and position saved
214 * VALIDATE_FREQ operations earlier.
216 if (write_nr
% VALIDATE_FREQ
== 0 && verify_mode
) {
217 valcount
= validate(fd
, validate_buf
, validate_offset
);
219 printf("VALIDATION ERROR at offset %zu, %" PRIu64
" bytes differ\n",
220 validate_offset
, valcount
);
227 int main(int argc
, char **argv
)
229 int fd
, ret
, i
, seed
;
235 printf("Usage: %s <output file> <len (64-bit)> <seed (32-bit)> <-z to write zeroes> <-v to verify written data>\n", argv
[0]);
239 fd
= open(argv
[1], O_RDWR
| O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
);
245 len
= atoll(argv
[2]);
246 seed
= atoi(argv
[3]);
249 printf("Creating file %s of length %zu, random seed %u\n", argv
[1], len
,
252 for (i
= 4; i
< argc
; i
++) {
253 if (strcmp(argv
[i
], "-z") == 0) {
254 write_mode
= WRITE_ZEROES
;
255 } else if (strcmp(argv
[i
], "-v") == 0) {
260 switch (write_mode
) {
262 printf("Generating random data\n");
265 printf("Filling with zeroes (compressible pattern)\n");
268 printf("Unsupported write-mode\n");
273 printf("Verification mode activated.\n");
277 pos
= lseek(fd
, len
- 1, SEEK_SET
);
282 wret
= write(fd
, "", 1);
288 /* Advise the OS that we are performing random accesses */
289 ret
= posix_fadvise(fd
, 0, len
, POSIX_FADV_RANDOM
);
291 perror("posix_fadvise");
295 ret
= rand_write(fd
, len
);
This page took 0.034387 seconds and 4 git commands to generate.