Commit c22cf8f7 authored by Denis Barakhtanov's avatar Denis Barakhtanov Committed by Tomasz Zawadzki
Browse files

bdev/daos: Pass through IO errors to upper layers



In order to enhance the operational aspect, it is more convenient to expose
the underlying errors instead of generic EIO.
This improvement enables quick detection of issues such as out-of-space errors
or incorrect permissions.

Additionally, this patch addresses error codes from `daos_xxx()` and `dfs_xxx()`
API calls. The latter always returns positive `errno`, while the former returns
a subset of `DER_XXX` that requires conversion to the POSIX equivalent.

Signed-off-by: default avatarDenis Barakhtanov <denis.barahtanov@croit.io>
Change-Id: I3f3302c2e1b591448bf5e96f4daf3af5dd8847f1
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/18457


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <smatsumoto@nvidia.com>
parent d5da6912
Loading
Loading
Loading
Loading
+123 −43
Original line number Diff line number Diff line
@@ -33,8 +33,7 @@ struct bdev_daos_task {
	struct spdk_thread *submit_td;
	struct spdk_bdev_io *bdev_io;

	enum spdk_bdev_io_status status;

	int io_status;
	uint64_t offset;

	/* DAOS version of iovec and scatter/gather */
@@ -71,7 +70,7 @@ static pthread_mutex_t g_bdev_daos_init_mutex = PTHREAD_MUTEX_INITIALIZER;

static int bdev_daos_initialize(void);

static int bdev_get_daos_engine(void);
static int bdev_daos_get_engine(void);
static int bdev_daos_put_engine(void);

static int
@@ -88,6 +87,77 @@ static struct spdk_bdev_module daos_if = {

SPDK_BDEV_MODULE_REGISTER(daos, &daos_if)


/* Convert DAOS errors to closest POSIX errno
 * This is pretty much copy of daos_der2errno()
 * from https://github.com/daos-stack/daos/blob/master/src/include/daos/common.h
 * but unfortunately it's not exported in DAOS packages
 */
static inline int
daos2posix_errno(int err)
{
	if (err > 0) {
		return EINVAL;
	}

	switch (err) {
	case -DER_SUCCESS:
		return 0;
	case -DER_NO_PERM:
	case -DER_EP_RO:
	case -DER_EP_OLD:
		return EPERM;
	case -DER_ENOENT:
	case -DER_NONEXIST:
		return ENOENT;
	case -DER_INVAL:
	case -DER_NOTYPE:
	case -DER_NOSCHEMA:
	case -DER_NOLOCAL:
	case -DER_NO_HDL:
	case -DER_IO_INVAL:
		return EINVAL;
	case -DER_KEY2BIG:
	case -DER_REC2BIG:
		return E2BIG;
	case -DER_EXIST:
		return EEXIST;
	case -DER_UNREACH:
		return EHOSTUNREACH;
	case -DER_NOSPACE:
		return ENOSPC;
	case -DER_ALREADY:
		return EALREADY;
	case -DER_NOMEM:
		return ENOMEM;
	case -DER_TIMEDOUT:
		return ETIMEDOUT;
	case -DER_BUSY:
	case -DER_EQ_BUSY:
		return EBUSY;
	case -DER_AGAIN:
		return EAGAIN;
	case -DER_PROTO:
		return EPROTO;
	case -DER_IO:
		return EIO;
	case -DER_CANCELED:
	case DER_OP_CANCELED:
		return ECANCELED;
	case -DER_OVERFLOW:
		return EOVERFLOW;
	case -DER_BADPATH:
	case -DER_NOTDIR:
		return ENOTDIR;
	case -DER_STALE:
		return ESTALE;
	case -DER_TX_RESTART:
		return ERESTART;
	default:
		return EIO;
	}
};

static void
bdev_daos_free(struct bdev_daos *bdev_daos)
{
@@ -132,21 +202,25 @@ _bdev_daos_io_complete(void *bdev_daos_task)
{
	struct bdev_daos_task *task = bdev_daos_task;

	SPDK_DEBUGLOG(bdev_daos, "completed IO at %#lx with status %s\n", task->offset,
		      task->status == SPDK_BDEV_IO_STATUS_SUCCESS ? "SUCCESS" : "FAILURE");
	SPDK_DEBUGLOG(bdev_daos, "completed IO at %#lx with status %s (errno=%d)\n",
		      task->offset, task->io_status ? "FAILURE" : "SUCCESS", task->io_status);

	spdk_bdev_io_complete(spdk_bdev_io_from_ctx(task), task->status);
	if (task->io_status == 0) {
		spdk_bdev_io_complete(spdk_bdev_io_from_ctx(task), SPDK_BDEV_IO_STATUS_SUCCESS);
	} else {
		spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(task), task->io_status);
	}
}

static void
bdev_daos_io_complete(struct spdk_bdev_io *bdev_io, enum spdk_bdev_io_status status)
bdev_daos_io_complete(struct spdk_bdev_io *bdev_io, int io_status)
{
	struct bdev_daos_task *task = (struct bdev_daos_task *)bdev_io->driver_ctx;
	struct spdk_thread *current_thread = spdk_get_thread();

	assert(task->submit_td != NULL);

	task->status = status;
	task->io_status = io_status;
	if (task->submit_td != current_thread) {
		spdk_thread_send_msg(task->submit_td, _bdev_daos_io_complete, task);
	} else {
@@ -178,7 +252,7 @@ bdev_daos_writev(struct bdev_daos *daos, struct bdev_daos_io_channel *ch,
	if ((rc = daos_event_init(&task->ev, ch->queue, NULL))) {
		SPDK_ERRLOG("%s: could not initialize async event: " DF_RC "\n",
			    daos->disk.name, DP_RC(rc));
		return -EINVAL;
		return -daos2posix_errno(rc);
	}

	for (int i = 0; i < iovcnt; i++, iov++) {
@@ -191,10 +265,10 @@ bdev_daos_writev(struct bdev_daos *daos, struct bdev_daos_io_channel *ch,
	task->offset = offset;

	if ((rc = dfs_write(ch->dfs, ch->obj, &task->sgl, offset, &task->ev))) {
		SPDK_ERRLOG("%s: could not start async write: " DF_RC "\n",
			    daos->disk.name, DP_RC(rc));
		SPDK_ERRLOG("%s: could not start async write: %s\n",
			    daos->disk.name, strerror(rc));
		daos_event_fini(&task->ev);
		return -EINVAL;
		return -rc;
	}

	return nbytes;
@@ -224,7 +298,7 @@ bdev_daos_readv(struct bdev_daos *daos, struct bdev_daos_io_channel *ch,
	if ((rc = daos_event_init(&task->ev, ch->queue, NULL))) {
		SPDK_ERRLOG("%s: could not initialize async event: " DF_RC "\n",
			    daos->disk.name, DP_RC(rc));
		return -EINVAL;
		return -daos2posix_errno(rc);
	}

	for (int i = 0; i < iovcnt; i++, iov++) {
@@ -237,10 +311,10 @@ bdev_daos_readv(struct bdev_daos *daos, struct bdev_daos_io_channel *ch,
	task->offset = offset;

	if ((rc = dfs_read(ch->dfs, ch->obj, &task->sgl, offset, &task->read_size, &task->ev))) {
		SPDK_ERRLOG("%s: could not start async read: " DF_RC "\n",
			    daos->disk.name, DP_RC(rc));
		SPDK_ERRLOG("%s: could not start async read: %s\n",
			    daos->disk.name, strerror(rc));
		daos_event_fini(&task->ev);
		return -EINVAL;
		return -rc;
	}

	return nbytes;
@@ -254,7 +328,7 @@ bdev_daos_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
	struct bdev_daos_io_channel *dch = spdk_io_channel_get_ctx(ch);

	if (!success) {
		bdev_daos_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
		return;
	}

@@ -267,7 +341,7 @@ bdev_daos_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
			     bdev_io->u.bdev.offset_blocks * bdev_io->bdev->blocklen);

	if (rc < 0) {
		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
		spdk_bdev_io_complete_aio_status(bdev_io, rc);
		return;
	}
}
@@ -334,8 +408,13 @@ static int64_t
bdev_daos_unmap(struct bdev_daos_io_channel *ch, uint64_t nbytes,
		uint64_t offset)
{
	int rc = 0;

	SPDK_DEBUGLOG(bdev_daos, "unmap at %#lx with size %#lx\n", offset, nbytes);
	return dfs_punch(ch->dfs, ch->obj, offset, nbytes);
	if ((rc = dfs_punch(ch->dfs, ch->obj, offset, nbytes))) {
		return -rc;
	}
	return 0;
}

static void
@@ -359,7 +438,7 @@ _bdev_daos_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_
				      bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
				      bdev_io->u.bdev.offset_blocks * bdev_io->bdev->blocklen);
		if (rc < 0) {
			spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
			spdk_bdev_io_complete_aio_status(bdev_io, rc);
			return;
		}
		break;
@@ -382,9 +461,9 @@ _bdev_daos_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_
		if (!rc) {
			spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
		} else {
			SPDK_DEBUGLOG(bdev_daos, "%s: could not unmap: " DF_RC "\n",
				      dch->disk->disk.name, DP_RC((int)rc));
			spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
			SPDK_DEBUGLOG(bdev_daos, "%s: could not unmap: %s",
				      dch->disk->disk.name, strerror(-rc));
			spdk_bdev_io_complete_aio_status(bdev_io, rc);
		}

		break;
@@ -437,13 +516,13 @@ bdev_daos_channel_poll(void *arg)
	}

	for (int i = 0; i < rc; ++i) {
		int status = 0;
		struct bdev_daos_task *task = SPDK_CONTAINEROF(evp[i], struct bdev_daos_task, ev);
		enum spdk_bdev_io_status status = SPDK_BDEV_IO_STATUS_SUCCESS;

		assert(task != NULL);

		if (task->ev.ev_error != DER_SUCCESS) {
			status = SPDK_BDEV_IO_STATUS_FAILED;
			status = -task->ev.ev_error;
		}

		daos_event_fini(&task->ev);
@@ -518,40 +597,40 @@ bdev_daos_io_channel_setup_daos(struct bdev_daos_io_channel *ch)
	int fd_oflag = O_CREAT | O_RDWR;
	mode_t mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;

	rc = bdev_get_daos_engine();
	rc = bdev_daos_get_engine();
	if (rc) {
		SPDK_ERRLOG("could not initialize DAOS engine: " DF_RC "\n", DP_RC(rc));
		return rc;
		return -daos2posix_errno(rc);
	}

	SPDK_DEBUGLOG(bdev_daos, "connecting to daos pool '%s'\n", daos->pool_name);
	if ((rc = daos_pool_connect(daos->pool_name, NULL, DAOS_PC_RW, &ch->pool, &pinfo, NULL))) {
		SPDK_ERRLOG("%s: could not connect to daos pool: " DF_RC "\n",
			    daos->disk.name, DP_RC(rc));
		return rc;
		return -daos2posix_errno(rc);
	}
	SPDK_DEBUGLOG(bdev_daos, "connecting to daos container '%s'\n", daos->cont_name);
	if ((rc = daos_cont_open(ch->pool, daos->cont_name, DAOS_COO_RW, &ch->cont, &cinfo, NULL))) {
		SPDK_ERRLOG("%s: could not open daos container: " DF_RC "\n",
			    daos->disk.name, DP_RC(rc));
		rc = daos2posix_errno(rc);
		goto cleanup_pool;
	}
	SPDK_DEBUGLOG(bdev_daos, "mounting daos dfs\n");
	if ((rc = dfs_mount(ch->pool, ch->cont, O_RDWR, &ch->dfs))) {
		SPDK_ERRLOG("%s: could not mount daos dfs: " DF_RC "\n",
			    daos->disk.name, DP_RC(rc));
		SPDK_ERRLOG("%s: could not mount daos dfs: %s\n", daos->disk.name, strerror(rc));
		goto cleanup_cont;
	}
	SPDK_DEBUGLOG(bdev_daos, "opening dfs object\n");
	if ((rc = dfs_open(ch->dfs, NULL, daos->disk.name, mode, fd_oflag, daos->oclass,
			   0, NULL, &ch->obj))) {
		SPDK_ERRLOG("%s: could not open dfs object: " DF_RC "\n",
			    daos->disk.name, DP_RC(rc));
		SPDK_ERRLOG("%s: could not open dfs object: %s\n", daos->disk.name, strerror(rc));
		goto cleanup_mount;
	}
	if ((rc = daos_eq_create(&ch->queue))) {
		SPDK_ERRLOG("%s: could not create daos event queue: " DF_RC "\n",
			    daos->disk.name, DP_RC(rc));
		rc = daos2posix_errno(rc);
		goto cleanup_obj;
	}

@@ -566,18 +645,19 @@ cleanup_cont:
cleanup_pool:
	daos_pool_disconnect(ch->pool, NULL);

	return rc;
	return -rc;
}

static int
bdev_daos_io_channel_create_cb(void *io_device, void *ctx_buf)
{
	int rc;
	struct bdev_daos_io_channel *ch = ctx_buf;

	ch->disk = io_device;

	if (bdev_daos_io_channel_setup_daos(ch)) {
		return -EINVAL;
	if ((rc = bdev_daos_io_channel_setup_daos(ch))) {
		return rc;
	}

	SPDK_DEBUGLOG(bdev_daos, "%s: starting daos event queue poller\n",
@@ -602,10 +682,10 @@ bdev_daos_io_channel_destroy_cb(void *io_device, void *ctx_buf)
		SPDK_ERRLOG("could not destroy daos event queue: " DF_RC "\n", DP_RC(rc));
	}
	if ((rc = dfs_release(ch->obj))) {
		SPDK_ERRLOG("could not release dfs object: " DF_RC "\n", DP_RC(rc));
		SPDK_ERRLOG("could not release dfs object: %s\n", strerror(rc));
	}
	if ((rc = dfs_umount(ch->dfs))) {
		SPDK_ERRLOG("could not unmount dfs: " DF_RC "\n", DP_RC(rc));
		SPDK_ERRLOG("could not unmount dfs: %s\n", strerror(rc));
	}
	if ((rc = daos_cont_close(ch->cont, NULL))) {
		SPDK_ERRLOG("could not close container: " DF_RC "\n", DP_RC(rc));
@@ -703,11 +783,11 @@ create_bdev_daos(struct spdk_bdev **bdev,
	daos->disk.fn_table = &daos_fn_table;
	daos->disk.module = &daos_if;

	rc = bdev_get_daos_engine();
	rc = bdev_daos_get_engine();
	if (rc) {
		SPDK_ERRLOG("could not initialize DAOS engine: " DF_RC "\n", DP_RC(rc));
		bdev_daos_free(daos);
		return rc;
		return -daos2posix_errno(rc);
	}

	/* We try to connect to the DAOS container during channel creation, so simulate
@@ -717,7 +797,7 @@ create_bdev_daos(struct spdk_bdev **bdev,
	 */
	rc = bdev_daos_io_channel_create_cb(daos, &ch);
	if (rc) {
		SPDK_ERRLOG("'%s' could not initialize io-channel: %s", name, strerror(-rc));
		SPDK_ERRLOG("'%s' could not initialize io-channel: %s\n", name, strerror(-rc));
		bdev_daos_free(daos);
		return rc;
	}
@@ -782,8 +862,8 @@ bdev_daos_resize(const char *name, const uint64_t new_size_in_mb)
	rc = dfs_punch(dch->dfs, dch->obj, new_size_in_byte, DFS_MAX_FSIZE);
	spdk_put_io_channel(ch);
	if (rc != 0) {
		SPDK_ERRLOG("failed to resize daos bdev: " DF_RC "\n", DP_RC(rc));
		rc = -EINTR;
		SPDK_ERRLOG("failed to resize daos bdev: %s", strerror(rc));
		rc = -rc;
		goto exit;
	}

@@ -815,7 +895,7 @@ delete_bdev_daos(const char *bdev_name, spdk_bdev_unregister_cb cb_fn, void *cb_
}

static int
bdev_get_daos_engine(void)
bdev_daos_get_engine(void)
{
	int rc = 0;