On 11/21/2013 05:11 PM, Lei Li wrote:
The control message for exchange of pipe file descriptor should
be received by recvmsg, and it might be eaten to stream file by
qemu_recv() when receiving by two callbacks. So this patch adds
unix_msgfd_lookup() to callback get_buffer as the only one receiver,
where the pipe file descriptor would be caughted.
Signed-off-by: Lei Li <li...@linux.vnet.ibm.com>
---
migration-local.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 65 insertions(+), 3 deletions(-)
diff --git a/migration-local.c b/migration-local.c
index e028beb..0f0896b 100644
--- a/migration-local.c
+++ b/migration-local.c
@@ -50,6 +50,8 @@ typedef struct QEMUFileLocal {
bool unix_page_flipping;
} QEMUFileLocal;
+static bool pipefd_passed;
+
static int qemu_local_get_sockfd(void *opaque)
{
QEMUFileLocal *s = opaque;
@@ -57,16 +59,76 @@ static int qemu_local_get_sockfd(void *opaque)
return s->sockfd;
}
+static int unix_msgfd_lookup(void *opaque, struct msghdr *msg)
+{
+ QEMUFileLocal *s = opaque;
+ struct cmsghdr *cmsg;
+ bool found = false;
+
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
+ cmsg->cmsg_level != SOL_SOCKET ||
+ cmsg->cmsg_type != SCM_RIGHTS)
+ continue;
+
+ /* PIPE file descriptor to be received */
+ s->pipefd[0] = *((int *)CMSG_DATA(cmsg));
+ }
+
+ if (s->pipefd[0] <= 0) {
And this should be if (s->pipefd[0] < 0)..
+ fprintf(stderr, "no pipe fd can be received\n");
+ return found;
+ }
+
+ DPRINTF("pipefd successfully received\n");
+ return s->pipefd[0];
+}
+
static int qemu_local_get_buffer(void *opaque, uint8_t *buf,
int64_t pos, int size)
{
QEMUFileLocal *s = opaque;
ssize_t len;
+ struct msghdr msg = { NULL, };
+ struct iovec iov[1];
+ union {
+ struct cmsghdr cmsg;
+ char control[CMSG_SPACE(sizeof(int))];
+ } msg_control;
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = size;
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &msg_control;
+ msg.msg_controllen = sizeof(msg_control);
for (;;) {
- len = qemu_recv(s->sockfd, buf, size, 0);
- if (len != -1) {
- break;
+ if (!pipefd_passed) {
+ /*
+ * recvmsg is called here to catch the control message for
+ * the exchange of PIPE file descriptor until it is received.
+ */
+ len = recvmsg(s->sockfd, &msg, 0);
+ if (len != -1) {
+ if (unix_msgfd_lookup(s, &msg) > 0) {
+ pipefd_passed = 1;
+ /*
+ * Do not count one byte taken by the PIPE file
+ * descriptor.
+ */
+ len--;
+ } else {
+ len = -1;
+ }
Just found that this 'else' should go away as it will break the normal
Unix migration since pipefd_passed will always be 0 for it. I have
fixed this in my code, seems I mis-send it for some reason, sorry
for this...:-[
+ break;
+ }
+ } else {
+ len = qemu_recv(s->sockfd, buf, size, 0);
+ if (len != -1) {
+ break;
+ }
}
if (socket_error() == EAGAIN) {
--
Lei