blob: add write_zeroes support
Unmap does not guarantee that erased blocks will return all zeroes. using write_zeroes when unmapping metadata gives the desired behavior for a blob. Only metadata pages will be cleared with write_zeroes in this patch; blob data clusters will still call unmap. This behavior may be made configurable in a later patch (to allow the user to request zeroing of clusters rather than just unmapping). Change-Id: I1b210abac110867ce703bcfdeb634eb45aa9d5c9 Signed-off-by: Seth Howell <seth.howell@intel.com> Reviewed-on: https://review.gerrithub.io/372004 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
3fd7f28dc9
commit
3f9cbe513b
@ -132,6 +132,10 @@ struct spdk_bs_dev {
|
|||||||
void (*flush)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
|
void (*flush)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
|
||||||
struct spdk_bs_dev_cb_args *cb_args);
|
struct spdk_bs_dev_cb_args *cb_args);
|
||||||
|
|
||||||
|
void (*write_zeroes)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
|
||||||
|
uint64_t lba, uint32_t lba_count,
|
||||||
|
struct spdk_bs_dev_cb_args *cb_args);
|
||||||
|
|
||||||
void (*unmap)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
|
void (*unmap)(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
|
||||||
uint64_t lba, uint32_t lba_count,
|
uint64_t lba, uint32_t lba_count,
|
||||||
struct spdk_bs_dev_cb_args *cb_args);
|
struct spdk_bs_dev_cb_args *cb_args);
|
||||||
|
@ -123,6 +123,19 @@ bdev_blob_writev(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bdev_blob_write_zeroes(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, uint64_t lba,
|
||||||
|
uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = spdk_bdev_write_zeroes_blocks(__get_desc(dev), channel, lba,
|
||||||
|
lba_count, bdev_blob_io_complete, cb_args);
|
||||||
|
if (rc) {
|
||||||
|
cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bdev_blob_unmap(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, uint64_t lba,
|
bdev_blob_unmap(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, uint64_t lba,
|
||||||
uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args)
|
uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args)
|
||||||
@ -213,6 +226,7 @@ spdk_bdev_create_bs_dev(struct spdk_bdev *bdev, spdk_bdev_remove_cb_t remove_cb,
|
|||||||
b->bs_dev.write = bdev_blob_write;
|
b->bs_dev.write = bdev_blob_write;
|
||||||
b->bs_dev.readv = bdev_blob_readv;
|
b->bs_dev.readv = bdev_blob_readv;
|
||||||
b->bs_dev.writev = bdev_blob_writev;
|
b->bs_dev.writev = bdev_blob_writev;
|
||||||
|
b->bs_dev.write_zeroes = bdev_blob_write_zeroes;
|
||||||
b->bs_dev.unmap = bdev_blob_unmap;
|
b->bs_dev.unmap = bdev_blob_unmap;
|
||||||
|
|
||||||
return &b->bs_dev;
|
return &b->bs_dev;
|
||||||
|
@ -760,7 +760,7 @@ _spdk_blob_persist_unmap_clusters(spdk_bs_sequence_t *seq, void *cb_arg, int bse
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_spdk_blob_persist_unmap_pages_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
|
_spdk_blob_persist_zero_pages_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
|
||||||
{
|
{
|
||||||
struct spdk_blob_persist_ctx *ctx = cb_arg;
|
struct spdk_blob_persist_ctx *ctx = cb_arg;
|
||||||
struct spdk_blob *blob = ctx->blob;
|
struct spdk_blob *blob = ctx->blob;
|
||||||
@ -769,7 +769,7 @@ _spdk_blob_persist_unmap_pages_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bs
|
|||||||
|
|
||||||
/* This loop starts at 1 because the first page is special and handled
|
/* This loop starts at 1 because the first page is special and handled
|
||||||
* below. The pages (except the first) are never written in place,
|
* below. The pages (except the first) are never written in place,
|
||||||
* so any pages in the clean list must be unmapped.
|
* so any pages in the clean list must be zeroed.
|
||||||
*/
|
*/
|
||||||
for (i = 1; i < blob->clean.num_pages; i++) {
|
for (i = 1; i < blob->clean.num_pages; i++) {
|
||||||
spdk_bit_array_clear(bs->used_md_pages, blob->clean.pages[i]);
|
spdk_bit_array_clear(bs->used_md_pages, blob->clean.pages[i]);
|
||||||
@ -787,7 +787,7 @@ _spdk_blob_persist_unmap_pages_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bs
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_spdk_blob_persist_unmap_pages(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
|
_spdk_blob_persist_zero_pages(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
|
||||||
{
|
{
|
||||||
struct spdk_blob_persist_ctx *ctx = cb_arg;
|
struct spdk_blob_persist_ctx *ctx = cb_arg;
|
||||||
struct spdk_blob *blob = ctx->blob;
|
struct spdk_blob *blob = ctx->blob;
|
||||||
@ -797,21 +797,21 @@ _spdk_blob_persist_unmap_pages(spdk_bs_sequence_t *seq, void *cb_arg, int bserrn
|
|||||||
spdk_bs_batch_t *batch;
|
spdk_bs_batch_t *batch;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
batch = spdk_bs_sequence_to_batch(seq, _spdk_blob_persist_unmap_pages_cpl, ctx);
|
batch = spdk_bs_sequence_to_batch(seq, _spdk_blob_persist_zero_pages_cpl, ctx);
|
||||||
|
|
||||||
lba_count = _spdk_bs_byte_to_lba(bs, SPDK_BS_PAGE_SIZE);
|
lba_count = _spdk_bs_byte_to_lba(bs, SPDK_BS_PAGE_SIZE);
|
||||||
|
|
||||||
/* This loop starts at 1 because the first page is special and handled
|
/* This loop starts at 1 because the first page is special and handled
|
||||||
* below. The pages (except the first) are never written in place,
|
* below. The pages (except the first) are never written in place,
|
||||||
* so any pages in the clean list must be unmapped.
|
* so any pages in the clean list must be zeroed.
|
||||||
*/
|
*/
|
||||||
for (i = 1; i < blob->clean.num_pages; i++) {
|
for (i = 1; i < blob->clean.num_pages; i++) {
|
||||||
lba = _spdk_bs_page_to_lba(bs, bs->md_start + blob->clean.pages[i]);
|
lba = _spdk_bs_page_to_lba(bs, bs->md_start + blob->clean.pages[i]);
|
||||||
|
|
||||||
spdk_bs_batch_unmap(batch, lba, lba_count);
|
spdk_bs_batch_write_zeroes(batch, lba, lba_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The first page will only be unmapped if this is a delete. */
|
/* The first page will only be zeroed if this is a delete. */
|
||||||
if (blob->active.num_pages == 0) {
|
if (blob->active.num_pages == 0) {
|
||||||
uint32_t page_num;
|
uint32_t page_num;
|
||||||
|
|
||||||
@ -819,7 +819,7 @@ _spdk_blob_persist_unmap_pages(spdk_bs_sequence_t *seq, void *cb_arg, int bserrn
|
|||||||
page_num = _spdk_bs_blobid_to_page(blob->id);
|
page_num = _spdk_bs_blobid_to_page(blob->id);
|
||||||
lba = _spdk_bs_page_to_lba(bs, bs->md_start + page_num);
|
lba = _spdk_bs_page_to_lba(bs, bs->md_start + page_num);
|
||||||
|
|
||||||
spdk_bs_batch_unmap(batch, lba, lba_count);
|
spdk_bs_batch_write_zeroes(batch, lba, lba_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
spdk_bs_batch_close(batch);
|
spdk_bs_batch_close(batch);
|
||||||
@ -837,7 +837,7 @@ _spdk_blob_persist_write_page_root(spdk_bs_sequence_t *seq, void *cb_arg, int bs
|
|||||||
|
|
||||||
if (blob->active.num_pages == 0) {
|
if (blob->active.num_pages == 0) {
|
||||||
/* Move on to the next step */
|
/* Move on to the next step */
|
||||||
_spdk_blob_persist_unmap_pages(seq, ctx, 0);
|
_spdk_blob_persist_zero_pages(seq, ctx, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,7 +848,7 @@ _spdk_blob_persist_write_page_root(spdk_bs_sequence_t *seq, void *cb_arg, int bs
|
|||||||
lba = _spdk_bs_page_to_lba(bs, bs->md_start + _spdk_bs_blobid_to_page(blob->id));
|
lba = _spdk_bs_page_to_lba(bs, bs->md_start + _spdk_bs_blobid_to_page(blob->id));
|
||||||
|
|
||||||
spdk_bs_sequence_write(seq, page, lba, lba_count,
|
spdk_bs_sequence_write(seq, page, lba, lba_count,
|
||||||
_spdk_blob_persist_unmap_pages, ctx);
|
_spdk_blob_persist_zero_pages, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -994,7 +994,7 @@ _spdk_blob_persist(spdk_bs_sequence_t *seq, struct spdk_blob *blob,
|
|||||||
* Immediately jump to the clean up routine. */
|
* Immediately jump to the clean up routine. */
|
||||||
assert(blob->clean.num_pages > 0);
|
assert(blob->clean.num_pages > 0);
|
||||||
ctx->idx = blob->clean.num_pages - 1;
|
ctx->idx = blob->clean.num_pages - 1;
|
||||||
_spdk_blob_persist_unmap_pages(seq, ctx, 0);
|
_spdk_blob_persist_zero_pages(seq, ctx, 0);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2177,8 +2177,8 @@ spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *o,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TRIM the entire device */
|
/* Zero the entire device */
|
||||||
spdk_bs_sequence_unmap(seq, 0, bs->dev->blockcnt, _spdk_bs_init_trim_cpl, ctx);
|
spdk_bs_sequence_write_zeroes(seq, 0, bs->dev->blockcnt, _spdk_bs_init_trim_cpl, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* END spdk_bs_init */
|
/* END spdk_bs_init */
|
||||||
|
@ -226,6 +226,23 @@ spdk_bs_sequence_unmap(spdk_bs_sequence_t *seq,
|
|||||||
&set->cb_args);
|
&set->cb_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
spdk_bs_sequence_write_zeroes(spdk_bs_sequence_t *seq,
|
||||||
|
uint64_t lba, uint32_t lba_count,
|
||||||
|
spdk_bs_sequence_cpl cb_fn, void *cb_arg)
|
||||||
|
{
|
||||||
|
struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)seq;
|
||||||
|
struct spdk_bs_channel *channel = set->channel;
|
||||||
|
|
||||||
|
SPDK_DEBUGLOG(SPDK_TRACE_BLOB_RW, "writing zeroes to %u blocks at LBA %lu\n", lba_count, lba);
|
||||||
|
|
||||||
|
set->u.sequence.cb_fn = cb_fn;
|
||||||
|
set->u.sequence.cb_arg = cb_arg;
|
||||||
|
|
||||||
|
channel->dev->write_zeroes(channel->dev, channel->dev_channel, lba, lba_count,
|
||||||
|
&set->cb_args);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
spdk_bs_sequence_finish(spdk_bs_sequence_t *seq, int bserrno)
|
spdk_bs_sequence_finish(spdk_bs_sequence_t *seq, int bserrno)
|
||||||
{
|
{
|
||||||
@ -342,6 +359,20 @@ spdk_bs_batch_unmap(spdk_bs_batch_t *batch,
|
|||||||
&set->cb_args);
|
&set->cb_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
spdk_bs_batch_write_zeroes(spdk_bs_batch_t *batch,
|
||||||
|
uint64_t lba, uint32_t lba_count)
|
||||||
|
{
|
||||||
|
struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)batch;
|
||||||
|
struct spdk_bs_channel *channel = set->channel;
|
||||||
|
|
||||||
|
SPDK_DEBUGLOG(SPDK_TRACE_BLOB_RW, "Zeroing %u blocks at LBA %lu\n", lba_count, lba);
|
||||||
|
|
||||||
|
set->u.batch.outstanding_ops++;
|
||||||
|
channel->dev->write_zeroes(channel->dev, channel->dev_channel, lba, lba_count,
|
||||||
|
&set->cb_args);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
spdk_bs_batch_close(spdk_bs_batch_t *batch)
|
spdk_bs_batch_close(spdk_bs_batch_t *batch)
|
||||||
{
|
{
|
||||||
|
@ -155,6 +155,10 @@ void spdk_bs_sequence_unmap(spdk_bs_sequence_t *seq,
|
|||||||
uint64_t lba, uint32_t lba_count,
|
uint64_t lba, uint32_t lba_count,
|
||||||
spdk_bs_sequence_cpl cb_fn, void *cb_arg);
|
spdk_bs_sequence_cpl cb_fn, void *cb_arg);
|
||||||
|
|
||||||
|
void spdk_bs_sequence_write_zeroes(spdk_bs_sequence_t *seq,
|
||||||
|
uint64_t lba, uint32_t lba_count,
|
||||||
|
spdk_bs_sequence_cpl cb_fn, void *cb_arg);
|
||||||
|
|
||||||
void spdk_bs_sequence_finish(spdk_bs_sequence_t *seq, int bserrno);
|
void spdk_bs_sequence_finish(spdk_bs_sequence_t *seq, int bserrno);
|
||||||
|
|
||||||
spdk_bs_batch_t *spdk_bs_batch_open(struct spdk_io_channel *channel,
|
spdk_bs_batch_t *spdk_bs_batch_open(struct spdk_io_channel *channel,
|
||||||
@ -171,6 +175,9 @@ void spdk_bs_batch_flush(spdk_bs_batch_t *batch);
|
|||||||
void spdk_bs_batch_unmap(spdk_bs_batch_t *batch,
|
void spdk_bs_batch_unmap(spdk_bs_batch_t *batch,
|
||||||
uint64_t lba, uint32_t lba_count);
|
uint64_t lba, uint32_t lba_count);
|
||||||
|
|
||||||
|
void spdk_bs_batch_write_zeroes(spdk_bs_batch_t *batch,
|
||||||
|
uint64_t lba, uint32_t lba_count);
|
||||||
|
|
||||||
void spdk_bs_batch_close(spdk_bs_batch_t *batch);
|
void spdk_bs_batch_close(spdk_bs_batch_t *batch);
|
||||||
|
|
||||||
spdk_bs_batch_t *spdk_bs_sequence_to_batch(spdk_bs_sequence_t *seq,
|
spdk_bs_batch_t *spdk_bs_sequence_to_batch(spdk_bs_sequence_t *seq,
|
||||||
|
@ -151,6 +151,19 @@ dev_unmap(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
|
|||||||
{
|
{
|
||||||
uint64_t offset, length;
|
uint64_t offset, length;
|
||||||
|
|
||||||
|
offset = lba * DEV_BUFFER_BLOCKLEN;
|
||||||
|
length = lba_count * DEV_BUFFER_BLOCKLEN;
|
||||||
|
SPDK_CU_ASSERT_FATAL(offset + length <= DEV_BUFFER_SIZE);
|
||||||
|
cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_write_zeroes(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
|
||||||
|
uint64_t lba, uint32_t lba_count,
|
||||||
|
struct spdk_bs_dev_cb_args *cb_args)
|
||||||
|
{
|
||||||
|
uint64_t offset, length;
|
||||||
|
|
||||||
offset = lba * DEV_BUFFER_BLOCKLEN;
|
offset = lba * DEV_BUFFER_BLOCKLEN;
|
||||||
length = lba_count * DEV_BUFFER_BLOCKLEN;
|
length = lba_count * DEV_BUFFER_BLOCKLEN;
|
||||||
SPDK_CU_ASSERT_FATAL(offset + length <= DEV_BUFFER_SIZE);
|
SPDK_CU_ASSERT_FATAL(offset + length <= DEV_BUFFER_SIZE);
|
||||||
@ -174,6 +187,7 @@ init_dev(void)
|
|||||||
dev->writev = dev_writev;
|
dev->writev = dev_writev;
|
||||||
dev->flush = dev_flush;
|
dev->flush = dev_flush;
|
||||||
dev->unmap = dev_unmap;
|
dev->unmap = dev_unmap;
|
||||||
|
dev->write_zeroes = dev_write_zeroes;
|
||||||
dev->blockcnt = DEV_BUFFER_BLOCKCNT;
|
dev->blockcnt = DEV_BUFFER_BLOCKCNT;
|
||||||
dev->blocklen = DEV_BUFFER_BLOCKLEN;
|
dev->blocklen = DEV_BUFFER_BLOCKLEN;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user