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>
This commit is contained in:
parent
c7b858ff8d
commit
2aaacc1453
111
coreutils/dd.c
111
coreutils/dd.c
@ -59,7 +59,7 @@
|
||||
//usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]\n"
|
||||
//usage: IF_FEATURE_DD_IBS_OBS(
|
||||
//usage: " [conv=notrunc|noerror|sync|fsync]\n"
|
||||
//usage: " [iflag=skip_bytes|fullblock] [oflag=seek_bytes|append]"
|
||||
//usage: " [iflag=skip_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]"
|
||||
//usage: )
|
||||
//usage:#define dd_full_usage "\n\n"
|
||||
//usage: "Copy a file with converting and formatting\n"
|
||||
@ -82,9 +82,11 @@
|
||||
//usage: "\n conv=fsync Physically write data out before finishing"
|
||||
//usage: "\n conv=swab Swap every pair of bytes"
|
||||
//usage: "\n iflag=skip_bytes skip=N is in bytes"
|
||||
//usage: "\n iflag=fullblock Read full blocks"
|
||||
//usage: "\n oflag=seek_bytes seek=N is in bytes"
|
||||
//usage: "\n oflag=append Open output file in append mode"
|
||||
//usage: "\n iflag=direct O_DIRECT input"
|
||||
//usage: "\n oflag=direct O_DIRECT output"
|
||||
//usage: "\n iflag=fullblock Read full blocks"
|
||||
//usage: "\n oflag=append Open output in append mode"
|
||||
//usage: )
|
||||
//usage: IF_FEATURE_DD_STATUS(
|
||||
//usage: "\n status=noxfer Suppress rate output"
|
||||
@ -137,16 +139,18 @@ enum {
|
||||
FLAG_IFLAG_SHIFT = 5,
|
||||
FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
|
||||
FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS,
|
||||
FLAG_IDIRECT = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS,
|
||||
/* end of input flags */
|
||||
/* start of output flags */
|
||||
FLAG_OFLAG_SHIFT = 7,
|
||||
FLAG_SEEK_BYTES = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS,
|
||||
FLAG_APPEND = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS,
|
||||
FLAG_OFLAG_SHIFT = 8,
|
||||
FLAG_SEEK_BYTES = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS,
|
||||
FLAG_APPEND = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS,
|
||||
FLAG_ODIRECT = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS,
|
||||
/* end of output flags */
|
||||
FLAG_TWOBUFS = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS,
|
||||
FLAG_COUNT = 1 << 10,
|
||||
FLAG_STATUS_NONE = 1 << 11,
|
||||
FLAG_STATUS_NOXFER = 1 << 12,
|
||||
FLAG_TWOBUFS = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS,
|
||||
FLAG_COUNT = 1 << 12,
|
||||
FLAG_STATUS_NONE = 1 << 13,
|
||||
FLAG_STATUS_NOXFER = 1 << 14,
|
||||
};
|
||||
|
||||
static void dd_output_status(int UNUSED_PARAM cur_signal)
|
||||
@ -192,12 +196,50 @@ static void dd_output_status(int UNUSED_PARAM cur_signal)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_DD_IBS_OBS
|
||||
static int clear_O_DIRECT(int fd)
|
||||
{
|
||||
if (errno == EINVAL) {
|
||||
int fl = fcntl(fd, F_GETFL);
|
||||
if (fl & O_DIRECT) {
|
||||
fcntl(fd, F_SETFL, fl & ~O_DIRECT);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ssize_t dd_read(void *ibuf, size_t ibs)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
#if ENABLE_FEATURE_DD_IBS_OBS
|
||||
read_again:
|
||||
if (G.flags & FLAG_FULLBLOCK)
|
||||
n = full_read(ifd, ibuf, ibs);
|
||||
else
|
||||
#endif
|
||||
n = safe_read(ifd, ibuf, ibs);
|
||||
#if ENABLE_FEATURE_DD_IBS_OBS
|
||||
if (n < 0 && (G.flags & FLAG_IDIRECT) && clear_O_DIRECT(ifd))
|
||||
goto read_again;
|
||||
#endif
|
||||
return n;
|
||||
}
|
||||
|
||||
static bool write_and_stats(const void *buf, size_t len, size_t obs,
|
||||
const char *filename)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
IF_FEATURE_DD_IBS_OBS(write_again:)
|
||||
n = full_write(ofd, buf, len);
|
||||
#if ENABLE_FEATURE_DD_IBS_OBS
|
||||
if (n < 0 && (G.flags & FLAG_ODIRECT) && clear_O_DIRECT(ofd))
|
||||
goto write_again;
|
||||
#endif
|
||||
|
||||
#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
|
||||
if (n > 0)
|
||||
G.total_bytes += n;
|
||||
@ -254,6 +296,14 @@ static int parse_comma_flags(char *val, const char *words, const char *error_in)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void *alloc_buf(size_t size)
|
||||
{
|
||||
/* Important for "{i,o}flag=direct" - buffers must be page aligned */
|
||||
if (size >= bb_getpagesize())
|
||||
return xmmap_anon(size);
|
||||
return xmalloc(size);
|
||||
}
|
||||
|
||||
int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int dd_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
@ -267,9 +317,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
||||
static const char conv_words[] ALIGN1 =
|
||||
"notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
|
||||
static const char iflag_words[] ALIGN1 =
|
||||
"skip_bytes\0""fullblock\0";
|
||||
"skip_bytes\0""fullblock\0""direct\0";
|
||||
static const char oflag_words[] ALIGN1 =
|
||||
"seek_bytes\0append\0";
|
||||
"seek_bytes\0append\0""direct\0";
|
||||
#endif
|
||||
#if ENABLE_FEATURE_DD_STATUS
|
||||
static const char status_words[] ALIGN1 =
|
||||
@ -310,7 +360,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
||||
//swab swap every pair of input bytes: will abort on non-even reads
|
||||
OP_iflag_skip_bytes,
|
||||
OP_iflag_fullblock,
|
||||
OP_iflag_direct,
|
||||
OP_oflag_seek_bytes,
|
||||
OP_oflag_direct,
|
||||
#endif
|
||||
};
|
||||
smallint exitcode = EXIT_FAILURE;
|
||||
@ -426,13 +478,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
||||
#endif
|
||||
} /* end of "for (argv[i])" */
|
||||
|
||||
//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
|
||||
ibuf = xmalloc(ibs);
|
||||
ibuf = alloc_buf(ibs);
|
||||
obuf = ibuf;
|
||||
#if ENABLE_FEATURE_DD_IBS_OBS
|
||||
if (ibs != obs) {
|
||||
G.flags |= FLAG_TWOBUFS;
|
||||
obuf = xmalloc(obs);
|
||||
obuf = alloc_buf(obs);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -444,7 +495,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
||||
#endif
|
||||
|
||||
if (infile) {
|
||||
xmove_fd(xopen(infile, O_RDONLY), ifd);
|
||||
int iflag = O_RDONLY;
|
||||
#if ENABLE_FEATURE_DD_IBS_OBS
|
||||
if (G.flags & FLAG_IDIRECT)
|
||||
iflag |= O_DIRECT;
|
||||
#endif
|
||||
xmove_fd(xopen(infile, iflag), ifd);
|
||||
} else {
|
||||
infile = bb_msg_standard_input;
|
||||
}
|
||||
@ -455,7 +511,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
||||
oflag |= O_TRUNC;
|
||||
if (G.flags & FLAG_APPEND)
|
||||
oflag |= O_APPEND;
|
||||
|
||||
#if ENABLE_FEATURE_DD_IBS_OBS
|
||||
if (G.flags & FLAG_ODIRECT)
|
||||
oflag |= O_DIRECT;
|
||||
#endif
|
||||
xmove_fd(xopen(outfile, oflag), ofd);
|
||||
|
||||
if (seek && !(G.flags & FLAG_NOTRUNC)) {
|
||||
@ -478,13 +537,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
||||
size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs;
|
||||
if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) {
|
||||
do {
|
||||
ssize_t n;
|
||||
#if ENABLE_FEATURE_DD_IBS_OBS
|
||||
if (G.flags & FLAG_FULLBLOCK)
|
||||
n = full_read(ifd, ibuf, blocksz);
|
||||
else
|
||||
#endif
|
||||
n = safe_read(ifd, ibuf, blocksz);
|
||||
ssize_t n = dd_read(ibuf, blocksz);
|
||||
if (n < 0)
|
||||
goto die_infile;
|
||||
if (n == 0)
|
||||
@ -499,13 +552,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
||||
}
|
||||
|
||||
while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
|
||||
ssize_t n;
|
||||
#if ENABLE_FEATURE_DD_IBS_OBS
|
||||
if (G.flags & FLAG_FULLBLOCK)
|
||||
n = full_read(ifd, ibuf, ibs);
|
||||
else
|
||||
#endif
|
||||
n = safe_read(ifd, ibuf, ibs);
|
||||
ssize_t n = dd_read(ibuf, ibs);
|
||||
if (n == 0)
|
||||
break;
|
||||
if (n < 0) {
|
||||
@ -600,11 +647,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
||||
if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE))
|
||||
dd_output_status(0);
|
||||
|
||||
#if 0 /* can't just free(), they can be mmap()ed */
|
||||
if (ENABLE_FEATURE_CLEAN_UP) {
|
||||
free(obuf);
|
||||
if (G.flags & FLAG_TWOBUFS)
|
||||
free(ibuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
return exitcode;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user