Subject: add the drive into drives_table[] only if guest is using PV driver

now when blktapctrl asks qemu to add a device, it also set a watch
on the xenstore backend state path of the device, e.g.
/local/domain/<domian-id>/device/vbd/<device-id>/state and when the
state changed to 4, that means guest is using the PV driver and it's
ready, so the watch will tell qemu to add the disk entry to
drives_table[], otherwise the disk in qemu will just stay opened,not
showing up in drives_table[].

Index: xen-4.0.3-testing/tools/blktap/drivers/blktapctrl.c
===================================================================
--- xen-4.0.3-testing.orig/tools/blktap/drivers/blktapctrl.c
+++ xen-4.0.3-testing/tools/blktap/drivers/blktapctrl.c
@@ -380,7 +380,22 @@ static int write_msg(int fd, int msgtype
 		msg->cookie = blkif->cookie;
 		
 		break;
-		
+
+	case CTLMSG_ADDDEV:
+		DPRINTF("Write_msg called: CTLMSG_ADDDEV\n");
+
+                msglen = sizeof(msg_hdr_t);
+                buf = malloc(msglen);
+
+                /*Assign header fields*/
+                msg = (msg_hdr_t *)buf;
+                msg->type = CTLMSG_ADDDEV;
+                msg->len = msglen;
+                msg->drivertype = blkif->drivertype;
+                msg->cookie = blkif->cookie;
+
+                break;
+
 	default:
 		return -1;
 	}
@@ -475,6 +490,12 @@ static int read_msg(int fd, int msgtype,
 				DPRINTF("\tPID: [%d]\n",blkif->tappid);
 			}
 			break;
+
+		case CTLMSG_ADDDEV_RSP:
+			DPRINTF("Received CTLMSG_ADDDEV_RSP\n");
+                        if (msgtype != CTLMSG_ADDDEV_RSP) ret = 0;
+                        break;
+
 		default:
 			DPRINTF("UNKNOWN MESSAGE TYPE RECEIVED\n");
 			ret = 0;
@@ -757,6 +778,63 @@ static int unmap_blktapctrl(blkif_t *blk
 	return 0;
 }
 
