Skip to content

Commit e83d776

Browse files
keithbuschsagigrimberg
authored andcommitted
nvme: only use power of two io boundaries
The kernel requires a power of two for boundaries because that's the only way it can efficiently split commands that cross them. A controller, however, may report a non-power of two boundary. The driver had been rounding the controller's value to one the kernel can use, but splitting on the wrong boundary provides no benefit on the device side, and incurs additional submission overhead from non-optimal splits. Don't provide any boundary hint if the controller's value can't be used and log a warning when first scanning a disk's unreported IO boundary. Since the chunk sector logic has grown, move it to a separate function. Cc: Martin K. Petersen <[email protected]> Signed-off-by: Keith Busch <[email protected]> Reviewed-by: Martin K. Petersen <[email protected]> Signed-off-by: Sagi Grimberg <[email protected]>
1 parent 192f6c2 commit e83d776

File tree

1 file changed

+38
-9
lines changed

1 file changed

+38
-9
lines changed

drivers/nvme/host/core.c

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,13 +2026,49 @@ static void nvme_update_disk_info(struct gendisk *disk,
20262026
blk_mq_unfreeze_queue(disk->queue);
20272027
}
20282028

2029+
static inline bool nvme_first_scan(struct gendisk *disk)
2030+
{
2031+
/* nvme_alloc_ns() scans the disk prior to adding it */
2032+
return !(disk->flags & GENHD_FL_UP);
2033+
}
2034+
2035+
static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id)
2036+
{
2037+
struct nvme_ctrl *ctrl = ns->ctrl;
2038+
u32 iob;
2039+
2040+
if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) &&
2041+
is_power_of_2(ctrl->max_hw_sectors))
2042+
iob = ctrl->max_hw_sectors;
2043+
else
2044+
iob = nvme_lba_to_sect(ns, le16_to_cpu(id->noiob));
2045+
2046+
if (!iob)
2047+
return;
2048+
2049+
if (!is_power_of_2(iob)) {
2050+
if (nvme_first_scan(ns->disk))
2051+
pr_warn("%s: ignoring unaligned IO boundary:%u\n",
2052+
ns->disk->disk_name, iob);
2053+
return;
2054+
}
2055+
2056+
if (blk_queue_is_zoned(ns->disk->queue)) {
2057+
if (nvme_first_scan(ns->disk))
2058+
pr_warn("%s: ignoring zoned namespace IO boundary\n",
2059+
ns->disk->disk_name);
2060+
return;
2061+
}
2062+
2063+
blk_queue_chunk_sectors(ns->queue, iob);
2064+
}
2065+
20292066
static int __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
20302067
{
20312068
unsigned lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
20322069
struct nvme_ns *ns = disk->private_data;
20332070
struct nvme_ctrl *ctrl = ns->ctrl;
20342071
int ret;
2035-
u32 iob;
20362072

20372073
/*
20382074
* If identify namespace failed, use default 512 byte block size so
@@ -2060,12 +2096,6 @@ static int __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
20602096
return -ENODEV;
20612097
}
20622098

2063-
if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) &&
2064-
is_power_of_2(ctrl->max_hw_sectors))
2065-
iob = ctrl->max_hw_sectors;
2066-
else
2067-
iob = nvme_lba_to_sect(ns, le16_to_cpu(id->noiob));
2068-
20692099
ns->features = 0;
20702100
ns->ms = le16_to_cpu(id->lbaf[lbaf].ms);
20712101
/* the PI implementation requires metadata equal t10 pi tuple size */
@@ -2097,8 +2127,7 @@ static int __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
20972127
}
20982128
}
20992129

2100-
if (iob && !blk_queue_is_zoned(ns->queue))
2101-
blk_queue_chunk_sectors(ns->queue, rounddown_pow_of_two(iob));
2130+
nvme_set_chunk_sectors(ns, id);
21022131
nvme_update_disk_info(disk, ns, id);
21032132
#ifdef CONFIG_NVME_MULTIPATH
21042133
if (ns->head->disk) {

0 commit comments

Comments
 (0)