Skip to content

Commit 6e51a12

Browse files
shroffniaxboe
authored andcommitted
block: acquire q->limits_lock while reading sysfs attributes
There're few sysfs attributes(RW) whose store method is protected with q->limits_lock, however the corresponding show method of these attributes run holding q->sysfs_lock and that doesn't make sense as ideally the show method of these attributes should also run holding q->limits_lock instead of q->sysfs_lock. Hence update the show method of these sysfs attributes so that reading of these attributes acquire q->limits_lock instead of q->sysfs_lock. Similarly, there're few sysfs attributes(RO) whose show method is currently protected with q->sysfs_lock however updates to these attributes could occur using atomic limit update APIs such as queue_ limits_start_update() and queue_limits_commit_update() which run holding q->limits_lock. So that means that reading these attributes holding q->sysfs_lock doesn't make sense. Hence update the show method of these sysfs attributes(RO) such that they run with holding q-> limits_lock instead of q->sysfs_lock. We have defined a new macro QUEUE_LIM_RO_ENTRY() which uses new ->show_ limit() method and it runs holding q->limits_lock. All existing sysfs attributes(RO) which needs protection using q->limits_lock while reading have been now updated to use this new macro for initialization. Also, the existing QUEUE_LIM_RW_ENTRY() is updated to use new ->show_ limit() method for reading attributes instead of existing ->show() method. As ->show_limit() runs holding q->limits_lock, the existing sysfs attributes(RW) requiring protection are now inherently protected using q->limits_lock instead of q->sysfs_lock. Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Reviewed-by: Ming Lei <[email protected]> Signed-off-by: Nilay Shroff <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent d301f16 commit 6e51a12

File tree

1 file changed

+65
-37
lines changed

1 file changed

+65
-37
lines changed

block/blk-sysfs.c

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@
2323
struct queue_sysfs_entry {
2424
struct attribute attr;
2525
ssize_t (*show)(struct gendisk *disk, char *page);
26+
ssize_t (*show_limit)(struct gendisk *disk, char *page);
27+
2628
ssize_t (*store)(struct gendisk *disk, const char *page, size_t count);
2729
int (*store_limit)(struct gendisk *disk, const char *page,
2830
size_t count, struct queue_limits *lim);
31+
2932
void (*load_module)(struct gendisk *disk, const char *page, size_t count);
3033
};
3134

@@ -412,10 +415,16 @@ static struct queue_sysfs_entry _prefix##_entry = { \
412415
.store = _prefix##_store, \
413416
};
414417

418+
#define QUEUE_LIM_RO_ENTRY(_prefix, _name) \
419+
static struct queue_sysfs_entry _prefix##_entry = { \
420+
.attr = { .name = _name, .mode = 0444 }, \
421+
.show_limit = _prefix##_show, \
422+
}
423+
415424
#define QUEUE_LIM_RW_ENTRY(_prefix, _name) \
416425
static struct queue_sysfs_entry _prefix##_entry = { \
417426
.attr = { .name = _name, .mode = 0644 }, \
418-
.show = _prefix##_show, \
427+
.show_limit = _prefix##_show, \
419428
.store_limit = _prefix##_store, \
420429
}
421430

@@ -430,56 +439,56 @@ static struct queue_sysfs_entry _prefix##_entry = { \
430439
QUEUE_RW_ENTRY(queue_requests, "nr_requests");
431440
QUEUE_RW_ENTRY(queue_ra, "read_ahead_kb");
432441
QUEUE_LIM_RW_ENTRY(queue_max_sectors, "max_sectors_kb");
433-
QUEUE_RO_ENTRY(queue_max_hw_sectors, "max_hw_sectors_kb");
434-
QUEUE_RO_ENTRY(queue_max_segments, "max_segments");
435-
QUEUE_RO_ENTRY(queue_max_integrity_segments, "max_integrity_segments");
436-
QUEUE_RO_ENTRY(queue_max_segment_size, "max_segment_size");
442+
QUEUE_LIM_RO_ENTRY(queue_max_hw_sectors, "max_hw_sectors_kb");
443+
QUEUE_LIM_RO_ENTRY(queue_max_segments, "max_segments");
444+
QUEUE_LIM_RO_ENTRY(queue_max_integrity_segments, "max_integrity_segments");
445+
QUEUE_LIM_RO_ENTRY(queue_max_segment_size, "max_segment_size");
437446
QUEUE_RW_LOAD_MODULE_ENTRY(elv_iosched, "scheduler");
438447

