I could feel that you want to express "Oh, shit! How terrible the code it
is." from the reply, although across the screen. Anyway, I'm really glad
to thanks for your review and suggestions. :-)

On 2018年02月08日 07:55, John Ferlan wrote:

> That's where I'd expect to find the details of why someone would want to
> choose dlm over lockd or sanlock.  What goodies are provided? What
> advantage is there?

For those, assuming this scene: one customer has used cluster software
with DLM in their environment, why not choose DLM plugin instead of
sanlock/lockd ? Beside that, compared with sanlock/lockd, DLM don't need
the share storage, and sanlock would bring a little heavyheavily on disk
IO according to lockd RFC(2011-July/msg00337.html), but DLM only requires
 network.

I have sent a RFC in 12/2017 to ack how the opinion is. Daniel said that
"it can be considered in scope for a libvirt lock manager plugin if you
want to try writing one"(2017-December/msg00706.html). So I draft this
patch set which could only make DLM run in libvirt(with configure flag
`--with-dlm` to compile 'dlm.so' module by force). Hope some suggestion
bringed from libvirt community to help me improve, if accepted DLM lock
manager plugin RFC, so I don't update 'docs/locking.html.in'.

-------------

The following is the reply contents, aim to answer why I do that
for most comments:

1) sorry for indent in my code. I coded them in two notebooks,
both using vim. However one is newer, I have not configured '.vimrc' in
that one.

2)
>> > +AC_DEFUN([LIBVIRT_CHECK_CPG],[
>> > +  dnl in some distribution, Version is `UNKNOW` in libcpg.pc
>
> UNKNOWN
> doesn't make it very useful does it?

In some distribution, for example, openSUSE Tumbleweed:
    $ cat /usr/lib64/pkgconfig/libcpg.pc

    prefix=/usr
    exec_prefix=${prefix}
    libdir=/usr/lib64
    includedir=${prefix}/include

    Name: cpg
    Version: UNKNOWN
    Description: cpg
    Requires:
    Libs: -L${libdir} -lcpg
    Cflags: -I${includedir}

using `LIBVIRT_CHECK_PKG([CPG], [libcpg], [xxx])` directly would make
build error. So I decide to ignore 'version'. I also don't know why
that is.

3)
>> > +#define LOCK_RECORD_FILE_PATH "/tmp/libvirtd-dlm-file"
>
> Is somewhere in /tmp the best/only place to put this? What not similar
> to lockd/sanlock using /var/lib/libvirt/dlm... (which would seemingly
> need to be created on installation).

In my opinion, if one node reboots, DLM cluster would drop locks belong
that node, most of Linux distribution would clean '/tmp' directory...

4)
>> > +
>> > +#define STATUS             "STATUS"
>> > +#define RESOURCE_NAME      "RESOURCE_NAME"
>> > +#define LOCK_ID            "LOCK_ID"
>> > +#define LOCK_MODE          "LOCK_MODE"
>> > +#define VM_PID             "VM_PID"
>> > +
>> > +#define BUFFERLEN          128
>
> Yuck - for a stack variable...

>> > +    for (i = 0, str = raw, status = 0; ; str = NULL, i++) {
>> > +        subtoken = strtok_r(str, " \n", &saveptr);
>> > +        if (subtoken == NULL)
>> > +            break;
>> > +
>> > +        switch(i) {
>> > +        case 0:
>
> These are magic numbers?


Badly code wants to provided a readable file, like that:

STATUS RESOURCE_NAME LOCK_MODE     VM_PID
         0 1501e418dedd122b050c91ec61650ae30d3c217806125d3c2f365989143aa28d EXMODE      21857

The first line is the form header, the following is the lock
information.

5)
>> > +    char    *name;
>> > +    uint32_t mode;
>> > +    uint32_t lkid;
>
> I would think uint32_t would be limiting...  Why not just unsigned int?

view in '/usr/include/libdlm.h', it use `uint32_t` instead of
`unsigned int`.

6)
>> > +    virMutexLock(&(lockListWait.listMutex));
>> > +    virListAddTail(&lock->entry, &(lockListWait.list));
>> > + virMutexUnlock(&(lockListWait.listMutex));
>
> What is this list for?  I think this also is completely separable.  I
> wouldn't use a list either... 10s of domains probably works fine.  100s
> of domains perhaps not as well 1000s of domains starts being a
> bottleneck for sure.

Hashtable is a good idea, and I wanted to use it but I had never read
it's code... Chosing list because that there won't be too much vms in
one host, is it offten common that there is more than 50 vms in normal
usage?

