Commit 68c43f13 authored by Damien Le Moal's avatar Damien Le Moal Committed by Jens Axboe
Browse files

block: Introduce elevator features



Introduce the definition of elevator features through the
elevator_features flags in the elevator_type structure. Each flag can
represent a feature supported by an elevator. The first feature defined
by this patch is support for zoned block device sequential write
constraint with the flag ELEVATOR_F_ZBD_SEQ_WRITE, which is implemented
by the mq-deadline elevator using zone write locking.

Other possible features are IO priorities, write hints, latency targets
or single-LUN dual-actuator disks (for which the elevator could maintain
one LBA ordered list per actuator).

The required_elevator_features field is also added to the request_queue
structure to allow a device driver to specify elevator feature flags
that an elevator must support for the correct operation of the device
(e.g. device drivers for zoned block devices can have the
ELEVATOR_F_ZBD_SEQ_WRITE flag as a required feature).
The helper function blk_queue_required_elevator_features() is
defined for setting this new field.

With these two new fields in place, the elevator functions
elevator_match() and elevator_find() are modified to allow a user to set
only an elevator with a set of features that satisfies the device
required features. Elevators not matching the device requirements are
not shown in the device sysfs queue/scheduler file to prevent their use.

The "none" elevator can always be selected as before.

Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarMing Lei <ming.lei@redhat.com>
Signed-off-by: default avatarDamien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 954b4a5c
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -832,6 +832,22 @@ void blk_queue_write_cache(struct request_queue *q, bool wc, bool fua)
}
EXPORT_SYMBOL_GPL(blk_queue_write_cache);

/**
 * blk_queue_required_elevator_features - Set a queue required elevator features
 * @q:		the request queue for the target device
 * @features:	Required elevator features OR'ed together
 *
 * Tell the block layer that for the device controlled through @q, only the
 * only elevators that can be used are those that implement at least the set of
 * features specified by @features.
 */
void blk_queue_required_elevator_features(struct request_queue *q,
					  unsigned int features)
{
	q->required_elevator_features = features;
}
EXPORT_SYMBOL_GPL(blk_queue_required_elevator_features);

static int __init blk_settings_init(void)
{
	blk_max_low_pfn = max_low_pfn - 1;
+38 −11
Original line number Diff line number Diff line
@@ -83,8 +83,26 @@ bool elv_bio_merge_ok(struct request *rq, struct bio *bio)
}
EXPORT_SYMBOL(elv_bio_merge_ok);

static bool elevator_match(const struct elevator_type *e, const char *name)
static inline bool elv_support_features(unsigned int elv_features,
					unsigned int required_features)
{
	return (required_features & elv_features) == required_features;
}

/**
 * elevator_match - Test an elevator name and features
 * @e: Scheduler to test
 * @name: Elevator name to test
 * @required_features: Features that the elevator must provide
 *
 * Return true is the elevator @e name matches @name and if @e provides all the
 * the feratures spcified by @required_features.
 */
static bool elevator_match(const struct elevator_type *e, const char *name,
			   unsigned int required_features)
{
	if (!elv_support_features(e->elevator_features, required_features))
		return false;
	if (!strcmp(e->elevator_name, name))
		return true;
	if (e->elevator_alias && !strcmp(e->elevator_alias, name))
@@ -93,15 +111,21 @@ static bool elevator_match(const struct elevator_type *e, const char *name)
	return false;
}

/*
 * Return scheduler with name 'name'
/**
 * elevator_find - Find an elevator
 * @name: Name of the elevator to find
 * @required_features: Features that the elevator must provide
 *
 * Return the first registered scheduler with name @name and supporting the
 * features @required_features and NULL otherwise.
 */
