Skip to content
This repository was archived by the owner on Feb 8, 2021. It is now read-only.

Commit e47ae41

Browse files
committed
use netlink uevents to wait for block device
In normal case, netlink uevents are consumed by hyper_loop() event handler. In the case of failing to find block devices, another epoll is set up to check for specific device. Signed-off-by: Peng Tao <bergwolf@gmail.com>
1 parent d1187bb commit e47ae41

File tree

7 files changed

+177
-22
lines changed

7 files changed

+177
-22
lines changed

src/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
COMMIT=`git describe --dirty --always --tags 2> /dev/null || true`
22
AM_CFLAGS = -Wall -Werror -DVERSIONCOMMIT=\""$(VERSION), commit: $(COMMIT)"\"
33
bin_PROGRAMS=hyperstart
4-
hyperstart_SOURCES=init.c jsmn.c net.c util.c parse.c parson.c container.c exec.c event.c portmapping.c
4+
hyperstart_SOURCES=init.c jsmn.c net.c util.c parse.c parson.c container.c exec.c event.c portmapping.c netlink.c
55
if HAVE_VSOCK
66
hyperstart_SOURCES+=vsock.c
77
endif

src/container.c

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "hyper.h"
2121
#include "parse.h"
2222
#include "syscall.h"
23+
#include "netlink.h"
2324