7)
>> > +    if (safewrite(fd, buffer, strlen(buffer)) != strlen(buffer)) {
>> > +        virReportSystemError(errno,
>> > +                             _("unable to write lock information '%s' to file '%s'"), >> > +                             buffer, NULLSTR(driver->lockRecordFilePath));
>> > +        return;
>> > +    }
>
> Not sure I understand the reason of the file

Compared with sanlock and lockd, this implement of DLM has no daemon,
some area is needed to record lock information in order to resume lock
after libvirtd reboot. I chose file.

8)
>> > +     *   found with another mode, and -ENOENT if no orphan.
>> > +     *
>> > +     *   cast/bast/param are (void *)1 because the kernel
>> > +     *   returns errors if some are null.
>> > +     */
>> > +
>> > +    status = dlm_ls_lockx(lockspace, mode, &lksb, LKF_PERSISTENT|LKF_ORPHAN,
>> > +                          name, strlen(name), 0,
>> > +                          (void *)1, (void *)1, (void *)1,
>
> ^^ These would seem to relate to the same parametes used for
> dlm_lock[_wait].  They are actually quite useful when it comes to lock
> conversions.  You may want to considering investigating that...
>
>
> Still seems like a "bug" to me to need to pass 1 as a callback function
> or a blocking callback function.
>
>> > +                          NULL, NULL);
>
> Why not dlm_is_lock() instead since you're not using xid and timeout

The code is from lvm2, I try to use `dlm_lock_wait`, however it failed,
I don't know why. `(void *)1` is the same reason. Maybe a bug from
libdlm or 'dlm.ko'.

9)
>> > +
>> > +    /* create thread to receive notification from kernel */
>
> notification for what? what gets called?

This is implemented by libdlm, the result is writted in `lksb`.

       int dlm_lock_wait(uint32_t mode,
                 struct dlm_lksb *lksb,
                 uint32_t flags,
                 const void *name,
                 unsigned int namelen,
                 uint32_t parent,         /* unused */
                 void *bastarg,
                 void (*bastaddr) (void *bastarg),
                 void *range);            /* unused */

10)
>> > +                    priv->hasRWDisks = true;
>> > +                    /* ignore disk resource without error */
>> > +                    return 0;
>> > +                }
>> > +            }
>> > +
>> > +            if (virCryptoHashString(VIR_CRYPTO_HASH_SHA256, name, &newName) < 0)
>
>> Interesting _lockd uses SHA256 and _sanlock uses MD5...
>
>
>> > +        /* we need format the lock information, so the lock name must be the constant length */ >> > +        if (virCryptoHashString(VIR_CRYPTO_HASH_SHA256, name, &newName) < 0)
>> > +            goto cleanup;
>
> Neither _lockd nor _sandisk do any sort of Hash on this name.
>
>
>> > +            memset(&lksb, 0, sizeof(lksb));
>> > +            rv = dlm_ls_lock_wait(lockspace, priv->resources[i].mode,
>> > +                                  &lksb, LKF_NOQUEUE|LKF_PERSISTENT,
>> > + priv->resources[i].name, strlen(priv->resources[i].name),
>
> This is where I wonder why we cannot pass the path to the disk to dlm
> instead of the hash

It's interesting here. Originally I use MD5 instead of SHA256, but I found that:

    typedef enum {
        VIR_CRYPTO_HASH_MD5, /* Don't use this except for historic compat */
        VIR_CRYPTO_HASH_SHA256,

        VIR_CRYPTO_HASH_LAST
    } virCryptoHash;

Futhermore, I find the bug patch related sanlock name: sanlock's name
length is limited 48, there is always someone use more than 48 characters
(see https://bugzilla.redhat.com/show_bug.cgi?id=735443). The same
situation, why not use the constant length? DLM limits name is 64 bytes
to avoid some potential bugs. Besides, it's convenient to format write
it to file.

11)
>> > +     * 'ensure sanlock socket is labelled with the VM process label',
>> > +     * however, fixing sanlock socket security labelling remove related
>> > +     * code. Now, `fd` parameter is useless.
>> > +     */
>> > +    if (fd)
>> > +        *fd = -1;
>
> But you just set it to -1??!

Maybe I can submit a patch to cut those code. Afterall it's useless now.

12)
>> > +    virCheckFlags(0, -1);
>> > +
>> > +    if (state)
>> > +        *state = NULL;
>
> Why would this return NULL?  My recollection is there is some sort of
> inquiry API for dlm.

Inquiry API is disappeared now... Only lock/unlock refered to libdlm
source code and reference book.
 http://people.redhat.com/ccaulfie/docs/rhdlmbook.pdf
 Chapter 4.3. Lock Query Operations

--
Regards
Lin Fu(river)

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to