Commit 6433c103 authored by Xiaodong Liu's avatar Xiaodong Liu Committed by Changpeng Liu
Browse files

blobfs: add blobfs_create RPC as mkfs



Following test/blobfs/mkfs case, add it as one RPC
method to let build a new blobfs on given block
device.

Change-Id: I0ffbb1add95dfbc8655e0238ed6f3cd519dd945b
Signed-off-by: default avatarXiaodong Liu <xiaodong.liu@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/466485


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
parent 3ce759a1
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -79,6 +79,8 @@ A new blobfs module `bdev` has been added to simplify the operations of blobfs o

Function spdk_blobfs_bdev_detect is added to detect whether blobfs exists on the given block device.

Function spdk_blobfs_bdev_create is added to create a blobfs on the given block device.

### nvme

Added `no_shn_notification` to NVMe controller initialization options, users can enable
@@ -137,6 +139,8 @@ RPC method.

Added `blobfs_detect` RPC method to detect whether a blobfs exists on given bdev.

Added `blobfs_create` RPC method to build blobfs on given bdev.

## v19.07:

### ftl
+37 −0
Original line number Diff line number Diff line
@@ -5734,6 +5734,43 @@ Example response:
}
~~~

## blobfs_create {#rpc_blobfs_create}

Build blobfs on bdev.

### Parameters

Name                    | Optional | Type        | Description
----------------------- | -------- | ----------- | -----------
bdev_name               | Required | string      | Block device name to create blobfs
cluster_sz              | Optional | number      | Size of cluster in bytes. Must be multiple of 4KiB page size, default and minimal value is 1M.

### Example

Example request:

~~~
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "blobfs_create",
  "params": {
    "bdev_name": "Malloc0",
    "cluster_sz": 1M
  }
}
~~~

Example response:

~~~
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "true"
}
~~~

# Miscellaneous RPC commands

## bdev_nvme_send_cmd {#rpc_bdev_nvme_send_cmd}
+11 −0
Original line number Diff line number Diff line
@@ -63,6 +63,17 @@ typedef void (*spdk_blobfs_bdev_op_complete)(void *cb_arg, int fserrno);
void spdk_blobfs_bdev_detect(const char *bdev_name,
			     spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg);

/**
 * Create a blobfs on the given device.
 *
 * \param bdev_name Name of block device.
 * \param cluster_sz Size of cluster in bytes. Must be multiple of 4KiB page size.
 * \param cb_fn Called when the creation is complete.
 * \param cb_arg Argument passed to function cb_fn.
 */
void spdk_blobfs_bdev_create(const char *bdev_name, uint32_t cluster_sz,
			     spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg);

#ifdef __cplusplus
}
#endif
+68 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include "spdk/stdinc.h"
#include "spdk/blobfs.h"
#include "spdk/bdev.h"
#include "spdk/bdev_module.h"
#include "spdk/event.h"
#include "spdk/blob_bdev.h"
#include "spdk/blobfs_bdev.h"
@@ -44,6 +45,11 @@

#include "spdk_internal/log.h"

/* Dummy bdev module used to to claim bdevs. */
static struct spdk_bdev_module blobfs_bdev_module = {
	.name	= "blobfs",
};

static void
blobfs_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
		     void *event_ctx)
@@ -141,3 +147,65 @@ invalid:

	cb_fn(cb_arg, rc);
}

void
spdk_blobfs_bdev_create(const char *bdev_name, uint32_t cluster_sz,
			spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
{
	struct blobfs_bdev_operation_ctx *ctx;
	struct spdk_blobfs_opts blobfs_opt;
	struct spdk_bs_dev *bs_dev;
	struct spdk_bdev_desc *desc;
	int rc;

	ctx = calloc(1, sizeof(*ctx));
	if (ctx == NULL) {
		SPDK_ERRLOG("Failed to allocate ctx.\n");
		cb_fn(cb_arg, -ENOMEM);

		return;
	}

	ctx->bdev_name = bdev_name;
	ctx->cb_fn = cb_fn;
	ctx->cb_arg = cb_arg;

	/* Creation requires WRITE operation */
	rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc);
	if (rc != 0) {
		SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Failed to open bdev(%s): %s\n", ctx->bdev_name, spdk_strerror(rc));

		goto invalid;
	}

	bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
	if (bs_dev == NULL) {
		SPDK_INFOLOG(SPDK_LOG_BLOBFS,  "Failed to create a blobstore block device from bdev desc\n");
		rc = -ENOMEM;
		spdk_bdev_close(desc);

		goto invalid;
	}

	rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
	if (rc) {
		SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Blobfs base bdev already claimed by another bdev\n");
		bs_dev->destroy(bs_dev);

		goto invalid;
	}

	spdk_fs_opts_init(&blobfs_opt);
	if (cluster_sz) {
		blobfs_opt.cluster_sz = cluster_sz;
	}

	spdk_fs_init(bs_dev, &blobfs_opt, NULL, blobfs_bdev_load_cb_to_unload, ctx);

	return;

invalid:
	free(ctx);

	cb_fn(cb_arg, rc);
}
+102 −0
Original line number Diff line number Diff line
@@ -44,6 +44,12 @@

