For stacking devices, not all underlying bottom devices may support atomic writes, so a feature flag would be helpful in deciding whether the top device may support atomic writes. Furthermore, even if all bottom devices support atomic writes, a md/dm personality may not. Add flag BLK_FEAT_ATOMIC_WRITES to decide whether a block device supports atomic writes. Signed-off-by: John Garry <john.g.garry@xxxxxxxxxx> --- block/blk-settings.c | 3 ++- drivers/nvme/host/core.c | 3 +++ drivers/scsi/sd.c | 13 ++++++++++--- include/linux/blkdev.h | 3 +++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/block/blk-settings.c b/block/blk-settings.c index cd8a8eabc9a5..036e67f73116 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -176,7 +176,7 @@ static void blk_validate_atomic_write_limits(struct queue_limits *lim) { unsigned int boundary_sectors; - if (!lim->atomic_write_hw_max) + if (!(lim->features & BLK_FEAT_ATOMIC_WRITES) || !lim->atomic_write_hw_max) goto unsupported; boundary_sectors = lim->atomic_write_hw_boundary >> SECTOR_SHIFT; @@ -217,6 +217,7 @@ static void blk_validate_atomic_write_limits(struct queue_limits *lim) lim->atomic_write_boundary_sectors = 0; lim->atomic_write_unit_min = 0; lim->atomic_write_unit_max = 0; + lim->features &= ~BLK_FEAT_ATOMIC_WRITES; } /* diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 0dc8bcc664f2..c70d8e7602bf 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1975,6 +1975,7 @@ static void nvme_update_atomic_write_disk_info(struct nvme_ns *ns, lim->atomic_write_hw_boundary = boundary; lim->atomic_write_hw_unit_min = bs; lim->atomic_write_hw_unit_max = rounddown_pow_of_two(atomic_bs); + lim->features |= BLK_FEAT_ATOMIC_WRITES; } static u32 nvme_max_drv_segments(struct nvme_ctrl *ctrl) @@ -2025,6 +2026,8 @@ static bool nvme_update_disk_info(struct nvme_ns *ns, struct nvme_id_ns *id, atomic_bs = (1 + ns->ctrl->subsys->awupf) * bs; nvme_update_atomic_write_disk_info(ns, id, lim, bs, atomic_bs); + } else { + lim->features &= ~BLK_FEAT_ATOMIC_WRITES; } if (id->nsfeat & NVME_NS_FEAT_IO_OPT) { diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 9db86943d04c..aecd05165ee8 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -948,7 +948,7 @@ static void sd_config_atomic(struct scsi_disk *sdkp, struct queue_limits *lim) if ((!sdkp->max_atomic && !sdkp->max_atomic_with_boundary) || sdkp->protection_type == T10_PI_TYPE2_PROTECTION) - return; + goto out_unsupported; physical_block_size_sectors = sdkp->physical_block_size / sdkp->device->sector_size; @@ -988,15 +988,22 @@ static void sd_config_atomic(struct scsi_disk *sdkp, struct queue_limits *lim) if (sdkp->atomic_alignment > 1) { if (unit_min > 1 && unit_min % sdkp->atomic_alignment) - return; + goto out_unsupported; if (unit_max > 1 && unit_max % sdkp->atomic_alignment) - return; + goto out_unsupported; } lim->atomic_write_hw_max = max_atomic * logical_block_size; lim->atomic_write_hw_boundary = 0; lim->atomic_write_hw_unit_min = unit_min * logical_block_size; lim->atomic_write_hw_unit_max = unit_max * logical_block_size; + + lim->features |= BLK_FEAT_ATOMIC_WRITES; + return; + +out_unsupported: + lim->features &= ~BLK_FEAT_ATOMIC_WRITES; + return; } static blk_status_t sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd, diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index af8434e391fa..c8c6a496a6ed 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -332,6 +332,9 @@ typedef unsigned int __bitwise blk_features_t; #define BLK_FEAT_RAID_PARTIAL_STRIPES_EXPENSIVE \ ((__force blk_features_t)(1u << 15)) +/* device supports atomic writes */ +#define BLK_FEAT_ATOMIC_WRITES ((__force blk_features_t)(1u << 16)) + /* * Flags automatically inherited when stacking limits. */ -- 2.31.1