Motohiro Kawahito
2022-Jul-12 05:33 UTC
[Libguestfs] Error ret=-1 with EINTR in nbd_connect_systemd_socket_activation()
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 One more problem is that this qemu-nbd process still remains when error occurred. 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. #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) { static const char *keyTemplate = "secret,id=sec0,data=%s"; static const char *fileNameTemplate = "driver=qcow2,encrypt.format=luks,encrypt.key-secret=sec0,file.filename=%s"; num = 6 + (sync ? 1 : 0); ret = (char **)malloc(sizeof(*ret) * num); ret[pos++] = (char *)"qemu-nbd"; // 0 ret[pos++] = (char *)"--object"; // 1 ret[pos] = (char *)malloc(strlen(keyTemplate) + strlen(key_encrypted_qcow2)); // 2 sprintf(ret[pos], keyTemplate, key_encrypted_qcow2); pos++; ret[pos++] = (char *)"--image-opts"; // 3 ret[pos] = (char *)malloc(strlen(fileNameTemplate) + strlen(fileName)); // 4 sprintf(ret[pos], fileNameTemplate, fileName); pos++; 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) { nbd_close(openNbd(pinfo, false)); } else { uint64_t i; for (i = 0; i < 10000000; i++) { kill(pid, SIGUSR1); } fprintf(stderr, "kill end\n"); } } Debug output is like this. Before nbd_create libnbd: debug: nbd1: nbd_create: opening handle Before nbd_connect_systemd_socket_activation libnbd: debug: nbd1: nbd_connect_systemd_socket_activation: enter: argv=<list> libnbd: debug: nbd1: nbd_connect_systemd_socket_activation: event CmdConnectSA: START -> CONNECT_SA.START libnbd: debug: nbd1: nbd_connect_systemd_socket_activation: transition: CONNECT_SA.START -> CONNECT.START libnbd: debug: nbd1: nbd_connect_systemd_socket_activation: poll start: events=4 libnbd: debug: nbd1: nbd_connect_systemd_socket_activation: poll end: r=1 revents=4 libnbd: debug: nbd1: nbd_connect_systemd_socket_activation: event NotifyWrite: CONNECT.START -> CONNECT.CONNECTING libnbd: debug: nbd1: nbd_connect_systemd_socket_activation: transition: CONNECT.CONNECTING -> MAGIC.START libnbd: debug: nbd1: nbd_connect_systemd_socket_activation: transition: MAGIC.START -> MAGIC.RECV_MAGIC libnbd: debug: nbd1: nbd_connect_systemd_socket_activation: poll start: events=1 libnbd: debug: nbd1: nbd_connect_systemd_socket_activation: poll end: r=-1 revents=0 libnbd: debug: nbd1: nbd_connect_systemd_socket_activation: leave: error="nbd_connect_systemd_socket_activation: poll: Interrupted system call" nbd_connect_systemd_socket_activation failed. nbd_connect_systemd_socket_activation: poll: Interrupted system call libnbd: debug: nbd1: nbd_close: closing handle kill end Many thanks, Motohiro Kawahito -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://listman.redhat.com/archives/libguestfs/attachments/20220712/c9aea6e4/attachment.htm>
Richard W.M. Jones
2022-Jul-12 12:51 UTC
[Libguestfs] Error ret=-1 with EINTR in nbd_connect_systemd_socket_activation()
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.qcow2The 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"); } }