Skip to content

Commit 19d3961

Browse files
ixhamzaRyan Moeller
andauthored
Use setproctitle to report progress of zfs send
This allows parsing of zfs send progress by checking the process title. Doing so requires some changes to the send code in libzfs_sendrecv.c; primarily these changes move some of the accounting around, to allow for the code to be verbose as normal, or set the process title. Unlike BSD, setproctitle() isn't standard in Linux; thus, borrowed it from libbsd with slight modifications. Authored-by: Sean Eric Fagan <[email protected]> Co-authored-by: Ryan Moeller <[email protected]> Co-authored-by: Ameer Hamza <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Ryan Moeller <[email protected]> Signed-off-by: Ameer Hamza <[email protected]> Closes openzfs#14376
1 parent 2e7f664 commit 19d3961

File tree

9 files changed

+413
-48
lines changed

9 files changed

+413
-48
lines changed

cmd/zfs/zfs_main.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -327,15 +327,15 @@ get_usage(zfs_help_t idx)
327327
case HELP_ROLLBACK:
328328
return (gettext("\trollback [-rRf] <snapshot>\n"));
329329
case HELP_SEND:
330-
return (gettext("\tsend [-DLPbcehnpsvw] "
330+
return (gettext("\tsend [-DLPbcehnpsVvw] "
331331
"[-i|-I snapshot]\n"
332332
"\t [-R [-X dataset[,dataset]...]] <snapshot>\n"
333-
"\tsend [-DnvPLecw] [-i snapshot|bookmark] "
333+
"\tsend [-DnVvPLecw] [-i snapshot|bookmark] "
334334
"<filesystem|volume|snapshot>\n"
335-
"\tsend [-DnPpvLec] [-i bookmark|snapshot] "
335+
"\tsend [-DnPpVvLec] [-i bookmark|snapshot] "
336336
"--redact <bookmark> <snapshot>\n"
337-
"\tsend [-nvPe] -t <receive_resume_token>\n"
338-
"\tsend [-Pnv] --saved filesystem\n"));
337+
"\tsend [-nVvPe] -t <receive_resume_token>\n"
338+
"\tsend [-PnVv] --saved filesystem\n"));
339339
case HELP_SET:
340340
return (gettext("\tset <property=value> ... "
341341
"<filesystem|volume|snapshot> ...\n"));
@@ -4388,6 +4388,7 @@ zfs_do_send(int argc, char **argv)
43884388
{"props", no_argument, NULL, 'p'},
43894389
{"parsable", no_argument, NULL, 'P'},
43904390
{"dedup", no_argument, NULL, 'D'},
4391+
{"proctitle", no_argument, NULL, 'V'},
43914392
{"verbose", no_argument, NULL, 'v'},
43924393
{"dryrun", no_argument, NULL, 'n'},
43934394
{"large-block", no_argument, NULL, 'L'},
@@ -4403,7 +4404,7 @@ zfs_do_send(int argc, char **argv)
44034404
};
44044405

