mirror of
				https://git.proxmox.com/git/mirror_zfs.git
				synced 2025-10-26 18:05:04 +03:00 
			
		
		
		
	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
	
	Block a user
	 наб
						наб