aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2020-12-14 20:27:57 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2020-12-14 20:27:57 +0100
commit2aaacc1453e98bd24341e7dc6edd8e7fdf84e576 (patch)
tree413efc5bd1b945a3cbb1be27ba67ca37f088e7c5
parentc7b858ff8d2e8b2d785f74b2d319bc9c839f4faa (diff)
downloadbusybox-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.c111
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
152static void dd_output_status(int UNUSED_PARAM cur_signal) 156static 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
200static 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
213static 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
195static bool write_and_stats(const void *buf, size_t len, size_t obs, 231static 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
299static 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
257int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 307int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
258int dd_main(int argc UNUSED_PARAM, char **argv) 308int 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}