bdev: retry IOs on ENOMEM when pushing bounce data/md

Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com>
Change-Id: Ia7634b570eb7d04c22003337a46630d152171157
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/17764
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Konrad Sztyber 2023-04-20 08:49:53 +02:00 committed by Jim Harris
parent fafb7d4741
commit f8a33650d2
2 changed files with 71 additions and 7 deletions

View File

@ -371,6 +371,8 @@ enum bdev_io_retry_state {
BDEV_IO_RETRY_STATE_PULL, BDEV_IO_RETRY_STATE_PULL,
BDEV_IO_RETRY_STATE_PULL_MD, BDEV_IO_RETRY_STATE_PULL_MD,
BDEV_IO_RETRY_STATE_SUBMIT, BDEV_IO_RETRY_STATE_SUBMIT,
BDEV_IO_RETRY_STATE_PUSH,
BDEV_IO_RETRY_STATE_PUSH_MD,
}; };
#define __bdev_to_io_dev(bdev) (((char *)bdev) + 1) #define __bdev_to_io_dev(bdev) (((char *)bdev) + 1)
@ -380,6 +382,8 @@ enum bdev_io_retry_state {
static inline void bdev_io_complete(void *ctx); static inline void bdev_io_complete(void *ctx);
static inline void bdev_io_complete_unsubmitted(struct spdk_bdev_io *bdev_io); static inline void bdev_io_complete_unsubmitted(struct spdk_bdev_io *bdev_io);
static void bdev_io_push_bounce_md_buf(struct spdk_bdev_io *bdev_io);
static void bdev_io_push_bounce_data(struct spdk_bdev_io *bdev_io);
static void bdev_write_zero_buffer_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg); static void bdev_write_zero_buffer_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg);
static int bdev_write_zero_buffer(struct spdk_bdev_io *bdev_io); static int bdev_write_zero_buffer(struct spdk_bdev_io *bdev_io);
@ -1482,6 +1486,12 @@ bdev_ch_retry_io(struct spdk_bdev_channel *bdev_ch)
case BDEV_IO_RETRY_STATE_PULL_MD: case BDEV_IO_RETRY_STATE_PULL_MD:
bdev_io_pull_md_buf(bdev_io); bdev_io_pull_md_buf(bdev_io);
break; break;
case BDEV_IO_RETRY_STATE_PUSH:
bdev_io_push_bounce_data(bdev_io);
break;
case BDEV_IO_RETRY_STATE_PUSH_MD:
bdev_io_push_bounce_md_buf(bdev_io);
break;
default: default:
assert(0 && "invalid retry state"); assert(0 && "invalid retry state");
break; break;
@ -1557,6 +1567,11 @@ _bdev_io_push_bounce_md_buf_done(void *ctx, int rc)
TAILQ_REMOVE(&ch->io_memory_domain, bdev_io, internal.link); TAILQ_REMOVE(&ch->io_memory_domain, bdev_io, internal.link);
bdev_io_decrement_outstanding(ch, ch->shared_resource); bdev_io_decrement_outstanding(ch, ch->shared_resource);
if (spdk_unlikely(!TAILQ_EMPTY(&ch->shared_resource->nomem_io))) {
bdev_ch_retry_io(ch);
}
bdev_io->internal.data_transfer_cpl(bdev_io, rc); bdev_io->internal.data_transfer_cpl(bdev_io, rc);
} }
@ -1589,8 +1604,11 @@ bdev_io_push_bounce_md_buf(struct spdk_bdev_io *bdev_io)
} }
TAILQ_REMOVE(&ch->io_memory_domain, bdev_io, internal.link); TAILQ_REMOVE(&ch->io_memory_domain, bdev_io, internal.link);
bdev_io_decrement_outstanding(ch, ch->shared_resource); bdev_io_decrement_outstanding(ch, ch->shared_resource);
if (rc != -ENOMEM) {
SPDK_ERRLOG("Failed to push md to memory domain %s\n", SPDK_ERRLOG("Failed to push md to memory domain %s\n",
spdk_memory_domain_get_dma_device_id(bdev_io->internal.memory_domain)); spdk_memory_domain_get_dma_device_id(
bdev_io->internal.memory_domain));
}
} else { } else {
memcpy(bdev_io->internal.orig_md_iov.iov_base, bdev_io->u.bdev.md_buf, memcpy(bdev_io->internal.orig_md_iov.iov_base, bdev_io->u.bdev.md_buf,
bdev_io->internal.orig_md_iov.iov_len); bdev_io->internal.orig_md_iov.iov_len);
@ -1598,8 +1616,12 @@ bdev_io_push_bounce_md_buf(struct spdk_bdev_io *bdev_io)
} }
} }
if (spdk_unlikely(rc == -ENOMEM)) {
bdev_queue_nomem_io_head(ch->shared_resource, bdev_io, BDEV_IO_RETRY_STATE_PUSH_MD);
} else {
assert(bdev_io->internal.data_transfer_cpl); assert(bdev_io->internal.data_transfer_cpl);
bdev_io->internal.data_transfer_cpl(bdev_io, rc); bdev_io->internal.data_transfer_cpl(bdev_io, rc);
}
} }
static inline void static inline void
@ -1632,6 +1654,10 @@ _bdev_io_push_bounce_data_buffer_done(void *ctx, int status)
TAILQ_REMOVE(&ch->io_memory_domain, bdev_io, internal.link); TAILQ_REMOVE(&ch->io_memory_domain, bdev_io, internal.link);
bdev_io_decrement_outstanding(ch, ch->shared_resource); bdev_io_decrement_outstanding(ch, ch->shared_resource);
if (spdk_unlikely(!TAILQ_EMPTY(&ch->shared_resource->nomem_io))) {
bdev_ch_retry_io(ch);
}
bdev_io_push_bounce_data_buffer_done(ctx, status); bdev_io_push_bounce_data_buffer_done(ctx, status);
} }
@ -1662,8 +1688,11 @@ bdev_io_push_bounce_data(struct spdk_bdev_io *bdev_io)
TAILQ_REMOVE(&ch->io_memory_domain, bdev_io, internal.link); TAILQ_REMOVE(&ch->io_memory_domain, bdev_io, internal.link);
bdev_io_decrement_outstanding(ch, ch->shared_resource); bdev_io_decrement_outstanding(ch, ch->shared_resource);
if (rc != -ENOMEM) {
SPDK_ERRLOG("Failed to push data to memory domain %s\n", SPDK_ERRLOG("Failed to push data to memory domain %s\n",
spdk_memory_domain_get_dma_device_id(bdev_io->internal.memory_domain)); spdk_memory_domain_get_dma_device_id(
bdev_io->internal.memory_domain));
}
} else { } else {
spdk_copy_buf_to_iovs(bdev_io->internal.orig_iovs, spdk_copy_buf_to_iovs(bdev_io->internal.orig_iovs,
bdev_io->internal.orig_iovcnt, bdev_io->internal.orig_iovcnt,
@ -1672,7 +1701,11 @@ bdev_io_push_bounce_data(struct spdk_bdev_io *bdev_io)
} }
} }
if (spdk_unlikely(rc == -ENOMEM)) {
bdev_queue_nomem_io_head(ch->shared_resource, bdev_io, BDEV_IO_RETRY_STATE_PUSH);
} else {
bdev_io_push_bounce_data_buffer_done(bdev_io, rc); bdev_io_push_bounce_data_buffer_done(bdev_io, rc);
}
} }
static inline void static inline void

