[sheepdog] [PATCH v3 1/3] bs_sheepdog.c: mock the behavior of QEMU's sheepdog driver in a correct manner

Hitoshi Mitake mitake.hitoshi at lab.ntt.co.jp
Thu Oct 17 09:38:32 CEST 2013


Current bs_sheepdog.c doesn't mock the behavior of QEMU's sheepdog
driver in a correct manner when it opens snapshot VDIs. It treats the
snapshot VDIs as read-only disks, but this behavior is different from
the QEMU's driver. This patch lets bs_sheepdog.c mock the original
behavior (delete an original VDI of the snapshot -> create a new non
snapshot VDI based on the snapshot and open it). This patch also
removes confusing notations of --backing-store option of
bs_sheepdog.c.

Signed-off-by: Hitoshi Mitake <mitake.hitoshi at lab.ntt.co.jp>
---
 usr/bs_sheepdog.c |  109 +++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 76 insertions(+), 33 deletions(-)

diff --git a/usr/bs_sheepdog.c b/usr/bs_sheepdog.c
index 4f7cde0..11ddce6 100644
--- a/usr/bs_sheepdog.c
+++ b/usr/bs_sheepdog.c
@@ -622,8 +622,11 @@ static int reload_inode(struct sheepdog_access_info *ai)
 	if (ret)
 		return -1;
 
-	read_object(ai, (char *)&ai->inode, vid_to_vdi_oid(vid),
-		    ai->inode.nr_copies, SD_INODE_SIZE, 0);
+	ret = read_object(ai, (char *)&ai->inode, vid_to_vdi_oid(vid),
+			  ai->inode.nr_copies, SD_INODE_SIZE, 0);
+	if (ret)
+		return -1;
+
 	return 0;
 }
 
@@ -917,9 +920,9 @@ static int sd_open(struct sheepdog_access_info *ai, char *filename, int flags)
 	enum {
 		EXPECT_PROTO,
 		EXPECT_PATH,
-		EXPECT_VDI,
-		EXPECT_HOST_OR_PORT,
+		EXPECT_HOST,
 		EXPECT_PORT,
+		EXPECT_VDI,
 		EXPECT_TAG_OR_SNAP,
 		EXPECT_NOTHING,
 	} parse_state = EXPECT_PROTO;
@@ -942,9 +945,6 @@ static int sd_open(struct sheepdog_access_info *ai, char *filename, int flags)
 	 * tcp:<host>:<port>:<vdi>
 	 * tcp:<host>:<port>:<vdi>:<tag>
 	 * tcp:<host>:<port>:<vdi>:<snapid>
-	 * tcp:<port>:<vdi>
-	 * tcp:<port>:<vdi>:<tag>
-	 * tcp:<port>:<vdi>:<snapid>
 	 */
 
 	result = strtok_r(filename, ":", &saveptr);
@@ -957,7 +957,7 @@ static int sd_open(struct sheepdog_access_info *ai, char *filename, int flags)
 				parse_state = EXPECT_PATH;
 			} else if (!strcmp("tcp", result)) {
 				ai->is_unix = 0;
-				parse_state = EXPECT_HOST_OR_PORT;
+				parse_state = EXPECT_HOST;
 			} else {
 				eprintf("unknown protocol of sheepdog vdi:"\
 					" %s\n", result);
@@ -968,26 +968,14 @@ static int sd_open(struct sheepdog_access_info *ai, char *filename, int flags)
 			strncpy(ai->uds_path, result, UNIX_PATH_MAX);
 			parse_state = EXPECT_VDI;
 			break;
-		case EXPECT_HOST_OR_PORT:
-			len = strlen(result);
-			for (i = 0; i < len; i++) {
-				if (!isdigit(result[i])) {
-					/* result is a hostname */
-					strncpy(ai->hostname, result,
-						HOST_NAME_MAX);
-					parse_state = EXPECT_PORT;
-					goto next_token;
-				}
-			}
-
-			/* result is a port, use localhost as hostname */
-			strncpy(ai->hostname, "localhost", strlen("localhost"));
-set_port:
+		case EXPECT_HOST:
+			strncpy(ai->hostname, result, HOST_NAME_MAX);
+			parse_state = EXPECT_PORT;
+			break;
+		case EXPECT_PORT:
 			ai->port = atoi(result);
 			parse_state = EXPECT_VDI;
 			break;
-		case EXPECT_PORT:
-			goto set_port;
 		case EXPECT_VDI:
 			strncpy(vdi_name, result, SD_MAX_VDI_LEN);
 			parse_state = EXPECT_TAG_OR_SNAP;
@@ -1017,8 +1005,6 @@ trans_to_expect_nothing:
 				parse_state);
 			exit(1);
 		}