static struct elevator_type *elevator_find(const char *name)
static struct elevator_type *elevator_find(const char *name,
					   unsigned int required_features)
{
	struct elevator_type *e;

	list_for_each_entry(e, &elv_list, list) {
		if (elevator_match(e, name))
		if (elevator_match(e, name, required_features))
			return e;
	}

@@ -120,12 +144,12 @@ static struct elevator_type *elevator_get(struct request_queue *q,

	spin_lock(&elv_list_lock);

	e = elevator_find(name);
	e = elevator_find(name, q->required_elevator_features);
	if (!e && try_loading) {
		spin_unlock(&elv_list_lock);
		request_module("%s-iosched", name);
		spin_lock(&elv_list_lock);
		e = elevator_find(name);
		e = elevator_find(name, q->required_elevator_features);
	}

	if (e && !try_module_get(e->elevator_owner))
@@ -525,7 +549,7 @@ int elv_register(struct elevator_type *e)

	/* register, don't allow duplicate names */
	spin_lock(&elv_list_lock);
	if (elevator_find(e->elevator_name)) {
	if (elevator_find(e->elevator_name, 0)) {
		spin_unlock(&elv_list_lock);
		kmem_cache_destroy(e->icq_cache);
		return -EBUSY;
@@ -709,7 +733,8 @@ static int __elevator_change(struct request_queue *q, const char *name)
	if (!e)
		return -EINVAL;

	if (q->elevator && elevator_match(q->elevator->type, elevator_name)) {
	if (q->elevator &&
	    elevator_match(q->elevator->type, elevator_name, 0)) {
		elevator_put(e);
		return 0;
	}
@@ -749,11 +774,13 @@ ssize_t elv_iosched_show(struct request_queue *q, char *name)

	spin_lock(&elv_list_lock);
	list_for_each_entry(__e, &elv_list, list) {
		if (elv && elevator_match(elv, __e->elevator_name)) {
		if (elv && elevator_match(elv, __e->elevator_name, 0)) {
			len += sprintf(name+len, "[%s] ", elv->elevator_name);
			continue;
		}
		if (elv_support_iosched(q))
		if (elv_support_iosched(q) &&
		    elevator_match(__e, __e->elevator_name,
				   q->required_elevator_features))
			len += sprintf(name+len, "%s ", __e->elevator_name);
	}
	spin_unlock(&elv_list_lock);
+1 −0
Original line number Diff line number Diff line
@@ -794,6 +794,7 @@ static struct elevator_type mq_deadline = {
	.elevator_attrs = deadline_attrs,
	.elevator_name = "mq-deadline",
	.elevator_alias = "deadline",
	.elevator_features = ELEVATOR_F_ZBD_SEQ_WRITE,
	.elevator_owner = THIS_MODULE,
};
MODULE_ALIAS("mq-deadline-iosched");
+4 −0
Original line number Diff line number Diff line
@@ -496,6 +496,8 @@ struct request_queue {

	struct queue_limits	limits;

	unsigned int		required_elevator_features;

#ifdef CONFIG_BLK_DEV_ZONED
	/*
	 * Zoned block device information for request dispatch control.
@@ -1097,6 +1099,8 @@ extern void blk_queue_dma_alignment(struct request_queue *, int);
extern void blk_queue_update_dma_alignment(struct request_queue *, int);
extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
extern void blk_queue_write_cache(struct request_queue *q, bool enabled, bool fua);
extern void blk_queue_required_elevator_features(struct request_queue *q,
						 unsigned int features);

/*
 * Number of physical segments as sent to the device.
+8 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ struct elevator_type
	struct elv_fs_entry *elevator_attrs;
	const char *elevator_name;
	const char *elevator_alias;
	const unsigned int elevator_features;
	struct module *elevator_owner;
#ifdef CONFIG_BLK_DEBUG_FS
	const struct blk_mq_debugfs_attr *queue_debugfs_attrs;
@@ -165,5 +166,12 @@ extern struct request *elv_rb_find(struct rb_root *, sector_t);
#define rq_entry_fifo(ptr)	list_entry((ptr), struct request, queuelist)
#define rq_fifo_clear(rq)	list_del_init(&(rq)->queuelist)

/*
 * Elevator features.
 */

/* Supports zoned block devices sequential write constraint */
#define ELEVATOR_F_ZBD_SEQ_WRITE	(1U << 0)

#endif /* CONFIG_BLOCK */
#endif