[sheepdog] [PATCH v5 06/14] sheep: decrement generational reference count on vdi deletion

Hitoshi Mitake mitake.hitoshi at lab.ntt.co.jp
Tue Mar 4 06:42:50 CET 2014


From: Hitoshi Mitake <mitake.hitoshi at gmail.com>

This removes old vdi deletion code, which reclaims objects only when
all relevant snapshots are deleted, and uses a generational reference
counting algorithm.

Cc: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
Cc: Valerio Pachera <sirio81 at gmail.com>
Cc: Alessandro Bolgia <alessandro at extensys.it>
Signed-off-by: Hitoshi Mitake <mitake.hitoshi at lab.ntt.co.jp>
---
 sheep/vdi.c |  272 ++++++-----------------------------------------------------
 1 file changed, 27 insertions(+), 245 deletions(-)

diff --git a/sheep/vdi.c b/sheep/vdi.c
index e3e63d8..6d83e8c 100644
--- a/sheep/vdi.c
+++ b/sheep/vdi.c
@@ -797,41 +797,11 @@ int read_vdis(char *data, int len, unsigned int *rsp_len)
 
 struct deletion_work {
 	struct work work;
-
 	uint32_t target_vid;
-	int delete_vid_count;
-	uint32_t *delete_vid_array;
-
+	bool succeed;
 	int finish_fd;		/* eventfd for notifying finish */
 };
 
-static int delete_inode(uint32_t vid)
-{
-	struct sd_inode *inode = NULL;
-	int ret = SD_RES_SUCCESS;
-
-	inode = xzalloc(sizeof(*inode));
-	ret = sd_read_object(vid_to_vdi_oid(vid), (char *)inode,
-			     SD_INODE_HEADER_SIZE, 0);
-	if (ret != SD_RES_SUCCESS) {
-		ret = SD_RES_EIO;
-		goto out;
-	}
-
-	memset(inode->name, 0, sizeof(inode->name));
-
-	ret = sd_write_object(vid_to_vdi_oid(vid), (char *)inode,
-			      SD_INODE_HEADER_SIZE, 0, false);
-	if (ret != 0) {
-		ret = SD_RES_EIO;
-		goto out;
-	}
-
-out:
-	free(inode);
-	return ret;
-}
-
 static int notify_vdi_deletion(uint32_t vdi_id)
 {
 	struct sd_req hdr;
@@ -875,16 +845,20 @@ static void delete_cb(struct sd_index *idx, void *arg, int ignore)
 	}
 }
 
-static int delete_one_vdi(uint32_t vdi_id)
+static void delete_vdi_work(struct work *work)
 {
+	struct deletion_work *dw =
+		container_of(work, struct deletion_work, work);
 	int ret = 0;
 	uint32_t i, nr_deleted, nr_objs;
 	struct sd_inode *inode = NULL;
+	uint32_t vdi_id = dw->target_vid;
 
 	inode = malloc(sizeof(*inode));
 	if (!inode) {
 		sd_err("failed to allocate memory");
-		return -1;
+		dw->succeed = false;
+		return;
 	}
 
 	ret = read_backend_object(vid_to_vdi_oid(vdi_id),
@@ -892,7 +866,7 @@ static int delete_one_vdi(uint32_t vdi_id)
 
 	if (ret != SD_RES_SUCCESS) {
 		sd_err("cannot find VDI object");
-		ret = -1;
+		dw->succeed = false;
 		goto out;
 	}
 
@@ -909,21 +883,20 @@ static int delete_one_vdi(uint32_t vdi_id)
 				continue;
 
 			oid = vid_to_data_oid(vid, i);
-
-			if (vid != inode->vdi_id) {
-				sd_debug("object %" PRIx64 " is base's data, "
-					 "would not be deleted.", oid);
-				continue;
-			}
-
-			ret = sd_remove_object(oid);
+			ret = sd_dec_object_refcnt(oid,
+						inode->gref[i].generation,
+						inode->gref[i].count);
 			if (ret != SD_RES_SUCCESS)
-				sd_err("remove object %" PRIx64 " fail, %d",
+				sd_err("discard ref %" PRIx64 " fail, %d",
 				       oid, ret);
 
 			nr_deleted++;
 		}
 	} else {
+		/*
+		 * todo: generational reference counting is not supported by
+		 * hypervolume yet
+		 */
 		struct delete_arg arg = {inode, &nr_deleted};
 		sd_inode_index_walk(inode, delete_cb, &arg);
 	}
@@ -933,6 +906,8 @@ static int delete_one_vdi(uint32_t vdi_id)
 
 	inode->vdi_size = 0;
 	memset(inode->name, 0, sizeof(inode->name));
+	memset((char *)inode + SD_INODE_HEADER_SIZE, 0,
+	       SD_INODE_SIZE - SD_INODE_HEADER_SIZE);
 
 	sd_write_object(vid_to_vdi_oid(vdi_id), (void *)inode,
 			sizeof(*inode), 0, false);
@@ -941,173 +916,27 @@ static int delete_one_vdi(uint32_t vdi_id)
 		notify_vdi_deletion(vdi_id);
 out:
 	free(inode);
-	return ret;
+	dw->succeed = true;
 }
 
