[stgt] [PATCH] bs_sheepdog.c: support various VDI options in --backing-store option

Hitoshi Mitake mitake.hitoshi at lab.ntt.co.jp
Tue Oct 8 10:39:21 CEST 2013


Current bs_sheepdog.c only supports connections to sheep process which
listen on localhost:7000 (tcp). This patch makes the address, port,
and protocol specifiable via --backing-store option of tgtadm. In
addition, snapshots of VDIs can be logical units when tag or snapshot
ID is passed to the option.

The form of --backing-store option:
 - unix:<path_of_unix_domain_socket>:<vdi>
 - unix:<path_of_unix_domain_socket>:<vdi>:<tag>
 - unix:<path_of_unix_domain_socket>:<vdi>:<snapid>
 - 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>

Example of the option: -b unix:/sheep_store/sock:tgt0:1
(connect via unix domain socket, the path of socket is
/sheep_store/sock, VDI name is tgt0, use snapshot of ID 1)

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

diff --git a/usr/bs_sheepdog.c b/usr/bs_sheepdog.c
index 4b5a951..4f7cde0 100644
--- a/usr/bs_sheepdog.c
+++ b/usr/bs_sheepdog.c
@@ -32,6 +32,9 @@
 #include <sys/epoll.h>
 #include <sys/socket.h>
 #include <pthread.h>
+#include <limits.h>
+#include <ctype.h>
+#include <sys/un.h>
 
 #include "list.h"
 #include "tgtd.h"
@@ -43,7 +46,7 @@
 #define SD_PROTO_VER 0x01
 
 #define SD_DEFAULT_ADDR "localhost"
-#define SD_DEFAULT_PORT "7000"
+#define SD_DEFAULT_PORT 7000
 
 #define SD_OP_CREATE_AND_WRITE_OBJ  0x01
 #define SD_OP_READ_OBJ       0x02
@@ -217,7 +220,21 @@ struct sheepdog_fd_list {
 	struct list_head list;
 };
 
+#define UNIX_PATH_MAX (108 + 1)
+
 struct sheepdog_access_info {
+	int is_unix;
+
+	/* tcp */
+	char hostname[HOST_NAME_MAX + 1];
+	int port;
+
+	/* unix domain socket */
+	char uds_path[UNIX_PATH_MAX];
+
+	/* if the opened VDI is a snapshot, write commands cannot be issued */
+	int is_snapshot;
+
 	/*
 	 * maximum length of fd_list_head: nr_iothreads + 1
 	 * (+ 1 is for main thread)
@@ -313,21 +330,25 @@ static const char *sd_strerror(int err)
 	return "Invalid error code";
 }
 
-static int connect_to_sdog(const char *addr, const char *port)
+static int connect_to_sdog_tcp(const char *addr, int port)
 {
 	char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
 	int fd, ret;
 	struct addrinfo hints, *res, *res0;
+	char port_s[6];
 
 	if (!addr) {
 		addr = SD_DEFAULT_ADDR;
 		port = SD_DEFAULT_PORT;
 	}
 
+	memset(port_s, 0, 6);
+	snprintf(port_s, 5, "%d", port);
+
 	memset(&hints, 0, sizeof(hints));
 	hints.ai_socktype = SOCK_STREAM;
 
-	ret = getaddrinfo(addr, port, &hints, &res0);
+	ret = getaddrinfo(addr, port_s, &hints, &res0);
 	if (ret) {
 		eprintf("unable to get address info %s, %s\n",
 			addr, strerror(errno));
@@ -354,16 +375,41 @@ reconnect:
 			break;
 		}
 
-		dprintf("connected to %s:%s\n", addr, port);
+		dprintf("connected to %s:%d\n", addr, port);
 		goto success;
 	}
 	fd = -1;
-	eprintf("failed connect to %s:%s\n", addr, port);
+	eprintf("failed connect to %s:%d\n", addr, port);
 success:
 	freeaddrinfo(res0);
 	return fd;
 }
 
+static int connect_to_sdog_unix(const char *path)
+{
+	int fd, ret;
+	struct sockaddr_un un;
+
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0) {
+		eprintf("socket() failed: %m\n");
+		return -1;
+	}
+
+	memset(&un, 0, sizeof(un));
+	un.sun_family = AF_UNIX;
+	strncpy(un.sun_path, path, UNIX_PATH_MAX);
+
+	ret = connect(fd, (const struct sockaddr *)&un, (socklen_t)sizeof(un));
+	if (ret < 0) {
+		eprintf("connect() failed: %m\n");
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
+
 static int get_my_fd(struct sheepdog_access_info *ai)
 {
 	pthread_t self_id = pthread_self();
@@ -379,7 +425,10 @@ static int get_my_fd(struct sheepdog_access_info *ai)
 	}
 	pthread_rwlock_unlock(&ai->fd_list_lock);
 
-	fd = connect_to_sdog(NULL, NULL);
+	if (ai->is_unix)
+		fd = connect_to_sdog_unix(ai->uds_path);
+	else
+		fd = connect_to_sdog_tcp(ai->hostname, ai->port);
 	if (fd < 0)
 		return -1;
 
@@ -857,13 +906,142 @@ out:
 
 static int sd_open(struct sheepdog_access_info *ai, char *filename, int flags)
 {
-	int ret;
+	int ret = 0, i, len;
 	uint32_t vid = 0;
-	char tag[SD_MAX_VDI_TAG_LEN];
+	char *orig_filename;
+
+	uint32_t snapid = -1;
+	char tag[SD_MAX_VDI_TAG_LEN + 1];
+	char vdi_name[SD_MAX_VDI_LEN + 1];
+	char *saveptr, *result;
+	enum {
+		EXPECT_PROTO,
+		EXPECT_PATH,
+		EXPECT_VDI,
+		EXPECT_HOST_OR_PORT,
+		EXPECT_PORT,
+		EXPECT_TAG_OR_SNAP,
+		EXPECT_NOTHING,
+	} parse_state = EXPECT_PROTO;
 
 	memset(tag, 0, sizeof(tag));
+	memset(vdi_name, 0, sizeof(vdi_name));
+
+	orig_filename = strdup(filename);
+	if (!orig_filename) {
+		eprintf("saving original filename failed\n");
+		return -1;
+	}
+
+	/*
+	 * expected form of filename:
+	 *
+	 * unix:<path_of_unix_domain_socket>:<vdi>
+	 * unix:<path_of_unix_domain_socket>:<vdi>:<tag>
+	 * unix:<path_of_unix_domain_socket>:<vdi>:<snapid>
+	 * 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);
+
+	do {
+		switch (parse_state) {
+		case EXPECT_PROTO:
+			if (!strcmp("unix", result)) {
+				ai->is_unix = 1;
+				parse_state = EXPECT_PATH;
+			} else if (!strcmp("tcp", result)) {
+				ai->is_unix = 0;
+				parse_state = EXPECT_HOST_OR_PORT;
+			} else {
+				eprintf("unknown protocol of sheepdog vdi:"\
+					" %s\n", result);
+				return -1;
+			}
+			break;
+		case EXPECT_PATH:
+			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:
+			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;
+			break;
+		case EXPECT_TAG_OR_SNAP:
+			len = strlen(result);
+			for (i = 0; i < len; i++) {
+				if (!isdigit(result[i])) {
+					/* result is a tag */
+					strncpy(tag, result,
+						SD_MAX_VDI_TAG_LEN);
+					goto trans_to_expect_nothing;
+				}
+			}
+
+			snapid = atoi(result);
+trans_to_expect_nothing:
+			parse_state = EXPECT_NOTHING;
+			break;
+		case EXPECT_NOTHING:
+			eprintf("invalid VDI path of sheepdog, unexpected"\
+				" token: %s (entire: %s)\n",
+				result, orig_filename);
+			goto out;
+		default:
+			eprintf("BUG: invalid state of parser: %d\n",
+				parse_state);
+			exit(1);
+		}
 
