lib/bdev: media management events
Media management event was introduced. It's sent out to notify that some portion of the data needs to be rewritten (e.g. due to data refresh, wear leveling, high error rate, etc.). This type of notification is only utilized by devices exposing raw access to the physical medium (e.g. Open Channel SSDs). Change-Id: Ia30faa5866d71fd597009b441f69c609de974161 Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com> Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/471460 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Broadcom SPDK FC-NVMe CI <spdk-ci.pdl@broadcom.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
parent
64fe514efa
commit
a69f90ddd8
@ -63,7 +63,14 @@ extern "C" {
|
||||
/** Asynchronous event type */
|
||||
enum spdk_bdev_event_type {
|
||||
SPDK_BDEV_EVENT_REMOVE,
|
||||
SPDK_BDEV_EVENT_RESIZE
|
||||
SPDK_BDEV_EVENT_RESIZE,
|
||||
SPDK_BDEV_EVENT_MEDIA_MANAGEMENT,
|
||||
};
|
||||
|
||||
/** Media management event details */
|
||||
struct spdk_bdev_media_event {
|
||||
uint64_t offset;
|
||||
uint64_t num_blocks;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1458,6 +1465,20 @@ void spdk_bdev_histogram_get(struct spdk_bdev *bdev, struct spdk_histogram_data
|
||||
spdk_bdev_histogram_data_cb cb_fn,
|
||||
void *cb_arg);
|
||||
|
||||
/**
|
||||
* Retrieves media events. Can only be called from the context of
|
||||
* SPDK_BDEV_EVENT_MEDIA_MANAGEMENT event callback. These events are sent by
|
||||
* devices exposing raw access to the physical medium (e.g. Open Channel SSD).
|
||||
*
|
||||
* \param bdev_desc Block device descriptor
|
||||
* \param events Array of media mangement event descriptors
|
||||
* \param max_events Size of the events array
|
||||
*
|
||||
* \return number of events retrieved
|
||||
*/
|
||||
size_t spdk_bdev_get_media_events(struct spdk_bdev_desc *bdev_desc,
|
||||
struct spdk_bdev_media_event *events, size_t max_events);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -355,6 +355,11 @@ struct spdk_bdev {
|
||||
*/
|
||||
uint32_t optimal_open_zones;
|
||||
|
||||
/**
|
||||
* Specifies whether bdev supports media management events.
|
||||
*/
|
||||
bool media_events;
|
||||
|
||||
/**
|
||||
* Pointer to the bdev module that registered this bdev.
|
||||
*/
|
||||
@ -1110,6 +1115,27 @@ struct spdk_bdev *spdk_bdev_part_get_base_bdev(struct spdk_bdev_part *part);
|
||||
*/
|
||||
uint64_t spdk_bdev_part_get_offset_blocks(struct spdk_bdev_part *part);
|
||||
|
||||
/**
|
||||
* Push media management events. To send the notification that new events are
|
||||
* available, spdk_bdev_notify_media_management needs to be called.
|
||||
*
|
||||
* \param bdev Block device
|
||||
* \param events Array of media events
|
||||
* \param num_events Size of the events array
|
||||
*
|
||||
* \return number of events pushed or negative errno in case of failure
|
||||
*/
|
||||
int spdk_bdev_push_media_events(struct spdk_bdev *bdev, const struct spdk_bdev_media_event *events,
|
||||
size_t num_events);
|
||||
|
||||
/**
|
||||
* Send SPDK_BDEV_EVENT_MEDIA_MANAGEMENT to all open descriptors that have
|
||||
* pending media events.
|
||||
*
|
||||
* \param bdev Block device
|
||||
*/
|
||||
void spdk_bdev_notify_media_management(struct spdk_bdev *bdev);
|
||||
|
||||
/*
|
||||
* Macro used to register module for later initialization.
|
||||
*/
|
||||
|
110
lib/bdev/bdev.c
110
lib/bdev/bdev.c
@ -278,6 +278,13 @@ struct spdk_bdev_channel {
|
||||
bdev_io_tailq_t queued_resets;
|
||||
};
|
||||
|
||||
struct media_event_entry {
|
||||
struct spdk_bdev_media_event event;
|
||||
TAILQ_ENTRY(media_event_entry) tailq;
|
||||
};
|
||||
|
||||
#define MEDIA_EVENT_POOL_SIZE 64
|
||||
|
||||
struct spdk_bdev_desc {
|
||||
struct spdk_bdev *bdev;
|
||||
struct spdk_thread *thread;
|
||||
@ -293,6 +300,9 @@ struct spdk_bdev_desc {
|
||||
bool write;
|
||||
pthread_mutex_t mutex;
|
||||
uint32_t refs;
|
||||
TAILQ_HEAD(, media_event_entry) pending_media_events;
|
||||
TAILQ_HEAD(, media_event_entry) free_media_events;
|
||||
struct media_event_entry *media_events_buffer;
|
||||
TAILQ_ENTRY(spdk_bdev_desc) link;
|
||||
|
||||
uint64_t timeout_in_sec;
|
||||
@ -2136,6 +2146,7 @@ static void
|
||||
bdev_desc_free(struct spdk_bdev_desc *desc)
|
||||
{
|
||||
pthread_mutex_destroy(&desc->mutex);
|
||||
free(desc->media_events_buffer);
|
||||
free(desc);
|
||||
}
|
||||
|
||||
@ -4606,6 +4617,9 @@ spdk_bdev_open(struct spdk_bdev *bdev, bool write, spdk_bdev_remove_cb_t remove_
|
||||
remove_cb = bdev_dummy_event_cb;
|
||||
}
|
||||
|
||||
TAILQ_INIT(&desc->pending_media_events);
|
||||
TAILQ_INIT(&desc->free_media_events);
|
||||
|
||||
desc->callback.open_with_ext = false;
|
||||
desc->callback.remove_fn = remove_cb;
|
||||
desc->callback.ctx = remove_ctx;
|
||||
@ -4632,6 +4646,7 @@ spdk_bdev_open_ext(const char *bdev_name, bool write, spdk_bdev_event_cb_t event
|
||||
{
|
||||
struct spdk_bdev_desc *desc;
|
||||
struct spdk_bdev *bdev;
|
||||
unsigned int event_id;
|
||||
int rc;
|
||||
|
||||
if (event_cb == NULL) {
|
||||
@ -4656,11 +4671,30 @@ spdk_bdev_open_ext(const char *bdev_name, bool write, spdk_bdev_event_cb_t event
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
TAILQ_INIT(&desc->pending_media_events);
|
||||
TAILQ_INIT(&desc->free_media_events);
|
||||
|
||||
desc->callback.open_with_ext = true;
|
||||
desc->callback.event_fn = event_cb;
|
||||
desc->callback.ctx = event_ctx;
|
||||
pthread_mutex_init(&desc->mutex, NULL);
|
||||
|
||||
if (bdev->media_events) {
|
||||
desc->media_events_buffer = calloc(MEDIA_EVENT_POOL_SIZE,
|
||||
sizeof(*desc->media_events_buffer));
|
||||
if (desc->media_events_buffer == NULL) {
|
||||
SPDK_ERRLOG("Failed to initialize media event pool\n");
|
||||
bdev_desc_free(desc);
|
||||
pthread_mutex_unlock(&g_bdev_mgr.mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (event_id = 0; event_id < MEDIA_EVENT_POOL_SIZE; ++event_id) {
|
||||
TAILQ_INSERT_TAIL(&desc->free_media_events,
|
||||
&desc->media_events_buffer[event_id], tailq);
|
||||
}
|
||||
}
|
||||
|
||||
rc = bdev_open(bdev, write, desc);
|
||||
if (rc != 0) {
|
||||
bdev_desc_free(desc);
|
||||
@ -5314,6 +5348,82 @@ spdk_bdev_histogram_get(struct spdk_bdev *bdev, struct spdk_histogram_data *hist
|
||||
bdev_histogram_get_channel_cb);
|
||||
}
|
||||
|
||||
size_t
|
||||
spdk_bdev_get_media_events(struct spdk_bdev_desc *desc, struct spdk_bdev_media_event *events,
|
||||
size_t max_events)
|
||||
{
|
||||
struct media_event_entry *entry;
|
||||
size_t num_events = 0;
|
||||
|
||||
for (; num_events < max_events; ++num_events) {
|
||||
entry = TAILQ_FIRST(&desc->pending_media_events);
|
||||
if (entry == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
events[num_events] = entry->event;
|
||||
TAILQ_REMOVE(&desc->pending_media_events, entry, tailq);
|
||||
TAILQ_INSERT_TAIL(&desc->free_media_events, entry, tailq);
|
||||
}
|
||||
|
||||
return num_events;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_bdev_push_media_events(struct spdk_bdev *bdev, const struct spdk_bdev_media_event *events,
|
||||
size_t num_events)
|
||||
{
|
||||
struct spdk_bdev_desc *desc;
|
||||
struct media_event_entry *entry;
|
||||
size_t event_id;
|
||||
int rc = 0;
|
||||
|
||||
assert(bdev->media_events);
|
||||
|
||||
pthread_mutex_lock(&bdev->internal.mutex);
|
||||
TAILQ_FOREACH(desc, &bdev->internal.open_descs, link) {
|
||||
if (desc->write) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (desc == NULL || desc->media_events_buffer == NULL) {
|
||||
rc = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (event_id = 0; event_id < num_events; ++event_id) {
|
||||
entry = TAILQ_FIRST(&desc->free_media_events);
|
||||
if (entry == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&desc->free_media_events, entry, tailq);
|
||||
TAILQ_INSERT_TAIL(&desc->pending_media_events, entry, tailq);
|
||||
entry->event = events[event_id];
|
||||
}
|
||||
|
||||
rc = event_id;
|
||||
out:
|
||||
pthread_mutex_unlock(&bdev->internal.mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_bdev_notify_media_management(struct spdk_bdev *bdev)
|
||||
{
|
||||
struct spdk_bdev_desc *desc;
|
||||
|
||||
pthread_mutex_lock(&bdev->internal.mutex);
|
||||
TAILQ_FOREACH(desc, &bdev->internal.open_descs, link) {
|
||||
if (!TAILQ_EMPTY(&desc->pending_media_events)) {
|
||||
desc->callback.event_fn(SPDK_BDEV_EVENT_MEDIA_MANAGEMENT, bdev,
|
||||
desc->callback.ctx);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&bdev->internal.mutex);
|
||||
}
|
||||
|
||||
SPDK_LOG_REGISTER_COMPONENT("bdev", SPDK_LOG_BDEV)
|
||||
|
||||
SPDK_TRACE_REGISTER_FN(bdev_trace, "bdev", TRACE_GROUP_BDEV)
|
||||
|
Loading…
Reference in New Issue
Block a user