-static void delete_vdis_work(struct work *work)
-{
-	struct deletion_work *dw =
-		container_of(work, struct deletion_work, work);
-
-	for (int i = 0; i < dw->delete_vid_count; i++) {
-		int ret;
-
-		ret = delete_one_vdi(dw->delete_vid_array[i]);
-		if (ret < 0)
-			sd_err("deleting VDI %x failed",
-			       dw->delete_vid_array[i]);
-	}
-}
-
-static void delete_vdis_done(struct work *work)
+static void delete_vdi_done(struct work *work)
 {
 	struct deletion_work *dw =
 		container_of(work, struct deletion_work, work);
 
 	eventfd_xwrite(dw->finish_fd, 1);
-
-	/* the deletion info is completed */
-	free(dw->delete_vid_array);
+	if (!dw->succeed)
+		sd_err("deleting vdi: %x failed", dw->target_vid);
+	/* the deletion work is completed */
 	free(dw);
 }
 
-static int fill_delete_vid_array(struct deletion_work *dw, uint32_t root_vid)
-{
-	int ret = 0;
-	struct sd_inode *inode = NULL;
-	int done = 0;
-	uint32_t vid;
-
-	inode = malloc(SD_INODE_HEADER_SIZE);
-	if (!inode) {
-		sd_err("failed to allocate memory");
-		return -1;
-	}
-
-	dw->delete_vid_array[dw->delete_vid_count++] = root_vid;
-
-	do {
-		vid = dw->delete_vid_array[done++];
-		ret = read_backend_object(vid_to_vdi_oid(vid), (char *)inode,
-					  SD_INODE_HEADER_SIZE, 0);
-		if (ret != SD_RES_SUCCESS) {
-			sd_err("cannot find VDI object");
-			ret = -1;
-			break;
-		}
-
-		if (!vdi_is_deleted(inode) && vid != dw->target_vid) {
-			ret = 1;
-			break;
-		}
-
-		for (int i = 0; i < ARRAY_SIZE(inode->child_vdi_id); i++) {
-			if (!inode->child_vdi_id[i])
-				continue;
-
-			dw->delete_vid_array[dw->delete_vid_count++] =
-				inode->child_vdi_id[i];
-		}
-	} while (dw->delete_vid_array[done]);
-
-	free(inode);
-	return ret;
-}
-
-static uint64_t get_vdi_root(uint32_t vid, bool *cloned)
-{
-	int ret;
-	struct sd_inode *inode = NULL;
-
-	*cloned = false;
-
-	inode = malloc(SD_INODE_HEADER_SIZE);
-	if (!inode) {
-		sd_err("failed to allocate memory");
-		return 0;
-	}
-
-	do {
-		ret = read_backend_object(vid_to_vdi_oid(vid), (char *)inode,
-					  SD_INODE_HEADER_SIZE, 0);
-		if (ret != SD_RES_SUCCESS) {
-			sd_err("cannot find VDI object");
-			vid = 0;
-			break;
-		}
-
-		if (vid == inode->vdi_id && inode->snap_id == 1
-		    && inode->parent_vdi_id != 0 && !inode->snap_ctime) {
-			sd_debug("vdi %" PRIx32 " is a cloned vdi.", vid);
-			/* current vdi is a cloned vdi */
-			*cloned = true;
-		}
-
-		if (!inode->parent_vdi_id)
-			break;
-
-		vid = inode->parent_vdi_id;
-	} while (true);
-
-	free(inode);
-	return vid;
-}
-
-static void clear_parent_child_vdi(uint32_t vid)
-{
-	struct sd_inode * inode = xmalloc(SD_INODE_HEADER_SIZE);
-	uint32_t pvid, i;
-	int ret;
-
-	ret = read_backend_object(vid_to_vdi_oid(vid), (char *)inode,
-				  SD_INODE_HEADER_SIZE, 0);
-	if (ret != SD_RES_SUCCESS) {
-		sd_err("failed to read inode %"PRIx32, vid);
-		goto out;
-	}
-
-	pvid = inode->parent_vdi_id;
-	if (!pvid)
-		goto out;
-	ret = read_backend_object(vid_to_vdi_oid(pvid), (char *)inode,
-				  SD_INODE_HEADER_SIZE, 0);
-	if (ret != SD_RES_SUCCESS) {
-		sd_err("failed to read parent inode %"PRIx32, pvid);
-		goto out;
-	}
-
-	for (i = 0; i < MAX_CHILDREN; i++)
-		if (inode->child_vdi_id[i] == vid) {
-			inode->child_vdi_id[i] = 0;
-			break;
-		}
-
-	if (i == MAX_CHILDREN) {
-		sd_info("failed to find child %"PRIx32, vid);
-		goto out;
-	}
-
-	ret = sd_write_object(vid_to_vdi_oid(pvid), (char *)inode,
-			      SD_INODE_HEADER_SIZE, 0, false);
-	if (ret != SD_RES_SUCCESS) {
-		sd_err("failed to update parent %"PRIx32, pvid);
-		goto out;
-	}
-	sd_debug("parent %"PRIx32, pvid);
-out:
-	free(inode);
-}
-
 static int start_deletion(struct request *req, uint32_t vid)
 {
 	struct deletion_work *dw = NULL;
 	int ret = SD_RES_SUCCESS, finish_fd;
-	bool cloned;
-	uint32_t root_vid;
 
 	dw = xzalloc(sizeof(*dw));
-	dw->delete_vid_array = xzalloc(SD_INODE_SIZE - SD_INODE_HEADER_SIZE);
-	dw->delete_vid_count = 0;
 	dw->target_vid = vid;
 	finish_fd = dw->finish_fd = eventfd(0, 0);
 	if (dw->finish_fd < 0) {
@@ -1116,67 +945,20 @@ static int start_deletion(struct request *req, uint32_t vid)
 		goto out;
 	}
 
-	root_vid = get_vdi_root(dw->target_vid, &cloned);
-	if (!root_vid) {
-		ret = SD_RES_EIO;
-		goto out;
-	}
-
-	ret = fill_delete_vid_array(dw, root_vid);
-	if (ret < 0) {
-		ret = SD_RES_EIO;
-		goto out;
-	} else if (ret == 1) {
-		/*
-		 * if the VDI is a cloned VDI, delete its objects
-		 * no matter whether the VDI tree is clear.
-		 */
-		ret = SD_RES_SUCCESS;
-
-		if (cloned) {
-			dw->delete_vid_array[0] = vid;
-			dw->delete_vid_count = 1;
-			/*
-			 * FIXME:
-			 *
-			 * We can't clear snapshot's parent because it is not
-			 * removed. We only remove the whole snapshot chain. So
-			 * we can only create MAX_CHILDREN snapshots for one
-			 * base even if we later remove some of them.
-			 *
-			 * But for clone (writable snapshot, we can clear
-			 * parent for deletion, thus make room for new clones.
-			 */
-			clear_parent_child_vdi(vid);
-		} else {
-			sd_debug("snapshot chain has valid vdi, just mark vdi %"
-				 PRIx32 " as deleted.", dw->target_vid);
-			delete_inode(dw->target_vid);
-			goto out;
-		}
-	}
-
-	sd_debug("number of VDI deletion: %d", dw->delete_vid_count);
-
-	if (dw->delete_vid_count == 0)
-		goto out;
-
-	dw->work.fn = delete_vdis_work;
-	dw->work.done = delete_vdis_done;
+	dw->work.fn = delete_vdi_work;
+	dw->work.done = delete_vdi_done;
 
 	queue_work(sys->deletion_wqueue, &dw->work);
 
 	/*
-	 * the event fd is written by delete_one_vdi_done(), when all vdis of
-	 * deletion_work are deleted
+	 * the event fd is written by delete_vdi_done(), when all reference
+	 * counters are decremented
 	 */
 	eventfd_xread(finish_fd);
 	close(finish_fd);
 
 	return ret;
 out:
-	if (dw)
-		free(dw->delete_vid_array);
 	free(dw);
 
 	return ret;
-- 
1.7.10.4




More information about the sheepdog mailing list