public inbox for linux-erofs@ozlabs.org
 help / color / mirror / Atom feed
From: Gao Xiang <hsiangkao@linux.alibaba.com>
To: Yifan Zhao <zhaoyifan28@huawei.com>, linux-erofs@lists.ozlabs.org
Cc: jingrui@huawei.com, zhukeqian1@huawei.com
Subject: Re: [PATCH 1/2] erofs-utils: mount: gracefully handle long-lived backend workers
Date: Thu, 9 Apr 2026 12:19:09 +0800	[thread overview]
Message-ID: <48e31164-920a-40d1-b509-be5cfb1591cc@linux.alibaba.com> (raw)
In-Reply-To: <20260403064230.914563-1-zhaoyifan28@huawei.com>

Hi Yifan,

On 2026/4/3 14:42, Yifan Zhao wrote:
> Currently long-lived backend workers were created with a bare fork() and
> kept running with the caller's process context. They still inherited
> CLI-oriented session and stdio, making the background worker fragile.
> 
> Refine the worker setup used by the NBD and fanotify mount paths so
> forked children behave like well-formed long-lived background processes.
> 
> Assisted-by: Codex:GPT-5.4
> Signed-off-by: Yifan Zhao <zhaoyifan28@huawei.com>
> ---
>   mount/main.c | 208 ++++++++++++++++++++++++++++++++++++++-------------
>   1 file changed, 156 insertions(+), 52 deletions(-)
> 
> diff --git a/mount/main.c b/mount/main.c
> index e09e585..45ac32e 100644
> --- a/mount/main.c
> +++ b/mount/main.c
> @@ -98,6 +98,75 @@ static struct erofsmount_source {
>   	};
>   } mountsrc;
>   
> +static int erofsmount_spawn_worker(pid_t *pid)
> +{
> +	*pid = fork();
> +	if (*pid < 0)
> +		return -errno;
> +	return *pid;
> +}

I think this helper is not useful, let's just open-coded it.