#include "spdk_internal/log.h"

#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif

#define MIN_CLUSTER_SZ (1024 * 1024)

struct rpc_blobfs_detect {
	char *bdev_name;

@@ -115,3 +121,99 @@ spdk_rpc_blobfs_detect(struct spdk_jsonrpc_request *request,
}

SPDK_RPC_REGISTER("blobfs_detect", spdk_rpc_blobfs_detect, SPDK_RPC_RUNTIME)

struct rpc_blobfs_create {
	char *bdev_name;
	uint64_t cluster_sz;

	struct spdk_jsonrpc_request *request;
};

static void
free_rpc_blobfs_create(struct rpc_blobfs_create *req)
{
	free(req->bdev_name);
	free(req);
}

static int
rpc_decode_cluster_sz(const struct spdk_json_val *val, void *out)
{
	uint64_t *cluster_sz = out;
	char *sz_str = NULL;
	bool has_prefix;
	int rc;

	rc = spdk_json_decode_string(val, &sz_str);
	if (rc) {
		SPDK_NOTICELOG("Invalid parameter value: cluster_sz\n");
		return -EINVAL;
	}

	rc = spdk_parse_capacity(sz_str, cluster_sz, &has_prefix);
	free(sz_str);

	if (rc || *cluster_sz % PAGE_SIZE != 0 || *cluster_sz < MIN_CLUSTER_SZ) {
		SPDK_NOTICELOG("Invalid parameter value: cluster_sz\n");
		return -EINVAL;
	}

	SPDK_DEBUGLOG(SPDK_LOG_BLOBFS, "cluster_sz of blobfs: %ld\n", *cluster_sz);
	return 0;
}

static const struct spdk_json_object_decoder rpc_blobfs_create_decoders[] = {
	{"bdev_name", offsetof(struct rpc_blobfs_create, bdev_name), spdk_json_decode_string},
	{"cluster_sz", offsetof(struct rpc_blobfs_create, cluster_sz), rpc_decode_cluster_sz, true},
};

static void
_rpc_blobfs_create_done(void *cb_arg, int fserrno)
{
	struct rpc_blobfs_create *req = cb_arg;
	struct spdk_json_write_ctx *w;

	if (fserrno != 0) {
		spdk_jsonrpc_send_error_response(req->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
						 spdk_strerror(-fserrno));

		return;
	}

	w = spdk_jsonrpc_begin_result(req->request);
	spdk_json_write_bool(w, true);
	spdk_jsonrpc_end_result(req->request, w);

	free_rpc_blobfs_create(req);
}

static void
spdk_rpc_blobfs_create(struct spdk_jsonrpc_request *request,
		       const struct spdk_json_val *params)
{
	struct rpc_blobfs_create *req;

	req = calloc(1, sizeof(*req));
	if (req == NULL) {
		SPDK_ERRLOG("could not allocate rpc_blobfs_create request.\n");
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
		return;
	}

	if (spdk_json_decode_object(params, rpc_blobfs_create_decoders,
				    SPDK_COUNTOF(rpc_blobfs_create_decoders),
				    req)) {
		SPDK_ERRLOG("spdk_json_decode_object failed\n");
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
						 "spdk_json_decode_object failed");

		free_rpc_blobfs_create(req);

		return;
	}

	req->request = request;
	spdk_blobfs_bdev_create(req->bdev_name, req->cluster_sz, _rpc_blobfs_create_done, req);
}

SPDK_RPC_REGISTER("blobfs_create", spdk_rpc_blobfs_create, SPDK_RPC_RUNTIME)
Loading