Skip to content
15 changes: 15 additions & 0 deletions Documentation/ABI/stable/sysfs-block
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,21 @@ Description:
zone commands, they will be treated as regular block devices and
zoned will report "none".

What: /sys/block/<disk>/queue/zoned_qd1_writes
Date: January 2026
Contact: Damien Le Moal <dlemoal@kernel.org>
Description:
[RW] zoned_qd1_writes indicates if write operations to a zoned
block device are being handled using a single issuer context (a
kernel thread) operating at a maximum queue depth of 1. This
attribute is visible only for zoned block devices. The default
value for zoned block devices that are not rotational devices
(e.g. ZNS SSDs or zoned UFS devices) is 0. For rotational zoned
block devices (e.g. SMR HDDs) the default value is 1. Since
this default may not be appropriate for some devices, e.g.
remotely connected devices over high latency networks, the user
can disable this feature by setting this attribute to 0.


What: /sys/block/<disk>/hidden
Date: March 2023
Expand Down
1 change: 1 addition & 0 deletions block/blk-mq-debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ static const char *const blk_queue_flag_name[] = {
QUEUE_FLAG_NAME(NO_ELV_SWITCH),
QUEUE_FLAG_NAME(QOS_ENABLED),
QUEUE_FLAG_NAME(BIO_ISSUE_TIME),
QUEUE_FLAG_NAME(ZONED_QD1_WRITES),
};
#undef QUEUE_FLAG_NAME

Expand Down
43 changes: 42 additions & 1 deletion block/blk-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,36 @@ static ssize_t queue_nr_zones_show(struct gendisk *disk, char *page)
return queue_var_show(disk_nr_zones(disk), page);
}

static ssize_t queue_zoned_qd1_writes_show(struct gendisk *disk, char *page)
{
return queue_var_show(!!blk_queue_zoned_qd1_writes(disk->queue),
page);
}

static ssize_t queue_zoned_qd1_writes_store(struct gendisk *disk,
const char *page, size_t count)
{
struct request_queue *q = disk->queue;
unsigned long qd1_writes;
unsigned int memflags;
ssize_t ret;

ret = queue_var_store(&qd1_writes, page, count);
if (ret < 0)
return ret;

memflags = blk_mq_freeze_queue(q);
blk_mq_quiesce_queue(q);
if (qd1_writes)
blk_queue_flag_set(QUEUE_FLAG_ZONED_QD1_WRITES, q);
else
blk_queue_flag_clear(QUEUE_FLAG_ZONED_QD1_WRITES, q);
blk_mq_unquiesce_queue(q);
blk_mq_unfreeze_queue(q, memflags);

return count;
}

static ssize_t queue_iostats_passthrough_show(struct gendisk *disk, char *page)
{
return queue_var_show(!!blk_queue_passthrough_stat(disk->queue), page);
Expand Down Expand Up @@ -617,6 +647,7 @@ QUEUE_LIM_RO_ENTRY(queue_max_zone_append_sectors, "zone_append_max_bytes");
QUEUE_LIM_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity");

QUEUE_LIM_RO_ENTRY(queue_zoned, "zoned");
QUEUE_RW_ENTRY(queue_zoned_qd1_writes, "zoned_qd1_writes");
QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones");
QUEUE_LIM_RO_ENTRY(queue_max_open_zones, "max_open_zones");
QUEUE_LIM_RO_ENTRY(queue_max_active_zones, "max_active_zones");
Expand Down Expand Up @@ -754,6 +785,7 @@ static struct attribute *queue_attrs[] = {
&queue_nomerges_entry.attr,
&queue_poll_entry.attr,
&queue_poll_delay_entry.attr,
&queue_zoned_qd1_writes_entry.attr,

NULL,
};
Expand Down Expand Up @@ -786,7 +818,8 @@ static umode_t queue_attr_visible(struct kobject *kobj, struct attribute *attr,
struct request_queue *q = disk->queue;

if ((attr == &queue_max_open_zones_entry.attr ||
attr == &queue_max_active_zones_entry.attr) &&
attr == &queue_max_active_zones_entry.attr ||
attr == &queue_zoned_qd1_writes_entry.attr) &&
!blk_queue_is_zoned(q))
return 0;

Expand Down Expand Up @@ -934,6 +967,14 @@ int blk_register_queue(struct gendisk *disk)
blk_mq_debugfs_register(q);
blk_debugfs_unlock(q, memflags);

/*
* For blk-mq rotational zoned devices, default to using QD=1
* writes. For non-mq rotational zoned devices, the device driver can
* set an appropriate default.
*/
if (queue_is_mq(q) && blk_queue_rot(q) && blk_queue_is_zoned(q))
blk_queue_flag_set(QUEUE_FLAG_ZONED_QD1_WRITES, q);

ret = disk_register_independent_access_ranges(disk);
if (ret)
goto out_debugfs_remove;
Expand Down
Loading