Commit 2d18887f authored by Cunyin Chang's avatar Cunyin Chang Committed by Jim Harris
Browse files

blobfs: Make the behaviour of "delete file" as unlink.



Mark the file as deleted in the function spdk_fs_delete_file()
when the referance is not 0, and delete the file when it is closed,
make the behaviour as "unlink".

Change-Id: Ia934bb73c82c48fdbab79dbe4b56296a73abc01e
Signed-off-by: default avatarCunyin Chang <cunyin.chang@intel.com>
Reviewed-on: https://review.gerrithub.io/374944


Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
parent 09af33b6
Loading
Loading
Loading
Loading
+101 −23
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ struct spdk_file {
	struct spdk_blob	*blob;
	char			*name;
	uint64_t		length;
	bool                    is_deleted;
	bool			open_for_writing;
	uint64_t		length_flushed;
	uint64_t		append_pos;
@@ -97,6 +98,11 @@ struct spdk_file {
	TAILQ_ENTRY(spdk_file)	cache_tailq;
};

struct spdk_deleted_file {
	spdk_blob_id	id;
	TAILQ_ENTRY(spdk_deleted_file)	tailq;
};

struct spdk_filesystem {
	struct spdk_blob_store	*bs;
	TAILQ_HEAD(, spdk_file)	files;
@@ -136,6 +142,9 @@ struct spdk_fs_cb_args {
	int rc;
	bool from_request;
	union {
		struct {
			TAILQ_HEAD(, spdk_deleted_file)	deleted_files;
		} fs_load;
		struct {
			uint64_t	length;
		} truncate;
@@ -484,19 +493,57 @@ file_alloc(struct spdk_filesystem *fs)
	return file;
}

static void iter_delete_cb(void *ctx, int bserrno);

static int
_handle_deleted_files(struct spdk_fs_request *req)
{
	struct spdk_fs_cb_args *args = &req->args;
	struct spdk_filesystem *fs = args->fs;

	if (!TAILQ_EMPTY(&args->op.fs_load.deleted_files)) {
		struct spdk_deleted_file *deleted_file;

		deleted_file = TAILQ_FIRST(&args->op.fs_load.deleted_files);
		TAILQ_REMOVE(&args->op.fs_load.deleted_files, deleted_file, tailq);
		spdk_bs_md_delete_blob(fs->bs, deleted_file->id, iter_delete_cb, req);
		free(deleted_file);
		return 0;
	}

	return 1;
}

static void
iter_delete_cb(void *ctx, int bserrno)
{
	struct spdk_fs_request *req = ctx;
	struct spdk_fs_cb_args *args = &req->args;
	struct spdk_filesystem *fs = args->fs;

	if (_handle_deleted_files(req) == 0)
		return;

	args->fn.fs_op_with_handle(args->arg, fs, 0);
	free_fs_request(req);

}

static void
iter_cb(void *ctx, struct spdk_blob *blob, int rc)
{
	struct spdk_fs_request *req = ctx;
	struct spdk_fs_cb_args *args = &req->args;
	struct spdk_filesystem *fs = args->fs;
	struct spdk_file *f;
	uint64_t *length;
	const char *name;
	uint32_t *is_deleted;
	size_t value_len;

	if (rc == -ENOENT) {
		/* Finished iterating */
		if (_handle_deleted_files(req) == 0)
			return;
		args->fn.fs_op_with_handle(args->arg, fs, 0);
		free_fs_request(req);
		return;
@@ -519,8 +566,14 @@ iter_cb(void *ctx, struct spdk_blob *blob, int rc)
		free_fs_request(req);
		return;
	}

	assert(value_len == 8);

	/* This file could be deleted last time without close it, then app crashed, so we delete it now */
	rc = spdk_bs_md_get_xattr_value(blob, "is_deleted", (const void **)&is_deleted, &value_len);
	if (rc < 0) {
		struct spdk_file *f;

		f = file_alloc(fs);
		if (f == NULL) {
			args->fn.fs_op_with_handle(args->arg, fs, -ENOMEM);
@@ -534,6 +587,18 @@ iter_cb(void *ctx, struct spdk_blob *blob, int rc)
		f->length_flushed = *length;
		f->append_pos = *length;
		SPDK_DEBUGLOG(SPDK_TRACE_BLOBFS, "added file %s length=%ju\n", f->name, f->length);
	} else {
		struct spdk_deleted_file *deleted_file;

		deleted_file = calloc(1, sizeof(*deleted_file));
		if (deleted_file == NULL) {
			args->fn.fs_op_with_handle(args->arg, fs, -ENOMEM);
			free_fs_request(req);
			return;
		}
		deleted_file->id = spdk_blob_get_id(blob);
		TAILQ_INSERT_TAIL(&args->op.fs_load.deleted_files, deleted_file, tailq);
	}

	spdk_bs_md_iter_next(fs->bs, &blob, iter_cb, req);
}
@@ -586,7 +651,7 @@ spdk_fs_load(struct spdk_bs_dev *dev, fs_send_request_fn send_request_fn,
	args->fn.fs_op_with_handle = cb_fn;
	args->arg = cb_arg;
	args->fs = fs;

	TAILQ_INIT(&args->op.fs_load.deleted_files);
	spdk_bs_load(dev, load_cb, req);
}

@@ -919,6 +984,11 @@ spdk_fs_open_file_async(struct spdk_filesystem *fs, const char *name, uint32_t f
		return;
	}

	if (f != NULL && f->is_deleted == true) {
		cb_fn(cb_arg, NULL, -ENOENT);
		return;
	}

	req = alloc_fs_request(fs->md_target.md_fs_channel);
	if (req == NULL) {
		cb_fn(cb_arg, NULL, -ENOMEM);
@@ -1160,18 +1230,24 @@ spdk_fs_delete_file_async(struct spdk_filesystem *fs, const char *name,
		return;
	}

	if (f->ref_count > 0) {
		/* For now, do not allow deleting files with open references. */
		cb_fn(cb_arg, -EBUSY);
		return;
	}

	req = alloc_fs_request(fs->md_target.md_fs_channel);
	if (req == NULL) {
		cb_fn(cb_arg, -ENOMEM);
		return;
	}

	args = &req->args;
	args->fn.file_op = cb_fn;
	args->arg = cb_arg;

	if (f->ref_count > 0) {
		/* If the ref > 0, we mark the file as deleted and delete it when we close it. */
		f->is_deleted = true;
		spdk_blob_md_set_xattr(f->blob, "is_deleted", &f->is_deleted, sizeof(bool));
		spdk_bs_md_sync_blob(f->blob, blob_delete_cb, args);
		return;
	}

	TAILQ_REMOVE(&fs->files, f, tailq);

	cache_free_buffers(f);
@@ -1182,9 +1258,6 @@ spdk_fs_delete_file_async(struct spdk_filesystem *fs, const char *name,
	free(f->tree);
	free(f);

	args = &req->args;
	args->fn.file_op = cb_fn;
	args->arg = cb_arg;
	spdk_bs_md_delete_blob(fs->bs, blobid, blob_delete_cb, req);
}

@@ -2218,7 +2291,12 @@ __file_close_async_done(void *ctx, int bserrno)
{
	struct spdk_fs_request *req = ctx;
	struct spdk_fs_cb_args *args = &req->args;
	struct spdk_file *file = args->file;

	if (file->is_deleted) {
		spdk_fs_delete_file_async(file->fs, file->name, blob_delete_cb, ctx);
		return;
	}
	args->fn.file_op(args->arg, bserrno);
	free_fs_request(req);
}
+2 −12
Original line number Diff line number Diff line
@@ -150,24 +150,14 @@ fs_open(void)
	CU_ASSERT(iter == NULL);

	g_fserrno = 0;
	/* Delete should fail, since we have an open reference. */
	/* Delete should successful, we will mark the file as deleted. */
	spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
	CU_ASSERT(g_fserrno == -EBUSY);
	CU_ASSERT(g_fserrno == 0);
	CU_ASSERT(!TAILQ_EMPTY(&fs->files));

	g_fserrno = 1;
	spdk_file_close_async(g_file, fs_op_complete, NULL);
	CU_ASSERT(g_fserrno == 0);
	CU_ASSERT(g_file->ref_count == 0);

	g_fserrno = 0;
	spdk_file_close_async(g_file, fs_op_complete, NULL);
	CU_ASSERT(g_fserrno == -EBADF);
	CU_ASSERT(g_file->ref_count == 0);

	g_fserrno = 1;
	spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
	CU_ASSERT(g_fserrno == 0);
	CU_ASSERT(TAILQ_EMPTY(&fs->files));

	g_fserrno = 1;
+37 −1
Original line number Diff line number Diff line
@@ -286,6 +286,41 @@ cache_append_no_cache(void)
	ut_send_request(_fs_unload, NULL);
}

static void
fs_delete_file_without_close(void)
{
	int rc;
	struct spdk_io_channel *channel;
	struct spdk_file *file;

	ut_send_request(_fs_init, NULL);
	spdk_allocate_thread(_fs_send_msg, NULL, "thread0");
	channel = spdk_fs_alloc_io_channel_sync(g_fs);
	CU_ASSERT(channel != NULL);

	rc = spdk_fs_open_file(g_fs, channel, "testfile", SPDK_BLOBFS_OPEN_CREATE, &g_file);
	CU_ASSERT(rc == 0);

	rc = spdk_fs_delete_file(g_fs, channel, "testfile");
	CU_ASSERT(rc == 0);
	CU_ASSERT(g_file->ref_count != 0);
	CU_ASSERT(g_file->is_deleted == true);

	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file);
	CU_ASSERT(rc != 0);

	spdk_file_close(g_file, channel);

	rc = spdk_fs_open_file(g_fs, channel, "testfile", 0, &file);
	CU_ASSERT(rc != 0);

	spdk_fs_free_io_channel(channel);
	spdk_free_thread();

	ut_send_request(_fs_unload, NULL);

}

static void
terminate_spdk_thread(void *arg)
{
@@ -337,7 +372,8 @@ int main(int argc, char **argv)
		CU_add_test(suite, "write", cache_write) == NULL ||
		CU_add_test(suite, "write_null_buffer", cache_write_null_buffer) == NULL ||
		CU_add_test(suite, "create_sync", fs_create_sync) == NULL ||
		CU_add_test(suite, "append_no_cache", cache_append_no_cache) == NULL
		CU_add_test(suite, "append_no_cache", cache_append_no_cache) == NULL ||
		CU_add_test(suite, "delete_file_without_close", fs_delete_file_without_close) == NULL
	) {
		CU_cleanup_registry();
		return CU_get_error();