diff options
| author | Simon Rettberg | 2025-11-07 14:28:56 +0100 |
|---|---|---|
| committer | Simon Rettberg | 2025-12-09 15:33:20 +0100 |
| commit | 79e9fedc148d9287ab5267e5d83938e0555440bf (patch) | |
| tree | 9e5878e1df786dfefaca9b13c60a4b5a33e74de0 /src | |
| parent | [SERVER] iscsi: Make iscsi_task stack-allocated (diff) | |
| download | dnbd3-79e9fedc148d9287ab5267e5d83938e0555440bf.tar.gz dnbd3-79e9fedc148d9287ab5267e5d83938e0555440bf.tar.xz dnbd3-79e9fedc148d9287ab5267e5d83938e0555440bf.zip | |
[SERVER] iscsi: Make kernel fast again
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/iscsi.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/src/server/iscsi.c b/src/server/iscsi.c index 400c90c..45f5ef2 100644 --- a/src/server/iscsi.c +++ b/src/server/iscsi.c @@ -1315,12 +1315,27 @@ static int iscsi_scsi_emu_primary_inquiry(const dnbd3_image_t *image, iscsi_scsi vpd_page_block_limits_inquiry_data_pkt->flags = 0; - // Calculate maximum number of logical blocks that would fit into a maximum-size transfer (16MiB), - // but make sure it is a multiple of the physical block size - const uint32_t blocks = ((ISCSI_MAX_DS_SIZE / ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE) - * ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE) / ISCSI_SCSI_EMU_LOGICAL_BLOCK_SIZE; - - vpd_page_block_limits_inquiry_data_pkt->max_cmp_write_len = (uint8_t) blocks; + // So, this has caused some headache, nice. With the kernel's iscsi implementation, we have to limit our + // reported maximum supported transfer length to the client's maximum supported DS size. If you just do + // ISCSI_MAX_DS_SIZE / ISCSI_SCSI_EMU_LOGICAL_BLOCK_SIZE + // the kernel will complain that the maximum transfer size is not a multiple of the physical block size, + // so you might be tempted to use + // ((ISCSI_MAX_DS_SIZE / ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE) + // * ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE) / ISCSI_SCSI_EMU_LOGICAL_BLOCK_SIZE + // to make sure it is. But then *surprise*, maximum transfer speeds drop from ~1.5GB/s to ~250MB/s. + // OK, then you revert back to the simple formula and accept that annoying warning in dmesg, only to + // realize that while "pv < /dev/sda > /dev/null" and dd with bs=256k are fast, a dd with bs=1M ends up + // at about 25MB/s (!!!!) + // So what finally, hopefully, seems to work properly is limiting the reported maximum transfer length to + // the client's MaxRecvDataSegmentLength, which coincidentally is the same as its FirstBurstLength, so + // let's hope picking MaxRecvDataSegmentLength is the right choice here. You'd think the client would + // automatically pick a suitable transfer length that it can handle efficiently; the kernel however just + // goes for the maximum supported by the server. Even just lowering the reported *optimal* length is not + // sufficient. But maybe I'm just not good with computers. + const uint32_t blocks = (scsi_task->connection->session->opts.MaxRecvDataSegmentLength + / ISCSI_SCSI_EMU_LOGICAL_BLOCK_SIZE); + + vpd_page_block_limits_inquiry_data_pkt->max_cmp_write_len = 0; iscsi_put_be16( (uint8_t *) &vpd_page_block_limits_inquiry_data_pkt->optimal_granularity_xfer_len, (uint16_t) ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE / ISCSI_SCSI_EMU_LOGICAL_BLOCK_SIZE ); @@ -1333,7 +1348,7 @@ static int iscsi_scsi_emu_primary_inquiry(const dnbd3_image_t *image, iscsi_scsi vpd_page_block_limits_inquiry_data_pkt->optimal_unmap_granularity = 0UL; vpd_page_block_limits_inquiry_data_pkt->unmap_granularity_align_ugavalid = 0UL; - iscsi_put_be64( (uint8_t *) &vpd_page_block_limits_inquiry_data_pkt->max_write_same_len, blocks ); + vpd_page_block_limits_inquiry_data_pkt->max_write_same_len = 0; vpd_page_block_limits_inquiry_data_pkt->reserved[0] = 0ULL; vpd_page_block_limits_inquiry_data_pkt->reserved[1] = 0ULL; vpd_page_block_limits_inquiry_data_pkt->reserved2 = 0UL; |
