2016-09-20 04:12:45 +00:00
|
|
|
/*-
|
|
|
|
* BSD LICENSE
|
|
|
|
*
|
|
|
|
* Copyright (c) Intel Corporation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2017-05-02 18:18:25 +00:00
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
|
2017-07-13 04:08:53 +00:00
|
|
|
#include "bdev_rbd.h"
|
2016-10-10 01:01:47 +00:00
|
|
|
|
2016-09-20 04:12:45 +00:00
|
|
|
#include <rbd/librbd.h>
|
|
|
|
#include <rados/librados.h>
|
2017-05-02 18:18:25 +00:00
|
|
|
#include <sys/eventfd.h>
|
2016-09-20 04:12:45 +00:00
|
|
|
|
|
|
|
#include "spdk/conf.h"
|
2016-11-07 17:08:11 +00:00
|
|
|
#include "spdk/env.h"
|
2016-09-20 04:12:45 +00:00
|
|
|
#include "spdk/bdev.h"
|
2018-06-11 20:32:15 +00:00
|
|
|
#include "spdk/thread.h"
|
2017-08-09 00:54:26 +00:00
|
|
|
#include "spdk/json.h"
|
2017-06-02 17:25:43 +00:00
|
|
|
#include "spdk/string.h"
|
2017-10-13 00:20:10 +00:00
|
|
|
#include "spdk/util.h"
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2018-05-23 21:01:03 +00:00
|
|
|
#include "spdk/bdev_module.h"
|
2017-08-25 21:22:46 +00:00
|
|
|
#include "spdk_internal/log.h"
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2017-07-20 14:47:34 +00:00
|
|
|
#define SPDK_RBD_QUEUE_DEPTH 128
|
|
|
|
|
2017-07-13 04:08:53 +00:00
|
|
|
static int bdev_rbd_count = 0;
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2018-07-02 07:24:17 +00:00
|
|
|
#define BDEV_RBD_POLL_US 50
|
|
|
|
|
2017-07-13 04:08:53 +00:00
|
|
|
struct bdev_rbd {
|
2016-09-20 04:12:45 +00:00
|
|
|
struct spdk_bdev disk;
|
2016-10-14 11:17:54 +00:00
|
|
|
char *rbd_name;
|
2018-10-26 12:06:15 +00:00
|
|
|
char *user_id;
|
2016-11-08 18:25:29 +00:00
|
|
|
char *pool_name;
|
2018-10-26 12:06:15 +00:00
|
|
|
char **config;
|
2016-09-20 04:12:45 +00:00
|
|
|
rbd_image_info_t info;
|
2017-07-13 04:08:53 +00:00
|
|
|
TAILQ_ENTRY(bdev_rbd) tailq;
|
2018-02-23 23:51:20 +00:00
|
|
|
struct spdk_poller *reset_timer;
|
|
|
|
struct spdk_bdev_io *reset_bdev_io;
|
2016-09-20 04:12:45 +00:00
|
|
|
};
|
|
|
|
|
2017-07-13 04:08:53 +00:00
|
|
|
struct bdev_rbd_io_channel {
|
2016-09-20 04:12:45 +00:00
|
|
|
rados_ioctx_t io_ctx;
|
|
|
|
rados_t cluster;
|
2016-10-08 05:09:01 +00:00
|
|
|
struct pollfd pfd;
|
2016-09-20 04:12:45 +00:00
|
|
|
rbd_image_t image;
|
2017-07-13 04:08:53 +00:00
|
|
|
struct bdev_rbd *disk;
|
2017-11-17 21:49:36 +00:00
|
|
|
struct spdk_poller *poller;
|
2016-09-20 04:12:45 +00:00
|
|
|
};
|
|
|
|
|
2017-10-13 00:20:10 +00:00
|
|
|
struct bdev_rbd_io {
|
|
|
|
uint64_t remaining_len;
|
|
|
|
int num_segments;
|
|
|
|
bool failed;
|
|
|
|
};
|
|
|
|
|
2016-10-14 11:17:54 +00:00
|
|
|
static void
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_free(struct bdev_rbd *rbd)
|
2016-10-14 11:17:54 +00:00
|
|
|
{
|
|
|
|
if (!rbd) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-02 17:25:43 +00:00
|
|
|
free(rbd->disk.name);
|
2016-10-14 11:17:54 +00:00
|
|
|
free(rbd->rbd_name);
|
2018-10-26 12:06:15 +00:00
|
|
|
free(rbd->user_id);
|
2016-11-08 18:25:29 +00:00
|
|
|
free(rbd->pool_name);
|
2018-10-26 12:06:15 +00:00
|
|
|
spdk_bdev_rbd_free_config(rbd->config);
|
2016-10-14 11:17:54 +00:00
|
|
|
free(rbd);
|
|
|
|
}
|
|
|
|
|
2018-10-26 12:06:15 +00:00
|
|
|
void
|
|
|
|
spdk_bdev_rbd_free_config(char **config)
|
|
|
|
{
|
|
|
|
char **entry;
|
|
|
|
|
|
|
|
if (config) {
|
|
|
|
for (entry = config; *entry; entry++) {
|
|
|
|
free(*entry);
|
|
|
|
}
|
|
|
|
free(config);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char **
|
|
|
|
spdk_bdev_rbd_dup_config(const char *const *config)
|
|
|
|
{
|
|
|
|
size_t count;
|
|
|
|
char **copy;
|
|
|
|
|
|
|
|
if (!config) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
for (count = 0; config[count]; count++) {}
|
|
|
|
copy = calloc(count + 1, sizeof(*copy));
|
|
|
|
if (!copy) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
for (count = 0; config[count]; count++) {
|
|
|
|
if (!(copy[count] = strdup(config[count]))) {
|
|
|
|
spdk_bdev_rbd_free_config(copy);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2016-09-20 04:12:45 +00:00
|
|
|
static int
|
2018-10-26 12:06:15 +00:00
|
|
|
bdev_rados_context_init(const char *user_id, const char *rbd_pool_name, const char *const *config,
|
|
|
|
rados_t *cluster, rados_ioctx_t *io_ctx)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2018-10-26 12:06:15 +00:00
|
|
|
ret = rados_create(cluster, user_id);
|
2016-09-20 04:12:45 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
SPDK_ERRLOG("Failed to create rados_t struct\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-10-26 12:06:15 +00:00
|
|
|
if (config) {
|
|
|
|
const char *const *entry = config;
|
|
|
|
while (*entry) {
|
|
|
|
ret = rados_conf_set(*cluster, entry[0], entry[1]);
|
|
|
|
if (ret < 0) {
|
|
|
|
SPDK_ERRLOG("Failed to set %s = %s\n", entry[0], entry[1]);
|
|
|
|
rados_shutdown(*cluster);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
entry += 2;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = rados_conf_read_file(*cluster, NULL);
|
|
|
|
if (ret < 0) {
|
|
|
|
SPDK_ERRLOG("Failed to read conf file\n");
|
|
|
|
rados_shutdown(*cluster);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = rados_connect(*cluster);
|
|
|
|
if (ret < 0) {
|
2018-10-24 07:46:12 +00:00
|
|
|
SPDK_ERRLOG("Failed to connect to rbd_pool\n");
|
2016-09-20 04:12:45 +00:00
|
|
|
rados_shutdown(*cluster);
|
2018-10-24 07:46:12 +00:00
|
|
|
return -1;
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = rados_ioctx_create(*cluster, rbd_pool_name, io_ctx);
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
SPDK_ERRLOG("Failed to create ioctx\n");
|
|
|
|
rados_shutdown(*cluster);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2018-10-26 12:06:15 +00:00
|
|
|
bdev_rbd_init(const char *user_id, const char *rbd_pool_name, const char *const *config,
|
|
|
|
const char *rbd_name, rbd_image_info_t *info)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
rados_t cluster = NULL;
|
|
|
|
rados_ioctx_t io_ctx = NULL;
|
|
|
|
rbd_image_t image = NULL;
|
|
|
|
|
2018-10-26 12:06:15 +00:00
|
|
|
ret = bdev_rados_context_init(user_id, rbd_pool_name, config, &cluster, &io_ctx);
|
2016-09-20 04:12:45 +00:00
|
|
|
if (ret < 0) {
|
2018-10-26 12:06:15 +00:00
|
|
|
SPDK_ERRLOG("Failed to create rados context for user_id=%s and rbd_pool=%s\n",
|
|
|
|
user_id ? user_id : "admin (the default)", rbd_pool_name);
|
2016-09-20 04:12:45 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = rbd_open(io_ctx, rbd_name, &image, NULL);
|
|
|
|
if (ret < 0) {
|
|
|
|
SPDK_ERRLOG("Failed to open specified rbd device\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
ret = rbd_stat(image, info, sizeof(*info));
|
|
|
|
rbd_close(image);
|
|
|
|
if (ret < 0) {
|
|
|
|
SPDK_ERRLOG("Failed to stat specified rbd device\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2018-06-14 08:27:52 +00:00
|
|
|
rados_ioctx_destroy(io_ctx);
|
2016-09-20 04:12:45 +00:00
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
rados_ioctx_destroy(io_ctx);
|
|
|
|
rados_shutdown(cluster);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_exit(rbd_image_t image)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
|
|
|
rbd_flush(image);
|
|
|
|
rbd_close(image);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_finish_aiocb(rbd_completion_t cb, void *arg)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
2016-10-08 05:09:01 +00:00
|
|
|
/* Doing nothing here */
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-07-20 14:47:34 +00:00
|
|
|
bdev_rbd_start_aio(rbd_image_t image, struct spdk_bdev_io *bdev_io,
|
2017-07-13 04:08:53 +00:00
|
|
|
void *buf, uint64_t offset, size_t len)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
|
|
|
int ret;
|
2017-07-20 14:47:34 +00:00
|
|
|
rbd_completion_t comp;
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2017-07-20 14:47:34 +00:00
|
|
|
ret = rbd_aio_create_completion(bdev_io, bdev_rbd_finish_aiocb,
|
|
|
|
&comp);
|
2016-09-20 04:12:45 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-11-08 20:03:40 +00:00
|
|
|
if (bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
|
2016-09-20 04:12:45 +00:00
|
|
|
ret = rbd_aio_read(image, offset, len,
|
2017-07-20 14:47:34 +00:00
|
|
|
buf, comp);
|
2016-11-08 20:03:40 +00:00
|
|
|
} else if (bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE) {
|
2016-09-20 04:12:45 +00:00
|
|
|
ret = rbd_aio_write(image, offset, len,
|
2017-07-20 14:47:34 +00:00
|
|
|
buf, comp);
|
2016-11-08 20:03:40 +00:00
|
|
|
} else if (bdev_io->type == SPDK_BDEV_IO_TYPE_FLUSH) {
|
2017-07-20 14:47:34 +00:00
|
|
|
ret = rbd_aio_flush(image, comp);
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ret < 0) {
|
2017-07-20 14:47:34 +00:00
|
|
|
rbd_aio_release(comp);
|
2016-09-20 04:12:45 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-13 17:36:19 +00:00
|
|
|
static int bdev_rbd_library_init(void);
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2017-10-13 00:20:10 +00:00
|
|
|
static int
|
|
|
|
bdev_rbd_get_ctx_size(void)
|
|
|
|
{
|
|
|
|
return sizeof(struct bdev_rbd_io);
|
|
|
|
}
|
|
|
|
|
2018-03-09 22:20:21 +00:00
|
|
|
static struct spdk_bdev_module rbd_if = {
|
2018-03-06 18:52:46 +00:00
|
|
|
.name = "rbd",
|
|
|
|
.module_init = bdev_rbd_library_init,
|
|
|
|
.get_ctx_size = bdev_rbd_get_ctx_size,
|
|
|
|
|
|
|
|
};
|
2019-02-05 10:46:48 +00:00
|
|
|
SPDK_BDEV_MODULE_REGISTER(rbd, &rbd_if)
|
2016-09-20 04:12:45 +00:00
|
|
|
|
|
|
|
static int64_t
|
2017-10-12 23:34:46 +00:00
|
|
|
bdev_rbd_rw(struct bdev_rbd *disk, struct spdk_io_channel *ch,
|
|
|
|
struct spdk_bdev_io *bdev_io, struct iovec *iov,
|
|
|
|
int iovcnt, size_t len, uint64_t offset)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
2017-10-13 00:20:10 +00:00
|
|
|
struct bdev_rbd_io *rbd_io = (struct bdev_rbd_io *)bdev_io->driver_ctx;
|
2017-07-13 04:08:53 +00:00
|
|
|
struct bdev_rbd_io_channel *rbdio_ch = spdk_io_channel_get_ctx(ch);
|
2017-10-13 00:20:10 +00:00
|
|
|
size_t remaining = len;
|
|
|
|
int i, rc;
|
|
|
|
|
|
|
|
rbd_io->remaining_len = 0;
|
|
|
|
rbd_io->num_segments = 0;
|
|
|
|
rbd_io->failed = false;
|
|
|
|
|
|
|
|
for (i = 0; i < iovcnt && remaining > 0; i++) {
|
|
|
|
size_t seg_len = spdk_min(remaining, iov[i].iov_len);
|
|
|
|
|
|
|
|
rc = bdev_rbd_start_aio(rbdio_ch->image, bdev_io, iov[i].iov_base, offset, seg_len);
|
|
|
|
if (rc) {
|
|
|
|
/*
|
|
|
|
* This bdev_rbd_start_aio() call failed, but if any previous ones were
|
|
|
|
* submitted, we need to wait for them to finish.
|
|
|
|
*/
|
|
|
|
if (rbd_io->num_segments == 0) {
|
|
|
|
/* No previous I/O submitted - return error code immediately. */
|
|
|
|
return rc;
|
|
|
|
}
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2017-10-13 00:20:10 +00:00
|
|
|
/* Return and wait for outstanding I/O to complete. */
|
|
|
|
rbd_io->failed = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
rbd_io->num_segments++;
|
|
|
|
rbd_io->remaining_len += seg_len;
|
|
|
|
|
|
|
|
offset += seg_len;
|
|
|
|
remaining -= seg_len;
|
2017-12-07 23:23:48 +00:00
|
|
|
}
|
2016-10-04 14:39:27 +00:00
|
|
|
|
2017-10-13 00:20:10 +00:00
|
|
|
return 0;
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
2016-10-11 23:47:27 +00:00
|
|
|
static int64_t
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_flush(struct bdev_rbd *disk, struct spdk_io_channel *ch,
|
2017-07-20 14:47:34 +00:00
|
|
|
struct spdk_bdev_io *bdev_io, uint64_t offset, uint64_t nbytes)
|
2016-10-11 23:47:27 +00:00
|
|
|
{
|
2017-07-13 04:08:53 +00:00
|
|
|
struct bdev_rbd_io_channel *rbdio_ch = spdk_io_channel_get_ctx(ch);
|
2016-10-11 23:47:27 +00:00
|
|
|
|
2017-07-20 14:47:34 +00:00
|
|
|
return bdev_rbd_start_aio(rbdio_ch->image, bdev_io, NULL, offset, nbytes);
|
2016-10-11 23:47:27 +00:00
|
|
|
}
|
|
|
|
|
2018-03-13 00:16:47 +00:00
|
|
|
static int
|
2018-02-23 23:51:20 +00:00
|
|
|
bdev_rbd_reset_timer(void *arg)
|
|
|
|
{
|
|
|
|
struct bdev_rbd *disk = arg;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: This should check if any I/O is still in flight before completing the reset.
|
|
|
|
* For now, just complete after the timer expires.
|
|
|
|
*/
|
|
|
|
spdk_bdev_io_complete(disk->reset_bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
|
|
|
|
spdk_poller_unregister(&disk->reset_timer);
|
|
|
|
disk->reset_bdev_io = NULL;
|
2018-03-13 00:16:47 +00:00
|
|
|
|
|
|
|
return -1;
|
2018-02-23 23:51:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bdev_rbd_reset(struct bdev_rbd *disk, struct spdk_bdev_io *bdev_io)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* HACK: Since librbd doesn't provide any way to cancel outstanding aio, just kick off a
|
|
|
|
* timer to wait for in-flight I/O to complete.
|
|
|
|
*/
|
|
|
|
assert(disk->reset_bdev_io == NULL);
|
|
|
|
disk->reset_bdev_io = bdev_io;
|
|
|
|
disk->reset_timer = spdk_poller_register(bdev_rbd_reset_timer, disk, 1 * 1000 * 1000);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-20 04:12:45 +00:00
|
|
|
static int
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_destruct(void *ctx)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
2017-12-02 00:34:20 +00:00
|
|
|
struct bdev_rbd *rbd = ctx;
|
|
|
|
|
2018-08-31 13:39:27 +00:00
|
|
|
spdk_io_device_unregister(rbd, NULL);
|
|
|
|
|
2017-12-02 00:34:20 +00:00
|
|
|
bdev_rbd_free(rbd);
|
2016-09-20 04:12:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
bdev: Not assert but pass completion status to spdk_bdev_io_get_buf_cb
When the specified buffer size to spdk_bdev_io_get_buf() is greater
than the permitted maximum, spdk_bdev_io_get_buf() asserts simply and
doesn't call the specified callback function.
SPDK SCSI library doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
Bdev perf tool also doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
When we support DIF insert and strip in iSCSI target, the read
buffer size iSCSI initiator requests and the read buffer size iSCSI target
requests will become different.
Even after that, iSCSI initiator and iSCSI target will negotiate correctly
not to cause buffer overflow in spdk_bdev_io_get_buf(), but if iSCSI
initiator ignores the result of negotiation, iSCSI initiator can request
read buffer size larger than the permitted maximum, and can cause
failure in iSCSI target. This is very flagile and should be avoided.
This patch do the following
- Add the completion status of spdk_bdev_io_get_buf() to
spdk_bdev_io_get_buf_cb(),
- spdk_bdev_io_get_buf() calls spdk_bdev_io_get_buf_cb() by setting
success to false, and return.
- spdk_bdev_io_get_buf_cb() in each bdev module calls assert if success
is false.
Subsequent patches will process the case that success is false
in spdk_bdev_io_get_buf_cb().
Change-Id: I76429a86e18a69aa085a353ac94743296d270b82
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/446045
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
2019-02-25 00:34:28 +00:00
|
|
|
static void
|
|
|
|
bdev_rbd_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
|
|
|
|
bool success)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2019-02-25 01:43:13 +00:00
|
|
|
if (!success) {
|
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
|
|
|
return;
|
|
|
|
}
|
bdev: Not assert but pass completion status to spdk_bdev_io_get_buf_cb
When the specified buffer size to spdk_bdev_io_get_buf() is greater
than the permitted maximum, spdk_bdev_io_get_buf() asserts simply and
doesn't call the specified callback function.
SPDK SCSI library doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
Bdev perf tool also doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
When we support DIF insert and strip in iSCSI target, the read
buffer size iSCSI initiator requests and the read buffer size iSCSI target
requests will become different.
Even after that, iSCSI initiator and iSCSI target will negotiate correctly
not to cause buffer overflow in spdk_bdev_io_get_buf(), but if iSCSI
initiator ignores the result of negotiation, iSCSI initiator can request
read buffer size larger than the permitted maximum, and can cause
failure in iSCSI target. This is very flagile and should be avoided.
This patch do the following
- Add the completion status of spdk_bdev_io_get_buf() to
spdk_bdev_io_get_buf_cb(),
- spdk_bdev_io_get_buf() calls spdk_bdev_io_get_buf_cb() by setting
success to false, and return.
- spdk_bdev_io_get_buf_cb() in each bdev module calls assert if success
is false.
Subsequent patches will process the case that success is false
in spdk_bdev_io_get_buf_cb().
Change-Id: I76429a86e18a69aa085a353ac94743296d270b82
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/446045
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
2019-02-25 00:34:28 +00:00
|
|
|
|
2017-10-12 23:34:46 +00:00
|
|
|
ret = bdev_rbd_rw(bdev_io->bdev->ctxt,
|
|
|
|
ch,
|
|
|
|
bdev_io,
|
|
|
|
bdev_io->u.bdev.iovs,
|
|
|
|
bdev_io->u.bdev.iovcnt,
|
|
|
|
bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
|
|
|
|
bdev_io->u.bdev.offset_blocks * bdev_io->bdev->blocklen);
|
2016-09-20 04:12:45 +00:00
|
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-13 04:08:53 +00:00
|
|
|
static int _bdev_rbd_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
|
|
|
switch (bdev_io->type) {
|
|
|
|
case SPDK_BDEV_IO_TYPE_READ:
|
2017-09-22 20:59:55 +00:00
|
|
|
spdk_bdev_io_get_buf(bdev_io, bdev_rbd_get_buf_cb,
|
|
|
|
bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
|
2016-09-20 04:12:45 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SPDK_BDEV_IO_TYPE_WRITE:
|
2017-10-12 23:34:46 +00:00
|
|
|
return bdev_rbd_rw((struct bdev_rbd *)bdev_io->bdev->ctxt,
|
|
|
|
ch,
|
|
|
|
bdev_io,
|
|
|
|
bdev_io->u.bdev.iovs,
|
|
|
|
bdev_io->u.bdev.iovcnt,
|
|
|
|
bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
|
|
|
|
bdev_io->u.bdev.offset_blocks * bdev_io->bdev->blocklen);
|
|
|
|
|
2016-10-11 23:47:27 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_FLUSH:
|
2017-07-13 04:08:53 +00:00
|
|
|
return bdev_rbd_flush((struct bdev_rbd *)bdev_io->bdev->ctxt,
|
|
|
|
ch,
|
2017-07-20 14:47:34 +00:00
|
|
|
bdev_io,
|
2017-09-20 13:10:17 +00:00
|
|
|
bdev_io->u.bdev.offset_blocks * bdev_io->bdev->blocklen,
|
|
|
|
bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
|
2018-02-23 23:51:20 +00:00
|
|
|
|
|
|
|
case SPDK_BDEV_IO_TYPE_RESET:
|
|
|
|
return bdev_rbd_reset((struct bdev_rbd *)bdev_io->bdev->ctxt,
|
|
|
|
bdev_io);
|
|
|
|
|
2016-09-20 04:12:45 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-13 04:08:53 +00:00
|
|
|
static void bdev_rbd_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
2017-07-13 04:08:53 +00:00
|
|
|
if (_bdev_rbd_submit_request(ch, bdev_io) < 0) {
|
2016-09-20 04:12:45 +00:00
|
|
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
|
|
|
switch (io_type) {
|
|
|
|
case SPDK_BDEV_IO_TYPE_READ:
|
|
|
|
case SPDK_BDEV_IO_TYPE_WRITE:
|
2016-10-11 23:47:27 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_FLUSH:
|
2018-02-23 23:51:20 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_RESET:
|
2016-09-20 04:12:45 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-13 00:16:47 +00:00
|
|
|
static int
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_io_poll(void *arg)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
2017-07-13 04:08:53 +00:00
|
|
|
struct bdev_rbd_io_channel *ch = arg;
|
2017-07-20 14:47:34 +00:00
|
|
|
int i, io_status, rc;
|
|
|
|
rbd_completion_t comps[SPDK_RBD_QUEUE_DEPTH];
|
2016-11-08 20:03:40 +00:00
|
|
|
struct spdk_bdev_io *bdev_io;
|
2017-10-13 00:20:10 +00:00
|
|
|
struct bdev_rbd_io *rbd_io;
|
2016-10-08 05:09:01 +00:00
|
|
|
|
|
|
|
rc = poll(&ch->pfd, 1, 0);
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2016-10-08 05:09:01 +00:00
|
|
|
/* check the return value of poll since we have only one fd for each channel */
|
|
|
|
if (rc != 1) {
|
2018-03-13 00:16:47 +00:00
|
|
|
return 0;
|
2016-10-08 05:09:01 +00:00
|
|
|
}
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2017-07-20 14:47:34 +00:00
|
|
|
rc = rbd_poll_io_events(ch->image, comps, SPDK_RBD_QUEUE_DEPTH);
|
2016-10-08 05:09:01 +00:00
|
|
|
for (i = 0; i < rc; i++) {
|
2017-07-20 14:47:34 +00:00
|
|
|
bdev_io = rbd_aio_get_arg(comps[i]);
|
2017-10-13 00:20:10 +00:00
|
|
|
rbd_io = (struct bdev_rbd_io *)bdev_io->driver_ctx;
|
2017-07-20 14:47:34 +00:00
|
|
|
io_status = rbd_aio_get_return_value(comps[i]);
|
2017-10-13 00:20:10 +00:00
|
|
|
|
|
|
|
assert(rbd_io->num_segments > 0);
|
|
|
|
rbd_io->num_segments--;
|
|
|
|
|
2016-11-08 20:03:40 +00:00
|
|
|
if (bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
|
2017-10-13 00:20:10 +00:00
|
|
|
if (io_status > 0) {
|
|
|
|
/* For reads, io_status is the length */
|
|
|
|
rbd_io->remaining_len -= io_status;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rbd_io->num_segments == 0 && rbd_io->remaining_len != 0) {
|
|
|
|
rbd_io->failed = true;
|
2016-10-08 05:09:01 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* For others, 0 means success */
|
2017-10-13 00:20:10 +00:00
|
|
|
if (io_status != 0) {
|
|
|
|
rbd_io->failed = true;
|
2016-10-08 05:09:01 +00:00
|
|
|
}
|
|
|
|
}
|
2017-10-13 00:20:10 +00:00
|
|
|
|
2017-07-20 14:47:34 +00:00
|
|
|
rbd_aio_release(comps[i]);
|
2017-10-13 00:20:10 +00:00
|
|
|
|
|
|
|
if (rbd_io->num_segments == 0) {
|
|
|
|
spdk_bdev_io_complete(bdev_io,
|
|
|
|
rbd_io->failed ? SPDK_BDEV_IO_STATUS_FAILED : SPDK_BDEV_IO_STATUS_SUCCESS);
|
|
|
|
}
|
2016-10-08 05:09:01 +00:00
|
|
|
}
|
2018-03-13 00:16:47 +00:00
|
|
|
|
|
|
|
return rc;
|
2016-10-08 05:09:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_free_channel(struct bdev_rbd_io_channel *ch)
|
2016-10-08 05:09:01 +00:00
|
|
|
{
|
|
|
|
if (!ch) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ch->image) {
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_exit(ch->image);
|
2016-10-08 05:09:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ch->io_ctx) {
|
|
|
|
rados_ioctx_destroy(ch->io_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ch->cluster) {
|
|
|
|
rados_shutdown(ch->cluster);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ch->pfd.fd >= 0) {
|
|
|
|
close(ch->pfd.fd);
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-07 17:08:11 +00:00
|
|
|
static void *
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_handle(void *arg)
|
2016-11-07 17:08:11 +00:00
|
|
|
{
|
2017-07-13 04:08:53 +00:00
|
|
|
struct bdev_rbd_io_channel *ch = arg;
|
2016-11-07 17:08:11 +00:00
|
|
|
void *ret = arg;
|
|
|
|
|
|
|
|
if (rbd_open(ch->io_ctx, ch->disk->rbd_name, &ch->image, NULL) < 0) {
|
|
|
|
SPDK_ERRLOG("Failed to open specified rbd device\n");
|
|
|
|
ret = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-09-20 04:12:45 +00:00
|
|
|
static int
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_create_cb(void *io_device, void *ctx_buf)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
2017-07-13 04:08:53 +00:00
|
|
|
struct bdev_rbd_io_channel *ch = ctx_buf;
|
2016-09-20 04:12:45 +00:00
|
|
|
int ret;
|
|
|
|
|
2018-02-19 22:28:16 +00:00
|
|
|
ch->disk = io_device;
|
2016-09-20 04:12:45 +00:00
|
|
|
ch->image = NULL;
|
|
|
|
ch->io_ctx = NULL;
|
2016-10-08 05:09:01 +00:00
|
|
|
ch->pfd.fd = -1;
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2018-10-26 12:06:15 +00:00
|
|
|
ret = bdev_rados_context_init(ch->disk->user_id, ch->disk->pool_name,
|
|
|
|
(const char *const *)ch->disk->config,
|
|
|
|
&ch->cluster, &ch->io_ctx);
|
2016-09-20 04:12:45 +00:00
|
|
|
if (ret < 0) {
|
2018-10-26 12:06:15 +00:00
|
|
|
SPDK_ERRLOG("Failed to create rados context for user_id %s and rbd_pool=%s\n",
|
|
|
|
ch->disk->user_id ? ch->disk->user_id : "admin (the default)", ch->disk->pool_name);
|
2016-10-08 05:09:01 +00:00
|
|
|
goto err;
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
2017-07-13 04:08:53 +00:00
|
|
|
if (spdk_call_unaffinitized(bdev_rbd_handle, ch) == NULL) {
|
2016-10-08 05:09:01 +00:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ch->pfd.fd = eventfd(0, EFD_NONBLOCK);
|
|
|
|
if (ch->pfd.fd < 0) {
|
|
|
|
SPDK_ERRLOG("Failed to get eventfd\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ch->pfd.events = POLLIN;
|
|
|
|
ret = rbd_set_image_notification(ch->image, ch->pfd.fd, EVENT_TYPE_EVENTFD);
|
|
|
|
if (ret < 0) {
|
|
|
|
SPDK_ERRLOG("Failed to set rbd image notification\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2018-07-02 07:24:17 +00:00
|
|
|
ch->poller = spdk_poller_register(bdev_rbd_io_poll, ch, BDEV_RBD_POLL_US);
|
2016-09-20 04:12:45 +00:00
|
|
|
|
|
|
|
return 0;
|
2016-10-08 05:09:01 +00:00
|
|
|
|
|
|
|
err:
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_free_channel(ch);
|
2016-10-08 05:09:01 +00:00
|
|
|
return -1;
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_destroy_cb(void *io_device, void *ctx_buf)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
2017-07-13 04:08:53 +00:00
|
|
|
struct bdev_rbd_io_channel *io_channel = ctx_buf;
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_free_channel(io_channel);
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2017-11-17 21:49:36 +00:00
|
|
|
spdk_poller_unregister(&io_channel->poller);
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct spdk_io_channel *
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_get_io_channel(void *ctx)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
2017-07-13 04:08:53 +00:00
|
|
|
struct bdev_rbd *rbd_bdev = ctx;
|
2016-09-20 04:12:45 +00:00
|
|
|
|
2018-02-19 22:28:16 +00:00
|
|
|
return spdk_get_io_channel(rbd_bdev);
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
2017-08-09 00:54:26 +00:00
|
|
|
static int
|
2018-02-22 12:48:13 +00:00
|
|
|
bdev_rbd_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
|
2017-08-09 00:54:26 +00:00
|
|
|
{
|
|
|
|
struct bdev_rbd *rbd_bdev = ctx;
|
|
|
|
|
2019-02-01 05:34:45 +00:00
|
|
|
spdk_json_write_named_object_begin(w, "rbd");
|
2017-08-09 00:54:26 +00:00
|
|
|
|
2019-02-01 05:34:45 +00:00
|
|
|
spdk_json_write_named_string(w, "pool_name", rbd_bdev->pool_name);
|
2017-08-09 00:54:26 +00:00
|
|
|
|
2019-02-01 05:34:45 +00:00
|
|
|
spdk_json_write_named_string(w, "rbd_name", rbd_bdev->rbd_name);
|
2017-08-09 00:54:26 +00:00
|
|
|
|
2018-10-26 12:06:15 +00:00
|
|
|
if (rbd_bdev->user_id) {
|
|
|
|
spdk_json_write_named_string(w, "user_id", rbd_bdev->user_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rbd_bdev->config) {
|
|
|
|
char **entry = rbd_bdev->config;
|
|
|
|
|
2019-02-01 05:34:45 +00:00
|
|
|
spdk_json_write_named_object_begin(w, "config");
|
2018-10-26 12:06:15 +00:00
|
|
|
while (*entry) {
|
|
|
|
spdk_json_write_named_string(w, entry[0], entry[1]);
|
|
|
|
entry += 2;
|
|
|
|
}
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
|
2017-08-09 00:54:26 +00:00
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-02-23 19:05:47 +00:00
|
|
|
static void
|
|
|
|
bdev_rbd_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
|
|
|
|
{
|
|
|
|
struct bdev_rbd *rbd = bdev->ctxt;
|
|
|
|
|
|
|
|
spdk_json_write_object_begin(w);
|
|
|
|
|
|
|
|
spdk_json_write_named_string(w, "method", "construct_rbd_bdev");
|
|
|
|
|
|
|
|
spdk_json_write_named_object_begin(w, "params");
|
|
|
|
spdk_json_write_named_string(w, "name", bdev->name);
|
|
|
|
spdk_json_write_named_string(w, "pool_name", rbd->pool_name);
|
|
|
|
spdk_json_write_named_string(w, "rbd_name", rbd->rbd_name);
|
2018-04-05 16:57:37 +00:00
|
|
|
spdk_json_write_named_uint32(w, "block_size", bdev->blocklen);
|
2018-10-26 12:06:15 +00:00
|
|
|
if (rbd->user_id) {
|
|
|
|
spdk_json_write_named_string(w, "user_id", rbd->user_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rbd->config) {
|
|
|
|
char **entry = rbd->config;
|
|
|
|
|
2019-02-01 05:34:45 +00:00
|
|
|
spdk_json_write_named_object_begin(w, "config");
|
2018-10-26 12:06:15 +00:00
|
|
|
while (*entry) {
|
|
|
|
spdk_json_write_named_string(w, entry[0], entry[1]);
|
|
|
|
entry += 2;
|
|
|
|
}
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
|
2018-02-23 19:05:47 +00:00
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
|
2016-09-20 04:12:45 +00:00
|
|
|
static const struct spdk_bdev_fn_table rbd_fn_table = {
|
2017-07-13 04:08:53 +00:00
|
|
|
.destruct = bdev_rbd_destruct,
|
|
|
|
.submit_request = bdev_rbd_submit_request,
|
|
|
|
.io_type_supported = bdev_rbd_io_type_supported,
|
|
|
|
.get_io_channel = bdev_rbd_get_io_channel,
|
2018-02-22 12:48:13 +00:00
|
|
|
.dump_info_json = bdev_rbd_dump_info_json,
|
2018-02-23 19:05:47 +00:00
|
|
|
.write_config_json = bdev_rbd_write_config_json,
|
2016-09-20 04:12:45 +00:00
|
|
|
};
|
|
|
|
|
2016-10-25 23:19:53 +00:00
|
|
|
struct spdk_bdev *
|
2018-10-26 12:06:15 +00:00
|
|
|
spdk_bdev_rbd_create(const char *name, const char *user_id, const char *pool_name,
|
|
|
|
const char *const *config,
|
|
|
|
const char *rbd_name,
|
2018-02-23 19:05:47 +00:00
|
|
|
uint32_t block_size)
|
2016-10-10 01:01:47 +00:00
|
|
|
{
|
2017-07-13 04:08:53 +00:00
|
|
|
struct bdev_rbd *rbd;
|
2016-10-10 01:01:47 +00:00
|
|
|
int ret;
|
|
|
|
|
2016-10-14 11:17:54 +00:00
|
|
|
if ((pool_name == NULL) || (rbd_name == NULL)) {
|
2016-10-25 23:19:53 +00:00
|
|
|
return NULL;
|
2016-10-14 11:17:54 +00:00
|
|
|
}
|
|
|
|
|
2017-07-13 04:08:53 +00:00
|
|
|
rbd = calloc(1, sizeof(struct bdev_rbd));
|
2016-10-10 01:01:47 +00:00
|
|
|
if (rbd == NULL) {
|
2017-07-13 04:08:53 +00:00
|
|
|
SPDK_ERRLOG("Failed to allocate bdev_rbd struct\n");
|
2016-10-25 23:19:53 +00:00
|
|
|
return NULL;
|
2016-10-10 01:01:47 +00:00
|
|
|
}
|
|
|
|
|
2016-10-14 11:17:54 +00:00
|
|
|
rbd->rbd_name = strdup(rbd_name);
|
|
|
|
if (!rbd->rbd_name) {
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_free(rbd);
|
2016-10-25 23:19:53 +00:00
|
|
|
return NULL;
|
2016-10-14 11:17:54 +00:00
|
|
|
}
|
|
|
|
|
2018-10-26 12:06:15 +00:00
|
|
|
if (user_id) {
|
|
|
|
rbd->user_id = strdup(user_id);
|
|
|
|
if (!rbd->user_id) {
|
|
|
|
bdev_rbd_free(rbd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-08 18:25:29 +00:00
|
|
|
rbd->pool_name = strdup(pool_name);
|
|
|
|
if (!rbd->pool_name) {
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_free(rbd);
|
2016-11-08 18:25:29 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-10-26 12:06:15 +00:00
|
|
|
if (config && !(rbd->config = spdk_bdev_rbd_dup_config(config))) {
|
|
|
|
bdev_rbd_free(rbd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = bdev_rbd_init(rbd->user_id, rbd->pool_name,
|
|
|
|
(const char *const *)rbd->config,
|
|
|
|
rbd_name, &rbd->info);
|
2016-10-10 01:01:47 +00:00
|
|
|
if (ret < 0) {
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_free(rbd);
|
2016-10-10 01:01:47 +00:00
|
|
|
SPDK_ERRLOG("Failed to init rbd device\n");
|
2016-10-25 23:19:53 +00:00
|
|
|
return NULL;
|
2016-10-10 01:01:47 +00:00
|
|
|
}
|
|
|
|
|
2018-02-23 19:05:47 +00:00
|
|
|
if (name) {
|
|
|
|
rbd->disk.name = strdup(name);
|
|
|
|
} else {
|
|
|
|
rbd->disk.name = spdk_sprintf_alloc("Ceph%d", bdev_rbd_count);
|
|
|
|
}
|
2017-06-02 17:25:43 +00:00
|
|
|
if (!rbd->disk.name) {
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_free(rbd);
|
2017-06-02 17:25:43 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
rbd->disk.product_name = "Ceph Rbd Disk";
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_count++;
|
2016-10-10 01:01:47 +00:00
|
|
|
|
|
|
|
rbd->disk.write_cache = 0;
|
|
|
|
rbd->disk.blocklen = block_size;
|
|
|
|
rbd->disk.blockcnt = rbd->info.size / rbd->disk.blocklen;
|
|
|
|
rbd->disk.ctxt = rbd;
|
|
|
|
rbd->disk.fn_table = &rbd_fn_table;
|
2018-03-06 18:52:46 +00:00
|
|
|
rbd->disk.module = &rbd_if;
|
2016-10-10 01:01:47 +00:00
|
|
|
|
|
|
|
SPDK_NOTICELOG("Add %s rbd disk to lun\n", rbd->disk.name);
|
|
|
|
|
2018-02-19 22:28:16 +00:00
|
|
|
spdk_io_device_register(rbd, bdev_rbd_create_cb,
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_destroy_cb,
|
2018-08-30 20:26:50 +00:00
|
|
|
sizeof(struct bdev_rbd_io_channel),
|
|
|
|
rbd_name);
|
2017-11-20 09:31:39 +00:00
|
|
|
ret = spdk_bdev_register(&rbd->disk);
|
|
|
|
if (ret) {
|
2018-02-19 22:28:16 +00:00
|
|
|
spdk_io_device_unregister(rbd, NULL);
|
2017-11-20 09:31:39 +00:00
|
|
|
bdev_rbd_free(rbd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-10-25 23:19:53 +00:00
|
|
|
return &rbd->disk;
|
2016-10-10 01:01:47 +00:00
|
|
|
}
|
|
|
|
|
2018-06-22 11:51:35 +00:00
|
|
|
void
|
|
|
|
spdk_bdev_rbd_delete(struct spdk_bdev *bdev, spdk_delete_rbd_complete cb_fn, void *cb_arg)
|
|
|
|
{
|
|
|
|
if (!bdev || bdev->module != &rbd_if) {
|
|
|
|
cb_fn(cb_arg, -ENODEV);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_bdev_unregister(bdev, cb_fn, cb_arg);
|
|
|
|
}
|
|
|
|
|
2017-07-13 17:36:19 +00:00
|
|
|
static int
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_rbd_library_init(void)
|
2016-09-20 04:12:45 +00:00
|
|
|
{
|
2017-05-26 04:58:04 +00:00
|
|
|
int i, rc = 0;
|
2016-09-20 04:12:45 +00:00
|
|
|
const char *val;
|
2016-10-10 01:01:47 +00:00
|
|
|
const char *pool_name;
|
2016-09-20 04:12:45 +00:00
|
|
|
const char *rbd_name;
|
|
|
|
uint32_t block_size;
|
2019-01-22 23:27:37 +00:00
|
|
|
long int tmp;
|
2016-10-10 01:01:47 +00:00
|
|
|
|
2016-09-20 04:12:45 +00:00
|
|
|
struct spdk_conf_section *sp = spdk_conf_find_section(NULL, "Ceph");
|
|
|
|
|
|
|
|
if (sp == NULL) {
|
|
|
|
/*
|
|
|
|
* Ceph section not found. Do not initialize any rbd LUNS.
|
|
|
|
*/
|
2017-05-26 04:58:04 +00:00
|
|
|
goto end;
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Init rbd block devices */
|
|
|
|
for (i = 0; ; i++) {
|
|
|
|
val = spdk_conf_section_get_nval(sp, "Ceph", i);
|
2017-12-07 23:23:48 +00:00
|
|
|
if (val == NULL) {
|
2016-09-20 04:12:45 +00:00
|
|
|
break;
|
2017-12-07 23:23:48 +00:00
|
|
|
}
|
2016-09-20 04:12:45 +00:00
|
|
|
|
|
|
|
/* get the Rbd_pool name */
|
2016-10-10 01:01:47 +00:00
|
|
|
pool_name = spdk_conf_section_get_nmval(sp, "Ceph", i, 0);
|
|
|
|
if (pool_name == NULL) {
|
2016-09-20 04:12:45 +00:00
|
|
|
SPDK_ERRLOG("Ceph%d: rbd pool name needs to be provided\n", i);
|
2017-05-26 04:58:04 +00:00
|
|
|
rc = -1;
|
|
|
|
goto end;
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rbd_name = spdk_conf_section_get_nmval(sp, "Ceph", i, 1);
|
|
|
|
if (rbd_name == NULL) {
|
|
|
|
SPDK_ERRLOG("Ceph%d: format error\n", i);
|
2017-05-26 04:58:04 +00:00
|
|
|
rc = -1;
|
|
|
|
goto end;
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
val = spdk_conf_section_get_nmval(sp, "Ceph", i, 2);
|
|
|
|
|
|
|
|
if (val == NULL) {
|
|
|
|
block_size = 512; /* default value */
|
|
|
|
} else {
|
2019-01-22 23:27:37 +00:00
|
|
|
tmp = spdk_strtol(val, 10);
|
|
|
|
if (tmp <= 0) {
|
|
|
|
SPDK_ERRLOG("Invalid block size\n");
|
|
|
|
rc = -1;
|
|
|
|
goto end;
|
|
|
|
} else if (tmp & 0x1ff) {
|
|
|
|
SPDK_ERRLOG("current block_size = %ld, it should be multiple of 512\n",
|
|
|
|
tmp);
|
2017-05-26 04:58:04 +00:00
|
|
|
rc = -1;
|
|
|
|
goto end;
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
2019-01-22 23:27:37 +00:00
|
|
|
block_size = (uint32_t)tmp;
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
2018-10-26 12:06:15 +00:00
|
|
|
/* TODO(?): user_id and rbd config values */
|
|
|
|
if (spdk_bdev_rbd_create(NULL, NULL, pool_name, NULL, rbd_name, block_size) == NULL) {
|
2017-05-26 04:58:04 +00:00
|
|
|
rc = -1;
|
|
|
|
goto end;
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-26 04:58:04 +00:00
|
|
|
end:
|
2017-07-13 17:36:19 +00:00
|
|
|
return rc;
|
2016-09-20 04:12:45 +00:00
|
|
|
}
|
2017-08-25 21:22:46 +00:00
|
|
|
|
2017-08-30 18:06:33 +00:00
|
|
|
SPDK_LOG_REGISTER_COMPONENT("bdev_rbd", SPDK_LOG_BDEV_RBD)
|