block/blk-sysfs.c

Source file repositories/reference/linux-study-clean/block/blk-sysfs.c

File Facts

System
Linux kernel
Corpus path
block/blk-sysfs.c
Extension
.c
Size
30061 bytes
Lines
1077
Domain
Representative Device Path
Bucket
PCIe NVMe Storage Path
Inferred role
Representative Device Path: implementation source
Status
source implementation candidate

Why This File Exists

Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.

Dependency Surface

Detected Declarations

Annotated Snippet

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_t
queue_var_show(unsigned long var, char *page)
{
	return sysfs_emit(page, "%lu\n", var);
}

static ssize_t
queue_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_t
queue_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

Annotation

Implementation Notes