View File

@ -5895,6 +5895,37 @@ bdev_io_ext_bounce_buffer(void)
stub_complete_io(1); stub_complete_io(1);
CU_ASSERT(g_io_done == true); CU_ASSERT(g_io_done == true);
/* Verify the request is queued after receiving ENOMEM from push */
g_io_done = false;
expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 32, 14, 1);
ut_expected_io_set_iov(expected_io, 0, iov.iov_base, iov.iov_len);
TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
MOCK_SET(spdk_memory_domain_push_data, -ENOMEM);
rc = spdk_bdev_readv_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, &ext_io_opts);
CU_ASSERT(rc == 0);
CU_ASSERT(g_io_done == false);
CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
aux_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 14, 1);
ut_expected_io_set_iov(aux_io, 0, iov.iov_base, iov.iov_len);
TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, aux_io, link);
rc = spdk_bdev_writev_blocks(desc, io_ch, &iov, 1, 32, 14, io_done, NULL);
CU_ASSERT(rc == 0);
CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
stub_complete_io(1);
/* The IO isn't done yet, it's still waiting on push */
CU_ASSERT(g_io_done == false);
CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
MOCK_CLEAR(spdk_memory_domain_push_data);
g_memory_domain_push_data_called = false;
/* Completing the second IO should also trigger push on the first one */
stub_complete_io(1);
CU_ASSERT(g_io_done == true);
CU_ASSERT(g_memory_domain_push_data_called == true);
CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
spdk_put_io_channel(io_ch); spdk_put_io_channel(io_ch);
spdk_bdev_close(desc); spdk_bdev_close(desc);
free_bdev(bdev); free_bdev(bdev);