-
-next_token:;
 	} while ((result = strtok_r(NULL, ":", &saveptr)) != NULL);
 
 	if (parse_state != EXPECT_NOTHING &&
@@ -1039,7 +1025,8 @@ next_token:;
 	else
 		dprintf("snapid: %d\n", snapid);
 
-	ai->is_snapshot = !(snapid == -1) && strlen(tag);
+	dprintf("VDI name: %s\n", vdi_name);
+	ai->is_snapshot = !(snapid == -1) || strlen(tag);
 	ret = find_vdi_name(ai, vdi_name, snapid == -1 ? 0 : snapid, tag, &vid,
 			    ai->is_snapshot);
 	if (ret)
@@ -1087,6 +1074,53 @@ static void set_medium_error(int *result, uint8_t *key, uint16_t *asc)
 	*asc = ASC_READ_ERROR;
 }
 
+static int create_branch(struct sheepdog_access_info *ai)
+{
+	struct sheepdog_vdi_req hdr;
+	struct sheepdog_vdi_rsp *rsp = (struct sheepdog_vdi_rsp *)&hdr;
+	unsigned int wlen = 0, rlen;
+	int ret;
+
+	hdr.opcode = SD_OP_DEL_VDI;
+	hdr.vdi_id = ai->inode.vdi_id;
+	hdr.flags = SD_FLAG_CMD_WRITE;
+	wlen = SD_MAX_VDI_LEN;
+	hdr.data_length = wlen;
+
+	ret = do_req(ai, (struct sheepdog_req *)&hdr, ai->inode.name,
+		     &wlen, &rlen);
+	if (ret) {
+		eprintf("deleting snapshot VDI for creating branch failed\n");
+		return -1;
+	}
+
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.opcode = SD_OP_NEW_VDI;
+	hdr.vdi_id = ai->inode.vdi_id;
+
+	hdr.flags = SD_FLAG_CMD_WRITE;
+	wlen = SD_MAX_VDI_LEN;
+	hdr.data_length = wlen;
+	hdr.vdi_size = ai->inode.vdi_size;
+	ret = do_req(ai, (struct sheepdog_req *)&hdr, ai->inode.name,
+		     &wlen, &rlen);
+	if (ret) {
+		eprintf("creating new VDI for creating branch failed\n");
+		return -1;
+	}
+
+	ret = read_object(ai, (char *)&ai->inode, vid_to_vdi_oid(rsp->vdi_id),
+			  ai->inode.nr_copies, SD_INODE_SIZE, 0);
+	if (ret) {
+		eprintf("reloading new inode object failed");
+		return -1;
+	}
+
+	dprintf("creating branch from snapshot, new VDI ID: %x\n", rsp->vdi_id);
+
+	return 0;
+}
+
 static void bs_sheepdog_request(struct scsi_cmd *cmd)
 {
 	int ret = 0;
@@ -1110,11 +1144,20 @@ static void bs_sheepdog_request(struct scsi_cmd *cmd)
 	case WRITE_12:
 	case WRITE_16:
 		if (ai->is_snapshot) {
-			length = scsi_get_out_length(cmd);
-			ret = sd_io(ai, 1, scsi_get_out_buffer(cmd),
-				    length, cmd->offset);
-		} else
-			ret = -1;
+			ret = create_branch(ai);
+			if (ret) {
+				eprintf("creating writable VDI from"\
+					" snapshot failed\n");
+				set_medium_error(&result, &key, &asc);
+
+				return;
+			}
+			ai->is_snapshot = 0;
+		}
+
+		length = scsi_get_out_length(cmd);
+		ret = sd_io(ai, 1, scsi_get_out_buffer(cmd),
+			    length, cmd->offset);
 
 		if (ret)
 			set_medium_error(&result, &key, &asc);
-- 
1.7.10.4




More information about the sheepdog mailing list