Skip to content

Commit c2995a8

Browse files
nabijaczlewelibehlendorf
authored andcommitted
libzfs: sendrecv: send_progress_thread: handle SIGINFO/SIGUSR1
POSIX timers target the process, not the thread (as does SIGINFO), so we need to block it in the main thread which will die if interrupted. Ref: https://101010.pl/@[email protected]/110731819189629373 Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Jorgen Lundman <[email protected]> Signed-off-by: Ahelenia Ziemiańska <[email protected]> Closes openzfs#15113
1 parent 39bf443 commit c2995a8

File tree

3 files changed

+96
-19
lines changed

3 files changed

+96
-19
lines changed

lib/libzfs/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ libzfs_la_LIBADD = \
5757
libzutil.la \
5858
libuutil.la
5959

60-
libzfs_la_LIBADD += -lm $(LIBCRYPTO_LIBS) $(ZLIB_LIBS) $(LIBFETCH_LIBS) $(LTLIBINTL)
60+
libzfs_la_LIBADD += -lrt -lm $(LIBCRYPTO_LIBS) $(ZLIB_LIBS) $(LIBFETCH_LIBS) $(LTLIBINTL)
6161

6262
libzfs_la_LDFLAGS = -pthread
6363

lib/libzfs/libzfs_sendrecv.c

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,39 @@ zfs_send_progress(zfs_handle_t *zhp, int fd, uint64_t *bytes_written,
928928
return (0);
929929
}
930930

