From: Mariusz Tkaczyk <mtkaczyk@kernel.org>
To: Coly Li <colyli@suse.de>
Cc: linux-raid@vger.kernel.org
Subject: Re: [PATCH v2] mdopen: add sbin path to env PATH when call system("modprobe md_mod")
Date: Wed, 22 Jan 2025 14:26:55 +0100 [thread overview]
Message-ID: <20250122142655.031435cc@mtkaczyk-private-dev> (raw)
In-Reply-To: <9F1A4711-351B-4E58-BC5F-D281AC936A4A@suse.de>
On Wed, 22 Jan 2025 20:43:19 +0800
Coly Li <colyli@suse.de> wrote:
> > 2025年1月22日 20:01,Mariusz Tkaczyk <mtkaczyk@kernel.org> 写道:
> >
> > Hi Coly,
> > I read that once again and I have more comments. Even if it
> > looks simple, we are calling many env commands in mdadm, that is
> > why I'm trying to be careful.
> >
> > On Wed, 22 Jan 2025 11:53:59 +0800
> > Coly Li <colyli@suse.de> wrote:
> >
> >> During the boot process if mdadm is called in udev context, sbin
> >> paths like /sbin, /usr/sbin, /usr/local/sbin normally not defined
> >> in PATH
> >
> > normally defined? Please remove "not".
>
> This is correct, normally NOT defined. In boot time udev tasks just
> normally called binaries in their private directory, they don’t call
> system binaries.
>
Oh, got you. Thanks!
> >
> >> env variable, calling system("modprobe md_mod") in
> >> create_named_array() may fail with 'sh: modprobe: command not
> >> found' error message.
> >>
> >> We don't want to move modprobe binary into udev private directory,
> >> so setting the PATH env is a more proper method to avoid the above
> >> issue.
> >
> > Curios, did you verified what is happening to our "systemctl" calls?
> >
> > mdmon and grow-continue are started this way, they are later
> > followed by "WANTS=" in udev rule so the issue there is probably
> > hidden, maybe we should fix these calls too?
>
> For this specific case, md kernel module was not loaded yet, it was
> in quite early stage from observation of me and bug reporter.
>
>
> >
> >>
> >> This patch sets PATH env variable with
> >> "/sbin:/usr/sbin:/usr/local/sbin" before calling system("modprobe
> >> md_mod"). The change only takes effect within the udev worker
> >> context, not seen by global udev environment.
> >
> > If we are running app from terminal (i.e mdadm -I, or ./mdadm -I)
> > this change should not affect the terminal environment. I verified
> > it to be sure. Could you please mention that in description?
> >
>
> OK, let me do it in next version.
>
> >>
> >> Signed-off-by: Coly Li <colyli@suse.de>
> >> ---
> >> Changelog,
> >> v2: set buf[PATH_MAX] to 0 in stack variable announcement.
> >> v1: the original version.
> >>
> >>
> >> mdopen.c | 11 +++++++++++
> >> 1 file changed, 11 insertions(+)
> >>
> >> diff --git a/mdopen.c b/mdopen.c
> >> index 26f0c716..65bd8a1b 100644
> >> --- a/mdopen.c
> >> +++ b/mdopen.c
> >> @@ -39,6 +39,17 @@ int create_named_array(char *devnm)
> >>
> >> fd = open(new_array_file, O_WRONLY);
> >> if (fd < 0 && errno == ENOENT) {
> >> + char buf[PATH_MAX] = {0};
> >> +
> >> + /*
> >> + * When called by udev worker context, path of
> >> modprobe
> >> + * might not be in env PATH. Set sbin paths into PATH
> >> + * env to avoid potential failure when run modprobe
> >> here.
> >> + */
> >> + snprintf(buf, PATH_MAX - 1, "%s:%s", getenv("PATH"),
> >> + "/sbin:/usr/sbin:/usr/local/sbin");
> >
> > We can get NULL returned by getenv("PATH"), should we handle it? We
> > probably rely on compiler behavior here.
> >
> > I did simple test. I tried: printf("%s\n", getenv("NOT_EXISTING"));
> > I got segmentation fault.
>
> Yes, this was my fault, I took it for granted that PATH should always
> be set in udev context.
>
> You are right, I will add a NULL check in next version.
>
> >
> >> + setenv("PATH", buf, 1);
> >
> > I see here portability issues. We, assume that these binaries must
> > be in locations we added here. We may even double them, if they are
> > already defined.
> > Even if I know that probably no one is enough brave to
> > not have base binaries there, we should not force our PATH. I think
> > it is not our task and responsibility to deal with binaries location
> > issues. We should take what system provided.
> >
> > I still think that we should pass locations during compilation. Here
> > example with EXTRAVERSION, of course it may require some adjustments
> > but it is generally the way it can be achieved:
> > https://git.kernel.org/pub/scm/utils/mdadm/mdadm.git/commit/?id=03ab9763f51ddf2030f60f83e76cf9c1b50b726c
> >
> > I'm not strong convinced to the option I proposed, I just need
> > argument because more or less code is not an argument. What we will
> > choose today will stay here for years, we need to choose the best
> > possible way we see.
>
> The installation path might vary, depends on the way how mdadm is
> installed. If from rpm or other installation pack, the dest location
> can be predicted. If mdadm is installed from source code compiling,
> the destination varies depends on the pre-defined installation
> location, similar situation happens in containers.
This is what I wanted to propose:
in makefile:
# If provided respect that, otherwise, search for it
MODPROBE_PATH ?= $(which modprobe)
DMODPROBE_PATH = $(if $(MODPROBE_PATH),-DMODPROBE_PATH="\" -
$(MODPROBE_PATH)\"",)
+CFLAGS += $(DVERS) $(DDATE) $(DEXTRAVERSION) $(DMODPROBE_PATH)
and finally in code:
if (system(MODPROBE_PATH " md_mod")
with that we would detect location of modprobe during compilation or
rpm building, or allow user to customize it. It assumes that location
of modprobe won't change.
I checked whether it is provided by pkg-config with no success.
>
> So the patch is just a best-effort-try, if the binary is not
> installed in /sbin, /usr/sbin or /usr/local/sbin, my patch just gives
> up.
>
Maybe we can print error then? It would be useful for programmers
to understand the problem. Sometimes, to debug early stages I simply
redirected all error messages from mdadm to /dev/kmsg.
> >
> >> +
> >> if (system("modprobe md_mod") == 0)
> >> fd = open(new_array_file, O_WRONLY);
> >
> >> }
> >
> > The change will affect code executed later, probably we don't want
> > that. Shouldn't we restore old PATH here to minimize risk?
>
> For my understanding if the code was called after boot up, these path
> should be set already by shell initialization scripts. And for udev
> context, it is called and exited, and NOT shared with other udev
> tasks, almost no influence.
I see, it is more theoretical problem, almost to possible to met.
All fine then, we can continue with no clean up here as I cannot find
normal scenario it can occur.
Your change (after getenv fixes) LGTM. You can take a look into concept
I proposed but I have no strong preference.
Thanks,
Mariusz
next prev parent reply other threads:[~2025-01-22 13:27 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-22 3:53 [PATCH v2] mdopen: add sbin path to env PATH when call system("modprobe md_mod") Coly Li
2025-01-22 12:01 ` Mariusz Tkaczyk
2025-01-22 12:43 ` Coly Li
2025-01-22 13:26 ` Mariusz Tkaczyk [this message]
2025-01-22 15:30 ` Coly Li
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=20250122142655.031435cc@mtkaczyk-private-dev \
--to=mtkaczyk@kernel.org \
--cc=colyli@suse.de \
--cc=linux-raid@vger.kernel.org \
/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