[PATCH 1/2] virdevmapper: Don't error on kernels without DM support

Pino Toscano ptoscano at redhat.com
Tue Aug 18 08:10:55 UTC 2020


On Tuesday, 18 August 2020 09:54:25 CEST Michal Privoznik wrote:
> On 8/17/20 5:58 PM, Peter Krempa wrote:
> > On Mon, Aug 17, 2020 at 17:40:04 +0200, Michal Privoznik wrote:
> >> On 8/17/20 5:16 PM, Peter Krempa wrote:
> >>> On Mon, Aug 17, 2020 at 16:26:54 +0200, Michal Privoznik wrote:
> >>>> In one of my latest patch (v6.6.0~30) I was trying to remove
> >>>> libdevmapper use in favor of our own implementation. However, the
> >>>> code did not take into account that device mapper can be not
> >>>> compiled into the kernel (e.g. be a separate module that's not
> >>>> loaded) in which case /proc/devices won't have the device-mapper
> >>>> major number and thus virDevMapperGetTargets() and/or
> >>>> virIsDevMapperDevice() fails.
> >>>>
> >>>> Fixes: 22494556542c676d1b9e7f1c1f2ea13ac17e1e3e
> >>>> Reported-by: Andrea Bolognani <abologna at redhat.com>
> >>>> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
> >>>> ---
> >>>>    src/util/virdevmapper.c | 41 +++++++++++++++++++++++++++++++----------
> >>>>    1 file changed, 31 insertions(+), 10 deletions(-)
> >>>>
> >>>> diff --git a/src/util/virdevmapper.c b/src/util/virdevmapper.c
> >>>> index fe7f611496..cc33d8211e 100644
> >>>> --- a/src/util/virdevmapper.c
> >>>> +++ b/src/util/virdevmapper.c
> >>>> @@ -47,10 +47,11 @@
> >>>>    G_STATIC_ASSERT(BUF_SIZE > sizeof(struct dm_ioctl));
> >>>>    static unsigned int virDMMajor;
> >>>> +static virMutex virDevMapperInitMutex = VIR_MUTEX_INITIALIZER;
> >>>
> >>> 'virDMMajor' should now be initialized explicitly ...
> >>
> >> Aren't global static variables initialized to zero automatically (something
> >> about .bss section)?
> > 
> > Yes, they are.
> > 
> >>
> >>>
> >>>>    static int
> >>>> -virDevMapperOnceInit(void)
> >>>> +virDevMapperGetMajor(unsigned int *dmmaj)
> >>>>    {
> >>>>        g_autofree char *buf = NULL;
> >>>>        VIR_AUTOSTRINGLIST lines = NULL;
> >>>> @@ -69,23 +70,34 @@ virDevMapperOnceInit(void)
> >>>>            if (sscanf(lines[i], "%u %ms\n", &maj, &dev) == 2 &&
> >>>>                STREQ(dev, DM_NAME)) {
> >>>> -            virDMMajor = maj;
> >>>
> >>> ... since it's not always initialized here.
> >>>
> >>>> +            *dmmaj = maj;
> >>>>                break;
> >>>>            }
> >>>>        }
> >>>>        if (!lines[i]) {
> >>>> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> >>>> -                       _("Unable to find major for %s"),
> >>>> -                       DM_NAME);
> >>>> -        return -1;
> >>>> +        /* Don't error here. Maybe the kernel was built without
> >>>> +         * devmapper. Let the caller decide. */
> >>>> +        return -2;
> >>>>        }
> >>>>        return 0;
> >>>>    }
> >>>> -VIR_ONCE_GLOBAL_INIT(virDevMapper);
> >>>> +static int
> >>>> +virDevMapperInit(void)
> >>>> +{
> >>>> +    int rc = 0;
> >>>> +
> >>>> +    virMutexLock(&virDevMapperInitMutex);
> >>>> +
> >>>> +    if (virDMMajor == 0)
> >>>
> >>> I'm not quite persuaded with this caching here. For cases when the
> >>> device mapper is loaded we cache it, but in the negative case ...
> >>>
> >>>> +        rc = virDevMapperGetMajor(&virDMMajor);
> >>>
> >>> ... we always process /proc/devices. Why is caching necessary then?
> >>
> >> Are you suggesting to parse /proc/devices every time? My concern is it will
> >> burn CPU cycles needlessly. And I'm not sure how to address the negative
> >> case when DM module is not loaded. It's ineffective, I agree, I just don't
> >> see how to make it better.
> > 
> > Well, at first we should establish when the value is determined/can
> > change:
> > 
> > 1) at kernel build time/boot time (any case when the libvirtd process
> >     will need to be restarted for it to change)
> > 
> >    In these scenarios it doesn't actually make sense to check it prior to
> >    trying to open the device mapper control socket first. You can look it
> >    up and cache it after you open the socket and don't ever need to re-do
> >    it. In that case you can also use the existing VIR_ONCE code.
> > 
> >    You then don't have to clear it when the module is ejected, because
> >    afterwards the control socket will not exist. In case the module is
> >    re-injected, given the contstraints above the value will not change so
> >    no need to re-load.
> > 
> > 2) at module insertion time
> > 
> >    In this case it's actually wrong to cache it, because the module can
> >    be unloaded and reloaded while libvirt will not check and update the
> >    cached value. In those scenarios it should also be determined only
> >    after you open the control fd frist.
> > 
> As promised yesterday, I've dived into the code and found out that the 
> major number can be specified as a parameter to the dm module (just 
> tested and it works). So the next thing I tried was to see how could we 
> check whether the module was reloaded. I've tried opening 
> /dev/mapper/control hoping that I will get EOF on module unload (which I 
> could then use to run a callback that would invalidate the cached 
> value). But having the file open prevents unloading the module.
> 
> Loading/unloading a module results in an udev event, BUT we listen for 
> udev events only in nodedev driver and moving the code out to a driver 
> agnostic location and making it driver agnostic is too much code for a 
> little gain.
> 
> Then I looked whether it's possible to get the major number via an 
> ioctl(). But haven't found anything.

What about stat()ing /dev/mapper/control? That should give you the
major/minor of that special character device.

-- 
Pino Toscano
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: This is a digitally signed message part.
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20200818/13d829e5/attachment-0001.sig>


More information about the libvir-list mailing list