931+
static volatile boolean_t send_progress_thread_signal_duetotimer;
932+
static void
933+
send_progress_thread_act(int sig, siginfo_t *info, void *ucontext)
934+
{
935+
(void) sig, (void) ucontext;
936+
send_progress_thread_signal_duetotimer = info->si_code == SI_TIMER;
937+
}
938+
939+
struct timer_desirability {
940+
timer_t timer;
941+
boolean_t desired;
942+
};
943+
static void
944+
timer_delete_cleanup(void *timer)
945+
{
946+
struct timer_desirability *td = timer;
947+
if (td->desired)
948+
timer_delete(td->timer);
949+
}
950+
951+
#ifdef SIGINFO
952+
#define SEND_PROGRESS_THREAD_PARENT_BLOCK_SIGINFO sigaddset(&new, SIGINFO)
953+
#else
954+
#define SEND_PROGRESS_THREAD_PARENT_BLOCK_SIGINFO
955+
#endif
956+
#define SEND_PROGRESS_THREAD_PARENT_BLOCK(old) { \
957+
sigset_t new; \
958+
sigemptyset(&new); \
959+
sigaddset(&new, SIGUSR1); \
960+
SEND_PROGRESS_THREAD_PARENT_BLOCK_SIGINFO; \
961+
pthread_sigmask(SIG_BLOCK, &new, old); \
962+
}
963+
931964
static void *
932965
send_progress_thread(void *arg)
933966
{
@@ -941,6 +974,26 @@ send_progress_thread(void *arg)
941974
struct tm tm;
942975
int err;
943976

977+
const struct sigaction signal_action =
978+
{.sa_sigaction = send_progress_thread_act, .sa_flags = SA_SIGINFO};
979+
struct sigevent timer_cfg =
980+
{.sigev_notify = SIGEV_SIGNAL, .sigev_signo = SIGUSR1};
981+
const struct itimerspec timer_time =
982+
{.it_value = {.tv_sec = 1}, .it_interval = {.tv_sec = 1}};
983+
struct timer_desirability timer = {};
984+
985+
sigaction(SIGUSR1, &signal_action, NULL);
986+
#ifdef SIGINFO
987+
sigaction(SIGINFO, &signal_action, NULL);
988+
#endif
989+
990+
if ((timer.desired = pa->pa_progress || pa->pa_astitle)) {
991+
if (timer_create(CLOCK_MONOTONIC, &timer_cfg, &timer.timer))
992+
return ((void *)(uintptr_t)errno);
993+
(void) timer_settime(timer.timer, 0, &timer_time, NULL);
994+
}
995+
pthread_cleanup_push(timer_delete_cleanup, &timer);
996+
944997
if (!pa->pa_parsable && pa->pa_progress) {
945998
(void) fprintf(stderr,
946999
"TIME %s %sSNAPSHOT %s\n",
@@ -953,12 +1006,12 @@ send_progress_thread(void *arg)
9531006
* Print the progress from ZFS_IOC_SEND_PROGRESS every second.
9541007
*/
9551008
for (;;) {
956-
(void) sleep(1);
1009+
pause();
9571010
if ((err = zfs_send_progress(zhp, pa->pa_fd, &bytes,
9581011
&blocks)) != 0) {
9591012
if (err == EINTR || err == ENOENT)
960-
return ((void *)0);
961-
return ((void *)(uintptr_t)err);
1013+
err = 0;
1014+
pthread_exit(((void *)(uintptr_t)err));
9621015
}
9631016

9641017
(void) time(&t);
@@ -991,21 +1044,25 @@ send_progress_thread(void *arg)
9911044
(void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n",
9921045
tm.tm_hour, tm.tm_min, tm.tm_sec,
9931046
(u_longlong_t)bytes, zhp->zfs_name);
994-
} else if (pa->pa_progress) {
1047+
} else if (pa->pa_progress ||
1048+
!send_progress_thread_signal_duetotimer) {
9951049
zfs_nicebytes(bytes, buf, sizeof (buf));
9961050
(void) fprintf(stderr, "%02d:%02d:%02d %5s %s\n",
9971051
tm.tm_hour, tm.tm_min, tm.tm_sec,
9981052
buf, zhp->zfs_name);
9991053
}
10001054
}
1055+
pthread_cleanup_pop(B_TRUE);
10011056
}
10021057

10031058
static boolean_t
1004-
send_progress_thread_exit(libzfs_handle_t *hdl, pthread_t ptid)
1059+
send_progress_thread_exit(
1060+
libzfs_handle_t *hdl, pthread_t ptid, sigset_t *oldmask)
10051061
{
10061062
void *status = NULL;
10071063
(void) pthread_cancel(ptid);
10081064
(void) pthread_join(ptid, &status);
1065+
pthread_sigmask(SIG_SETMASK, oldmask, NULL);
10091066
int error = (int)(uintptr_t)status;
10101067
if (error != 0 && status != PTHREAD_CANCELED)
10111068
return (zfs_standard_error(hdl, error,
@@ -1199,7 +1256,8 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
11991256
* If progress reporting is requested, spawn a new thread to
12001257
* poll ZFS_IOC_SEND_PROGRESS at a regular interval.
12011258
*/
1202-
if (sdd->progress || sdd->progressastitle) {
1259+
sigset_t oldmask;
1260+
{
12031261
pa.pa_zhp = zhp;
12041262
pa.pa_fd = sdd->outfd;
12051263
pa.pa_parsable = sdd->parsable;
@@ -1214,13 +1272,13 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
12141272
zfs_close(zhp);
12151273
return (err);
12161274
}
1275+
SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);
12171276
}
12181277

12191278
err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
12201279
fromorigin, sdd->outfd, flags, sdd->debugnv);
12211280

1222-
if ((sdd->progress || sdd->progressastitle) &&
1223-
send_progress_thread_exit(zhp->zfs_hdl, tid))
1281+
if (send_progress_thread_exit(zhp->zfs_hdl, tid, &oldmask))
12241282
return (-1);
12251283
}
12261284

@@ -1562,8 +1620,9 @@ estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
15621620
progress_arg_t pa = { 0 };
15631621
int err = 0;
15641622
pthread_t ptid;
1623+
sigset_t oldmask;
15651624

1566-
if (flags->progress || flags->progressastitle) {
1625+
{
15671626
pa.pa_zhp = zhp;
15681627
pa.pa_fd = fd;
15691628
pa.pa_parsable = flags->parsable;
@@ -1577,15 +1636,15 @@ estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
15771636
return (zfs_error(zhp->zfs_hdl,
15781637
EZFS_THREADCREATEFAILED, errbuf));
15791638
}
1639+
SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);
15801640
}
15811641

15821642
err = lzc_send_space_resume_redacted(zhp->zfs_name, from,
15831643
lzc_flags_from_sendflags(flags), resumeobj, resumeoff, bytes,
15841644
redactbook, fd, &size);
15851645
*sizep = size;
15861646

1587-
if ((flags->progress || flags->progressastitle) &&
1588-
send_progress_thread_exit(zhp->zfs_hdl, ptid))
1647+
if (send_progress_thread_exit(zhp->zfs_hdl, ptid, &oldmask))
15891648
return (-1);
15901649

