diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2020-12-14 20:27:57 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2020-12-14 20:27:57 +0100 |
commit | 2aaacc1453e98bd24341e7dc6edd8e7fdf84e576 (patch) | |
tree | 413efc5bd1b945a3cbb1be27ba67ca37f088e7c5 | |
parent | c7b858ff8d2e8b2d785f74b2d319bc9c839f4faa (diff) | |
download | busybox-w32-2aaacc1453e98bd24341e7dc6edd8e7fdf84e576.tar.gz busybox-w32-2aaacc1453e98bd24341e7dc6edd8e7fdf84e576.tar.bz2 busybox-w32-2aaacc1453e98bd24341e7dc6edd8e7fdf84e576.zip |
dd: support for O_DIRECT i/o
Based on patch by Akash Hadke <hadkeakash4@gmail.com>
function old new delta
dd_read - 66 +66
clear_O_DIRECT - 55 +55
write_and_stats 102 135 +33
dd_main 1578 1601 +23
static.oflag_words 19 26 +7
static.iflag_words 22 29 +7
packed_usage 33665 33668 +3
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 5/0 up/down: 194/0) Total: 194 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | coreutils/dd.c | 111 |
1 files changed, 80 insertions, 31 deletions
diff --git a/coreutils/dd.c b/coreutils/dd.c index b5f3cbec5..24d7f0b84 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c | |||
@@ -59,7 +59,7 @@ | |||
59 | //usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]\n" | 59 | //usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]\n" |
60 | //usage: IF_FEATURE_DD_IBS_OBS( | 60 | //usage: IF_FEATURE_DD_IBS_OBS( |
61 | //usage: " [conv=notrunc|noerror|sync|fsync]\n" | 61 | //usage: " [conv=notrunc|noerror|sync|fsync]\n" |
62 | //usage: " [iflag=skip_bytes|fullblock] [oflag=seek_bytes|append]" | 62 | //usage: " [iflag=skip_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]" |
63 | //usage: ) | 63 | //usage: ) |
64 | //usage:#define dd_full_usage "\n\n" | 64 | //usage:#define dd_full_usage "\n\n" |
65 | //usage: "Copy a file with converting and formatting\n" | 65 | //usage: "Copy a file with converting and formatting\n" |
@@ -82,9 +82,11 @@ | |||
82 | //usage: "\n conv=fsync Physically write data out before finishing" | 82 | //usage: "\n conv=fsync Physically write data out before finishing" |
83 | //usage: "\n conv=swab Swap every pair of bytes" | 83 | //usage: "\n conv=swab Swap every pair of bytes" |
84 | //usage: "\n iflag=skip_bytes skip=N is in bytes" | 84 | //usage: "\n iflag=skip_bytes skip=N is in bytes" |
85 | //usage: "\n iflag=fullblock Read full blocks" | ||
86 | //usage: "\n oflag=seek_bytes seek=N is in bytes" | 85 | //usage: "\n oflag=seek_bytes seek=N is in bytes" |
87 | //usage: "\n oflag=append Open output file in append mode" | 86 | //usage: "\n iflag=direct O_DIRECT input" |
87 | //usage: "\n oflag=direct O_DIRECT output" | ||
88 | //usage: "\n iflag=fullblock Read full blocks" | ||
89 | //usage: "\n oflag=append Open output in append mode" | ||
88 | //usage: ) | 90 | //usage: ) |
89 | //usage: IF_FEATURE_DD_STATUS( | 91 | //usage: IF_FEATURE_DD_STATUS( |
90 | //usage: "\n status=noxfer Suppress rate output" | 92 | //usage: "\n status=noxfer Suppress rate output" |
@@ -137,16 +139,18 @@ enum { | |||
137 | FLAG_IFLAG_SHIFT = 5, | 139 | FLAG_IFLAG_SHIFT = 5, |
138 | FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, | 140 | FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, |
139 | FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, | 141 | FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, |
142 | FLAG_IDIRECT = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, | ||
140 | /* end of input flags */ | 143 | /* end of input flags */ |
141 | /* start of output flags */ | 144 | /* start of output flags */ |
142 | FLAG_OFLAG_SHIFT = 7, | 145 | FLAG_OFLAG_SHIFT = 8, |
143 | FLAG_SEEK_BYTES = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, | 146 | FLAG_SEEK_BYTES = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, |
144 | FLAG_APPEND = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, | 147 | FLAG_APPEND = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, |
148 | FLAG_ODIRECT = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS, | ||
145 | /* end of output flags */ | 149 | /* end of output flags */ |
146 | FLAG_TWOBUFS = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, | 150 | FLAG_TWOBUFS = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS, |
147 | FLAG_COUNT = 1 << 10, | 151 | FLAG_COUNT = 1 << 12, |
148 | FLAG_STATUS_NONE = 1 << 11, | 152 | FLAG_STATUS_NONE = 1 << 13, |
149 | FLAG_STATUS_NOXFER = 1 << 12, | 153 | FLAG_STATUS_NOXFER = 1 << 14, |
150 | }; | 154 | }; |
151 | 155 | ||
152 | static void dd_output_status(int UNUSED_PARAM cur_signal) | 156 | static void dd_output_status(int UNUSED_PARAM cur_signal) |
@@ -192,12 +196,50 @@ static void dd_output_status(int UNUSED_PARAM cur_signal) | |||
192 | #endif | 196 | #endif |
193 | } | 197 | } |
194 | 198 | ||
199 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
200 | static int clear_O_DIRECT(int fd) | ||
201 | { | ||
202 | if (errno == EINVAL) { | ||
203 | int fl = fcntl(fd, F_GETFL); | ||
204 | if (fl & O_DIRECT) { | ||
205 | fcntl(fd, F_SETFL, fl & ~O_DIRECT); | ||
206 | return 1; | ||
207 | } | ||
208 | } | ||
209 | return 0; | ||
210 | } | ||
211 | #endif | ||
212 | |||
213 | static ssize_t dd_read(void *ibuf, size_t ibs) | ||
214 | { | ||
215 | ssize_t n; | ||
216 | |||
217 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
218 | read_again: | ||
219 | if (G.flags & FLAG_FULLBLOCK) | ||
220 | n = full_read(ifd, ibuf, ibs); | ||
221 | else | ||
222 | #endif | ||
223 | n = safe_read(ifd, ibuf, ibs); | ||
224 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
225 | if (n < 0 && (G.flags & FLAG_IDIRECT) && clear_O_DIRECT(ifd)) | ||
226 | goto read_again; | ||
227 | #endif | ||
228 | return n; | ||
229 | } | ||
230 | |||
195 | static bool write_and_stats(const void *buf, size_t len, size_t obs, | 231 | static bool write_and_stats(const void *buf, size_t len, size_t obs, |
196 | const char *filename) | 232 | const char *filename) |
197 | { | 233 | { |
198 | ssize_t n; | 234 | ssize_t n; |
199 | 235 | ||
236 | IF_FEATURE_DD_IBS_OBS(write_again:) | ||
200 | n = full_write(ofd, buf, len); | 237 | n = full_write(ofd, buf, len); |
238 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
239 | if (n < 0 && (G.flags & FLAG_ODIRECT) && clear_O_DIRECT(ofd)) | ||
240 | goto write_again; | ||
241 | #endif | ||
242 | |||
201 | #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE | 243 | #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE |
202 | if (n > 0) | 244 | if (n > 0) |
203 | G.total_bytes += n; | 245 | G.total_bytes += n; |
@@ -254,6 +296,14 @@ static int parse_comma_flags(char *val, const char *words, const char *error_in) | |||
254 | } | 296 | } |
255 | #endif | 297 | #endif |
256 | 298 | ||
299 | static void *alloc_buf(size_t size) | ||
300 | { | ||
301 | /* Important for "{i,o}flag=direct" - buffers must be page aligned */ | ||
302 | if (size >= bb_getpagesize()) | ||
303 | return xmmap_anon(size); | ||
304 | return xmalloc(size); | ||
305 | } | ||
306 | |||
257 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 307 | int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
258 | int dd_main(int argc UNUSED_PARAM, char **argv) | 308 | int dd_main(int argc UNUSED_PARAM, char **argv) |
259 | { | 309 | { |
@@ -267,9 +317,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
267 | static const char conv_words[] ALIGN1 = | 317 | static const char conv_words[] ALIGN1 = |
268 | "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; | 318 | "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; |
269 | static const char iflag_words[] ALIGN1 = | 319 | static const char iflag_words[] ALIGN1 = |
270 | "skip_bytes\0""fullblock\0"; | 320 | "skip_bytes\0""fullblock\0""direct\0"; |
271 | static const char oflag_words[] ALIGN1 = | 321 | static const char oflag_words[] ALIGN1 = |
272 | "seek_bytes\0append\0"; | 322 | "seek_bytes\0append\0""direct\0"; |
273 | #endif | 323 | #endif |
274 | #if ENABLE_FEATURE_DD_STATUS | 324 | #if ENABLE_FEATURE_DD_STATUS |
275 | static const char status_words[] ALIGN1 = | 325 | static const char status_words[] ALIGN1 = |
@@ -310,7 +360,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
310 | //swab swap every pair of input bytes: will abort on non-even reads | 360 | //swab swap every pair of input bytes: will abort on non-even reads |
311 | OP_iflag_skip_bytes, | 361 | OP_iflag_skip_bytes, |
312 | OP_iflag_fullblock, | 362 | OP_iflag_fullblock, |
363 | OP_iflag_direct, | ||
313 | OP_oflag_seek_bytes, | 364 | OP_oflag_seek_bytes, |
365 | OP_oflag_direct, | ||
314 | #endif | 366 | #endif |
315 | }; | 367 | }; |
316 | smallint exitcode = EXIT_FAILURE; | 368 | smallint exitcode = EXIT_FAILURE; |
@@ -426,13 +478,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
426 | #endif | 478 | #endif |
427 | } /* end of "for (argv[i])" */ | 479 | } /* end of "for (argv[i])" */ |
428 | 480 | ||
429 | //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever | 481 | ibuf = alloc_buf(ibs); |
430 | ibuf = xmalloc(ibs); | ||
431 | obuf = ibuf; | 482 | obuf = ibuf; |
432 | #if ENABLE_FEATURE_DD_IBS_OBS | 483 | #if ENABLE_FEATURE_DD_IBS_OBS |
433 | if (ibs != obs) { | 484 | if (ibs != obs) { |
434 | G.flags |= FLAG_TWOBUFS; | 485 | G.flags |= FLAG_TWOBUFS; |
435 | obuf = xmalloc(obs); | 486 | obuf = alloc_buf(obs); |
436 | } | 487 | } |
437 | #endif | 488 | #endif |
438 | 489 | ||
@@ -444,7 +495,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
444 | #endif | 495 | #endif |
445 | 496 | ||
446 | if (infile) { | 497 | if (infile) { |
447 | xmove_fd(xopen(infile, O_RDONLY), ifd); | 498 | int iflag = O_RDONLY; |
499 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
500 | if (G.flags & FLAG_IDIRECT) | ||
501 | iflag |= O_DIRECT; | ||
502 | #endif | ||
503 | xmove_fd(xopen(infile, iflag), ifd); | ||
448 | } else { | 504 | } else { |
449 | infile = bb_msg_standard_input; | 505 | infile = bb_msg_standard_input; |
450 | } | 506 | } |
@@ -455,7 +511,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
455 | oflag |= O_TRUNC; | 511 | oflag |= O_TRUNC; |
456 | if (G.flags & FLAG_APPEND) | 512 | if (G.flags & FLAG_APPEND) |
457 | oflag |= O_APPEND; | 513 | oflag |= O_APPEND; |
458 | 514 | #if ENABLE_FEATURE_DD_IBS_OBS | |
515 | if (G.flags & FLAG_ODIRECT) | ||
516 | oflag |= O_DIRECT; | ||
517 | #endif | ||
459 | xmove_fd(xopen(outfile, oflag), ofd); | 518 | xmove_fd(xopen(outfile, oflag), ofd); |
460 | 519 | ||
461 | if (seek && !(G.flags & FLAG_NOTRUNC)) { | 520 | if (seek && !(G.flags & FLAG_NOTRUNC)) { |
@@ -478,13 +537,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
478 | size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs; | 537 | size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs; |
479 | if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) { | 538 | if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) { |
480 | do { | 539 | do { |
481 | ssize_t n; | 540 | ssize_t n = dd_read(ibuf, blocksz); |
482 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
483 | if (G.flags & FLAG_FULLBLOCK) | ||
484 | n = full_read(ifd, ibuf, blocksz); | ||
485 | else | ||
486 | #endif | ||
487 | n = safe_read(ifd, ibuf, blocksz); | ||
488 | if (n < 0) | 541 | if (n < 0) |
489 | goto die_infile; | 542 | goto die_infile; |
490 | if (n == 0) | 543 | if (n == 0) |
@@ -499,13 +552,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
499 | } | 552 | } |
500 | 553 | ||
501 | while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { | 554 | while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { |
502 | ssize_t n; | 555 | ssize_t n = dd_read(ibuf, ibs); |
503 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
504 | if (G.flags & FLAG_FULLBLOCK) | ||
505 | n = full_read(ifd, ibuf, ibs); | ||
506 | else | ||
507 | #endif | ||
508 | n = safe_read(ifd, ibuf, ibs); | ||
509 | if (n == 0) | 556 | if (n == 0) |
510 | break; | 557 | break; |
511 | if (n < 0) { | 558 | if (n < 0) { |
@@ -600,11 +647,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
600 | if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE)) | 647 | if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE)) |
601 | dd_output_status(0); | 648 | dd_output_status(0); |
602 | 649 | ||
650 | #if 0 /* can't just free(), they can be mmap()ed */ | ||
603 | if (ENABLE_FEATURE_CLEAN_UP) { | 651 | if (ENABLE_FEATURE_CLEAN_UP) { |
604 | free(obuf); | 652 | free(obuf); |
605 | if (G.flags & FLAG_TWOBUFS) | 653 | if (G.flags & FLAG_TWOBUFS) |
606 | free(ibuf); | 654 | free(ibuf); |
607 | } | 655 | } |
656 | #endif | ||
608 | 657 | ||
609 | return exitcode; | 658 | return exitcode; |
610 | } | 659 | } |