+static int blktapctrl_blkif_state(blkif_t *blkif, XenbusState state)
+{
+	struct disk_info *drivertype = NULL;
+
+	if (!blkif)
+		return -EINVAL;
+
+        switch (state)
+        {
+        case XenbusStateUnknown:
+                break;
+
+        case XenbusStateInitialising:
+                break;
+
+        case XenbusStateInitWait:
+                break;
+
+        case XenbusStateInitialised:
+                break;
+
+        case XenbusStateConnected:
+                drivertype = dtypes[blkif->drivertype];
+                if (drivertype->use_ioemu && blkif->state == CONNECTED) {
+                        if (write_msg(blkif->fds[WRITE], CTLMSG_ADDDEV, blkif, NULL)
+                            <=0) {
+                                DPRINTF("Write_msg failed - CTLMSG_ADDDEV\n");
+                                return -1;
+                        }
+                        if (read_msg(blkif->fds[READ], CTLMSG_ADDDEV_RSP, blkif) <= 0) {
+                                DPRINTF("Read_msg failure - CTLMSG_ADDDEV\n");
+                                return -1;
+                        }
+                }
+
+                break;
+
+        case XenbusStateClosing:
+                break;
+
+        case XenbusStateClosed:
+                break;
+
+        case XenbusStateReconfiguring:
+                break;
+
+        case XenbusStateReconfigured:
+                break;
+
+        default:
+                DPRINTF("Unrecognized XenbusState %d\n", state);
+		return -1;
+        }
+
+	return 0;
+}
+
 int open_ctrl_socket(char *devname)
 {
 	int ret;
@@ -853,6 +931,7 @@ int main(int argc, char *argv[])
 	register_new_blkif_hook(blktapctrl_new_blkif);
 	register_new_devmap_hook(map_new_blktapctrl);
 	register_new_unmap_hook(unmap_blktapctrl);
+	register_blkif_state_hook(blktapctrl_blkif_state);
 
 	ctlfd = blktap_interface_open();
 	if (ctlfd < 0) {
Index: xen-4.0.3-testing/tools/blktap/lib/blkif.c
===================================================================
--- xen-4.0.3-testing.orig/tools/blktap/lib/blkif.c
+++ xen-4.0.3-testing/tools/blktap/lib/blkif.c
@@ -89,6 +89,11 @@ void register_new_blkif_hook(int (*fn)(b
 {
 	new_blkif_hook = fn;
 }
+static int (*blkif_state_hook)(blkif_t *blkif, XenbusState state) = NULL;
+void register_blkif_state_hook(int (*fn)(blkif_t *blkif, XenbusState state))
+{
+	blkif_state_hook = fn;
+}
 
 int blkif_init(blkif_t *blkif, long int handle, long int pdev, 
                long int readonly)
@@ -179,6 +184,24 @@ void free_blkif(blkif_t *blkif)
 	}
 }
 
+int blkif_handle_state(blkif_t *blkif, XenbusState state)
+{
+	if (blkif == NULL)
+		return -EINVAL;	
+
+	if (blkif_state_hook == NULL)
+	{
+		DPRINTF("Probe handling blkif state, but no blkif_state_hook!\n");
+		return -1;
+	}
+	if (blkif_state_hook(blkif, state)!=0) {
+		DPRINTF("BLKIF: blkif_state_hook failed!\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 void __init_blkif(void)
 {    
 	memset(blkif_hash, 0, sizeof(blkif_hash));
Index: xen-4.0.3-testing/tools/blktap/lib/blktaplib.h
===================================================================
--- xen-4.0.3-testing.orig/tools/blktap/lib/blktaplib.h
+++ xen-4.0.3-testing/tools/blktap/lib/blktaplib.h
@@ -38,6 +38,7 @@
 #include <xen/xen.h>
 #include <xen/io/blkif.h>
 #include <xen/io/ring.h>
+#include <xen/io/xenbus.h>
 #include <xs.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -138,11 +139,13 @@ typedef struct blkif_info {
 void register_new_devmap_hook(int (*fn)(blkif_t *blkif));
 void register_new_unmap_hook(int (*fn)(blkif_t *blkif));
 void register_new_blkif_hook(int (*fn)(blkif_t *blkif));
+void register_blkif_state_hook(int (*fn)(blkif_t *blkif, XenbusState state));
 blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle);
 blkif_t *alloc_blkif(domid_t domid);
 int blkif_init(blkif_t *blkif, long int handle, long int pdev, 
                long int readonly);
 void free_blkif(blkif_t *blkif);
+int blkif_handle_state(blkif_t *blkif, XenbusState state);
 void __init_blkif(void);
 
 typedef struct busy_state {
@@ -209,6 +212,8 @@ typedef struct msg_pid {
 #define CTLMSG_CLOSE_RSP   8
 #define CTLMSG_PID         9
 #define CTLMSG_PID_RSP     10
+#define CTLMSG_ADDDEV      11
+#define CTLMSG_ADDDEV_RSP  12
 
 /* disk driver types */
 #define MAX_DISK_TYPES     20
Index: xen-4.0.3-testing/tools/blktap/lib/xenbus.c
===================================================================
--- xen-4.0.3-testing.orig/tools/blktap/lib/xenbus.c
+++ xen-4.0.3-testing/tools/blktap/lib/xenbus.c
@@ -318,6 +318,72 @@ static int check_image(struct xs_handle
 	return 0;
 }
 
+static void check_frontend_state(struct xs_handle *h, struct xenbus_watch *w,
+				 const char *state_path_im)
+{
+	struct backend_info *be = NULL;
+	struct blkif *blkif = NULL;
+	char *fepath = NULL, *bepath = NULL;
+	XenbusState state;
+	int er, len;
+
+	len = strsep_len(state_path_im, '/', 6);
+	if (len < 0)
+		return;
+	if (!(fepath = malloc(len + 1)))
+		return;
+	memset(fepath, 0, len + 1);
+	strncpy(fepath, state_path_im, len);
+
+	er = xs_gather(h, fepath, "state", "%d", &state,
+		       "backend", NULL, &bepath,
+		       NULL);
+
+	if (er) {
+		DPRINTF("Error getting state [%s]\n", fepath);
+		goto free_fe;
+	}
+
+	be = be_lookup_be(bepath);
+	if (!be || !be->blkif)
+		goto free_fe;
+
+	blkif = be->blkif;
+	blkif_handle_state(blkif, state);
+
+free_fe:
+	if (fepath)
+		free(fepath);
+	if (bepath)
+		free(bepath);
+	return;
+}
+
+static int add_blockdevice_state_watch(struct xs_handle *h, const char *frontend)
+{
+	char *path = NULL;
+	struct xenbus_watch *vbd_watch;
+
+	if (asprintf(&path, frontend) == -1)
+		return -ENOMEM;
+	if (!(path = realloc(path, strlen(path) + strlen("/state") + 1)))
+		return -ENOMEM;
+	strcpy(path + strlen(path), "/state");
+
+	vbd_watch = (struct xenbus_watch *)malloc(sizeof(struct xenbus_watch));
+	if (!vbd_watch) {
+		DPRINTF("ERROR: unable to malloc vbd_watch [%s]\n", path);
+		return -EINVAL;
+	}
+	vbd_watch->node     = path;
+	vbd_watch->callback = check_frontend_state;
+	if (register_xenbus_watch(h, vbd_watch) != 0) {
+		DPRINTF("ERROR: adding vbd probe watch %s\n", path);
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static void ueblktap_setup(struct xs_handle *h, char *bepath)
 {
 	struct backend_info *be;
@@ -512,6 +578,9 @@ static void ueblktap_probe(struct xs_han
 	
 	be->backpath = bepath;
 	be->frontpath = frontend;
+
+	if (add_blockdevice_state_watch(h, frontend) != 0)
+		goto free_be;
 	
 	list_add(&be->list, &belist);
 	
Index: xen-4.0.3-testing/tools/ioemu-qemu-xen/hw/xen_blktap.c
===================================================================
--- xen-4.0.3-testing.orig/tools/ioemu-qemu-xen/hw/xen_blktap.c
+++ xen-4.0.3-testing/tools/ioemu-qemu-xen/hw/xen_blktap.c
@@ -35,6 +35,8 @@
 #ifndef QEMU_TOOL
 #include "qemu-common.h"
 #include "sysemu.h"
+#include "irq.h"
+#include "hw.h"
 #endif
 
 #include "xen_blktap.h"
@@ -81,8 +83,18 @@ static void unmap_disk(struct td_state *
 {
 	tapdev_info_t *info = s->ring_info;
 	fd_list_entry_t *entry;
+	int i;
 	
 	bdrv_close(s->bs);
+#ifndef QEMU_TOOL
+	for (i = 0; i < MAX_DRIVES + 1; i++) {
+		if (drives_table[i].bdrv == s->bs) {
+			drives_table[i].bdrv = NULL;
+			nb_drives--;
+			break;
+		}
+	}
+#endif
 
 	if (info != NULL && info->mem > 0)
 	        munmap(info->mem, getpagesize() * BLKTAP_MMAP_REGION_SIZE);
@@ -242,18 +254,6 @@ static int open_disk(struct td_state *s,
 
 	s->info = ((s->flags & TD_RDONLY) ? VDISK_READONLY : 0);
 
-#ifndef QEMU_TOOL
-	for (i = 0; i < MAX_DRIVES + 1; i++) {
-		if (drives_table[i].bdrv == NULL) {
-			drives_table[i].bdrv = bs;
-			drives_table[i].type = IF_BLKTAP;
-			drives_table[i].bus = 0;
-			drives_table[i].unit = 0;
-			break;
-		}
-	}
-#endif
-
 	return 0;
 }
 
@@ -494,7 +494,7 @@ static void handle_blktap_ctrlmsg(void*
 	msg_hdr_t *msg;
 	msg_newdev_t *msg_dev;
 	msg_pid_t *msg_pid;
-	int ret = -1;
+	int ret = -1, i;
 	struct td_state *s = NULL;
 	fd_list_entry_t *entry;
 
@@ -584,6 +584,33 @@ static void handle_blktap_ctrlmsg(void*
 			len = write(write_fd, buf, msglen);
 			break;
 
+		case CTLMSG_ADDDEV:
+			s = get_state(msg->cookie);
+			if (s && !s->added) {
+#ifndef QEMU_TOOL
+				ide_unplug_harddisks();
+				for (i = 0; i < MAX_DRIVES + 1; i++) {
+					if (drives_table[i].bdrv == NULL) {
+						drives_table[i].bdrv = s->bs;
+						drives_table[i].type = IF_BLKTAP;
+						drives_table[i].bus = 0;
+						drives_table[i].unit = 0;
+						drives_table[i].used = 1;
+						nb_drives++;
+						s->added = 1;
+						break;
+					}
+				}
+#endif
+			}
+
+			memset(buf, 0x00, MSG_SIZE);
+			msglen = sizeof(msg_hdr_t);
+			msg->type = CTLMSG_ADDDEV_RSP;
+			msg->len = msglen;
+			len = write(write_fd, buf, msglen);
+			break;
+
 		default:
 			break;
 		}
Index: xen-4.0.3-testing/tools/ioemu-qemu-xen/hw/xen_blktap.h
===================================================================
--- xen-4.0.3-testing.orig/tools/ioemu-qemu-xen/hw/xen_blktap.h
+++ xen-4.0.3-testing/tools/ioemu-qemu-xen/hw/xen_blktap.h
@@ -40,7 +40,8 @@ struct td_state {
 	void *fd_entry;
 	uint64_t sector_size;
 	uint64_t size;
-	unsigned int       info;
+	unsigned int info;
+	int added;
 };
 
 typedef struct fd_list_entry {