15911650
if (!flags->progress && !flags->parsable)
@@ -1876,11 +1935,12 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,
18761935
if (!flags->dryrun) {
18771936
progress_arg_t pa = { 0 };
18781937
pthread_t tid;
1938+
sigset_t oldmask;
18791939
/*
18801940
* If progress reporting is requested, spawn a new thread to
18811941
* poll ZFS_IOC_SEND_PROGRESS at a regular interval.
18821942
*/
1883-
if (flags->progress || flags->progressastitle) {
1943+
{
18841944
pa.pa_zhp = zhp;
18851945
pa.pa_fd = outfd;
18861946
pa.pa_parsable = flags->parsable;
@@ -1898,15 +1958,15 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,
18981958
zfs_close(zhp);
18991959
return (error);
19001960
}
1961+
SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);
19011962
}
19021963

19031964
error = lzc_send_resume_redacted(zhp->zfs_name, fromname, outfd,
19041965
lzc_flags, resumeobj, resumeoff, redact_book);
19051966
if (redact_book != NULL)
19061967
free(redact_book);
19071968

1908-
if ((flags->progressastitle || flags->progress) &&
1909-
send_progress_thread_exit(hdl, tid)) {
1969+
if (send_progress_thread_exit(hdl, tid, &oldmask)) {
19101970
zfs_close(zhp);
19111971
return (-1);
19121972
}
@@ -2691,7 +2751,8 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
26912751
* If progress reporting is requested, spawn a new thread to poll
26922752
* ZFS_IOC_SEND_PROGRESS at a regular interval.
26932753
*/
2694-
if (flags->progress || flags->progressastitle) {
2754+
sigset_t oldmask;
2755+
{
26952756
pa.pa_zhp = zhp;
26962757
pa.pa_fd = fd;
26972758
pa.pa_parsable = flags->parsable;
@@ -2708,13 +2769,13 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
27082769
return (zfs_error(zhp->zfs_hdl,
27092770
EZFS_THREADCREATEFAILED, errbuf));
27102771
}
2772+
SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);
27112773
}
27122774

27132775
err = lzc_send_redacted(name, from, fd,
27142776
lzc_flags_from_sendflags(flags), redactbook);
27152777

2716-
if ((flags->progress || flags->progressastitle) &&
2717-
send_progress_thread_exit(hdl, ptid))
2778+
if (send_progress_thread_exit(hdl, ptid, &oldmask))
27182779
return (-1);
27192780

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

man/man8/zfs-send.8

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
.\" Copyright 2018 Nexenta Systems, Inc.
3030
.\" Copyright 2019 Joyent, Inc.
3131
.\"
32-
.Dd January 12, 2023
32+
.Dd July 27, 2023
3333
.Dt ZFS-SEND 8
3434
.Os
3535
.
@@ -297,6 +297,12 @@ This flag can only be used in conjunction with
297297
.It Fl v , -verbose
298298
Print verbose information about the stream package generated.
299299
This information includes a per-second report of how much data has been sent.
300+
The same report can be requested by sending
301+
.Dv SIGINFO
302+
or
303+
.Dv SIGUSR1 ,
304+
regardless of
305+
.Fl v .
300306
.Pp
301307
The format of the stream is committed.
302308
You will be able to receive your streams on future versions of ZFS.
@@ -433,6 +439,12 @@ and the verbose output goes to standard error
433439
.It Fl v , -verbose
434440
Print verbose information about the stream package generated.
435441
This information includes a per-second report of how much data has been sent.
442+
The same report can be requested by sending
443+
.Dv SIGINFO
444+
or
445+
.Dv SIGUSR1 ,
446+
regardless of
447+
.Fl v .
436448
.El
437449
.It Xo
438450
.Nm zfs
@@ -669,6 +681,10 @@ ones on the source, and are ready to be used, while the parent snapshot on the
669681
target contains none of the username and password data present on the source,
670682
because it was removed by the redacted send operation.
671683
.
684+
.Sh SIGNALS
685+
See
686+
.Fl v .
687+
.
672688
.Sh EXAMPLES
673689
.\" These are, respectively, examples 12, 13 from zfs.8
674690
.\" Make sure to update them bidirectionally

0 commit comments

Comments
 (0)