2425
static int container_populate_volume(char *src, char *dest)
2526
{
@@ -134,7 +135,7 @@ static int container_setup_volume(struct hyper_container *container)
134135
if (!strcmp(vol->fstype, "xfs"))
135136
options = "nouuid";
136137

137-
if (hyper_mount_blockdev(dev, path, vol->fstype, options) < 0) {
138+
if (mount(dev, path, vol->fstype, 0, options) < 0) {
138139
perror("mount volume device failed");
139140
return -1;
140141
}
@@ -528,6 +529,7 @@ struct hyper_container_arg {
528529
struct hyper_pod *pod;
529530
int mntns_referenced_efd;
530531
int container_inited_efd;
532+
int container_root_dev_efd;
531533
};
532534

533535
static int hyper_setup_container_rootfs(void *data)
@@ -551,11 +553,6 @@ static int hyper_setup_container_rootfs(void *data)
551553
/* To create files/directories accessible for all users. */
552554
umask(0);
553555

554-
if (container->fstype && hyper_rescan_scsi() < 0) {
555-
fprintf(stdout, "rescan scsi failed\n");
556-
goto fail;
557-
}
558-
559556
if (mount("", "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
560557
perror("mount SLAVE failed");
561558
goto fail;
@@ -576,19 +573,24 @@ static int hyper_setup_container_rootfs(void *data)
576573
char dev[128];
577574
char *options = NULL;
578575

576+
/* wait for rootfs ready message */
577+
if (hyper_eventfd_recv(arg->container_root_dev_efd) < 0) {
578+
fprintf(stderr, "wait for /proc/self/ns/mnt opened failed\n");
579+
goto fail;
580+
}
581+
579582
if (container->scsiaddr) {
580583
free(container->image);
581584
container->image = NULL;
582585
hyper_find_sd(container->scsiaddr, &container->image);
583586
}
584-
585587
sprintf(dev, "/dev/%s", container->image);
586588
fprintf(stdout, "device %s\n", dev);
587589

588590
if (!strncmp(container->fstype, "xfs", strlen("xfs")))
589591
options = "nouuid";
590592

591-
if (hyper_mount_blockdev(dev, root, container->fstype, options) < 0) {
593+
if (mount(dev, root, container->fstype, 0, options) < 0) {
592594
perror("mount device failed");
593595
goto fail;
594596
}
@@ -717,6 +719,36 @@ static void hyper_cleanup_pty(struct hyper_container *c)
717719
perror("clean up container pty failed");
718720
}
719721

722+
int container_prepare_rootfs_dev(struct hyper_container *container, struct hyper_pod *pod)
723+
{
724+
char dev[512];
725+
726+
if (container->fstype == NULL)
727+
return 0;
728+
729+
if (hyper_rescan_scsi() < 0) {
730+
fprintf(stderr, "failed to issue scsi rescan\n");
731+
return -1;
732+
}
733+
734+
if (container->scsiaddr) {
735+
free(container->image);
736+
container->image = NULL;
737+
hyper_find_sd(container->scsiaddr, &container->image);
738+
}
739+
740+
if (container->image) {
741+
sprintf(dev, "/dev/%s", container->image);
742+
if (access(dev, R_OK) == 0)
743+
return 0;
744+
sprintf(dev, "/block/%s", container->image);
745+
} else {
746+
sprintf(dev, "/0:0:%s/block/", container->scsiaddr);
747+
}
748+
749+
return hyper_netlink_wait_dev(pod->ueventfd, dev);
750+
}
751+
720752
int hyper_setup_container(struct hyper_container *container, struct hyper_pod *pod)
721753
{
722754
int stacksize = getpagesize() * 42;
@@ -725,6 +757,7 @@ int hyper_setup_container(struct hyper_container *container, struct hyper_pod *p
725757
.pod = pod,
726758
.mntns_referenced_efd = -1,
727759
.container_inited_efd = -1,
760+
.container_root_dev_efd = -1,
728761
};
729762
int flags = CLONE_NEWNS | SIGCHLD;
730763
char path[128];
@@ -735,7 +768,9 @@ int hyper_setup_container(struct hyper_container *container, struct hyper_pod *p
735768

736769
arg.mntns_referenced_efd = eventfd(0, EFD_CLOEXEC);
737770
arg.container_inited_efd = eventfd(0, EFD_CLOEXEC);
738-
if (arg.mntns_referenced_efd < 0 || arg.container_inited_efd < 0) {
771+
arg.container_root_dev_efd = eventfd(0, EFD_CLOEXEC);
772+
if (arg.mntns_referenced_efd < 0 || arg.container_inited_efd < 0 ||
773+
arg.container_root_dev_efd < 0) {
739774
perror("create eventfd between pod init execcmd failed");
740775
goto fail;
741776
}
@@ -772,6 +807,13 @@ int hyper_setup_container(struct hyper_container *container, struct hyper_pod *p
772807
fprintf(stdout, "hyper send mntns referenced event: normal\n");
773808
hyper_eventfd_send(arg.mntns_referenced_efd, HYPER_EVENTFD_NORMAL);
774809

810+
if (container_prepare_rootfs_dev(container, pod) < 0) {
811+
fprintf(stderr, "fail to prepare container rootfs dev\n");
812+
goto fail;
813+
}
814+
fprintf(stdout, "hyper send root dev ready event: normal\n");
815+
hyper_eventfd_send(arg.container_root_dev_efd, HYPER_EVENTFD_NORMAL);
816+
775817
/* wait for ready message */
776818
if (hyper_eventfd_recv(arg.container_inited_efd) < 0) {
777819
fprintf(stderr, "wait for setup container rootfs failed\n");
@@ -780,12 +822,14 @@ int hyper_setup_container(struct hyper_container *container, struct hyper_pod *p
780822

781823
close(arg.mntns_referenced_efd);
782824
close(arg.container_inited_efd);
825+
close(arg.container_root_dev_efd);
783826
return 0;
784827
fail:
785828
close(container->ns);
786829
container->ns = -1;
787830
close(arg.mntns_referenced_efd);
788831
close(arg.container_inited_efd);
832+
close(arg.container_root_dev_efd);
789833
return -1;
790834
}
791835

src/hyper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct hyper_pod {
3939
uint32_t remains;
4040
int req_destroy;
4141
int efd;
42+
int ueventfd;
4243
};
4344

4445
struct portmapping_white_list {
@@ -65,6 +66,7 @@ struct hyper_epoll {
6566
struct hyper_event tty;
6667
struct hyper_event vsock_ctl_listener;
6768
struct hyper_event vsock_msg_listener;
69+
struct hyper_event dev;
6870
};
6971

7072
static inline int hyper_symlink(char *oldpath, char *newpath)

src/init.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "container.h"
3333
#include "syscall.h"
3434
#include "vsock.h"
35+
#include "netlink.h"
3536

3637
static struct hyper_pod global_pod = {
3738
.containers = LIST_HEAD_INIT(global_pod.containers),
@@ -1443,6 +1444,11 @@ static int hyper_loop(void)
14431444
}
14441445
}
14451446

1447+
if (hyper_setup_netlink_listener(&hyper_epoll.dev) < 0 ||
1448+
hyper_add_event(hyper_epoll.efd, &hyper_epoll.dev, EPOLLIN))
1449+
return -1;
1450+
pod->ueventfd = hyper_epoll.dev.fd;
1451+
14461452
events = calloc(MAXEVENTS, sizeof(*events));
14471453

14481454
while (1) {

src/netlink.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include <stdio.h>
2+
#include <string.h>
3+
#include <unistd.h>
4+
#include <asm/types.h>
5+
#include <sys/socket.h>
6+
#include <linux/netlink.h>
7+
8+
#include "event.h"
9+
10+
static int hyper_netlink_expect_dev(int fd, const char *dev)
11+
{
12+
int len;
13+
char buf[1024] = {0};
14+
15+
do {
16+
len = recv(fd, buf, sizeof(buf), 0);
17+
if (len < 0)
18+
break;
19+
buf[len] = '\0';
20+
if (dev && strncmp(buf, "add@", strlen("add@")) == 0) {
21+
fprintf(stdout, "netlink add, expect %s, got %s\n", dev, buf);
22+
if (strstr(buf, dev) != NULL)
23+
return 1;
24+
}
25+
} while (len > 0);
26+
27+
return 0;
28+
}
29+
30+
static int hyper_ctlfd_read(struct hyper_event *e, int efd, int events)
31+
{
32+
return hyper_netlink_expect_dev(e->fd, NULL);
33+
}
34+
35+
static struct hyper_event_ops hyper_devfd_ops = {
36+
.read = hyper_ctlfd_read,
37+
};
38+
39+
int hyper_setup_netlink_listener(struct hyper_event *e)
40+
{
41+
int fd;
42+
struct sockaddr_nl sa;
43+
44+
memset(&sa, 0, sizeof(sa));
45+
sa.nl_family = AF_NETLINK;
46+
sa.nl_groups = 0xffffffff;
47+
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
48+
if (fd < 0) {
49+
perror("failed to create netlink socket");
50+
return -1;
51+
}
52+
if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
53+
perror("failed to bind netlink socket");
54+
close(fd);
55+
return -1;
56+
}
57+
e->fd = fd;
58+
59+
if (hyper_init_event(e, &hyper_devfd_ops, NULL) < 0) {
60+
hyper_reset_event(e);
61+
return -1;
62+
}
63+
64+
return 0;
65+
}
66+
67+
int hyper_netlink_wait_dev(int fd, const char *dev)
68+
{
69+
struct epoll_event event = {
70+
.events = EPOLLIN,
71+
};
72+
int efd, n;
73+
74+
efd = epoll_create1(EPOLL_CLOEXEC);
75+
if (efd < 0) {
76+
perror("failed to create event poll fd");
77+
return -1;
78+
}
79+
80+
if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &event) < 0) {
81+
perror("failed to add fd to epoll");
82+
goto fail;
83+
}
84+
85+
/* SIGCHLD is blocked by hyper_loop() */
86+
while (1) {
87+
n = epoll_wait(efd, &event, 1, 2000);
88+
if (n < 0) {
89+
perror("fail to wait netlink event");
90+
goto fail;
91+
} else if (n == 0) {
92+
fprintf(stderr, "timeout waiting for device %s\n", dev);
93+
goto fail;
94+
}
95+
if (hyper_netlink_expect_dev(fd, dev) > 0)
96+
break;
97+
}
98+
99+
close(efd);
100+
return 0;
101+
fail:
102+
close(efd);
103+
return -1;
104+
}

src/netlink.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef _NETLINK_H_
2+
#define _NETLINK_H_
3+
4+
int hyper_setup_netlink_listener(struct hyper_event *e);
5+
int hyper_netlink_wait_dev(int fd, const char *dev);
6+
#endif

src/util.c

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,22 +102,15 @@ int hyper_find_sd(char *addr, char **dev)
102102
struct dirent **list;
103103
struct dirent *dir;
104104
char path[512];
105-
int i, num, retry = 5;
105+
int i, num;
106106

107107
sprintf(path, "/sys/class/scsi_disk/0:0:%s/device/block/", addr);
108108
fprintf(stdout, "orig dev %s, scan path %s\n", *dev, path);
109109

110-
for (i = 0;; i++) {
111-
num = scandir(path, &list, NULL, NULL);
112-
if (num < 0) {
113-
if (errno != ENOENT || i >= retry) {
114-
perror("scan path failed");
115-
return -1;
116-
}
117-
usleep(20000);
118-
continue;
119-
}
120-
break;
110+
num = scandir(path, &list, NULL, NULL);
111+
if (num < 0) {
112+
perror("scan path failed");
113+
return -1;
121114
}
122115

123116
for (i = 0; i < num; i++) {

0 commit comments

Comments
 (0)