[sheepdog] [PATCH v2 2/7] sheep: revive lock operation

Hitoshi Mitake mitake.hitoshi at lab.ntt.co.jp
Wed Jul 30 09:24:37 CEST 2014


Current sheepdog doesn't support vdi locking. This patch and
succeeding ones revive the feature. With this feature, more than two
clients (including QEMU and tgt) are not allowed to open same VDI at
the same time.

Cc: Fabian Zimmermann <dev.faz at gmail.com>
Cc: Valerio Pachera <sirio81 at gmail.com>
Signed-off-by: Hitoshi Mitake <mitake.hitoshi at lab.ntt.co.jp>
---
 sheep/ops.c        | 41 ++++++++++++++++++++++----
 sheep/sheep_priv.h |  3 ++
 sheep/vdi.c        | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 125 insertions(+), 5 deletions(-)

diff --git a/sheep/ops.c b/sheep/ops.c
index 58ff397..7ca06d6 100644
--- a/sheep/ops.c
+++ b/sheep/ops.c
@@ -1306,6 +1306,34 @@ static int local_repair_replica(struct request *req)
 	return ret;
 }
 
+static int cluster_lock_vdi(const struct sd_req *req, struct sd_rsp *rsp,
+			    void *data, const struct sd_node *sender)
+{
+	uint32_t vid = rsp->vdi.vdi_id;
+
+	sd_info("node: %s is locking VDI: %"PRIx32, node_to_str(sender), vid);
+
+	if (!lock_vdi(vid, &sender->nid)) {
+		sd_err("locking %"PRIx32 "failed", vid);
+		return SD_RES_VDI_NOT_LOCKED;
+	}
+
+	return SD_RES_SUCCESS;
+}
+
+static int cluster_release_vdi_main(const struct sd_req *req,
+				    struct sd_rsp *rsp, void *data,
+				    const struct sd_node *sender)
+{
+	uint32_t vid = req->vdi.base_vdi_id;
+
+	sd_info("node: %s is unlocking VDI: %"PRIx32, node_to_str(sender), vid);
+
+	unlock_vdi(vid, &sender->nid);
+
+	return SD_RES_SUCCESS;
+}
+
 static struct sd_op_template sd_ops[] = {
 
 	/* cluster operations */
@@ -1400,6 +1428,14 @@ static struct sd_op_template sd_ops[] = {
 		.name = "LOCK_VDI",
 		.type = SD_OP_TYPE_CLUSTER,
 		.process_work = cluster_get_vdi_info,
+		.process_main = cluster_lock_vdi,
+	},
+
+	[SD_OP_RELEASE_VDI] = {
+		.name = "RELEASE_VDI",
+		.type = SD_OP_TYPE_CLUSTER,
+		.process_work = local_release_vdi,
+		.process_main = cluster_release_vdi_main,
 	},
 
 	[SD_OP_REWEIGHT] = {
@@ -1438,11 +1474,6 @@ static struct sd_op_template sd_ops[] = {
 	},
 
 	/* local operations */
-	[SD_OP_RELEASE_VDI] = {
-		.name = "RELEASE_VDI",
-		.type = SD_OP_TYPE_LOCAL,
-		.process_work = local_release_vdi,
-	},
 
 	[SD_OP_GET_STORE_LIST] = {
 		.name = "GET_STORE_LIST",
diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h
index b0156ee..74aa08e 100644
--- a/sheep/sheep_priv.h
+++ b/sheep/sheep_priv.h
@@ -345,6 +345,9 @@ int sd_delete_vdi(const char *name);
 int sd_lookup_vdi(const char *name, uint32_t *vid);
 int sd_create_hyper_volume(const char *name, uint32_t *vdi_id);
 
+bool lock_vdi(uint32_t vid, const struct node_id *owner);
+bool unlock_vdi(uint32_t vid, const struct node_id *owner);
+
 extern int ec_max_data_strip;
 
 int read_vdis(char *data, int len, unsigned int *rsp_len);
diff --git a/sheep/vdi.c b/sheep/vdi.c
index 747c810..8bcc7d4 100644
--- a/sheep/vdi.c
+++ b/sheep/vdi.c
@@ -11,11 +11,23 @@
 
 #include "sheep_priv.h"
 
+enum lock_state {
+	LOCK_STATE_INIT,
+	LOCK_STATE_LOCKED,
+	LOCK_STATE_UNLOCKED,
+};
+
+struct vdi_lock_state {
+	enum lock_state state;
+	struct node_id owner;
+};
+
 struct vdi_state_entry {
 	uint32_t vid;
 	unsigned int nr_copies;
 	bool snapshot;
 	uint8_t copy_policy;
+	struct vdi_lock_state lock_state;
 	struct rb_node node;
 };
 
@@ -148,6 +160,9 @@ int add_vdi_state(uint32_t vid, int nr_copies, bool snapshot, uint8_t cp)
 	entry->snapshot = snapshot;
 	entry->copy_policy = cp;
 
+	entry->lock_state.state = LOCK_STATE_INIT;
+	memset(&entry->lock_state.owner, 0, sizeof(struct node_id));
+
 	if (cp) {
 		int d;
 
@@ -235,6 +250,77 @@ out:
 	return ret;
 }
 
+bool lock_vdi(uint32_t vid, const struct node_id *owner)
+{
+	struct vdi_state_entry *entry;
+	bool ret = false;
+
+	sd_write_lock(&vdi_state_lock);
+
+	entry = vdi_state_search(&vdi_state_root, vid);
+	if (!entry) {
+		sd_err("no vdi state entry of %"PRIx32" found", vid);
+		goto out;
+	}
+
+	switch (entry->lock_state.state) {
+	case LOCK_STATE_INIT:
+	case LOCK_STATE_UNLOCKED:
+		entry->lock_state.state = LOCK_STATE_LOCKED;
+		memcpy(&entry->lock_state.owner, owner, sizeof(*owner));
+		sd_info("VDI %"PRIx32" is locked", vid);
+		ret = true;
+		goto out;
+	case LOCK_STATE_LOCKED:
+		sd_info("VDI %"PRIx32" is already locked", vid);
+		break;
+	default:
+		sd_alert("lock state of VDI (%"PRIx32") is unknown: %d",
+			 vid, entry->lock_state.state);
+		break;
+	}
+
+out:
+	sd_rw_unlock(&vdi_state_lock);
+	return ret;
+}
+
+bool unlock_vdi(uint32_t vid, const struct node_id *owner)
+{
+	struct vdi_state_entry *entry;
+	bool ret = false;
+
+	sd_write_lock(&vdi_state_lock);
+
+	entry = vdi_state_search(&vdi_state_root, vid);
+	if (!entry) {
+		sd_err("no vdi state entry of %"PRIx32" found", vid);
+		ret = false;
+		goto out;
+	}
+
+	switch (entry->lock_state.state) {
+	case LOCK_STATE_INIT:
+	case LOCK_STATE_UNLOCKED:
+		sd_err("unlocking unlocked VDI: %"PRIx32, vid);
+		break;
+	case LOCK_STATE_LOCKED:
+		entry->lock_state.state = LOCK_STATE_UNLOCKED;
+		memset(&entry->lock_state.owner, 0,
+		       sizeof(entry->lock_state.owner));
+		ret = true;
+		break;
+	default:
+		sd_alert("lock state of VDI (%"PRIx32") is unknown: %d",
+			 vid, entry->lock_state.state);
+		break;
+	}
+
+out:
+	sd_rw_unlock(&vdi_state_lock);
+	return ret;
+}
+
 static struct sd_inode *alloc_inode(const struct vdi_iocb *iocb,
 				    uint32_t new_snapid, uint32_t new_vid,
 				    uint32_t *data_vdi_id,
-- 
1.8.3.2




More information about the sheepdog mailing list