> +
> +static int erofsmount_worker_set_signal(int signum, sighandler_t handler)
> +{
> +	struct sigaction act = {
> +		.sa_handler = handler,
> +	};
> +
> +	if (sigemptyset(&act.sa_mask) < 0)
> +		return -errno;
> +	if (sigaction(signum, &act, NULL) < 0)
> +		return -errno;
> +	return 0;
> +}
> +
> +static int erofsmount_worker_detach(void)
> +{
> +	sigset_t mask;
> +	int fd, err;
> +
> +	if (setsid() < 0)
> +		return -errno;
> +
> +	if (sigemptyset(&mask) < 0)
> +		return -errno;
> +	if (sigprocmask(SIG_SETMASK, &mask, NULL) < 0)
> +		return -errno;
> +
> +	err = erofsmount_worker_set_signal(SIGHUP, SIG_DFL);
> +	if (err)
> +		return err;
> +	err = erofsmount_worker_set_signal(SIGINT, SIG_DFL);
> +	if (err)
> +		return err;
> +	err = erofsmount_worker_set_signal(SIGQUIT, SIG_DFL);
> +	if (err)
> +		return err;
> +	err = erofsmount_worker_set_signal(SIGTERM, SIG_DFL);
> +	if (err)
> +		return err;
> +	err = erofsmount_worker_set_signal(SIGPIPE, SIG_IGN);
> +	if (err)
> +		return err;
> +
> +	fd = open("/dev/null", O_RDWR);
> +	if (fd < 0)
> +		return -errno;
> +	if (dup2(fd, STDIN_FILENO) < 0 || dup2(fd, STDOUT_FILENO) < 0 ||
> +	    dup2(fd, STDERR_FILENO) < 0) {
> +		err = -errno;
> +		close(fd);
> +		return err;
> +	}
> +	if (fd > STDERR_FILENO)
> +		close(fd);
> +	return 0;
> +}
> +
> +static void erofsmount_worker_exit(int err)
> +{
> +	_exit(err ? EXIT_FAILURE : EXIT_SUCCESS);
> +}
> +
>   static void usage(int argc, char **argv)
>   {
>   	printf("Usage: %s [OPTIONS] SOURCE [MOUNTPOINT]\n"
> @@ -720,6 +789,13 @@ static int erofsmount_startnbd(int nbdfd, struct erofsmount_source *source)
>   	}
>   	ctx.sk.fd = err;
>   
> +	err = erofsmount_worker_detach();
> +	if (err) {
> +		erofs_io_close(&ctx.vd);
> +		erofs_io_close(&ctx.sk);
> +		goto out_closefd;
> +	}
> +
>   	err = -pthread_create(&th, NULL, erofsmount_nbd_loopfn, &ctx);
>   	if (err) {
>   		erofs_io_close(&ctx.vd);
> @@ -1050,67 +1126,79 @@ static int erofsmount_nbd_fix_backend_linkage(int num, char **recp)
>   static int erofsmount_startnbd_nl(pid_t *pid, struct erofsmount_source *source)
>   {
>   	int pipefd[2], err, num;
> +	pid_t ret;
>   
>   	err = pipe(pipefd);
>   	if (err < 0)
>   		return -errno;
>   
> -	if ((*pid = fork()) == 0) {
> +	ret = erofsmount_spawn_worker(pid);
> +	if (ret < 0) {
> +		close(pipefd[0]);
> +		close(pipefd[1]);
> +		return ret;
> +	}
> +	if (ret == 0) {
>   		struct erofsmount_nbd_ctx ctx = {};
>   		char *recp;
>   
> -		/* Otherwise, NBD disconnect sends SIGPIPE, skipping cleanup */
> -		if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
> -			exit(EXIT_FAILURE);
> -
>   		if (source->type == EROFSMOUNT_SOURCE_OCI) {
>   			if (source->ocicfg.tarindex_path || source->ocicfg.zinfo_path) {
>   				err = erofsmount_tarindex_open(&ctx.vd, &source->ocicfg,
>   							       source->ocicfg.tarindex_path,
>   							       source->ocicfg.zinfo_path);
>   				if (err)
> -					exit(EXIT_FAILURE);
> +					erofsmount_worker_exit(err);
>   			} else {
>   				err = ocierofs_io_open(&ctx.vd, &source->ocicfg);
>   				if (err)
> -					exit(EXIT_FAILURE);
> +					erofsmount_worker_exit(err);
>   			}
>   		} else {
>   			err = open(source->device_path, O_RDONLY);
>   			if (err < 0)
> -				exit(EXIT_FAILURE);
> +				erofsmount_worker_exit(-errno);
>   			ctx.vd.fd = err;
>   		}
>   		recp = erofsmount_write_recovery_info(source);
>   		if (IS_ERR(recp)) {
>   			erofs_io_close(&ctx.vd);
> -			exit(EXIT_FAILURE);
> +			erofsmount_worker_exit(PTR_ERR(recp));
>   		}
>   
>   		num = -1;
>   		err = erofs_nbd_nl_connect(&num, 9, EROFSMOUNT_NBD_DISK_SIZE, recp);
> -		if (err >= 0) {
> -			ctx.sk.fd = err;
> -			err = erofsmount_nbd_fix_backend_linkage(num, &recp);
> -			if (err) {
> -				erofs_io_close(&ctx.sk);
> -			} else {
> -				err = write(pipefd[1], &num, sizeof(int));
> -				if (err < 0)
> -					err = -errno;
> -				close(pipefd[1]);
> -				close(pipefd[0]);
> -				if (err >= sizeof(int)) {
> -					err = (int)(uintptr_t)erofsmount_nbd_loopfn(&ctx);
> -					goto out_fork;
> -				}
> -			}
> +		if (err < 0)
> +			goto err_vd;

Can we seperate refactering into another commit and
address this particular issue directly?

Also use `goto` for this particular case doesn't
seem much better for the code readability.

> +
> +		ctx.sk.fd = err;
> +		err = erofsmount_nbd_fix_backend_linkage(num, &recp);
> +		if (err)
> +			goto err_sk;
> +
> +		err = erofsmount_worker_detach();
> +		if (err)
> +			goto err_sk;
> +
> +		err = write(pipefd[1], &num, sizeof(int));
> +		if (err < 0)
> +			err = -errno;
> +		close(pipefd[1]);
> +		close(pipefd[0]);
> +		if (err >= (int)sizeof(int)) {
> +			err = (int)(uintptr_t)erofsmount_nbd_loopfn(&ctx);
> +			goto out_fork;
>   		}
> +		goto err_sk;
> +
> +err_sk:
> +		erofs_io_close(&ctx.sk);
> +err_vd:
>   		erofs_io_close(&ctx.vd);
>   out_fork:
>   		(void)unlink(recp);
>   		free(recp);
> -		exit(err ? EXIT_FAILURE : EXIT_SUCCESS);
> +		erofsmount_worker_exit(err);
>   	}
>   	close(pipefd[1]);
>   	err = read(pipefd[0], &num, sizeof(int));
> @@ -1122,11 +1210,12 @@ out_fork:
>   
>   static int erofsmount_reattach(const char *target)
>   {
> -	char *identifier, *line, *source, *recp = NULL;
> +	char *identifier, *line = NULL, *source, *recp = NULL;
>   	struct erofsmount_nbd_ctx ctx = {};
> +	pid_t pid;
>   	int nbdnum, err;
>   	struct stat st;
> -	size_t n;
> +	size_t n = 0;
>   	FILE *f;
>   
>   	err = lstat(target, &st);
> @@ -1154,18 +1243,16 @@ static int erofsmount_reattach(const char *target)
>   	}
>   
>   	f = fopen(identifier ?: recp, "r");
> +	free(recp);
> +
>   	if (!f) {
>   		err = -errno;
> -		free(recp);
>   		goto err_identifier;
>   	}
> -	free(recp);
> -
> -	line = NULL;
>   	if ((err = getline(&line, &n, f)) <= 0) {
>   		err = -errno;
>   		fclose(f);
> -		goto err_identifier;
> +		goto err_line;
>   	}
>   	fclose(f);
>   	if (err && line[err - 1] == '\n')
> @@ -1202,18 +1289,27 @@ static int erofsmount_reattach(const char *target)
>   	}
>   
>   	err = erofs_nbd_nl_reconnect(nbdnum, identifier);
> -	if (err >= 0) {

Same here.

Thanks,
Gao Xiang

> -		ctx.sk.fd = err;
> -		if (fork() == 0) {
> -			free(line);
> -			free(identifier);
> -			if ((uintptr_t)erofsmount_nbd_loopfn(&ctx))
> -				return EXIT_FAILURE;
> -			return EXIT_SUCCESS;
> -		}
> +	if (err < 0)
> +		goto err_vd;
> +	ctx.sk.fd = err;
> +
> +	err = erofsmount_spawn_worker(&pid);
> +	if (err < 0) {
>   		erofs_io_close(&ctx.sk);
> -		err = 0;
> +		goto err_vd;
> +	}
> +	if (err == 0) {
> +		free(line);
> +		free(identifier);
> +		err = erofsmount_worker_detach();
> +		if (!err)
> +			err = (int)(uintptr_t)erofsmount_nbd_loopfn(&ctx);
> +		erofsmount_worker_exit(err);
>   	}
> +	erofs_io_close(&ctx.sk);
> +
> +	err = 0;
> +err_vd:
>   	erofs_io_close(&ctx.vd);
>   err_line:
>   	free(line);
> @@ -1251,9 +1347,15 @@ static int erofsmount_nbd(struct erofsmount_source *source,
>   		if (nbdfd < 0)
>   			return -errno;
>   
> -		if ((pid = fork()) == 0)
> -			return erofsmount_startnbd(nbdfd, source) ?
> -				EXIT_FAILURE : EXIT_SUCCESS;
> +		err = erofsmount_spawn_worker(&pid);
> +		if (err < 0) {
> +			close(nbdfd);
> +			return err;
> +		}
> +		if (err == 0) {
> +			err = erofsmount_startnbd(nbdfd, source);
> +			erofsmount_worker_exit(err);
> +		}
>   	} else {
>   		num = err;
>   		(void)snprintf(nbdpath, sizeof(nbdpath), "/dev/nbd%d", num);
> @@ -1661,6 +1763,10 @@ static int erofsmount_fanotify_child(struct erofs_fanotify_ctx *ctx,
>   	if (err)
>   		goto notify;
>   
> +	err = erofsmount_worker_detach();
> +	if (err)
> +		goto notify;
> +
>   	err = 0;
>   notify:
>   	write(pipefd, &err, sizeof(err));
> @@ -1730,19 +1836,17 @@ static int erofsmount_fanotify(struct erofsmount_source *source,
>   		goto out;
>   	}
>   
> -	pid = fork();
> -	if (pid < 0) {
> -		err = -errno;
> +	err = erofsmount_spawn_worker(&pid);
> +	if (err < 0) {
>   		close(pipefd[0]);
>   		close(pipefd[1]);
>   		goto out;
>   	}
> -
> -	if (pid == 0) {
> +	if (err == 0) {
>   		close(pipefd[0]);
>   		err = erofsmount_fanotify_child(&ctx, pipefd[1]);
>   		erofsmount_fanotify_ctx_cleanup(&ctx);
> -		exit(err ? EXIT_FAILURE : EXIT_SUCCESS);
> +		erofsmount_worker_exit(err);
>   	}
>   
>   	/* Wait for child to report fanotify initialization result */



      parent reply	other threads:[~2026-04-09  4:19 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-03  6:42 [PATCH 1/2] erofs-utils: mount: gracefully handle long-lived backend workers Yifan Zhao
2026-04-03  6:42 ` [PATCH 2/2] erofs-utils: mount: add --worker-log for detached workers Yifan Zhao
2026-04-09  4:21   ` Gao Xiang
2026-04-09  4:19 ` Gao Xiang [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=48e31164-920a-40d1-b509-be5cfb1591cc@linux.alibaba.com \
    --to=hsiangkao@linux.alibaba.com \
    --cc=jingrui@huawei.com \
    --cc=linux-erofs@lists.ozlabs.org \
    --cc=zhaoyifan28@huawei.com \
    --cc=zhukeqian1@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox