Set process title during zfs send.

This adds a '-V' option to 'zfs send', which sets the process title once a
second to the progress information.

This code has been in FreeNAS for a long time now; this is just upstreaming
it here.  It was originially written by delphij.

Reviewed by:	mav
Obtained from:	iXsystems, Inc
Sponsored by:	iXsystems, Inc
Differential Revision:	https://reviews.freebsd.org/D19184
This commit is contained in:
sef 2019-02-26 19:23:22 +00:00
parent 080df95745
commit 122ed8691a
4 changed files with 44 additions and 14 deletions

View File

@ -32,7 +32,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd August 11, 2018 .Dd February 15, 2018
.Dt ZFS 8 .Dt ZFS 8
.Os .Os
.Sh NAME .Sh NAME
@ -184,7 +184,7 @@
.Ar bookmark .Ar bookmark
.Nm .Nm
.Cm send .Cm send
.Op Fl DLPRcenpv .Op Fl DLPRVcenpv
.Op Fl i Ar snapshot | Fl I Ar snapshot .Op Fl i Ar snapshot | Fl I Ar snapshot
.Ar snapshot .Ar snapshot
.Nm .Nm
@ -194,7 +194,7 @@
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot .Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
.Nm .Nm
.Cm send .Cm send
.Op Fl Penv .Op Fl PVenv
.Fl t Ar receive_resume_token .Fl t Ar receive_resume_token
.Nm .Nm
.Cm receive Ns | Ns Cm recv .Cm receive Ns | Ns Cm recv
@ -2607,7 +2607,7 @@ feature.
.It Xo .It Xo
.Nm .Nm
.Cm send .Cm send
.Op Fl DLPRcenpv .Op Fl DLPRVcenpv
.Op Fl i Ar snapshot | Fl I Ar snapshot .Op Fl i Ar snapshot | Fl I Ar snapshot
.Ar snapshot .Ar snapshot
.Xc .Xc
@ -2753,6 +2753,8 @@ Print machine-parsable verbose information about the stream package generated.
.It Fl v, -verbose .It Fl v, -verbose
Print verbose information about the stream package generated. Print verbose information about the stream package generated.
This information includes a per-second report of how much data has been sent. This information includes a per-second report of how much data has been sent.
.It Fl V
Set the process title to a per-second report of how much data has been sent.
.El .El
.Pp .Pp
The format of the stream is committed. You will be able to receive your streams The format of the stream is committed. You will be able to receive your streams

View File

