Add oflag=fsync and oflag=sync capability to dd

Sets the O_FSYNC flag on the output file. oflag=fsync and oflag=sync are
synonyms just as O_FSYNC and O_SYNC are synonyms. This functionality is
intended to improve portability of dd commands in the ZFS test suite.

Submitted by:	Ryan Moeller
Reviewed by:	manpages, mmacy@
MFC after:	1 week
Sponsored by:	 iXsytems, Inc.
Differential Revision:	https://reviews.freebsd.org/D21422
This commit is contained in:
Matt Macy 2019-09-30 21:56:42 +00:00
parent 2048fe7098
commit 919156e34c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=352922
4 changed files with 67 additions and 7 deletions

View File

@ -41,7 +41,7 @@ static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94";
#include <sys/cdefs.h> #include <sys/cdefs.h>
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <sys/types.h> #include <sys/param.h>
#include <ctype.h> #include <ctype.h>
#include <err.h> #include <err.h>
@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
static int c_arg(const void *, const void *); static int c_arg(const void *, const void *);
static int c_conv(const void *, const void *); static int c_conv(const void *, const void *);
static int c_oflag(const void *, const void *);
static void f_bs(char *); static void f_bs(char *);
static void f_cbs(char *); static void f_cbs(char *);
static void f_conv(char *); static void f_conv(char *);
@ -67,6 +68,7 @@ static void f_ibs(char *);
static void f_if(char *); static void f_if(char *);
static void f_obs(char *); static void f_obs(char *);
static void f_of(char *); static void f_of(char *);
static void f_oflag(char *);
static void f_seek(char *); static void f_seek(char *);
static void f_skip(char *); static void f_skip(char *);
static void f_speed(char *); static void f_speed(char *);
@ -90,6 +92,7 @@ static const struct arg {
{ "iseek", f_skip, C_SKIP, C_SKIP }, { "iseek", f_skip, C_SKIP, C_SKIP },
{ "obs", f_obs, C_OBS, C_BS|C_OBS }, { "obs", f_obs, C_OBS, C_BS|C_OBS },
{ "of", f_of, C_OF, C_OF }, { "of", f_of, C_OF, C_OF },
{ "oflag", f_oflag, 0, 0 },
{ "oseek", f_seek, C_SEEK, C_SEEK }, { "oseek", f_seek, C_SEEK, C_SEEK },
{ "seek", f_seek, C_SEEK, C_SEEK }, { "seek", f_seek, C_SEEK, C_SEEK },
{ "skip", f_skip, C_SKIP, C_SKIP }, { "skip", f_skip, C_SKIP, C_SKIP },
@ -348,8 +351,8 @@ f_conv(char *arg)
while (arg != NULL) { while (arg != NULL) {
tmp.name = strsep(&arg, ","); tmp.name = strsep(&arg, ",");
cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv), cp = bsearch(&tmp, clist, nitems(clist), sizeof(struct conv),
sizeof(struct conv), c_conv); c_conv);
if (cp == NULL) if (cp == NULL)
errx(1, "unknown conversion %s", tmp.name); errx(1, "unknown conversion %s", tmp.name);
if (ddflags & cp->noset) if (ddflags & cp->noset)
@ -368,6 +371,37 @@ c_conv(const void *a, const void *b)
((const struct conv *)b)->name)); ((const struct conv *)b)->name));
} }
static const struct oflag {
const char *name;
uint64_t set;
} olist[] = {
{ "fsync", C_OFSYNC },
{ "sync", C_OFSYNC },
};
static void
f_oflag(char *arg)
{
struct oflag *op, tmp;
while (arg != NULL) {
tmp.name = strsep(&arg, ",");
op = bsearch(&tmp, olist, nitems(olist), sizeof(struct oflag),
c_oflag);
if (op == NULL)
errx(1, "unknown open flag %s", tmp.name);
ddflags |= op->set;
}
}
static int
c_oflag(const void *a, const void *b)
{
return (strcmp(((const struct oflag *)a)->name,
((const struct oflag *)b)->name));
}
static intmax_t static intmax_t
postfix_to_mult(const char expr) postfix_to_mult(const char expr)
{ {

View File

@ -123,6 +123,19 @@ If an initial portion of the output file is seeked past (see the
.Cm oseek .Cm oseek
operand), operand),
the output file is truncated at that point. the output file is truncated at that point.
.It Cm oflag Ns = Ns Ar value Ns Op , Ns Ar value ...
Where
.Cm value
is one of the symbols from the following list.
.Bl -tag -width "fsync"
.It Cm fsync
Set the O_FSYNC flag on the output file to make writes synchronous.
.It Cm sync
Set the O_SYNC flag on the output file to make writes synchronous.
This is synonymous with the
.Cm fsync
value.
.El
.It Cm oseek Ns = Ns Ar n .It Cm oseek Ns = Ns Ar n
Seek on the output file Seek on the output file
.Ar n .Ar n

View File

@ -143,6 +143,7 @@ static void
setup(void) setup(void)
{ {
u_int cnt; u_int cnt;
int oflags;
cap_rights_t rights; cap_rights_t rights;
unsigned long cmds[] = { FIODTYPE, MTIOCTOP }; unsigned long cmds[] = { FIODTYPE, MTIOCTOP };
@ -171,17 +172,28 @@ setup(void)
/* No way to check for read access here. */ /* No way to check for read access here. */
out.fd = STDOUT_FILENO; out.fd = STDOUT_FILENO;
out.name = "stdout"; out.name = "stdout";
if (ddflags & C_OFSYNC) {
oflags = fcntl(out.fd, F_GETFL);
if (oflags == -1)
err(1, "unable to get fd flags for stdout");
oflags |= O_FSYNC;
if (fcntl(out.fd, F_SETFL, oflags) == -1)
err(1, "unable to set fd flags for stdout");
}
} else { } else {
#define OFLAGS \ oflags = O_CREAT;
(O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) if (!(ddflags & (C_SEEK | C_NOTRUNC)))
out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE); oflags |= O_TRUNC;
if (ddflags & C_OFSYNC)
oflags |= O_FSYNC;
out.fd = open(out.name, O_RDWR | oflags, DEFFILEMODE);
/* /*
* May not have read access, so try again with write only. * May not have read access, so try again with write only.
* Without read we may have a problem if output also does * Without read we may have a problem if output also does
* not support seeks. * not support seeks.
*/ */
if (out.fd == -1) { if (out.fd == -1) {
out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE); out.fd = open(out.name, O_WRONLY | oflags, DEFFILEMODE);
out.flags |= NOREAD; out.flags |= NOREAD;
cap_rights_clear(&rights, CAP_READ); cap_rights_clear(&rights, CAP_READ);
} }

View File

@ -103,6 +103,7 @@ typedef struct {
#define C_PROGRESS 0x0000000040000000ULL #define C_PROGRESS 0x0000000040000000ULL
#define C_FSYNC 0x0000000080000000ULL #define C_FSYNC 0x0000000080000000ULL
#define C_FDATASYNC 0x0000000100000000ULL #define C_FDATASYNC 0x0000000100000000ULL
#define C_OFSYNC 0x0000000200000000ULL
#define C_PARITY (C_PAREVEN | C_PARODD | C_PARNONE | C_PARSET) #define C_PARITY (C_PAREVEN | C_PARODD | C_PARNONE | C_PARSET)