[Libguestfs] Error ret=-1 with EINTR in nbd_connect_systemd_socket_activation()

Richard W.M. Jones rjones at redhat.com
Tue Jul 12 12:51:19 UTC 2022


On Tue, Jul 12, 2022 at 05:33:41AM +0000, Motohiro Kawahito wrote:
> Hi, I’d like to connect to an encrypted QCOW2 file by
> nbd_connect_systemd_socket_activation(), but I got ret=-1 with EINTR. In our
> program, signals are frequently occurred, so I think this is the background of
> the problem. Could you advise me what should I do next? (such as open issue in
> https://gitlab.com/nbdkit/libnbd or something).
> 
> The arg parameter I used is
> 
> qemu-nbd --object secret,id=sec0,data=abc123 --image-opts driver=
> qcow2,encrypt.format=luks,encrypt.key-secret=sec0,file.filename=/tmp/
> empty.qcow2

The program worked OK for me.  I cleaned up a few things.  The
attached program contains my clean-ups.

$ ./nbd
Before nbd_create
Before nbd_connect_systemd_socket_activation
After nbd_connect_systemd_socket_activation
size=8539292672
kill end

However I'm using a slightly newer libnbd & qemu-nbd:

libnbd-1.12.0-1.fc37.x86_64
qemu-img-6.1.0-14.fc35.x86_64

> One more problem is that this qemu-nbd process still remains when error
> occurred.

qemu-nbd should be cleaned up if you call nbd_close, otherwise it
won't be cleaned up (eg. if you immediately exit on error).  See:

https://gitlab.com/nbdkit/libnbd/-/blob/e714b9a7403311a1a173a31d86234324e554ce5b/lib/handle.c#L152

nbdkit has a feature called --exit-on-error which means it will always
be cleaned up when the parent process goes away, but qemu-nbd does not
have this feature as far as I know.  It would be a useful addition.

https://libguestfs.org/nbdkit-captive.1.html#EXIT-WITH-PARENT

> I also attached a test program below. Is there any problem in my test program?
> The version of qemu-nbd is
> 
> $ qemu-nbd -V
> 
> qemu-nbd 4.2.1 (Debian 1:4.2-3ubuntu6.23)
> 
> I created this encrypted QCOW2 image by the following command.
> 
> qemu-img create --object secret,id=sec0,data=abc123 -f qcow2 -o encrypt.format=
> luks,encrypt.key-secret=sec0 /tmp/empty.qcow2 8539292672
> 
> Here is a test program I made. I found that this error occurred even for a
> normal QCOW2 file (not encrypted one). If you need more information, please let
> me know.
> 

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-builder quickly builds VMs from scratch
http://libguestfs.org/virt-builder.1.html
-------------- next part --------------
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <libnbd.h>

typedef struct _processInfo {
    char *fname;
    int64_t filesize;
} processInfo;

processInfo pinfo[1024];
int pnum;

static char **
makeCommandQemuNbd(bool sync, char *key_encrypted_qcow2, char *fileName)
{
    int num = 0;
    int pos = 0;
    char **ret;
    if (key_encrypted_qcow2) {
        num = 6 + (sync ? 1 : 0);
        ret = (char **)malloc(sizeof(*ret) * num);
        ret[pos++] = (char *)"qemu-nbd";   // 0
        ret[pos++] = (char *)"--object";   // 1
        asprintf (&ret[pos++], "secret,id=sec0,data=%s",
                  key_encrypted_qcow2);
        ret[pos++] = (char *)"--image-opts";   // 3
        asprintf (&ret[pos++], "driver=qcow2,encrypt.format=luks,encrypt.key-secret=sec0,file.filename=%s",
                  fileName);
        if (sync)
            ret[pos++] = (char *)"--cache=writethrough";       // 5
        ret[pos++] = NULL;     // 5 or 6
    } else {
        num = 5 + (sync ? 1 : 0);
        ret = (char **)malloc(sizeof(*ret) * num);
        ret[pos++] = (char *)"qemu-nbd";   // 0
        ret[pos++] = (char *)"-f";   // 1
        ret[pos++] = (char *)"qcow2";   // 2
        ret[pos++] = fileName;   // 3
        if (sync)
            ret[pos++] = (char *)"--cache=writethrough";       // 4
        ret[pos++] = NULL;     // 4 or 5
    }
    return ret;
}

void sigHandler(int num)
{
              // do nothing
}

#define TEST_NORMAL 0

struct nbd_handle *
openNbd(processInfo *pi, bool isWritethrough)
{
    struct nbd_handle *nbd;
    fprintf(stderr, "Before nbd_create\n");
    nbd = nbd_create ();
    if (nbd == NULL) {
        fprintf(stderr, "nbd_create failed. %s\n", nbd_get_error ());
        return nbd;
    }
#if TEST_NORMAL         // not encrypted file
    char **args = makeCommandQemuNbd(isWritethrough, (char*)NULL, (char *)"/tmp/my.qcow2");
#else
    char **args = makeCommandQemuNbd(isWritethrough, (char*)"abc123", pi->fname);
#endif
    fprintf(stderr, "Before nbd_connect_systemd_socket_activation\n");
    int ret = nbd_connect_systemd_socket_activation (nbd, args);
    free(args);
    if (ret == -1) {
        fprintf(stderr, "nbd_connect_systemd_socket_activation failed. %s\n", nbd_get_error ());
        return nbd;
    }
    fprintf(stderr, "After nbd_connect_systemd_socket_activation\n");
    pi->filesize = nbd_get_size(nbd);
    fprintf(stderr, "size=%ld\n", pi->filesize);
    return nbd;
}

int main(int argc, char *argv[])
{
    pnum = 0;
    pinfo[0].fname = (char*)"/tmp/empty.qcow2";
    signal(SIGUSR1, sigHandler);
    pid_t pid;
    if ((pid = fork()) == 0) {
        struct nbd_handle *nbd = openNbd(pinfo, false);
        if (nbd) {
            nbd_shutdown (nbd, 0);
            nbd_close (nbd);
        }
    } else {
              uint64_t i;
              for (i = 0; i < 10000000; i++) {
                 kill(pid, SIGUSR1);
              }
              fprintf(stderr, "kill end\n");
    }
}


More information about the Libguestfs mailing list