-	ret = find_vdi_name(ai, filename, CURRENT_VDI_ID, tag, &vid, 0);
+next_token:;
+	} while ((result = strtok_r(NULL, ":", &saveptr)) != NULL);
+
+	if (parse_state != EXPECT_NOTHING &&
+	    parse_state != EXPECT_TAG_OR_SNAP) {
+		eprintf("invalid VDI path of sheepdog: %s (state: %d)\n",
+			orig_filename, parse_state);
+		goto out;
+	}
+
+	dprintf("protocol: %s\n", ai->is_unix ? "unix" : "tcp");
+	if (ai->is_unix)
+		dprintf("path of unix domain socket: %s\n", ai->uds_path);
+	else
+		dprintf("hostname: %s, port: %d\n", ai->hostname, ai->port);
+
+	if (snapid == -1)
+		dprintf("tag: %s\n", tag);
+	else
+		dprintf("snapid: %d\n", snapid);
+
+	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)
 		goto out;
 
@@ -872,13 +1050,15 @@ static int sd_open(struct sheepdog_access_info *ai, char *filename, int flags)
 
 	ret = read_object(ai, (char *)&ai->inode, vid_to_vdi_oid(vid),
 			  0, SD_INODE_SIZE, 0);
-
 	if (ret)
 		goto out;
 
-	return 0;
+	ret = 0;
 out:
-	return -1;
+	strcpy(filename, orig_filename);
+	free(orig_filename);
+
+	return ret;
 }
 
 static void sd_close(struct sheepdog_access_info *ai)
@@ -929,9 +1109,13 @@ static void bs_sheepdog_request(struct scsi_cmd *cmd)
 	case WRITE_10:
 	case WRITE_12:
 	case WRITE_16:
-		length = scsi_get_out_length(cmd);
-		ret = sd_io(ai, 1, scsi_get_out_buffer(cmd),
-			    length, cmd->offset);
+		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;
+
 		if (ret)
 			set_medium_error(&result, &key, &asc);
 		break;
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the stgt mailing list