1076 lines · 29.4 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * Functions related to sysfs handling */#include <linux/kernel.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/bio.h>#include <linux/blkdev.h>#include <linux/backing-dev.h>#include <linux/blktrace_api.h>#include <linux/debugfs.h> #include "blk.h"#include "blk-mq.h"#include "blk-mq-debugfs.h"#include "blk-mq-sched.h"#include "blk-rq-qos.h"#include "blk-wbt.h"#include "blk-cgroup.h"#include "blk-throttle.h"#include "error-injection.h" struct queue_sysfs_entry {	struct attribute attr;	ssize_t (*show)(struct gendisk *disk, char *page);	ssize_t (*show_limit)(struct gendisk *disk, char *page); 	ssize_t (*store)(struct gendisk *disk, const char *page, size_t count);	int (*store_limit)(struct gendisk *disk, const char *page,			size_t count, struct queue_limits *lim);}; static ssize_tqueue_var_show(unsigned long var, char *page){	return sysfs_emit(page, "%lu\n", var);} static ssize_tqueue_var_store(unsigned long *var, const char *page, size_t count){	int err;	unsigned long v; 	err = kstrtoul(page, 10, &v);	if (err || v > UINT_MAX)		return -EINVAL; 	*var = v; 	return count;} static ssize_t queue_requests_show(struct gendisk *disk, char *page){	ssize_t ret; 	mutex_lock(&disk->queue->elevator_lock);	ret = queue_var_show(disk->queue->nr_requests, page);	mutex_unlock(&disk->queue->elevator_lock);	return ret;} static ssize_tqueue_requests_store(struct gendisk *disk, const char *page, size_t count){	struct request_queue *q = disk->queue;	struct blk_mq_tag_set *set = q->tag_set;	struct elevator_tags *et = NULL;	unsigned int memflags;	unsigned long nr;	int ret; 	ret = queue_var_store(&nr, page, count);	if (ret < 0)		return ret; 	/*	 * Serialize updating nr_requests with concurrent queue_requests_store()	 * and switching elevator.	 *	 * Use trylock to avoid circular lock dependency with kernfs active	 * reference during concurrent disk deletion:	 *   update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)	 *   kn->active -> update_nr_hwq_lock (via this sysfs write path)	 */	if (!down_write_trylock(&set->update_nr_hwq_lock))		return -EBUSY; 	if (nr == q->nr_requests)		goto unlock; 	if (nr < BLKDEV_MIN_RQ)		nr = BLKDEV_MIN_RQ; 	/*	 * Switching elevator is protected by update_nr_hwq_lock:	 *  - read lock is held from elevator sysfs attribute;	 *  - write lock is held from updating nr_hw_queues;	 * Hence it's safe to access q->elevator here with write lock held.	 */	if (nr <= set->reserved_tags ||	    (q->elevator && nr > MAX_SCHED_RQ) ||	    (!q->elevator && nr > set->queue_depth)) {		ret = -EINVAL;		goto unlock;	} 	if (!blk_mq_is_shared_tags(set->flags) && q->elevator &&	    nr > q->elevator->et->nr_requests) {		/*		 * Tags will grow, allocate memory before freezing queue to		 * prevent deadlock.		 */		et = blk_mq_alloc_sched_tags(set, q->nr_hw_queues, nr);		if (!et) {			ret = -ENOMEM;			goto unlock;		}	} 	memflags = blk_mq_freeze_queue(q);	mutex_lock(&q->elevator_lock);	et = blk_mq_update_nr_requests(q, et, nr);	mutex_unlock(&q->elevator_lock);	blk_mq_unfreeze_queue(q, memflags); 	if (et)		blk_mq_free_sched_tags(et, set); unlock:	up_write(&set->update_nr_hwq_lock);	return ret;} static ssize_t queue_async_depth_show(struct gendisk *disk, char *page){	guard(mutex)(&disk->queue->elevator_lock); 	return queue_var_show(disk->queue->async_depth, page);} static ssize_tqueue_async_depth_store(struct gendisk *disk, const char *page, size_t count){	struct request_queue *q = disk->queue;	unsigned int memflags;	unsigned long nr;	int ret; 	if (!queue_is_mq(q))		return -EINVAL; 	ret = queue_var_store(&nr, page, count);	if (ret < 0)		return ret; 	if (nr == 0)		return -EINVAL; 	memflags = blk_mq_freeze_queue(q);	scoped_guard(mutex, &q->elevator_lock) {		if (q->elevator) {			q->async_depth = min(q->nr_requests, nr);			if (q->elevator->type->ops.depth_updated)				q->elevator->type->ops.depth_updated(q);		} else {			ret = -EINVAL;		}	}	blk_mq_unfreeze_queue(q, memflags); 	return ret;} static ssize_t queue_ra_show(struct gendisk *disk, char *page){	ssize_t ret; 	mutex_lock(&disk->queue->limits_lock);	ret = queue_var_show(disk->bdi->ra_pages << (PAGE_SHIFT - 10), page);	mutex_unlock(&disk->queue->limits_lock); 	return ret;} static ssize_tqueue_ra_store(struct gendisk *disk, const char *page, size_t count){	unsigned long ra_kb;	ssize_t ret;	struct request_queue *q = disk->queue; 	ret = queue_var_store(&ra_kb, page, count);	if (ret < 0)		return ret;	/*	 * The ->ra_pages change below is protected by ->limits_lock because it	 * is usually calculated from the queue limits by	 * queue_limits_commit_update().	 *	 * bdi->ra_pages reads are not serialized against bdi->ra_pages writes.	 * Use WRITE_ONCE() to write bdi->ra_pages once.	 */	mutex_lock(&q->limits_lock);	WRITE_ONCE(disk->bdi->ra_pages, ra_kb >> (PAGE_SHIFT - 10));	mutex_unlock(&q->limits_lock); 	return ret;} #define QUEUE_SYSFS_LIMIT_SHOW(_field)					\static ssize_t queue_##_field##_show(struct gendisk *disk, char *page)	\{									\	return queue_var_show(disk->queue->limits._field, page);	\} QUEUE_SYSFS_LIMIT_SHOW(max_segments)QUEUE_SYSFS_LIMIT_SHOW(max_discard_segments)QUEUE_SYSFS_LIMIT_SHOW(max_integrity_segments)QUEUE_SYSFS_LIMIT_SHOW(max_segment_size)QUEUE_SYSFS_LIMIT_SHOW(max_write_streams)QUEUE_SYSFS_LIMIT_SHOW(write_stream_granularity)QUEUE_SYSFS_LIMIT_SHOW(logical_block_size)QUEUE_SYSFS_LIMIT_SHOW(physical_block_size)QUEUE_SYSFS_LIMIT_SHOW(chunk_sectors)QUEUE_SYSFS_LIMIT_SHOW(io_min)QUEUE_SYSFS_LIMIT_SHOW(io_opt)QUEUE_SYSFS_LIMIT_SHOW(discard_granularity)QUEUE_SYSFS_LIMIT_SHOW(zone_write_granularity)QUEUE_SYSFS_LIMIT_SHOW(virt_boundary_mask)QUEUE_SYSFS_LIMIT_SHOW(dma_alignment)QUEUE_SYSFS_LIMIT_SHOW(max_open_zones)QUEUE_SYSFS_LIMIT_SHOW(max_active_zones)QUEUE_SYSFS_LIMIT_SHOW(atomic_write_unit_min)QUEUE_SYSFS_LIMIT_SHOW(atomic_write_unit_max) #define QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(_field)			\static ssize_t queue_##_field##_show(struct gendisk *disk, char *page)	\{									\	return sysfs_emit(page, "%llu\n",				\		(unsigned long long)disk->queue->limits._field <<	\			SECTOR_SHIFT);					\} QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(max_discard_sectors)QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(max_hw_discard_sectors)QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(max_write_zeroes_sectors)QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(max_hw_wzeroes_unmap_sectors)QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(max_wzeroes_unmap_sectors)QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(atomic_write_max_sectors)QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(atomic_write_boundary_sectors)QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(max_zone_append_sectors) #define QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_KB(_field)			\static ssize_t queue_##_field##_show(struct gendisk *disk, char *page)	\{									\	return queue_var_show(disk->queue->limits._field >> 1, page);	\} QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_KB(max_sectors)QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_KB(max_hw_sectors) #define QUEUE_SYSFS_SHOW_CONST(_name, _val)				\static ssize_t queue_##_name##_show(struct gendisk *disk, char *page)	\{									\	return sysfs_emit(page, "%d\n", _val);				\} /* deprecated fields */QUEUE_SYSFS_SHOW_CONST(discard_zeroes_data, 0)QUEUE_SYSFS_SHOW_CONST(write_same_max, 0)QUEUE_SYSFS_SHOW_CONST(poll_delay, -1) static int queue_max_discard_sectors_store(struct gendisk *disk,		const char *page, size_t count, struct queue_limits *lim){	unsigned long max_discard_bytes;	ssize_t ret; 	ret = queue_var_store(&max_discard_bytes, page, count);	if (ret < 0)		return ret; 	if (max_discard_bytes & (disk->queue->limits.discard_granularity - 1))		return -EINVAL; 	if ((max_discard_bytes >> SECTOR_SHIFT) > UINT_MAX)		return -EINVAL; 	lim->max_user_discard_sectors = max_discard_bytes >> SECTOR_SHIFT;	return 0;} static int queue_max_wzeroes_unmap_sectors_store(struct gendisk *disk,		const char *page, size_t count, struct queue_limits *lim){	unsigned long max_zeroes_bytes, max_hw_zeroes_bytes;	ssize_t ret; 	ret = queue_var_store(&max_zeroes_bytes, page, count);	if (ret < 0)		return ret; 	max_hw_zeroes_bytes = lim->max_hw_wzeroes_unmap_sectors << SECTOR_SHIFT;	if (max_zeroes_bytes != 0 && max_zeroes_bytes != max_hw_zeroes_bytes)		return -EINVAL; 	lim->max_user_wzeroes_unmap_sectors = max_zeroes_bytes >> SECTOR_SHIFT;	return 0;} static intqueue_max_sectors_store(struct gendisk *disk, const char *page, size_t count,		struct queue_limits *lim){	unsigned long max_sectors_kb;	ssize_t ret; 	ret = queue_var_store(&max_sectors_kb, page, count);	if (ret < 0)		return ret; 	lim->max_user_sectors = max_sectors_kb << 1;	return 0;} static ssize_t queue_feature_store(struct gendisk *disk, const char *page,		size_t count, struct queue_limits *lim, blk_features_t feature){	unsigned long val;	ssize_t ret; 	ret = queue_var_store(&val, page, count);	if (ret < 0)		return ret; 	if (val)		lim->features |= feature;	else		lim->features &= ~feature;	return 0;} #define QUEUE_SYSFS_FEATURE(_name, _feature)				\static ssize_t queue_##_name##_show(struct gendisk *disk, char *page)	\{									\	return sysfs_emit(page, "%u\n",					\		!!(disk->queue->limits.features & _feature));		\}									\static int queue_##_name##_store(struct gendisk *disk,			\		const char *page, size_t count, struct queue_limits *lim) \{									\	return queue_feature_store(disk, page, count, lim, _feature);	\} QUEUE_SYSFS_FEATURE(rotational, BLK_FEAT_ROTATIONAL)QUEUE_SYSFS_FEATURE(add_random, BLK_FEAT_ADD_RANDOM)QUEUE_SYSFS_FEATURE(iostats, BLK_FEAT_IO_STAT)QUEUE_SYSFS_FEATURE(stable_writes, BLK_FEAT_STABLE_WRITES); #define QUEUE_SYSFS_FEATURE_SHOW(_name, _feature)			\static ssize_t queue_##_name##_show(struct gendisk *disk, char *page)	\{									\	return sysfs_emit(page, "%u\n",					\		!!(disk->queue->limits.features & _feature));		\} QUEUE_SYSFS_FEATURE_SHOW(fua, BLK_FEAT_FUA);QUEUE_SYSFS_FEATURE_SHOW(dax, BLK_FEAT_DAX); static ssize_t queue_poll_show(struct gendisk *disk, char *page){	if (queue_is_mq(disk->queue))		return sysfs_emit(page, "%u\n", blk_mq_can_poll(disk->queue)); 	return sysfs_emit(page, "%u\n",			!!(disk->queue->limits.features & BLK_FEAT_POLL));} static ssize_t queue_zoned_show(struct gendisk *disk, char *page){	if (blk_queue_is_zoned(disk->queue))		return sysfs_emit(page, "host-managed\n");	return sysfs_emit(page, "none\n");} 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);} static int queue_iostats_passthrough_store(struct gendisk *disk,		const char *page, size_t count, struct queue_limits *lim){	unsigned long ios;	ssize_t ret; 	ret = queue_var_store(&ios, page, count);	if (ret < 0)		return ret; 	if (ios)		lim->flags |= BLK_FLAG_IOSTATS_PASSTHROUGH;	else		lim->flags &= ~BLK_FLAG_IOSTATS_PASSTHROUGH;	return 0;} static ssize_t queue_nomerges_show(struct gendisk *disk, char *page){	return queue_var_show((blk_queue_nomerges(disk->queue) << 1) |			       blk_queue_noxmerges(disk->queue), page);} static ssize_t queue_nomerges_store(struct gendisk *disk, const char *page,				    size_t count){	unsigned long nm;	struct request_queue *q = disk->queue;	ssize_t ret = queue_var_store(&nm, page, count); 	if (ret < 0)		return ret; 	blk_queue_flag_clear(QUEUE_FLAG_NOMERGES, q);	blk_queue_flag_clear(QUEUE_FLAG_NOXMERGES, q);	if (nm == 2)		blk_queue_flag_set(QUEUE_FLAG_NOMERGES, q);	else if (nm)		blk_queue_flag_set(QUEUE_FLAG_NOXMERGES, q); 	return ret;} static ssize_t queue_rq_affinity_show(struct gendisk *disk, char *page){	bool set = test_bit(QUEUE_FLAG_SAME_COMP, &disk->queue->queue_flags);	bool force = test_bit(QUEUE_FLAG_SAME_FORCE, &disk->queue->queue_flags); 	return queue_var_show(set << force, page);} static ssize_tqueue_rq_affinity_store(struct gendisk *disk, const char *page, size_t count){	ssize_t ret = -EINVAL;#ifdef CONFIG_SMP	struct request_queue *q = disk->queue;	unsigned long val; 	ret = queue_var_store(&val, page, count);	if (ret < 0)		return ret; 	/*	 * Here we update two queue flags each using atomic bitops, although	 * updating two flags isn't atomic it should be harmless as those flags	 * are accessed individually using atomic test_bit operation. So we	 * don't grab any lock while updating these flags.	 */	if (val == 2) {		blk_queue_flag_set(QUEUE_FLAG_SAME_COMP, q);		blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, q);

Lines 1–500 of 1076.