439-
QUEUE_RO_ENTRY(queue_logical_block_size, "logical_block_size");
440-
QUEUE_RO_ENTRY(queue_physical_block_size, "physical_block_size");
441-
QUEUE_RO_ENTRY(queue_chunk_sectors, "chunk_sectors");
442-
QUEUE_RO_ENTRY(queue_io_min, "minimum_io_size");
443-
QUEUE_RO_ENTRY(queue_io_opt, "optimal_io_size");
448+
QUEUE_LIM_RO_ENTRY(queue_logical_block_size, "logical_block_size");
449+
QUEUE_LIM_RO_ENTRY(queue_physical_block_size, "physical_block_size");
450+
QUEUE_LIM_RO_ENTRY(queue_chunk_sectors, "chunk_sectors");
451+
QUEUE_LIM_RO_ENTRY(queue_io_min, "minimum_io_size");
452+
QUEUE_LIM_RO_ENTRY(queue_io_opt, "optimal_io_size");
444453

445-
QUEUE_RO_ENTRY(queue_max_discard_segments, "max_discard_segments");
446-
QUEUE_RO_ENTRY(queue_discard_granularity, "discard_granularity");
447-
QUEUE_RO_ENTRY(queue_max_hw_discard_sectors, "discard_max_hw_bytes");
454+
QUEUE_LIM_RO_ENTRY(queue_max_discard_segments, "max_discard_segments");
455+
QUEUE_LIM_RO_ENTRY(queue_discard_granularity, "discard_granularity");
456+
QUEUE_LIM_RO_ENTRY(queue_max_hw_discard_sectors, "discard_max_hw_bytes");
448457
QUEUE_LIM_RW_ENTRY(queue_max_discard_sectors, "discard_max_bytes");
449458
QUEUE_RO_ENTRY(queue_discard_zeroes_data, "discard_zeroes_data");
450459