44054406
/* check options */
4406-
while ((c = getopt_long(argc, argv, ":i:I:RsDpvnPLeht:cwbd:SX:",
4407+
while ((c = getopt_long(argc, argv, ":i:I:RsDpVvnPLeht:cwbd:SX:",
44074408
long_options, NULL)) != -1) {
44084409
switch (c) {
44094410
case 'X':
@@ -4452,6 +4453,9 @@ zfs_do_send(int argc, char **argv)
44524453
case 'P':
44534454
flags.parsable = B_TRUE;
44544455
break;
4456+
case 'V':
4457+
flags.progressastitle = B_TRUE;
4458+
break;
44554459
case 'v':
44564460
flags.verbosity++;
44574461
flags.progress = B_TRUE;
@@ -8668,6 +8672,7 @@ main(int argc, char **argv)
86688672
int i = 0;
86698673
const char *cmdname;
86708674
char **newargv;
8675+
extern char **environ;
86718676

86728677
(void) setlocale(LC_ALL, "");
86738678
(void) setlocale(LC_NUMERIC, "C");
@@ -8725,6 +8730,8 @@ main(int argc, char **argv)
87258730

87268731
libzfs_print_on_error(g_zfs, B_TRUE);
87278732

8733+
zfs_setproctitle_init(argc, argv, environ);
8734+
87288735
/*
87298736
* Many commands modify input strings for string parsing reasons.
87308737
* We create a copy to protect the original argv.

include/libzfs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,9 @@ typedef struct sendflags {
740740
/* show progress (ie. -v) */
741741
boolean_t progress;
742742

743+
/* show progress as process title (ie. -V) */
744+
boolean_t progressastitle;
745+
743746
/* large blocks (>128K) are permitted */
744747
boolean_t largeblock;
745748

include/libzutil.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,13 @@ _LIBZUTIL_H int printf_color(const char *color, const char *format, ...);
182182

183183
_LIBZUTIL_H const char *zfs_basename(const char *path);
184184
_LIBZUTIL_H ssize_t zfs_dirnamelen(const char *path);
185+
#ifdef __linux__
186+
_LIBZUTIL_H void zfs_setproctitle_init(int argc, char *argv[], char *envp[]);
187+
_LIBZUTIL_H void zfs_setproctitle(const char *fmt, ...);
188+
#else
189+
#define zfs_setproctitle(fmt, ...) setproctitle(fmt, ##__VA_ARGS__)
190+
#define zfs_setproctitle_init(x, y, z) ((void)0)
191+
#endif
185192

186193
/*
187194
* These functions are used by the ZFS libraries and cmd/zpool code, but are

lib/libzfs/libzfs.abi

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,8 @@
416416
<elf-symbol name='zfs_send_resume_token_to_nvlist' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
417417
<elf-symbol name='zfs_send_saved' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
418418
<elf-symbol name='zfs_set_fsacl' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
419+
<elf-symbol name='zfs_setproctitle' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
420+
<elf-symbol name='zfs_setproctitle_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
419421
<elf-symbol name='zfs_share' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
420422
<elf-symbol name='zfs_show_diffs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
421423
<elf-symbol name='zfs_smb_acl_add' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -3834,6 +3836,11 @@
38343836
<pointer-type-def type-id='9e59d1d4' size-in-bits='64' id='4ea84b4f'/>
38353837
<pointer-type-def type-id='945467e6' size-in-bits='64' id='8def7735'/>
38363838
<pointer-type-def type-id='3d3ffb69' size-in-bits='64' id='72a26210'/>
3839+
<function-decl name='zfs_setproctitle' mangled-name='zfs_setproctitle' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_setproctitle'>
3840+
<parameter type-id='80f4b756'/>
3841+
<parameter is-variadic='yes'/>
3842+
<return type-id='48b5725f'/>
3843+
</function-decl>
38373844
<function-decl name='zfs_send_progress' mangled-name='zfs_send_progress' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_send_progress'>
38383845
<parameter type-id='9200a744' name='zhp'/>
38393846
<parameter type-id='95e97e5e' name='fd'/>
@@ -4525,6 +4532,12 @@
45254532
<parameter type-id='5ce45b60' name='nv'/>
45264533
<return type-id='48b5725f'/>
45274534
</function-decl>
4535+
<function-decl name='zfs_setproctitle_init' mangled-name='zfs_setproctitle_init' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_setproctitle_init'>
4536+
<parameter type-id='95e97e5e' name='argc'/>
4537+
<parameter type-id='9b23c9ad' name='argv'/>
4538+
<parameter type-id='9b23c9ad' name='envp'/>
4539+
<return type-id='48b5725f'/>
4540+
</function-decl>
45284541
</abi-instr>
45294542
<abi-instr address-size='64' path='lib/libzutil/zutil_device_path.c' language='LANG_C99'>
45304543
<typedef-decl name='ssize_t' type-id='41060289' id='79a0948f'/>

lib/libzfs/libzfs_sendrecv.c

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ typedef struct progress_arg {
8383
boolean_t pa_parsable;
8484
boolean_t pa_estimate;
8585
int pa_verbosity;
86+
boolean_t pa_astitle;
87+
uint64_t pa_size;
8688
} progress_arg_t;
8789

8890
static int
@@ -733,6 +735,7 @@ typedef struct send_dump_data {
733735
boolean_t seenfrom, seento, replicate, doall, fromorigin;
734736
boolean_t dryrun, parsable, progress, embed_data, std_out;
735737
boolean_t large_block, compress, raw, holds;
738+
boolean_t progressastitle;
736739
int outfd;
737740
boolean_t err;
738741
nvlist_t *fss;
@@ -931,12 +934,13 @@ send_progress_thread(void *arg)
931934
zfs_handle_t *zhp = pa->pa_zhp;
932935
uint64_t bytes;
933936
uint64_t blocks;
937+
uint64_t total = pa->pa_size / 100;
934938
char buf[16];
935939
time_t t;
936940
struct tm tm;
937941
int err;
938942

939-
if (!pa->pa_parsable) {
943+
if (!pa->pa_parsable && pa->pa_verbosity != 0) {
940944
(void) fprintf(stderr,
941945
"TIME %s %sSNAPSHOT %s\n",
942946
pa->pa_estimate ? "BYTES" : " SENT",
@@ -959,6 +963,17 @@ send_progress_thread(void *arg)
959963
(void) time(&t);
960964
localtime_r(&t, &tm);
961965

966+
if (pa->pa_astitle) {
967+
char buf_bytes[16];
968+
char buf_size[16];
969+
int pct;
970+
zfs_nicenum(bytes, buf_bytes, sizeof (buf_bytes));
971+
zfs_nicenum(pa->pa_size, buf_size, sizeof (buf_size));
972+
pct = (total > 0) ? bytes / total : 100;
973+
zfs_setproctitle("sending %s (%d%%: %s/%s)",
974+
zhp->zfs_name, MIN(pct, 100), buf_bytes, buf_size);
975+
}
976+
962977
if (pa->pa_verbosity >= 2 && pa->pa_parsable) {
963978
(void) fprintf(stderr,
964979
"%02d:%02d:%02d\t%llu\t%llu\t%s\n",
@@ -975,7 +990,7 @@ send_progress_thread(void *arg)
975990
(void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n",
976991
tm.tm_hour, tm.tm_min, tm.tm_sec,
977992
(u_longlong_t)bytes, zhp->zfs_name);
978-
} else {
993+
} else if (pa->pa_verbosity != 0) {
979994
zfs_nicebytes(bytes, buf, sizeof (buf));
980995
(void) fprintf(stderr, "%02d:%02d:%02d %5s %s\n",
981996
tm.tm_hour, tm.tm_min, tm.tm_sec,
@@ -1183,12 +1198,14 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
11831198
* If progress reporting is requested, spawn a new thread to
11841199
* poll ZFS_IOC_SEND_PROGRESS at a regular interval.
11851200
*/
1186-
if (sdd->progress) {
1201+
if (sdd->progress || sdd->progressastitle) {
11871202
pa.pa_zhp = zhp;
11881203
pa.pa_fd = sdd->outfd;
11891204
pa.pa_parsable = sdd->parsable;
11901205
pa.pa_estimate = B_FALSE;
11911206
pa.pa_verbosity = sdd->verbosity;
1207+
pa.pa_size = sdd->size;
1208+
pa.pa_astitle = sdd->progressastitle;
11921209

11931210
if ((err = pthread_create(&tid, NULL,
11941211
send_progress_thread, &pa)) != 0) {
@@ -1200,7 +1217,7 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
12001217
err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
12011218
fromorigin, sdd->outfd, flags, sdd->debugnv);
12021219

1203-
if (sdd->progress &&
1220+
if ((sdd->progress || sdd->progressastitle) &&
12041221
send_progress_thread_exit(zhp->zfs_hdl, tid))
12051222
return (-1);
12061223
}
@@ -1536,15 +1553,15 @@ lzc_flags_from_sendflags(const sendflags_t *flags)
15361553
static int
15371554
estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
15381555
uint64_t resumeobj, uint64_t resumeoff, uint64_t bytes,
1539-
const char *redactbook, char *errbuf)
1556+
const char *redactbook, char *errbuf, uint64_t *sizep)
15401557
{
15411558
uint64_t size;
15421559
FILE *fout = flags->dryrun ? stdout : stderr;
15431560
progress_arg_t pa = { 0 };
15441561
int err = 0;
15451562
pthread_t ptid;
15461563

1547-
if (flags->progress) {
1564+
if (flags->progress || flags->progressastitle) {
15481565
pa.pa_zhp = zhp;
15491566
pa.pa_fd = fd;
15501567
pa.pa_parsable = flags->parsable;
@@ -1563,10 +1580,15 @@ estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
15631580
err = lzc_send_space_resume_redacted(zhp->zfs_name, from,
15641581
lzc_flags_from_sendflags(flags), resumeobj, resumeoff, bytes,
15651582
redactbook, fd, &size);
1583+
*sizep = size;
15661584

1567-
if (flags->progress && send_progress_thread_exit(zhp->zfs_hdl, ptid))
1585+
if ((flags->progress || flags->progressastitle) &&
1586+
send_progress_thread_exit(zhp->zfs_hdl, ptid))
15681587
return (-1);
15691588

1589+
if (!flags->progress && !flags->parsable)
1590+
return (err);
1591+
15701592
if (err != 0) {
15711593
zfs_error_aux(zhp->zfs_hdl, "%s", strerror(err));
15721594
return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,
@@ -1743,6 +1765,7 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,
17431765
uint64_t *redact_snap_guids = NULL;
17441766
int num_redact_snaps = 0;
17451767
char *redact_book = NULL;
1768+
uint64_t size = 0;
17461769

17471770
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
17481771
"cannot resume send"));
@@ -1828,7 +1851,7 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,
18281851
enum lzc_send_flags lzc_flags = lzc_flags_from_sendflags(flags) |
18291852
lzc_flags_from_resume_nvl(resume_nvl);
18301853

1831-
if (flags->verbosity != 0) {
1854+
if (flags->verbosity != 0 || flags->progressastitle) {
18321855
/*
18331856
* Some of these may have come from the resume token, set them
18341857
* here for size estimate purposes.
@@ -1845,7 +1868,7 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,
18451868
if (lzc_flags & LZC_SEND_FLAG_SAVED)
18461869
tmpflags.saved = B_TRUE;
18471870
error = estimate_size(zhp, fromname, outfd, &tmpflags,
1848-
resumeobj, resumeoff, bytes, redact_book, errbuf);
1871+
resumeobj, resumeoff, bytes, redact_book, errbuf, &size);
18491872
}
18501873

18511874
if (!flags->dryrun) {
@@ -1855,12 +1878,14 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,
18551878
* If progress reporting is requested, spawn a new thread to
18561879
* poll ZFS_IOC_SEND_PROGRESS at a regular interval.
18571880
*/
1858-
if (flags->progress) {
1881+
if (flags->progress || flags->progressastitle) {
18591882
pa.pa_zhp = zhp;
18601883
pa.pa_fd = outfd;
18611884
pa.pa_parsable = flags->parsable;
18621885
pa.pa_estimate = B_FALSE;
18631886
pa.pa_verbosity = flags->verbosity;
1887+
pa.pa_size = size;
1888+
pa.pa_astitle = flags->progressastitle;
18641889

18651890
error = pthread_create(&tid, NULL,
18661891
send_progress_thread, &pa);
@@ -1877,8 +1902,11 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,
18771902
if (redact_book != NULL)
18781903
free(redact_book);
18791904

1880-
if (flags->progress && send_progress_thread_exit(hdl, tid))
1905+
if ((flags->progressastitle || flags->progress) &&
1906+
send_progress_thread_exit(hdl, tid)) {
1907+
zfs_close(zhp);
18811908
return (-1);
1909+
}
18821910

18831911
char errbuf[ERRBUFLEN];
18841912
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
@@ -2313,6 +2341,7 @@ zfs_send_cb_impl(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
23132341
sdd.verbosity = flags->verbosity;
23142342
sdd.parsable = flags->parsable;
23152343
sdd.progress = flags->progress;
2344+
sdd.progressastitle = flags->progressastitle;
23162345
sdd.dryrun = flags->dryrun;
23172346
sdd.large_block = flags->largeblock;
23182347
sdd.embed_data = flags->embed_data;
@@ -2562,6 +2591,7 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
25622591
char *name = zhp->zfs_name;
25632592
pthread_t ptid;
25642593
progress_arg_t pa = { 0 };
2594+
uint64_t size = 0;
25652595

25662596
char errbuf[ERRBUFLEN];
25672597
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
@@ -2644,9 +2674,9 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
26442674
/*
26452675
* Perform size estimate if verbose was specified.
26462676
*/
2647-
if (flags->verbosity != 0) {
2677+
if (flags->verbosity != 0 || flags->progressastitle) {
26482678
err = estimate_size(zhp, from, fd, flags, 0, 0, 0, redactbook,
2649-
errbuf);
2679+
errbuf, &size);
26502680
if (err != 0)
26512681
return (err);
26522682
}
@@ -2658,12 +2688,14 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
26582688
* If progress reporting is requested, spawn a new thread to poll
26592689
* ZFS_IOC_SEND_PROGRESS at a regular interval.
26602690
*/
2661-
if (flags->progress) {
2691+
if (flags->progress || flags->progressastitle) {
26622692
pa.pa_zhp = zhp;
26632693
pa.pa_fd = fd;
26642694
pa.pa_parsable = flags->parsable;
26652695
pa.pa_estimate = B_FALSE;
26662696
pa.pa_verbosity = flags->verbosity;
2697+
pa.pa_size = size;
2698+
pa.pa_astitle = flags->progressastitle;
26672699

26682700
err = pthread_create(&ptid, NULL,
26692701
send_progress_thread, &pa);
@@ -2677,7 +2709,8 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
26772709
err = lzc_send_redacted(name, from, fd,
26782710
lzc_flags_from_sendflags(flags), redactbook);
26792711

2680-
if (flags->progress && send_progress_thread_exit(hdl, ptid))
2712+
if ((flags->progress || flags->progressastitle) &&
2713+
send_progress_thread_exit(hdl, ptid))
26812714
return (-1);
26822715

26832716
if (err == 0 && (flags->props || flags->holds || flags->backup)) {

lib/libzutil/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ libzutil_la_SOURCES = \
1717

1818
if BUILD_LINUX
1919
libzutil_la_SOURCES += \
20+
%D%/os/linux/zutil_setproctitle.c \
2021
%D%/os/linux/zutil_device_path_os.c \
2122
%D%/os/linux/zutil_import_os.c
2223
endif

0 commit comments

Comments
 (0)