mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-17 02:15:57 +00:00
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: Johannes Thumshirn <jthumshirn@suse.de> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
954b4a5ce4
commit
68c43f133a
@ -832,6 +832,22 @@ void blk_queue_write_cache(struct request_queue *q, bool wc, bool fua)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(blk_queue_write_cache);
|
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)
|
static int __init blk_settings_init(void)
|
||||||
{
|
{
|
||||||
blk_max_low_pfn = max_low_pfn - 1;
|
blk_max_low_pfn = max_low_pfn - 1;
|
||||||
|
@ -83,8 +83,26 @@ bool elv_bio_merge_ok(struct request *rq, struct bio *bio)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(elv_bio_merge_ok);
|
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))
|
if (!strcmp(e->elevator_name, name))
|
||||||
return true;
|
return true;
|
||||||
if (e->elevator_alias && !strcmp(e->elevator_alias, name))
|
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 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;
|
struct elevator_type *e;
|
||||||
|
|
||||||
list_for_each_entry(e, &elv_list, list) {
|
list_for_each_entry(e, &elv_list, list) {
|
||||||
if (elevator_match(e, name))
|
if (elevator_match(e, name, required_features))
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,12 +144,12 @@ static struct elevator_type *elevator_get(struct request_queue *q,
|
|||||||
|
|
||||||
spin_lock(&elv_list_lock);
|
spin_lock(&elv_list_lock);
|
||||||
|
|
||||||
e = elevator_find(name);
|
e = elevator_find(name, q->required_elevator_features);
|
||||||
if (!e && try_loading) {
|
if (!e && try_loading) {
|
||||||
spin_unlock(&elv_list_lock);
|
spin_unlock(&elv_list_lock);
|
||||||
request_module("%s-iosched", name);
|
request_module("%s-iosched", name);
|
||||||
spin_lock(&elv_list_lock);
|
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))
|
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 */
|
/* register, don't allow duplicate names */
|
||||||
spin_lock(&elv_list_lock);
|
spin_lock(&elv_list_lock);
|
||||||
if (elevator_find(e->elevator_name)) {
|
if (elevator_find(e->elevator_name, 0)) {
|
||||||
spin_unlock(&elv_list_lock);
|
spin_unlock(&elv_list_lock);
|
||||||
kmem_cache_destroy(e->icq_cache);
|
kmem_cache_destroy(e->icq_cache);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
@ -709,7 +733,8 @@ static int __elevator_change(struct request_queue *q, const char *name)
|
|||||||
if (!e)
|
if (!e)
|
||||||
return -EINVAL;
|
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);
|
elevator_put(e);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -749,11 +774,13 @@ ssize_t elv_iosched_show(struct request_queue *q, char *name)
|
|||||||
|
|
||||||
spin_lock(&elv_list_lock);
|
spin_lock(&elv_list_lock);
|
||||||
list_for_each_entry(__e, &elv_list, list) {
|
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);
|
len += sprintf(name+len, "[%s] ", elv->elevator_name);
|
||||||
continue;
|
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);
|
len += sprintf(name+len, "%s ", __e->elevator_name);
|
||||||
}
|
}
|
||||||
spin_unlock(&elv_list_lock);
|
spin_unlock(&elv_list_lock);
|
||||||
|
@ -794,6 +794,7 @@ static struct elevator_type mq_deadline = {
|
|||||||
.elevator_attrs = deadline_attrs,
|
.elevator_attrs = deadline_attrs,
|
||||||
.elevator_name = "mq-deadline",
|
.elevator_name = "mq-deadline",
|
||||||
.elevator_alias = "deadline",
|
.elevator_alias = "deadline",
|
||||||
|
.elevator_features = ELEVATOR_F_ZBD_SEQ_WRITE,
|
||||||
.elevator_owner = THIS_MODULE,
|
.elevator_owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
MODULE_ALIAS("mq-deadline-iosched");
|
MODULE_ALIAS("mq-deadline-iosched");
|
||||||
|
@ -496,6 +496,8 @@ struct request_queue {
|
|||||||
|
|
||||||
struct queue_limits limits;
|
struct queue_limits limits;
|
||||||
|
|
||||||
|
unsigned int required_elevator_features;
|
||||||
|
|
||||||
#ifdef CONFIG_BLK_DEV_ZONED
|
#ifdef CONFIG_BLK_DEV_ZONED
|
||||||
/*
|
/*
|
||||||
* Zoned block device information for request dispatch control.
|
* 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_update_dma_alignment(struct request_queue *, int);
|
||||||
extern void blk_queue_rq_timeout(struct request_queue *, unsigned 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_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.
|
* Number of physical segments as sent to the device.
|
||||||
|
@ -76,6 +76,7 @@ struct elevator_type
|
|||||||
struct elv_fs_entry *elevator_attrs;
|
struct elv_fs_entry *elevator_attrs;
|
||||||
const char *elevator_name;
|
const char *elevator_name;
|
||||||
const char *elevator_alias;
|
const char *elevator_alias;
|
||||||
|
const unsigned int elevator_features;
|
||||||
struct module *elevator_owner;
|
struct module *elevator_owner;
|
||||||
#ifdef CONFIG_BLK_DEBUG_FS
|
#ifdef CONFIG_BLK_DEBUG_FS
|
||||||
const struct blk_mq_debugfs_attr *queue_debugfs_attrs;
|
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_entry_fifo(ptr) list_entry((ptr), struct request, queuelist)
|
||||||
#define rq_fifo_clear(rq) list_del_init(&(rq)->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 /* CONFIG_BLOCK */
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user