Skip to content

Commit

Permalink
Make it possible for 'zfs send' to report progress via process title.
Browse files Browse the repository at this point in the history
This is result of my project idea at the OpenZFS developer summit's
hackathon session on November 19th, 2013 at San Francisco.

Ticket: openzfs#3462
(cherry picked from commit 13cc5237d6dbed102722cf4d3655783ee7e32fa5)
  • Loading branch information
delphij authored and kithrup committed Mar 3, 2019
1 parent 762f9ef commit 0297015
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 12 deletions.
6 changes: 5 additions & 1 deletion cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3986,7 +3986,7 @@ zfs_do_send(int argc, char **argv)
};

/* check options */
while ((c = getopt_long(argc, argv, ":i:I:RDpvnPLeht:cwb", long_options,
while ((c = getopt_long(argc, argv, ":i:I:RDpVvnPLeht:cwb", long_options,
NULL)) != -1) {
switch (c) {
case 'i':
Expand Down Expand Up @@ -4016,6 +4016,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;
Expand Down
3 changes: 3 additions & 0 deletions include/libzfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,9 @@ typedef struct sendflags {

/* include snapshot holds in send stream */
boolean_t holds;

/* show progress as process title(ie. -V) */
boolean_t progressastitle;
} sendflags_t;

typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
Expand Down
44 changes: 33 additions & 11 deletions lib/libzfs/libzfs_sendrecv.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,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 {
Expand Down Expand Up @@ -1034,6 +1036,7 @@ typedef struct send_dump_data {
boolean_t seenfrom, seento, replicate, doall, fromorigin;
boolean_t verbose, dryrun, parsable, progress, embed_data, std_out;
boolean_t large_block, compress, raw, holds;
boolean_t progressastitle;
int outfd;
boolean_t err;
nvlist_t *fss;
Expand Down Expand Up @@ -1209,16 +1212,20 @@ 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;
int pct;
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");

if (pa->pa_astitle)
total = pa->pa_size / 100;

/*
* Print the progress from ZFS_IOC_SEND_PROGRESS every second.
*/
Expand All @@ -1233,15 +1240,27 @@ send_progress_thread(void *arg)
tm = localtime(&t);
bytes = zc.zc_cookie;

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);
if (pa->pa_astitle) {
if (total > 0) {
pct = bytes / total;
} else
pct = 100;
if (pct > 100)
pct = 100;

setproctitle("sending %s (%d%%: %llu/%llu)",
zhp->zfs_name, pct, bytes, pa->pa_size);
} else {
zfs_nicebytes(bytes, buf, sizeof (buf));
(void) fprintf(stderr, "%02d:%02d:%02d %5s %s\n",
tm->tm_hour, tm->tm_min, tm->tm_sec,
buf, zhp->zfs_name);
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);
} else {
zfs_nicenum(bytes, buf, sizeof (buf));
(void) fprintf(stderr, "%02d:%02d:%02d %5s %s\n",
tm->tm_hour, tm->tm_min, tm->tm_sec,
buf, zhp->zfs_name);
}
}
}
}
Expand Down Expand Up @@ -1407,6 +1426,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) {
Expand Down Expand Up @@ -2014,6 +2035,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;
Expand Down Expand Up @@ -2053,7 +2075,7 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
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,
Expand Down

0 comments on commit 0297015

Please sign in to comment.