From 50792eb553bf2cebaea3ddaea066100ab9e51f2d Mon Sep 17 00:00:00 2001 From: Sean Eric Fagan Date: Tue, 26 Feb 2019 19:23:22 +0000 Subject: [PATCH] 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 --- cddl/contrib/opensolaris/cmd/zfs/zfs.8 | 10 +++-- cddl/contrib/opensolaris/cmd/zfs/zfs_main.c | 6 ++- .../opensolaris/lib/libzfs/common/libzfs.h | 3 ++ .../lib/libzfs/common/libzfs_sendrecv.c | 39 ++++++++++++++----- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 b/cddl/contrib/opensolaris/cmd/zfs/zfs.8 index e152ad9ed4b4..3656f799ea98 100644 --- a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 +++ b/cddl/contrib/opensolaris/cmd/zfs/zfs.8 @@ -32,7 +32,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 11, 2018 +.Dd February 15, 2018 .Dt ZFS 8 .Os .Sh NAME @@ -184,7 +184,7 @@ .Ar bookmark .Nm .Cm send -.Op Fl DLPRcenpv +.Op Fl DLPRVcenpv .Op Fl i Ar snapshot | Fl I Ar snapshot .Ar snapshot .Nm @@ -194,7 +194,7 @@ .Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot .Nm .Cm send -.Op Fl Penv +.Op Fl PVenv .Fl t Ar receive_resume_token .Nm .Cm receive Ns | Ns Cm recv @@ -2607,7 +2607,7 @@ feature. .It Xo .Nm .Cm send -.Op Fl DLPRcenpv +.Op Fl DLPRVcenpv .Op Fl i Ar snapshot | Fl I Ar snapshot .Ar snapshot .Xc @@ -2753,6 +2753,8 @@ Print machine-parsable verbose information about the stream package generated. .It Fl v, -verbose Print verbose information about the stream package generated. 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 .Pp The format of the stream is committed. You will be able to receive your streams diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c index 89f2bdcb2d21..2275c3fb15fd 100644 --- a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c +++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c @@ -3813,7 +3813,7 @@ zfs_do_send(int argc, char **argv) }; /* 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) { switch (c) { case 'i': @@ -3837,6 +3837,10 @@ zfs_do_send(int argc, char **argv) flags.parsable = B_TRUE; flags.verbose = B_TRUE; break; + case 'V': + flags.progress = B_TRUE; + flags.progressastitle = B_TRUE; + break; case 'v': if (flags.verbose) extraverbose = B_TRUE; diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h index 337fd97f8bd3..f75effd338fc 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h @@ -651,6 +651,9 @@ typedef struct sendflags { /* compressed WRITE records are permitted */ boolean_t compress; + + /* show progress as process title(ie. -V) */ + boolean_t progressastitle; } sendflags_t; typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *); diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c index 9622778bdd0b..3b87c6910b2b 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c @@ -85,6 +85,8 @@ typedef struct progress_arg { zfs_handle_t *pa_zhp; int pa_fd; boolean_t pa_parsable; + boolean_t pa_astitle; + uint64_t pa_size; } progress_arg_t; typedef struct dataref { @@ -930,6 +932,7 @@ typedef struct send_dump_data { uint64_t prevsnap_obj; boolean_t seenfrom, seento, replicate, doall, fromorigin; boolean_t verbose, dryrun, parsable, progress, embed_data, std_out; + boolean_t progressastitle; boolean_t large_block, compress; int outfd; boolean_t err; @@ -1110,14 +1113,14 @@ send_progress_thread(void *arg) zfs_cmd_t zc = { 0 }; zfs_handle_t *zhp = pa->pa_zhp; libzfs_handle_t *hdl = zhp->zfs_hdl; - unsigned long long bytes; + unsigned long long bytes, total; char buf[16]; time_t t; struct tm *tm; (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"); /* @@ -1134,7 +1137,16 @@ send_progress_thread(void *arg) tm = localtime(&t); 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", tm->tm_hour, tm->tm_min, tm->tm_sec, bytes, zhp->zfs_name); @@ -1204,6 +1216,7 @@ dump_snapshot(zfs_handle_t *zhp, void *arg) boolean_t isfromsnap, istosnap, fromorigin; boolean_t exclude = B_FALSE; FILE *fout = sdd->std_out ? stdout : stderr; + uint64_t size = 0; err = 0; thissnap = strchr(zhp->zfs_name, '@') + 1; @@ -1278,15 +1291,16 @@ dump_snapshot(zfs_handle_t *zhp, void *arg) fromorigin = sdd->prevsnap[0] == '\0' && (sdd->fromorigin || sdd->replicate); - if (sdd->verbose) { - uint64_t size = 0; + if (sdd->progress && sdd->dryrun) { (void) estimate_ioctl(zhp, sdd->prevsnap_obj, fromorigin, flags, &size); + sdd->size += size; + } + if (sdd->verbose) { send_print_verbose(fout, zhp->zfs_name, sdd->prevsnap[0] ? sdd->prevsnap : NULL, size, sdd->parsable); - sdd->size += size; } if (!sdd->dryrun) { @@ -1298,6 +1312,8 @@ dump_snapshot(zfs_handle_t *zhp, void *arg) pa.pa_zhp = zhp; pa.pa_fd = sdd->outfd; pa.pa_parsable = sdd->parsable; + pa.pa_size = sdd->size; + pa.pa_astitle = sdd->progressastitle; if ((err = pthread_create(&tid, NULL, send_progress_thread, &pa)) != 0) { @@ -1580,6 +1596,7 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd, int error = 0; char name[ZFS_MAX_DATASET_NAME_LEN]; enum lzc_send_flags lzc_flags = 0; + uint64_t size = 0; FILE *fout = (flags->verbose && flags->dryrun) ? stdout : stderr; (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; } - if (flags->verbose) { - uint64_t size = 0; + if (flags->progress) { error = lzc_send_space(zhp->zfs_name, fromname, lzc_flags, &size); if (error == 0) size = MAX(0, (int64_t)(size - bytes)); + } + if (flags->verbose) { send_print_verbose(fout, zhp->zfs_name, fromname, 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_fd = outfd; pa.pa_parsable = flags->parsable; + pa.pa_size = size; + pa.pa_astitle = flags->progressastitle; error = pthread_create(&tid, NULL, 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.parsable = flags->parsable; sdd.progress = flags->progress; + sdd.progressastitle = flags->progressastitle; sdd.dryrun = flags->dryrun; sdd.large_block = flags->largeblock; 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.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 * or to gather snapshot hold's before generating any data,