diff --git a/lib/nbd/nbd.c b/lib/nbd/nbd.c index fc7726a44..097b7f491 100644 --- a/lib/nbd/nbd.c +++ b/lib/nbd/nbd.c @@ -649,12 +649,19 @@ spdk_nbd_io_xmit_internal(struct spdk_nbd_disk *nbd) return 0; } + /* Remove IO from list now assuming it will be completed. It will be inserted + * back to the head if it cannot be completed. This approach is specifically + * taken to work around a scan-build use-after-free mischaracterization. + */ + TAILQ_REMOVE(&nbd->executed_io_list, io, tailq); + /* resp error and handler are already set in io_done */ if (io->state == NBD_IO_XMIT_RESP) { ret = write_to_socket(nbd->spdk_sp_fd, (char *)&io->resp + io->offset, sizeof(io->resp) - io->offset); if (ret <= 0) { + TAILQ_INSERT_HEAD(&nbd->executed_io_list, io, tailq); return ret; } @@ -666,7 +673,6 @@ spdk_nbd_io_xmit_internal(struct spdk_nbd_disk *nbd) /* transmit payload only when NBD_CMD_READ with no resp error */ if (from_be32(&io->req.type) != NBD_CMD_READ || io->resp.error != 0) { - TAILQ_REMOVE(&nbd->executed_io_list, io, tailq); spdk_put_nbd_io(nbd, io); return 0; } else { @@ -678,6 +684,7 @@ spdk_nbd_io_xmit_internal(struct spdk_nbd_disk *nbd) if (io->state == NBD_IO_XMIT_PAYLOAD) { ret = write_to_socket(nbd->spdk_sp_fd, io->payload + io->offset, io->payload_size - io->offset); if (ret <= 0) { + TAILQ_INSERT_HEAD(&nbd->executed_io_list, io, tailq); return ret; } @@ -685,11 +692,12 @@ spdk_nbd_io_xmit_internal(struct spdk_nbd_disk *nbd) /* read payload is fully transmitted */ if (io->offset == io->payload_size) { - TAILQ_REMOVE(&nbd->executed_io_list, io, tailq); spdk_put_nbd_io(nbd, io); + return 0; } } + TAILQ_INSERT_HEAD(&nbd->executed_io_list, io, tailq); return 0; }