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/@ed1conf@bsd.network/110731819189629373 Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Jorgen Lundman <lundman@lundman.net> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz> Closes #15113
This commit is contained in:
parent
36261c8238
commit
683edb32b7
|
@ -57,7 +57,7 @@ libzfs_la_LIBADD = \
|
|||
libzutil.la \
|
||||
libuutil.la
|
||||
|
||||
libzfs_la_LIBADD += -lm $(LIBCRYPTO_LIBS) $(ZLIB_LIBS) $(LIBFETCH_LIBS) $(LTLIBINTL)
|
||||
libzfs_la_LIBADD += -lrt -lm $(LIBCRYPTO_LIBS) $(ZLIB_LIBS) $(LIBFETCH_LIBS) $(LTLIBINTL)
|
||||
|
||||
libzfs_la_LDFLAGS = -pthread
|
||||
|
||||
|
|
|
@ -928,6 +928,39 @@ zfs_send_progress(zfs_handle_t *zhp, int fd, uint64_t *bytes_written,
|
|||
return (0);
|
||||
}
|
||||
|
||||
static volatile boolean_t send_progress_thread_signal_duetotimer;
|
||||
static void
|
||||
send_progress_thread_act(int sig, siginfo_t *info, void *ucontext)
|
||||
{
|
||||
(void) sig, (void) ucontext;
|
||||
send_progress_thread_signal_duetotimer = info->si_code == SI_TIMER;
|
||||
}
|
||||
|
||||
struct timer_desirability {
|
||||
timer_t timer;
|
||||
boolean_t desired;
|
||||
};
|
||||
static void
|
||||
timer_delete_cleanup(void *timer)
|
||||
{
|
||||
struct timer_desirability *td = timer;
|
||||
if (td->desired)
|
||||
timer_delete(td->timer);
|
||||
}
|
||||
|
||||
#ifdef SIGINFO
|
||||
#define SEND_PROGRESS_THREAD_PARENT_BLOCK_SIGINFO sigaddset(&new, SIGINFO)
|
||||
#else
|
||||
#define SEND_PROGRESS_THREAD_PARENT_BLOCK_SIGINFO
|
||||
#endif
|
||||
#define SEND_PROGRESS_THREAD_PARENT_BLOCK(old) { \
|
||||
sigset_t new; \
|
||||
sigemptyset(&new); \
|
||||
sigaddset(&new, SIGUSR1); \
|
||||
SEND_PROGRESS_THREAD_PARENT_BLOCK_SIGINFO; \
|
||||
pthread_sigmask(SIG_BLOCK, &new, old); \
|
||||
}
|
||||
|
||||
static void *
|
||||
send_progress_thread(void *arg)
|
||||
{
|
||||
|
@ -941,6 +974,26 @@ send_progress_thread(void *arg)
|
|||
struct tm tm;
|
||||
int err;
|
||||
|
||||
const struct sigaction signal_action =
|
||||
{.sa_sigaction = send_progress_thread_act, .sa_flags = SA_SIGINFO};
|
||||
struct sigevent timer_cfg =
|
||||
{.sigev_notify = SIGEV_SIGNAL, .sigev_signo = SIGUSR1};
|
||||
const struct itimerspec timer_time =
|
||||
{.it_value = {.tv_sec = 1}, .it_interval = {.tv_sec = 1}};
|
||||
struct timer_desirability timer = {};
|
||||
|
||||
sigaction(SIGUSR1, &signal_action, NULL);
|
||||
#ifdef SIGINFO
|
||||
sigaction(SIGINFO, &signal_action, NULL);
|
||||
#endif
|
||||
|
||||
if ((timer.desired = pa->pa_progress || pa->pa_astitle)) {
|
||||
if (timer_create(CLOCK_MONOTONIC, &timer_cfg, &timer.timer))
|
||||
return ((void *)(uintptr_t)errno);
|
||||
(void) timer_settime(timer.timer, 0, &timer_time, NULL);
|
||||
}
|
||||
pthread_cleanup_push(timer_delete_cleanup, &timer);
|
||||
|
||||
if (!pa->pa_parsable && pa->pa_progress) {
|
||||
(void) fprintf(stderr,
|
||||
"TIME %s %sSNAPSHOT %s\n",
|
||||
|
@ -953,12 +1006,12 @@ send_progress_thread(void *arg)
|
|||
* Print the progress from ZFS_IOC_SEND_PROGRESS every second.
|
||||
*/
|
||||
for (;;) {
|
||||
(void) sleep(1);
|
||||
pause();
|
||||
if ((err = zfs_send_progress(zhp, pa->pa_fd, &bytes,
|
||||
&blocks)) != 0) {
|
||||
if (err == EINTR || err == ENOENT)
|
||||
return ((void *)0);
|
||||
return ((void *)(uintptr_t)err);
|
||||
err = 0;
|
||||
pthread_exit(((void *)(uintptr_t)err));
|
||||
}
|
||||
|
||||
(void) time(&t);
|
||||
|
@ -991,21 +1044,25 @@ send_progress_thread(void *arg)
|
|||
(void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n",
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||
(u_longlong_t)bytes, zhp->zfs_name);
|
||||
} else if (pa->pa_progress) {
|
||||
} else if (pa->pa_progress ||
|
||||
!send_progress_thread_signal_duetotimer) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
pthread_cleanup_pop(B_TRUE);
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
send_progress_thread_exit(libzfs_handle_t *hdl, pthread_t ptid)
|
||||
send_progress_thread_exit(
|
||||
libzfs_handle_t *hdl, pthread_t ptid, sigset_t *oldmask)
|
||||
{
|
||||
void *status = NULL;
|
||||
(void) pthread_cancel(ptid);
|
||||
(void) pthread_join(ptid, &status);
|
||||
pthread_sigmask(SIG_SETMASK, oldmask, NULL);
|
||||
int error = (int)(uintptr_t)status;
|
||||
if (error != 0 && status != PTHREAD_CANCELED)
|
||||
return (zfs_standard_error(hdl, error,
|
||||
|
@ -1199,7 +1256,8 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
|
|||
* If progress reporting is requested, spawn a new thread to
|
||||
* poll ZFS_IOC_SEND_PROGRESS at a regular interval.
|
||||
*/
|
||||
if (sdd->progress || sdd->progressastitle) {
|
||||
sigset_t oldmask;
|
||||
{
|
||||
pa.pa_zhp = zhp;
|
||||
pa.pa_fd = sdd->outfd;
|
||||
pa.pa_parsable = sdd->parsable;
|
||||
|
@ -1214,13 +1272,13 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
|
|||
zfs_close(zhp);
|
||||
return (err);
|
||||
}
|
||||
SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);
|
||||
}
|
||||
|
||||
err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
|
||||
fromorigin, sdd->outfd, flags, sdd->debugnv);
|
||||
|
||||
if ((sdd->progress || sdd->progressastitle) &&
|
||||
send_progress_thread_exit(zhp->zfs_hdl, tid))
|
||||
if (send_progress_thread_exit(zhp->zfs_hdl, tid, &oldmask))
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
@ -1562,8 +1620,9 @@ estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
|
|||
progress_arg_t pa = { 0 };
|
||||
int err = 0;
|
||||
pthread_t ptid;
|
||||
sigset_t oldmask;
|
||||
|
||||
if (flags->progress || flags->progressastitle) {
|
||||
{
|
||||
pa.pa_zhp = zhp;
|
||||
pa.pa_fd = fd;
|
||||
pa.pa_parsable = flags->parsable;
|
||||
|
@ -1577,6 +1636,7 @@ estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
|
|||
return (zfs_error(zhp->zfs_hdl,
|
||||
EZFS_THREADCREATEFAILED, errbuf));
|
||||
}
|
||||
SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);
|
||||
}
|
||||
|
||||
err = lzc_send_space_resume_redacted(zhp->zfs_name, from,
|
||||
|
@ -1584,8 +1644,7 @@ estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
|
|||
redactbook, fd, &size);
|
||||
*sizep = size;
|
||||
|
||||
if ((flags->progress || flags->progressastitle) &&
|
||||
send_progress_thread_exit(zhp->zfs_hdl, ptid))
|
||||
if (send_progress_thread_exit(zhp->zfs_hdl, ptid, &oldmask))
|
||||
return (-1);
|
||||
|
||||
if (!flags->progress && !flags->parsable)
|
||||
|
@ -1876,11 +1935,12 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,
|
|||
if (!flags->dryrun) {
|
||||
progress_arg_t pa = { 0 };
|
||||
pthread_t tid;
|
||||
sigset_t oldmask;
|
||||
/*
|
||||
* If progress reporting is requested, spawn a new thread to
|
||||
* poll ZFS_IOC_SEND_PROGRESS at a regular interval.
|
||||
*/
|
||||
if (flags->progress || flags->progressastitle) {
|
||||
{
|
||||
pa.pa_zhp = zhp;
|
||||
pa.pa_fd = outfd;
|
||||
pa.pa_parsable = flags->parsable;
|
||||
|
@ -1898,6 +1958,7 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,
|
|||
zfs_close(zhp);
|
||||
return (error);
|
||||
}
|
||||
SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);
|
||||
}
|
||||
|
||||
error = lzc_send_resume_redacted(zhp->zfs_name, fromname, outfd,
|
||||
|
@ -1905,8 +1966,7 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags,
|
|||
if (redact_book != NULL)
|
||||
free(redact_book);
|
||||
|
||||
if ((flags->progressastitle || flags->progress) &&
|
||||
send_progress_thread_exit(hdl, tid)) {
|
||||
if (send_progress_thread_exit(hdl, tid, &oldmask)) {
|
||||
zfs_close(zhp);
|
||||
return (-1);
|
||||
}
|
||||
|
@ -2691,7 +2751,8 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
|
|||
* If progress reporting is requested, spawn a new thread to poll
|
||||
* ZFS_IOC_SEND_PROGRESS at a regular interval.
|
||||
*/
|
||||
if (flags->progress || flags->progressastitle) {
|
||||
sigset_t oldmask;
|
||||
{
|
||||
pa.pa_zhp = zhp;
|
||||
pa.pa_fd = fd;
|
||||
pa.pa_parsable = flags->parsable;
|
||||
|
@ -2708,13 +2769,13 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
|
|||
return (zfs_error(zhp->zfs_hdl,
|
||||
EZFS_THREADCREATEFAILED, errbuf));
|
||||
}
|
||||
SEND_PROGRESS_THREAD_PARENT_BLOCK(&oldmask);
|
||||
}
|
||||
|
||||
err = lzc_send_redacted(name, from, fd,
|
||||
lzc_flags_from_sendflags(flags), redactbook);
|
||||
|
||||
if ((flags->progress || flags->progressastitle) &&
|
||||
send_progress_thread_exit(hdl, ptid))
|
||||
if (send_progress_thread_exit(hdl, ptid, &oldmask))
|
||||
return (-1);
|
||||
|
||||
if (err == 0 && (flags->props || flags->holds || flags->backup)) {
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
.\" Copyright 2018 Nexenta Systems, Inc.
|
||||
.\" Copyright 2019 Joyent, Inc.
|
||||
.\"
|
||||
.Dd January 12, 2023
|
||||
.Dd July 27, 2023
|
||||
.Dt ZFS-SEND 8
|
||||
.Os
|
||||
.
|
||||
|
@ -297,6 +297,12 @@ This flag can only be used in conjunction with
|
|||
.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.
|
||||
The same report can be requested by sending
|
||||
.Dv SIGINFO
|
||||
or
|
||||
.Dv SIGUSR1 ,
|
||||
regardless of
|
||||
.Fl v .
|
||||
.Pp
|
||||
The format of the stream is committed.
|
||||
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
|
|||
.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.
|
||||
The same report can be requested by sending
|
||||
.Dv SIGINFO
|
||||
or
|
||||
.Dv SIGUSR1 ,
|
||||
regardless of
|
||||
.Fl v .
|
||||
.El
|
||||
.It Xo
|
||||
.Nm zfs
|
||||
|
@ -669,6 +681,10 @@ ones on the source, and are ready to be used, while the parent snapshot on the
|
|||
target contains none of the username and password data present on the source,
|
||||
because it was removed by the redacted send operation.
|
||||
.
|
||||
.Sh SIGNALS
|
||||
See
|
||||
.Fl v .
|
||||
.
|
||||
.Sh EXAMPLES
|
||||
.\" These are, respectively, examples 12, 13 from zfs.8
|
||||
.\" Make sure to update them bidirectionally
|
||||
|
|
Loading…
Reference in New Issue