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"); } }