451-
QUEUE_RO_ENTRY(queue_atomic_write_max_sectors, "atomic_write_max_bytes");
452-
QUEUE_RO_ENTRY(queue_atomic_write_boundary_sectors,
460+
QUEUE_LIM_RO_ENTRY(queue_atomic_write_max_sectors, "atomic_write_max_bytes");
461+
QUEUE_LIM_RO_ENTRY(queue_atomic_write_boundary_sectors,
453462
"atomic_write_boundary_bytes");
454-
QUEUE_RO_ENTRY(queue_atomic_write_unit_max, "atomic_write_unit_max_bytes");
455-
QUEUE_RO_ENTRY(queue_atomic_write_unit_min, "atomic_write_unit_min_bytes");
463+
QUEUE_LIM_RO_ENTRY(queue_atomic_write_unit_max, "atomic_write_unit_max_bytes");
464+
QUEUE_LIM_RO_ENTRY(queue_atomic_write_unit_min, "atomic_write_unit_min_bytes");
456465

457466
QUEUE_RO_ENTRY(queue_write_same_max, "write_same_max_bytes");
458-
QUEUE_RO_ENTRY(queue_max_write_zeroes_sectors, "write_zeroes_max_bytes");
459-
QUEUE_RO_ENTRY(queue_max_zone_append_sectors, "zone_append_max_bytes");
460-
QUEUE_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity");
467+
QUEUE_LIM_RO_ENTRY(queue_max_write_zeroes_sectors, "write_zeroes_max_bytes");
468+
QUEUE_LIM_RO_ENTRY(queue_max_zone_append_sectors, "zone_append_max_bytes");
469+
QUEUE_LIM_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity");
461470

462-
QUEUE_RO_ENTRY(queue_zoned, "zoned");
471+
QUEUE_LIM_RO_ENTRY(queue_zoned, "zoned");
463472
QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones");
464-
QUEUE_RO_ENTRY(queue_max_open_zones, "max_open_zones");
465-
QUEUE_RO_ENTRY(queue_max_active_zones, "max_active_zones");
473+
QUEUE_LIM_RO_ENTRY(queue_max_open_zones, "max_open_zones");
474+
QUEUE_LIM_RO_ENTRY(queue_max_active_zones, "max_active_zones");
466475

467476
QUEUE_RW_ENTRY(queue_nomerges, "nomerges");
468477
QUEUE_LIM_RW_ENTRY(queue_iostats_passthrough, "iostats_passthrough");
469478
QUEUE_RW_ENTRY(queue_rq_affinity, "rq_affinity");
470479
QUEUE_RW_ENTRY(queue_poll, "io_poll");
471480
QUEUE_RW_ENTRY(queue_poll_delay, "io_poll_delay");
472481
QUEUE_LIM_RW_ENTRY(queue_wc, "write_cache");
473-
QUEUE_RO_ENTRY(queue_fua, "fua");
474-
QUEUE_RO_ENTRY(queue_dax, "dax");
482+
QUEUE_LIM_RO_ENTRY(queue_fua, "fua");
483+
QUEUE_LIM_RO_ENTRY(queue_dax, "dax");
475484
QUEUE_RW_ENTRY(queue_io_timeout, "io_timeout");
476-
QUEUE_RO_ENTRY(queue_virt_boundary_mask, "virt_boundary_mask");
477-
QUEUE_RO_ENTRY(queue_dma_alignment, "dma_alignment");
485+
QUEUE_LIM_RO_ENTRY(queue_virt_boundary_mask, "virt_boundary_mask");
486+
QUEUE_LIM_RO_ENTRY(queue_dma_alignment, "dma_alignment");
478487

479488
/* legacy alias for logical_block_size: */
480489
static struct queue_sysfs_entry queue_hw_sector_size_entry = {
481-
.attr = {.name = "hw_sector_size", .mode = 0444 },
482-
.show = queue_logical_block_size_show,
490+
.attr = {.name = "hw_sector_size", .mode = 0444 },
491+
.show_limit = queue_logical_block_size_show,
483492
};
484493

485494
QUEUE_LIM_RW_ENTRY(queue_rotational, "rotational");
@@ -561,7 +570,9 @@ QUEUE_RW_ENTRY(queue_wb_lat, "wbt_lat_usec");
561570

562571
/* Common attributes for bio-based and request-based queues. */
563572
static struct attribute *queue_attrs[] = {
564-
&queue_ra_entry.attr,
573+
/*
574+
* Attributes which are protected with q->limits_lock.
575+
*/
565576
&queue_max_hw_sectors_entry.attr,
566577
&queue_max_sectors_entry.attr,
567578
&queue_max_segments_entry.attr,
@@ -577,37 +588,46 @@ static struct attribute *queue_attrs[] = {
577588
&queue_discard_granularity_entry.attr,
578589
&queue_max_discard_sectors_entry.attr,
579590
&queue_max_hw_discard_sectors_entry.attr,
580-
&queue_discard_zeroes_data_entry.attr,
581591
&queue_atomic_write_max_sectors_entry.attr,
582592
&queue_atomic_write_boundary_sectors_entry.attr,
583593
&queue_atomic_write_unit_min_entry.attr,
584594
&queue_atomic_write_unit_max_entry.attr,
585-
&queue_write_same_max_entry.attr,
586595
&queue_max_write_zeroes_sectors_entry.attr,
587596
&queue_max_zone_append_sectors_entry.attr,
588597
&queue_zone_write_granularity_entry.attr,
589598
&queue_rotational_entry.attr,
590599
&queue_zoned_entry.attr,
591-
&queue_nr_zones_entry.attr,
592600
&queue_max_open_zones_entry.attr,
593601
&queue_max_active_zones_entry.attr,
594-
&queue_nomerges_entry.attr,
595602
&queue_iostats_passthrough_entry.attr,
596603
&queue_iostats_entry.attr,
597604
&queue_stable_writes_entry.attr,
598605
&queue_add_random_entry.attr,
599-
&queue_poll_entry.attr,
600606
&queue_wc_entry.attr,
601607
&queue_fua_entry.attr,
602608
&queue_dax_entry.attr,
603-
&queue_poll_delay_entry.attr,
604609
&queue_virt_boundary_mask_entry.attr,
605610
&queue_dma_alignment_entry.attr,
611+
612+
/*
613+
* Attributes which are protected with q->sysfs_lock.
614+
*/
615+
&queue_ra_entry.attr,
616+
&queue_discard_zeroes_data_entry.attr,
617+
&queue_write_same_max_entry.attr,
618+
&queue_nr_zones_entry.attr,
619+
&queue_nomerges_entry.attr,
620+
&queue_poll_entry.attr,
621+
&queue_poll_delay_entry.attr,
622+
606623
NULL,
607624
};
608625

609626
/* Request-based queue attributes that are not relevant for bio-based queues. */
610627
static struct attribute *blk_mq_queue_attrs[] = {
628+
/*
629+
* Attributes which are protected with q->sysfs_lock.
630+
*/
611631
&queue_requests_entry.attr,
612632
&elv_iosched_entry.attr,
613633
&queue_rq_affinity_entry.attr,
@@ -666,8 +686,16 @@ queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
666686
struct gendisk *disk = container_of(kobj, struct gendisk, queue_kobj);
667687
ssize_t res;
668688

669-
if (!entry->show)
689+
if (!entry->show && !entry->show_limit)
670690
return -EIO;
691+
692+
if (entry->show_limit) {
693+
mutex_lock(&disk->queue->limits_lock);
694+
res = entry->show_limit(disk, page);
695+
mutex_unlock(&disk->queue->limits_lock);
696+
return res;
697+
}
698+
671699
mutex_lock(&disk->queue->sysfs_lock);
672700
res = entry->show(disk, page);
673701
mutex_unlock(&disk->queue->sysfs_lock);

0 commit comments

Comments
 (0)