162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Block device elevator/IO-scheduler. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * 30042000 Jens Axboe <axboe@kernel.dk> : 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Split the elevator a bit so that it is possible to choose a different 1062306a36Sopenharmony_ci * one or even write a new "plug in". There are three pieces: 1162306a36Sopenharmony_ci * - elevator_fn, inserts a new request in the queue list 1262306a36Sopenharmony_ci * - elevator_merge_fn, decides whether a new buffer can be merged with 1362306a36Sopenharmony_ci * an existing request 1462306a36Sopenharmony_ci * - elevator_dequeue_fn, called when a request is taken off the active list 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * 20082000 Dave Jones <davej@suse.de> : 1762306a36Sopenharmony_ci * Removed tests for max-bomb-segments, which was breaking elvtune 1862306a36Sopenharmony_ci * when run without -bN 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Jens: 2162306a36Sopenharmony_ci * - Rework again to work with bio instead of buffer_heads 2262306a36Sopenharmony_ci * - loose bi_dev comparisons, partition handling is right now 2362306a36Sopenharmony_ci * - completely modularize elevator setup and teardown 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci#include <linux/kernel.h> 2762306a36Sopenharmony_ci#include <linux/fs.h> 2862306a36Sopenharmony_ci#include <linux/blkdev.h> 2962306a36Sopenharmony_ci#include <linux/bio.h> 3062306a36Sopenharmony_ci#include <linux/module.h> 3162306a36Sopenharmony_ci#include <linux/slab.h> 3262306a36Sopenharmony_ci#include <linux/init.h> 3362306a36Sopenharmony_ci#include <linux/compiler.h> 3462306a36Sopenharmony_ci#include <linux/blktrace_api.h> 3562306a36Sopenharmony_ci#include <linux/hash.h> 3662306a36Sopenharmony_ci#include <linux/uaccess.h> 3762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <trace/events/block.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include "elevator.h" 4262306a36Sopenharmony_ci#include "blk.h" 4362306a36Sopenharmony_ci#include "blk-mq-sched.h" 4462306a36Sopenharmony_ci#include "blk-pm.h" 4562306a36Sopenharmony_ci#include "blk-wbt.h" 4662306a36Sopenharmony_ci#include "blk-cgroup.h" 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(elv_list_lock); 4962306a36Sopenharmony_cistatic LIST_HEAD(elv_list); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* 5262306a36Sopenharmony_ci * Merge hash stuff. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci#define rq_hash_key(rq) (blk_rq_pos(rq) + blk_rq_sectors(rq)) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Query io scheduler to see if the current process issuing bio may be 5862306a36Sopenharmony_ci * merged with rq. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistatic bool elv_iosched_allow_bio_merge(struct request *rq, struct bio *bio) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct request_queue *q = rq->q; 6362306a36Sopenharmony_ci struct elevator_queue *e = q->elevator; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (e->type->ops.allow_merge) 6662306a36Sopenharmony_ci return e->type->ops.allow_merge(q, rq, bio); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return true; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* 7262306a36Sopenharmony_ci * can we safely merge with this request? 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cibool elv_bio_merge_ok(struct request *rq, struct bio *bio) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci if (!blk_rq_merge_ok(rq, bio)) 7762306a36Sopenharmony_ci return false; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (!elv_iosched_allow_bio_merge(rq, bio)) 8062306a36Sopenharmony_ci return false; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return true; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ciEXPORT_SYMBOL(elv_bio_merge_ok); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic inline bool elv_support_features(struct request_queue *q, 8762306a36Sopenharmony_ci const struct elevator_type *e) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci return (q->required_elevator_features & e->elevator_features) == 9062306a36Sopenharmony_ci q->required_elevator_features; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/** 9462306a36Sopenharmony_ci * elevator_match - Check whether @e's name or alias matches @name 9562306a36Sopenharmony_ci * @e: Scheduler to test 9662306a36Sopenharmony_ci * @name: Elevator name to test 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * Return true if the elevator @e's name or alias matches @name. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistatic bool elevator_match(const struct elevator_type *e, const char *name) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci return !strcmp(e->elevator_name, name) || 10362306a36Sopenharmony_ci (e->elevator_alias && !strcmp(e->elevator_alias, name)); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic struct elevator_type *__elevator_find(const char *name) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct elevator_type *e; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci list_for_each_entry(e, &elv_list, list) 11162306a36Sopenharmony_ci if (elevator_match(e, name)) 11262306a36Sopenharmony_ci return e; 11362306a36Sopenharmony_ci return NULL; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic struct elevator_type *elevator_find_get(struct request_queue *q, 11762306a36Sopenharmony_ci const char *name) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct elevator_type *e; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci spin_lock(&elv_list_lock); 12262306a36Sopenharmony_ci e = __elevator_find(name); 12362306a36Sopenharmony_ci if (e && (!elv_support_features(q, e) || !elevator_tryget(e))) 12462306a36Sopenharmony_ci e = NULL; 12562306a36Sopenharmony_ci spin_unlock(&elv_list_lock); 12662306a36Sopenharmony_ci return e; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic const struct kobj_type elv_ktype; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct elevator_queue *elevator_alloc(struct request_queue *q, 13262306a36Sopenharmony_ci struct elevator_type *e) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct elevator_queue *eq; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci eq = kzalloc_node(sizeof(*eq), GFP_KERNEL, q->node); 13762306a36Sopenharmony_ci if (unlikely(!eq)) 13862306a36Sopenharmony_ci return NULL; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci __elevator_get(e); 14162306a36Sopenharmony_ci eq->type = e; 14262306a36Sopenharmony_ci kobject_init(&eq->kobj, &elv_ktype); 14362306a36Sopenharmony_ci mutex_init(&eq->sysfs_lock); 14462306a36Sopenharmony_ci hash_init(eq->hash); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return eq; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ciEXPORT_SYMBOL(elevator_alloc); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic void elevator_release(struct kobject *kobj) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct elevator_queue *e; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci e = container_of(kobj, struct elevator_queue, kobj); 15562306a36Sopenharmony_ci elevator_put(e->type); 15662306a36Sopenharmony_ci kfree(e); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_civoid elevator_exit(struct request_queue *q) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct elevator_queue *e = q->elevator; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci ioc_clear_queue(q); 16462306a36Sopenharmony_ci blk_mq_sched_free_rqs(q); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci mutex_lock(&e->sysfs_lock); 16762306a36Sopenharmony_ci blk_mq_exit_sched(q, e); 16862306a36Sopenharmony_ci mutex_unlock(&e->sysfs_lock); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci kobject_put(&e->kobj); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic inline void __elv_rqhash_del(struct request *rq) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci hash_del(&rq->hash); 17662306a36Sopenharmony_ci rq->rq_flags &= ~RQF_HASHED; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_civoid elv_rqhash_del(struct request_queue *q, struct request *rq) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci if (ELV_ON_HASH(rq)) 18262306a36Sopenharmony_ci __elv_rqhash_del(rq); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(elv_rqhash_del); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_civoid elv_rqhash_add(struct request_queue *q, struct request *rq) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct elevator_queue *e = q->elevator; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci BUG_ON(ELV_ON_HASH(rq)); 19162306a36Sopenharmony_ci hash_add(e->hash, &rq->hash, rq_hash_key(rq)); 19262306a36Sopenharmony_ci rq->rq_flags |= RQF_HASHED; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(elv_rqhash_add); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_civoid elv_rqhash_reposition(struct request_queue *q, struct request *rq) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci __elv_rqhash_del(rq); 19962306a36Sopenharmony_ci elv_rqhash_add(q, rq); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistruct request *elv_rqhash_find(struct request_queue *q, sector_t offset) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct elevator_queue *e = q->elevator; 20562306a36Sopenharmony_ci struct hlist_node *next; 20662306a36Sopenharmony_ci struct request *rq; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci hash_for_each_possible_safe(e->hash, rq, next, hash, offset) { 20962306a36Sopenharmony_ci BUG_ON(!ELV_ON_HASH(rq)); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (unlikely(!rq_mergeable(rq))) { 21262306a36Sopenharmony_ci __elv_rqhash_del(rq); 21362306a36Sopenharmony_ci continue; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (rq_hash_key(rq) == offset) 21762306a36Sopenharmony_ci return rq; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return NULL; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* 22462306a36Sopenharmony_ci * RB-tree support functions for inserting/lookup/removal of requests 22562306a36Sopenharmony_ci * in a sorted RB tree. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_civoid elv_rb_add(struct rb_root *root, struct request *rq) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct rb_node **p = &root->rb_node; 23062306a36Sopenharmony_ci struct rb_node *parent = NULL; 23162306a36Sopenharmony_ci struct request *__rq; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci while (*p) { 23462306a36Sopenharmony_ci parent = *p; 23562306a36Sopenharmony_ci __rq = rb_entry(parent, struct request, rb_node); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (blk_rq_pos(rq) < blk_rq_pos(__rq)) 23862306a36Sopenharmony_ci p = &(*p)->rb_left; 23962306a36Sopenharmony_ci else if (blk_rq_pos(rq) >= blk_rq_pos(__rq)) 24062306a36Sopenharmony_ci p = &(*p)->rb_right; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci rb_link_node(&rq->rb_node, parent, p); 24462306a36Sopenharmony_ci rb_insert_color(&rq->rb_node, root); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ciEXPORT_SYMBOL(elv_rb_add); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_civoid elv_rb_del(struct rb_root *root, struct request *rq) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci BUG_ON(RB_EMPTY_NODE(&rq->rb_node)); 25162306a36Sopenharmony_ci rb_erase(&rq->rb_node, root); 25262306a36Sopenharmony_ci RB_CLEAR_NODE(&rq->rb_node); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ciEXPORT_SYMBOL(elv_rb_del); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistruct request *elv_rb_find(struct rb_root *root, sector_t sector) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct rb_node *n = root->rb_node; 25962306a36Sopenharmony_ci struct request *rq; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci while (n) { 26262306a36Sopenharmony_ci rq = rb_entry(n, struct request, rb_node); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (sector < blk_rq_pos(rq)) 26562306a36Sopenharmony_ci n = n->rb_left; 26662306a36Sopenharmony_ci else if (sector > blk_rq_pos(rq)) 26762306a36Sopenharmony_ci n = n->rb_right; 26862306a36Sopenharmony_ci else 26962306a36Sopenharmony_ci return rq; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return NULL; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ciEXPORT_SYMBOL(elv_rb_find); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cienum elv_merge elv_merge(struct request_queue *q, struct request **req, 27762306a36Sopenharmony_ci struct bio *bio) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct elevator_queue *e = q->elevator; 28062306a36Sopenharmony_ci struct request *__rq; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* 28362306a36Sopenharmony_ci * Levels of merges: 28462306a36Sopenharmony_ci * nomerges: No merges at all attempted 28562306a36Sopenharmony_ci * noxmerges: Only simple one-hit cache try 28662306a36Sopenharmony_ci * merges: All merge tries attempted 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci if (blk_queue_nomerges(q) || !bio_mergeable(bio)) 28962306a36Sopenharmony_ci return ELEVATOR_NO_MERGE; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* 29262306a36Sopenharmony_ci * First try one-hit cache. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci if (q->last_merge && elv_bio_merge_ok(q->last_merge, bio)) { 29562306a36Sopenharmony_ci enum elv_merge ret = blk_try_merge(q->last_merge, bio); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (ret != ELEVATOR_NO_MERGE) { 29862306a36Sopenharmony_ci *req = q->last_merge; 29962306a36Sopenharmony_ci return ret; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (blk_queue_noxmerges(q)) 30462306a36Sopenharmony_ci return ELEVATOR_NO_MERGE; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* 30762306a36Sopenharmony_ci * See if our hash lookup can find a potential backmerge. 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci __rq = elv_rqhash_find(q, bio->bi_iter.bi_sector); 31062306a36Sopenharmony_ci if (__rq && elv_bio_merge_ok(__rq, bio)) { 31162306a36Sopenharmony_ci *req = __rq; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (blk_discard_mergable(__rq)) 31462306a36Sopenharmony_ci return ELEVATOR_DISCARD_MERGE; 31562306a36Sopenharmony_ci return ELEVATOR_BACK_MERGE; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (e->type->ops.request_merge) 31962306a36Sopenharmony_ci return e->type->ops.request_merge(q, req, bio); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return ELEVATOR_NO_MERGE; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/* 32562306a36Sopenharmony_ci * Attempt to do an insertion back merge. Only check for the case where 32662306a36Sopenharmony_ci * we can append 'rq' to an existing request, so we can throw 'rq' away 32762306a36Sopenharmony_ci * afterwards. 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * Returns true if we merged, false otherwise. 'free' will contain all 33062306a36Sopenharmony_ci * requests that need to be freed. 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_cibool elv_attempt_insert_merge(struct request_queue *q, struct request *rq, 33362306a36Sopenharmony_ci struct list_head *free) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct request *__rq; 33662306a36Sopenharmony_ci bool ret; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (blk_queue_nomerges(q)) 33962306a36Sopenharmony_ci return false; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* 34262306a36Sopenharmony_ci * First try one-hit cache. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ci if (q->last_merge && blk_attempt_req_merge(q, q->last_merge, rq)) { 34562306a36Sopenharmony_ci list_add(&rq->queuelist, free); 34662306a36Sopenharmony_ci return true; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (blk_queue_noxmerges(q)) 35062306a36Sopenharmony_ci return false; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci ret = false; 35362306a36Sopenharmony_ci /* 35462306a36Sopenharmony_ci * See if our hash lookup can find a potential backmerge. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_ci while (1) { 35762306a36Sopenharmony_ci __rq = elv_rqhash_find(q, blk_rq_pos(rq)); 35862306a36Sopenharmony_ci if (!__rq || !blk_attempt_req_merge(q, __rq, rq)) 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci list_add(&rq->queuelist, free); 36262306a36Sopenharmony_ci /* The merged request could be merged with others, try again */ 36362306a36Sopenharmony_ci ret = true; 36462306a36Sopenharmony_ci rq = __rq; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return ret; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_civoid elv_merged_request(struct request_queue *q, struct request *rq, 37162306a36Sopenharmony_ci enum elv_merge type) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct elevator_queue *e = q->elevator; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (e->type->ops.request_merged) 37662306a36Sopenharmony_ci e->type->ops.request_merged(q, rq, type); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (type == ELEVATOR_BACK_MERGE) 37962306a36Sopenharmony_ci elv_rqhash_reposition(q, rq); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci q->last_merge = rq; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_civoid elv_merge_requests(struct request_queue *q, struct request *rq, 38562306a36Sopenharmony_ci struct request *next) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci struct elevator_queue *e = q->elevator; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (e->type->ops.requests_merged) 39062306a36Sopenharmony_ci e->type->ops.requests_merged(q, rq, next); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci elv_rqhash_reposition(q, rq); 39362306a36Sopenharmony_ci q->last_merge = rq; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistruct request *elv_latter_request(struct request_queue *q, struct request *rq) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct elevator_queue *e = q->elevator; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (e->type->ops.next_request) 40162306a36Sopenharmony_ci return e->type->ops.next_request(q, rq); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return NULL; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistruct request *elv_former_request(struct request_queue *q, struct request *rq) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct elevator_queue *e = q->elevator; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (e->type->ops.former_request) 41162306a36Sopenharmony_ci return e->type->ops.former_request(q, rq); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return NULL; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci#define to_elv(atr) container_of((atr), struct elv_fs_entry, attr) 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic ssize_t 41962306a36Sopenharmony_cielv_attr_show(struct kobject *kobj, struct attribute *attr, char *page) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct elv_fs_entry *entry = to_elv(attr); 42262306a36Sopenharmony_ci struct elevator_queue *e; 42362306a36Sopenharmony_ci ssize_t error; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (!entry->show) 42662306a36Sopenharmony_ci return -EIO; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci e = container_of(kobj, struct elevator_queue, kobj); 42962306a36Sopenharmony_ci mutex_lock(&e->sysfs_lock); 43062306a36Sopenharmony_ci error = e->type ? entry->show(e, page) : -ENOENT; 43162306a36Sopenharmony_ci mutex_unlock(&e->sysfs_lock); 43262306a36Sopenharmony_ci return error; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic ssize_t 43662306a36Sopenharmony_cielv_attr_store(struct kobject *kobj, struct attribute *attr, 43762306a36Sopenharmony_ci const char *page, size_t length) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct elv_fs_entry *entry = to_elv(attr); 44062306a36Sopenharmony_ci struct elevator_queue *e; 44162306a36Sopenharmony_ci ssize_t error; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (!entry->store) 44462306a36Sopenharmony_ci return -EIO; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci e = container_of(kobj, struct elevator_queue, kobj); 44762306a36Sopenharmony_ci mutex_lock(&e->sysfs_lock); 44862306a36Sopenharmony_ci error = e->type ? entry->store(e, page, length) : -ENOENT; 44962306a36Sopenharmony_ci mutex_unlock(&e->sysfs_lock); 45062306a36Sopenharmony_ci return error; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic const struct sysfs_ops elv_sysfs_ops = { 45462306a36Sopenharmony_ci .show = elv_attr_show, 45562306a36Sopenharmony_ci .store = elv_attr_store, 45662306a36Sopenharmony_ci}; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic const struct kobj_type elv_ktype = { 45962306a36Sopenharmony_ci .sysfs_ops = &elv_sysfs_ops, 46062306a36Sopenharmony_ci .release = elevator_release, 46162306a36Sopenharmony_ci}; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ciint elv_register_queue(struct request_queue *q, bool uevent) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct elevator_queue *e = q->elevator; 46662306a36Sopenharmony_ci int error; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci lockdep_assert_held(&q->sysfs_lock); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci error = kobject_add(&e->kobj, &q->disk->queue_kobj, "iosched"); 47162306a36Sopenharmony_ci if (!error) { 47262306a36Sopenharmony_ci struct elv_fs_entry *attr = e->type->elevator_attrs; 47362306a36Sopenharmony_ci if (attr) { 47462306a36Sopenharmony_ci while (attr->attr.name) { 47562306a36Sopenharmony_ci if (sysfs_create_file(&e->kobj, &attr->attr)) 47662306a36Sopenharmony_ci break; 47762306a36Sopenharmony_ci attr++; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci if (uevent) 48162306a36Sopenharmony_ci kobject_uevent(&e->kobj, KOBJ_ADD); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci set_bit(ELEVATOR_FLAG_REGISTERED, &e->flags); 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci return error; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_civoid elv_unregister_queue(struct request_queue *q) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct elevator_queue *e = q->elevator; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci lockdep_assert_held(&q->sysfs_lock); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (e && test_and_clear_bit(ELEVATOR_FLAG_REGISTERED, &e->flags)) { 49562306a36Sopenharmony_ci kobject_uevent(&e->kobj, KOBJ_REMOVE); 49662306a36Sopenharmony_ci kobject_del(&e->kobj); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ciint elv_register(struct elevator_type *e) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci /* finish request is mandatory */ 50362306a36Sopenharmony_ci if (WARN_ON_ONCE(!e->ops.finish_request)) 50462306a36Sopenharmony_ci return -EINVAL; 50562306a36Sopenharmony_ci /* insert_requests and dispatch_request are mandatory */ 50662306a36Sopenharmony_ci if (WARN_ON_ONCE(!e->ops.insert_requests || !e->ops.dispatch_request)) 50762306a36Sopenharmony_ci return -EINVAL; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* create icq_cache if requested */ 51062306a36Sopenharmony_ci if (e->icq_size) { 51162306a36Sopenharmony_ci if (WARN_ON(e->icq_size < sizeof(struct io_cq)) || 51262306a36Sopenharmony_ci WARN_ON(e->icq_align < __alignof__(struct io_cq))) 51362306a36Sopenharmony_ci return -EINVAL; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci snprintf(e->icq_cache_name, sizeof(e->icq_cache_name), 51662306a36Sopenharmony_ci "%s_io_cq", e->elevator_name); 51762306a36Sopenharmony_ci e->icq_cache = kmem_cache_create(e->icq_cache_name, e->icq_size, 51862306a36Sopenharmony_ci e->icq_align, 0, NULL); 51962306a36Sopenharmony_ci if (!e->icq_cache) 52062306a36Sopenharmony_ci return -ENOMEM; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* register, don't allow duplicate names */ 52462306a36Sopenharmony_ci spin_lock(&elv_list_lock); 52562306a36Sopenharmony_ci if (__elevator_find(e->elevator_name)) { 52662306a36Sopenharmony_ci spin_unlock(&elv_list_lock); 52762306a36Sopenharmony_ci kmem_cache_destroy(e->icq_cache); 52862306a36Sopenharmony_ci return -EBUSY; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci list_add_tail(&e->list, &elv_list); 53162306a36Sopenharmony_ci spin_unlock(&elv_list_lock); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci printk(KERN_INFO "io scheduler %s registered\n", e->elevator_name); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci return 0; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(elv_register); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_civoid elv_unregister(struct elevator_type *e) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci /* unregister */ 54262306a36Sopenharmony_ci spin_lock(&elv_list_lock); 54362306a36Sopenharmony_ci list_del_init(&e->list); 54462306a36Sopenharmony_ci spin_unlock(&elv_list_lock); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* 54762306a36Sopenharmony_ci * Destroy icq_cache if it exists. icq's are RCU managed. Make 54862306a36Sopenharmony_ci * sure all RCU operations are complete before proceeding. 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_ci if (e->icq_cache) { 55162306a36Sopenharmony_ci rcu_barrier(); 55262306a36Sopenharmony_ci kmem_cache_destroy(e->icq_cache); 55362306a36Sopenharmony_ci e->icq_cache = NULL; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(elv_unregister); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic inline bool elv_support_iosched(struct request_queue *q) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci if (!queue_is_mq(q) || 56162306a36Sopenharmony_ci (q->tag_set && (q->tag_set->flags & BLK_MQ_F_NO_SCHED))) 56262306a36Sopenharmony_ci return false; 56362306a36Sopenharmony_ci return true; 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci/* 56762306a36Sopenharmony_ci * For single queue devices, default to using mq-deadline. If we have multiple 56862306a36Sopenharmony_ci * queues or mq-deadline is not available, default to "none". 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_cistatic struct elevator_type *elevator_get_default(struct request_queue *q) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci if (q->tag_set && q->tag_set->flags & BLK_MQ_F_NO_SCHED_BY_DEFAULT) 57362306a36Sopenharmony_ci return NULL; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (q->nr_hw_queues != 1 && 57662306a36Sopenharmony_ci !blk_mq_is_shared_tags(q->tag_set->flags)) 57762306a36Sopenharmony_ci return NULL; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci return elevator_find_get(q, "mq-deadline"); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci/* 58362306a36Sopenharmony_ci * Get the first elevator providing the features required by the request queue. 58462306a36Sopenharmony_ci * Default to "none" if no matching elevator is found. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_cistatic struct elevator_type *elevator_get_by_features(struct request_queue *q) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct elevator_type *e, *found = NULL; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci spin_lock(&elv_list_lock); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci list_for_each_entry(e, &elv_list, list) { 59362306a36Sopenharmony_ci if (elv_support_features(q, e)) { 59462306a36Sopenharmony_ci found = e; 59562306a36Sopenharmony_ci break; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (found && !elevator_tryget(found)) 60062306a36Sopenharmony_ci found = NULL; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci spin_unlock(&elv_list_lock); 60362306a36Sopenharmony_ci return found; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci/* 60762306a36Sopenharmony_ci * For a device queue that has no required features, use the default elevator 60862306a36Sopenharmony_ci * settings. Otherwise, use the first elevator available matching the required 60962306a36Sopenharmony_ci * features. If no suitable elevator is find or if the chosen elevator 61062306a36Sopenharmony_ci * initialization fails, fall back to the "none" elevator (no elevator). 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_civoid elevator_init_mq(struct request_queue *q) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct elevator_type *e; 61562306a36Sopenharmony_ci int err; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (!elv_support_iosched(q)) 61862306a36Sopenharmony_ci return; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci WARN_ON_ONCE(blk_queue_registered(q)); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (unlikely(q->elevator)) 62362306a36Sopenharmony_ci return; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (!q->required_elevator_features) 62662306a36Sopenharmony_ci e = elevator_get_default(q); 62762306a36Sopenharmony_ci else 62862306a36Sopenharmony_ci e = elevator_get_by_features(q); 62962306a36Sopenharmony_ci if (!e) 63062306a36Sopenharmony_ci return; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* 63362306a36Sopenharmony_ci * We are called before adding disk, when there isn't any FS I/O, 63462306a36Sopenharmony_ci * so freezing queue plus canceling dispatch work is enough to 63562306a36Sopenharmony_ci * drain any dispatch activities originated from passthrough 63662306a36Sopenharmony_ci * requests, then no need to quiesce queue which may add long boot 63762306a36Sopenharmony_ci * latency, especially when lots of disks are involved. 63862306a36Sopenharmony_ci */ 63962306a36Sopenharmony_ci blk_mq_freeze_queue(q); 64062306a36Sopenharmony_ci blk_mq_cancel_work_sync(q); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci err = blk_mq_init_sched(q, e); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci blk_mq_unfreeze_queue(q); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (err) { 64762306a36Sopenharmony_ci pr_warn("\"%s\" elevator initialization failed, " 64862306a36Sopenharmony_ci "falling back to \"none\"\n", e->elevator_name); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci elevator_put(e); 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci/* 65562306a36Sopenharmony_ci * Switch to new_e io scheduler. 65662306a36Sopenharmony_ci * 65762306a36Sopenharmony_ci * If switching fails, we are most likely running out of memory and not able 65862306a36Sopenharmony_ci * to restore the old io scheduler, so leaving the io scheduler being none. 65962306a36Sopenharmony_ci */ 66062306a36Sopenharmony_ciint elevator_switch(struct request_queue *q, struct elevator_type *new_e) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci int ret; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci lockdep_assert_held(&q->sysfs_lock); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci blk_mq_freeze_queue(q); 66762306a36Sopenharmony_ci blk_mq_quiesce_queue(q); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (q->elevator) { 67062306a36Sopenharmony_ci elv_unregister_queue(q); 67162306a36Sopenharmony_ci elevator_exit(q); 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci ret = blk_mq_init_sched(q, new_e); 67562306a36Sopenharmony_ci if (ret) 67662306a36Sopenharmony_ci goto out_unfreeze; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci ret = elv_register_queue(q, true); 67962306a36Sopenharmony_ci if (ret) { 68062306a36Sopenharmony_ci elevator_exit(q); 68162306a36Sopenharmony_ci goto out_unfreeze; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci blk_add_trace_msg(q, "elv switch: %s", new_e->elevator_name); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ciout_unfreeze: 68662306a36Sopenharmony_ci blk_mq_unquiesce_queue(q); 68762306a36Sopenharmony_ci blk_mq_unfreeze_queue(q); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (ret) { 69062306a36Sopenharmony_ci pr_warn("elv: switch to \"%s\" failed, falling back to \"none\"\n", 69162306a36Sopenharmony_ci new_e->elevator_name); 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci return ret; 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_civoid elevator_disable(struct request_queue *q) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci lockdep_assert_held(&q->sysfs_lock); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci blk_mq_freeze_queue(q); 70262306a36Sopenharmony_ci blk_mq_quiesce_queue(q); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci elv_unregister_queue(q); 70562306a36Sopenharmony_ci elevator_exit(q); 70662306a36Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_SQ_SCHED, q); 70762306a36Sopenharmony_ci q->elevator = NULL; 70862306a36Sopenharmony_ci q->nr_requests = q->tag_set->queue_depth; 70962306a36Sopenharmony_ci blk_add_trace_msg(q, "elv switch: none"); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci blk_mq_unquiesce_queue(q); 71262306a36Sopenharmony_ci blk_mq_unfreeze_queue(q); 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci/* 71662306a36Sopenharmony_ci * Switch this queue to the given IO scheduler. 71762306a36Sopenharmony_ci */ 71862306a36Sopenharmony_cistatic int elevator_change(struct request_queue *q, const char *elevator_name) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct elevator_type *e; 72162306a36Sopenharmony_ci int ret; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci /* Make sure queue is not in the middle of being removed */ 72462306a36Sopenharmony_ci if (!blk_queue_registered(q)) 72562306a36Sopenharmony_ci return -ENOENT; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (!strncmp(elevator_name, "none", 4)) { 72862306a36Sopenharmony_ci if (q->elevator) 72962306a36Sopenharmony_ci elevator_disable(q); 73062306a36Sopenharmony_ci return 0; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (q->elevator && elevator_match(q->elevator->type, elevator_name)) 73462306a36Sopenharmony_ci return 0; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci e = elevator_find_get(q, elevator_name); 73762306a36Sopenharmony_ci if (!e) { 73862306a36Sopenharmony_ci request_module("%s-iosched", elevator_name); 73962306a36Sopenharmony_ci e = elevator_find_get(q, elevator_name); 74062306a36Sopenharmony_ci if (!e) 74162306a36Sopenharmony_ci return -EINVAL; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci ret = elevator_switch(q, e); 74462306a36Sopenharmony_ci elevator_put(e); 74562306a36Sopenharmony_ci return ret; 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cissize_t elv_iosched_store(struct request_queue *q, const char *buf, 74962306a36Sopenharmony_ci size_t count) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci char elevator_name[ELV_NAME_MAX]; 75262306a36Sopenharmony_ci int ret; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (!elv_support_iosched(q)) 75562306a36Sopenharmony_ci return count; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci strscpy(elevator_name, buf, sizeof(elevator_name)); 75862306a36Sopenharmony_ci ret = elevator_change(q, strstrip(elevator_name)); 75962306a36Sopenharmony_ci if (!ret) 76062306a36Sopenharmony_ci return count; 76162306a36Sopenharmony_ci return ret; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cissize_t elv_iosched_show(struct request_queue *q, char *name) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct elevator_queue *eq = q->elevator; 76762306a36Sopenharmony_ci struct elevator_type *cur = NULL, *e; 76862306a36Sopenharmony_ci int len = 0; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (!elv_support_iosched(q)) 77162306a36Sopenharmony_ci return sprintf(name, "none\n"); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (!q->elevator) { 77462306a36Sopenharmony_ci len += sprintf(name+len, "[none] "); 77562306a36Sopenharmony_ci } else { 77662306a36Sopenharmony_ci len += sprintf(name+len, "none "); 77762306a36Sopenharmony_ci cur = eq->type; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci spin_lock(&elv_list_lock); 78162306a36Sopenharmony_ci list_for_each_entry(e, &elv_list, list) { 78262306a36Sopenharmony_ci if (e == cur) 78362306a36Sopenharmony_ci len += sprintf(name+len, "[%s] ", e->elevator_name); 78462306a36Sopenharmony_ci else if (elv_support_features(q, e)) 78562306a36Sopenharmony_ci len += sprintf(name+len, "%s ", e->elevator_name); 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci spin_unlock(&elv_list_lock); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci len += sprintf(name+len, "\n"); 79062306a36Sopenharmony_ci return len; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistruct request *elv_rb_former_request(struct request_queue *q, 79462306a36Sopenharmony_ci struct request *rq) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci struct rb_node *rbprev = rb_prev(&rq->rb_node); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (rbprev) 79962306a36Sopenharmony_ci return rb_entry_rq(rbprev); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return NULL; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ciEXPORT_SYMBOL(elv_rb_former_request); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistruct request *elv_rb_latter_request(struct request_queue *q, 80662306a36Sopenharmony_ci struct request *rq) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct rb_node *rbnext = rb_next(&rq->rb_node); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (rbnext) 81162306a36Sopenharmony_ci return rb_entry_rq(rbnext); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci return NULL; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ciEXPORT_SYMBOL(elv_rb_latter_request); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic int __init elevator_setup(char *str) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci pr_warn("Kernel parameter elevator= does not have any effect anymore.\n" 82062306a36Sopenharmony_ci "Please use sysfs to set IO scheduler for individual devices.\n"); 82162306a36Sopenharmony_ci return 1; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci__setup("elevator=", elevator_setup); 825