@ -3813,7 +3813,7 @@ zfs_do_send(int argc, char **argv)
}; };
/* check options */ /* check options */
while ((c = getopt_long(argc, argv, ":i:I:RbDpvnPLet:c", long_options, while ((c = getopt_long(argc, argv, ":i:I:RbDpVvnPLet:c", long_options,
NULL)) != -1) { NULL)) != -1) {
switch (c) { switch (c) {
case 'i': case 'i':
@ -3837,6 +3837,10 @@ zfs_do_send(int argc, char **argv)
flags.parsable = B_TRUE; flags.parsable = B_TRUE;
flags.verbose = B_TRUE; flags.verbose = B_TRUE;
break; break;
case 'V':
flags.progress = B_TRUE;
flags.progressastitle = B_TRUE;
break;
case 'v': case 'v':
if (flags.verbose) if (flags.verbose)
extraverbose = B_TRUE; extraverbose = B_TRUE;

View File

@ -651,6 +651,9 @@ typedef struct sendflags {
/* compressed WRITE records are permitted */ /* compressed WRITE records are permitted */
boolean_t compress; boolean_t compress;
/* show progress as process title(ie. -V) */
boolean_t progressastitle;
} sendflags_t; } sendflags_t;
typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *); typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);

View File

@ -85,6 +85,8 @@ typedef struct progress_arg {
zfs_handle_t *pa_zhp; zfs_handle_t *pa_zhp;
int pa_fd; int pa_fd;
boolean_t pa_parsable; boolean_t pa_parsable;
boolean_t pa_astitle;
uint64_t pa_size;
} progress_arg_t; } progress_arg_t;
typedef struct dataref { typedef struct dataref {
@ -930,6 +932,7 @@ typedef struct send_dump_data {
uint64_t prevsnap_obj; uint64_t prevsnap_obj;
boolean_t seenfrom, seento, replicate, doall, fromorigin; boolean_t seenfrom, seento, replicate, doall, fromorigin;
boolean_t verbose, dryrun, parsable, progress, embed_data, std_out; boolean_t verbose, dryrun, parsable, progress, embed_data, std_out;
boolean_t progressastitle;
boolean_t large_block, compress; boolean_t large_block, compress;
int outfd; int outfd;
boolean_t err; boolean_t err;
@ -1110,14 +1113,14 @@ send_progress_thread(void *arg)
zfs_cmd_t zc = { 0 }; zfs_cmd_t zc = { 0 };
zfs_handle_t *zhp = pa->pa_zhp; zfs_handle_t *zhp = pa->pa_zhp;
libzfs_handle_t *hdl = zhp->zfs_hdl; libzfs_handle_t *hdl = zhp->zfs_hdl;
unsigned long long bytes; unsigned long long bytes, total;
char buf[16]; char buf[16];
time_t t; time_t t;
struct tm *tm; struct tm *tm;
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
if (!pa->pa_parsable) if (!pa->pa_parsable && !pa->pa_astitle)
(void) fprintf(stderr, "TIME SENT SNAPSHOT\n"); (void) fprintf(stderr, "TIME SENT SNAPSHOT\n");
/* /*
@ -1134,7 +1137,16 @@ send_progress_thread(void *arg)
tm = localtime(&t); tm = localtime(&t);
bytes = zc.zc_cookie; bytes = zc.zc_cookie;
if (pa->pa_parsable) { if (pa->pa_astitle) {
int pct;
if (pa->pa_size > bytes)
pct = 100 * bytes / pa->pa_size;
else
pct = 100;
setproctitle("sending %s (%d%%: %llu/%llu)",
zhp->zfs_name, pct, bytes, pa->pa_size);
} else if (pa->pa_parsable) {
(void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n", (void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n",
tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_hour, tm->tm_min, tm->tm_sec,
bytes, zhp->zfs_name); bytes, zhp->zfs_name);
@ -1204,6 +1216,7 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
boolean_t isfromsnap, istosnap, fromorigin; boolean_t isfromsnap, istosnap, fromorigin;
boolean_t exclude = B_FALSE; boolean_t exclude = B_FALSE;
FILE *fout = sdd->std_out ? stdout : stderr; FILE *fout = sdd->std_out ? stdout : stderr;
uint64_t size = 0;
err = 0; err = 0;
thissnap = strchr(zhp->zfs_name, '@') + 1; thissnap = strchr(zhp->zfs_name, '@') + 1;
@ -1278,15 +1291,16 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
fromorigin = sdd->prevsnap[0] == '\0' && fromorigin = sdd->prevsnap[0] == '\0' &&
(sdd->fromorigin || sdd->replicate); (sdd->fromorigin || sdd->replicate);
if (sdd->verbose) { if (sdd->progress && sdd->dryrun) {
uint64_t size = 0;
(void) estimate_ioctl(zhp, sdd->prevsnap_obj, (void) estimate_ioctl(zhp, sdd->prevsnap_obj,
fromorigin, flags, &size); fromorigin, flags, &size);
sdd->size += size;
}
if (sdd->verbose) {
send_print_verbose(fout, zhp->zfs_name, send_print_verbose(fout, zhp->zfs_name,
sdd->prevsnap[0] ? sdd->prevsnap : NULL, sdd->prevsnap[0] ? sdd->prevsnap : NULL,
size, sdd->parsable); size, sdd->parsable);
sdd->size += size;
} }
if (!sdd->dryrun) { if (!sdd->dryrun) {
@ -1298,6 +1312,8 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
pa.pa_zhp = zhp; pa.pa_zhp = zhp;
pa.pa_fd = sdd->outfd; pa.pa_fd = sdd->outfd;
pa.pa_parsable = sdd->parsable; pa.pa_parsable = sdd->parsable;
pa.pa_size = sdd->size;
pa.pa_astitle = sdd->progressastitle;
if ((err = pthread_create(&tid, NULL, if ((err = pthread_create(&tid, NULL,
send_progress_thread, &pa)) != 0) { send_progress_thread, &pa)) != 0) {
@ -1580,6 +1596,7 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
int error = 0; int error = 0;
char name[ZFS_MAX_DATASET_NAME_LEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
enum lzc_send_flags lzc_flags = 0; enum lzc_send_flags lzc_flags = 0;
uint64_t size = 0;
FILE *fout = (flags->verbose && flags->dryrun) ? stdout : stderr; FILE *fout = (flags->verbose && flags->dryrun) ? stdout : stderr;
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
@ -1648,12 +1665,13 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
fromname = name; fromname = name;
} }
if (flags->verbose) { if (flags->progress) {
uint64_t size = 0;
error = lzc_send_space(zhp->zfs_name, fromname, error = lzc_send_space(zhp->zfs_name, fromname,
lzc_flags, &size); lzc_flags, &size);
if (error == 0) if (error == 0)
size = MAX(0, (int64_t)(size - bytes)); size = MAX(0, (int64_t)(size - bytes));
}
if (flags->verbose) {
send_print_verbose(fout, zhp->zfs_name, fromname, send_print_verbose(fout, zhp->zfs_name, fromname,
size, flags->parsable); size, flags->parsable);
} }
@ -1669,6 +1687,8 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
pa.pa_zhp = zhp; pa.pa_zhp = zhp;
pa.pa_fd = outfd; pa.pa_fd = outfd;
pa.pa_parsable = flags->parsable; pa.pa_parsable = flags->parsable;
pa.pa_size = size;
pa.pa_astitle = flags->progressastitle;
error = pthread_create(&tid, NULL, error = pthread_create(&tid, NULL,
send_progress_thread, &pa); send_progress_thread, &pa);
@ -1878,6 +1898,7 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
sdd.verbose = flags->verbose; sdd.verbose = flags->verbose;
sdd.parsable = flags->parsable; sdd.parsable = flags->parsable;
sdd.progress = flags->progress; sdd.progress = flags->progress;
sdd.progressastitle = flags->progressastitle;
sdd.dryrun = flags->dryrun; sdd.dryrun = flags->dryrun;
sdd.large_block = flags->largeblock; sdd.large_block = flags->largeblock;
sdd.embed_data = flags->embed_data; sdd.embed_data = flags->embed_data;
@ -1914,7 +1935,7 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
sdd.cleanup_fd = -1; sdd.cleanup_fd = -1;
sdd.snapholds = NULL; sdd.snapholds = NULL;
} }
if (flags->verbose || sdd.snapholds != NULL) { if (flags->progress || sdd.snapholds != NULL) {
/* /*
* Do a verbose no-op dry run to get all the verbose output * Do a verbose no-op dry run to get all the verbose output
* or to gather snapshot hold's before generating any data, * or to gather snapshot hold's before generating any data,