[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