changeset 787:f53967574f3e

objstore: implement file unlink Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Wed, 25 Mar 2020 12:33:44 -0400
parents 3fc635b4636f
children 1eef9314f649
files src/objstore/CMakeLists.txt src/objstore/obj_dir.c src/objstore/obj_dir_unlink.c src/objstore/obj_ops.c src/objstore/objstore_impl.h
diffstat 5 files changed, 160 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/src/objstore/CMakeLists.txt	Tue Mar 31 13:09:46 2020 -0400
+++ b/src/objstore/CMakeLists.txt	Wed Mar 25 12:33:44 2020 -0400
@@ -27,6 +27,7 @@
 	obj.c
 	obj_dir.c
 	obj_dir_create.c
+	obj_dir_unlink.c
 	obj_ops.c
 	obj_txn.c
 	objstore.c
--- a/src/objstore/obj_dir.c	Tue Mar 31 13:09:46 2020 -0400
+++ b/src/objstore/obj_dir.c	Wed Mar 25 12:33:44 2020 -0400
@@ -401,26 +401,3 @@
 
 	return ret;
 }
-
-int dir_unlink(struct objver *dirver, const char *name, const struct noid *desired)
-{
-	uint8_t raw[DIR_BLOCK_SIZE];
-	struct ndirent_mem ent;
-	int ret;
-
-	ret = dir_lookup_entry(dirver, name, raw, &ent, NULL, NULL);
-	if (ret)
-		return ret;
-
-	if (ent.all_deleted)
-		return -ENOENT;
-
-	if (ent.conflicts && noid_is_null(desired))
-		return -ENOTUNIQ;
-
-	FIXME("not yet implemented");
-
-	/* TODO: mark dirent tgt as removed */
-
-	return -ENOTSUP;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/objstore/obj_dir_unlink.c	Wed Mar 25 12:33:44 2020 -0400
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2015-2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "dir.h"
+
+static int __dir_unlink_update(struct dirblock *block, const char *name,
+			       const struct noid *desired)
+{
+	const size_t namelen = strlen(name);
+	size_t non_deleted_targets;
+	size_t i, j;
+
+	/* find the dirent */
+	for (i = 0; i < block->ndirents; i++) {
+		if (namelen != block->entries[i].dirent.namelen)
+			continue;
+
+		if (!strncmp(name, block->entries[i].name, namelen))
+			break;
+	}
+
+	VERIFY3U(i, <, block->ndirents);
+
+	VERIFY(!block->entries[i].dirent.all_deleted);
+
+	/* find the target */
+	for (j = 0; j < block->entries[i].dirent.ntgts; j++) {
+		struct ndirent_tgt *tgt = &block->entries[i].tgts[j];
+
+		if (tgt->deleted)
+			continue;
+
+		if (noid_is_null(desired))
+			break; /* found it */
+
+		/* looking for a specific target */
+
+		if (tgt->type == NDIRENT_TYPE_GRAFT) {
+			if (xuuid_compare(&tgt->graft, noid_get_vol(desired)))
+				continue;
+		} else {
+			if ((tgt->host != noid_get_allocator(desired)) ||
+			    (tgt->uniq != noid_get_uniq(desired)))
+				continue;
+		}
+	}
+
+	VERIFY3U(j, <, block->entries[i].dirent.ntgts);
+	VERIFY(!block->entries[i].tgts[j].deleted);
+
+	if (block->entries[i].tgts[j].type == NDIRENT_TYPE_DIR)
+		return -EISDIR;
+
+	/* update the target */
+	block->entries[i].tgts[j].deleted = true;
+
+	non_deleted_targets = 0;
+	for (j = 0; j < block->entries[i].dirent.ntgts; j++)
+		if (!block->entries[i].tgts[j].deleted)
+			non_deleted_targets++;
+
+	if (!block->entries[i].dirent.conflicts)
+		VERIFY3U(non_deleted_targets, ==, 0);
+
+	block->entries[i].dirent.conflicts = (non_deleted_targets > 1);
+	block->entries[i].dirent.all_deleted = (non_deleted_targets == 0);
+
+	return 0;
+}
+
+int dir_unlink(struct txn *txn, struct objver *dirver, const char *name,
+	       const struct noid *desired)
+{
+	uint8_t raw[DIR_BLOCK_SIZE];
+	struct ndirent_mem ent;
+	struct dirblock block;
+	struct buffer buffer;
+	uint64_t diroff;
+	uint16_t ndirents;
+	int ret;
+
+	ret = dir_lookup_entry(dirver, name, raw, &ent, &diroff,
+			       &ndirents);
+	if (ret)
+		return ret;
+
+	if (ent.all_deleted)
+		return -ENOENT;
+
+	if (ent.conflicts && noid_is_null(desired))
+		return -ENOTUNIQ;
+
+	/* parse the block */
+	ret = dirblock_parse(&block, raw, ndirents);
+	if (ret)
+		return ret;
+
+	/* update the dirent target */
+	ret = __dir_unlink_update(&block, name, desired);
+	if (ret)
+		return ret;
+
+	/* serialize the block & write it out */
+	ret = buffer_init_heap(&buffer, DIR_BLOCK_SIZE);
+	if (ret)
+		return ret;
+
+	VERIFY0(buffer_truncate(&buffer, 0));
+
+	ret = dirblock_serialize(&block, &buffer);
+	if (ret) {
+		buffer_free(&buffer);
+		return ret;
+	}
+
+	obj_write(txn, dirver, &buffer, diroff);
+
+	return 0;
+}
--- a/src/objstore/obj_ops.c	Tue Mar 31 13:09:46 2020 -0400
+++ b/src/objstore/obj_ops.c	Wed Mar 25 12:33:44 2020 -0400
@@ -431,6 +431,7 @@
 int objstore_unlink(struct objstore_open_obj_info *diropen, const char *name,
 		    const struct noid *desired)
 {
+	struct txn txn;
 	struct obj *dir;
 	int ret;
 
@@ -446,10 +447,26 @@
 		return -EROFS;
 
 	MXLOCK(&dir->lock);
-	if (!NATTR_ISDIR(diropen->ver->attrs.mode))
+
+	if (!NATTR_ISDIR(diropen->ver->attrs.mode)) {
 		ret = -ENOTDIR;
-	else
-		ret = dir_unlink(diropen->ver, name, desired);
+		goto err;
+	}
+
+	ret = txn_begin(&txn, diropen->ver->obj->clone);
+	if (ret)
+		goto err;
+
+	ret = obj_cow(&txn, diropen);
+	if (ret)
+		goto err_txn;
+
+	ret = dir_unlink(&txn, diropen->ver, name, desired);
+
+err_txn:
+	ret = txn_commitabort(&txn, ret);
+
+err:
 	MXUNLOCK(&dir->lock);
 
 	return ret;
--- a/src/objstore/objstore_impl.h	Tue Mar 31 13:09:46 2020 -0400
+++ b/src/objstore/objstore_impl.h	Wed Mar 25 12:33:44 2020 -0400
@@ -83,7 +83,7 @@
 		       struct ndirent *child);
 extern int dir_create(struct txn *txn, struct objver *dirver, const char *name,
 		      uint16_t mode, struct noid *child);
-extern int dir_unlink(struct objver *dirver, const char *name,
+extern int dir_unlink(struct txn *txn, struct objver *dirver, const char *name,
 		      const struct noid *desired);
 
 /*