cfq-iosched.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 891 行 · 第 1/2 页
C
891 行
/* * linux/drivers/block/cfq-iosched.c * * CFQ, or complete fairness queueing, disk scheduler. * * Based on ideas from a previously unfinished io * scheduler (round robin per-process disk scheduling) and Andrea Arcangeli. * * Copyright (C) 2003 Jens Axboe <axboe@suse.de> */#include <linux/kernel.h>#include <linux/fs.h>#include <linux/blkdev.h>#include <linux/elevator.h>#include <linux/bio.h>#include <linux/config.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/compiler.h>#include <linux/hash.h>#include <linux/rbtree.h>#include <linux/mempool.h>/* * tunables */static int cfq_quantum = 4;static int cfq_queued = 8;#define CFQ_QHASH_SHIFT 6#define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT)#define list_entry_qhash(entry) list_entry((entry), struct cfq_queue, cfq_hash)#define CFQ_MHASH_SHIFT 8#define CFQ_MHASH_BLOCK(sec) ((sec) >> 3)#define CFQ_MHASH_ENTRIES (1 << CFQ_MHASH_SHIFT)#define CFQ_MHASH_FN(sec) (hash_long(CFQ_MHASH_BLOCK((sec)),CFQ_MHASH_SHIFT))#define ON_MHASH(crq) !list_empty(&(crq)->hash)#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)#define list_entry_hash(ptr) list_entry((ptr), struct cfq_rq, hash)#define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list)#define RQ_DATA(rq) ((struct cfq_rq *) (rq)->elevator_private)static kmem_cache_t *crq_pool;static kmem_cache_t *cfq_pool;static mempool_t *cfq_mpool;struct cfq_data { struct list_head rr_list; struct list_head *dispatch; struct list_head *cfq_hash; struct list_head *crq_hash; unsigned int busy_queues; unsigned int max_queued; mempool_t *crq_pool; request_queue_t *queue; /* * tunables */ unsigned int cfq_quantum; unsigned int cfq_queued;};struct cfq_queue { struct list_head cfq_hash; struct list_head cfq_list; struct rb_root sort_list; int pid; int queued[2];#if 0 /* * with a simple addition like this, we can do io priorities. almost. * does need a split request free list, too. */ int io_prio#endif};struct cfq_rq { struct rb_node rb_node; sector_t rb_key; struct request *request; struct cfq_queue *cfq_queue; struct list_head hash;};static void cfq_put_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq);static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *cfqd, int pid);static void cfq_dispatch_sort(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct cfq_rq *crq);/* * lots of deadline iosched dupes, can be abstracted later... */static inline void __cfq_del_crq_hash(struct cfq_rq *crq){ list_del_init(&crq->hash);}static inline void cfq_del_crq_hash(struct cfq_rq *crq){ if (ON_MHASH(crq)) __cfq_del_crq_hash(crq);}static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq){ cfq_del_crq_hash(crq); if (q->last_merge == crq->request) q->last_merge = NULL;}static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq){ struct request *rq = crq->request; BUG_ON(ON_MHASH(crq)); list_add(&crq->hash, &cfqd->crq_hash[CFQ_MHASH_FN(rq_hash_key(rq))]);}static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset){ struct list_head *hash_list = &cfqd->crq_hash[CFQ_MHASH_FN(offset)]; struct list_head *entry, *next = hash_list->next; while ((entry = next) != hash_list) { struct cfq_rq *crq = list_entry_hash(entry); struct request *__rq = crq->request; next = entry->next; BUG_ON(!ON_MHASH(crq)); if (!rq_mergeable(__rq)) { __cfq_del_crq_hash(crq); continue; } if (rq_hash_key(__rq) == offset) return __rq; } return NULL;}/* * rb tree support functions */#define RB_NONE (2)#define RB_EMPTY(node) ((node)->rb_node == NULL)#define RB_CLEAR(node) ((node)->rb_color = RB_NONE)#define RB_CLEAR_ROOT(root) ((root)->rb_node = NULL)#define ON_RB(node) ((node)->rb_color != RB_NONE)#define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node)#define rq_rb_key(rq) (rq)->sectorstatic inline void cfq_del_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq){ if (ON_RB(&crq->rb_node)) { cfqq->queued[rq_data_dir(crq->request)]--; rb_erase(&crq->rb_node, &cfqq->sort_list); crq->cfq_queue = NULL; }}static struct cfq_rq *__cfq_add_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq){ struct rb_node **p = &cfqq->sort_list.rb_node; struct rb_node *parent = NULL; struct cfq_rq *__crq; while (*p) { parent = *p; __crq = rb_entry_crq(parent); if (crq->rb_key < __crq->rb_key) p = &(*p)->rb_left; else if (crq->rb_key > __crq->rb_key) p = &(*p)->rb_right; else return __crq; } rb_link_node(&crq->rb_node, parent, p); return NULL;}static voidcfq_add_crq_rb(struct cfq_data *cfqd, struct cfq_queue *cfqq,struct cfq_rq *crq){ struct request *rq = crq->request; struct cfq_rq *__alias; crq->rb_key = rq_rb_key(rq); cfqq->queued[rq_data_dir(rq)]++;retry: __alias = __cfq_add_crq_rb(cfqq, crq); if (!__alias) { rb_insert_color(&crq->rb_node, &cfqq->sort_list); crq->cfq_queue = cfqq; return; } cfq_dispatch_sort(cfqd, cfqq, __alias); goto retry;}static struct request *cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector){ struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->tgid); struct rb_node *n; if (!cfqq) goto out; n = cfqq->sort_list.rb_node; while (n) { struct cfq_rq *crq = rb_entry_crq(n); if (sector < crq->rb_key) n = n->rb_left; else if (sector > crq->rb_key) n = n->rb_right; else return crq->request; }out: return NULL;}static void cfq_remove_request(request_queue_t *q, struct request *rq){ struct cfq_data *cfqd = q->elevator.elevator_data; struct cfq_rq *crq = RQ_DATA(rq); if (crq) { struct cfq_queue *cfqq = crq->cfq_queue; cfq_remove_merge_hints(q, crq); list_del_init(&rq->queuelist); if (cfqq) { cfq_del_crq_rb(cfqq, crq); if (RB_EMPTY(&cfqq->sort_list)) cfq_put_queue(cfqd, cfqq); } }}static intcfq_merge(request_queue_t *q, struct request **req, struct bio *bio){ struct cfq_data *cfqd = q->elevator.elevator_data; struct request *__rq; int ret; ret = elv_try_last_merge(q, bio); if (ret != ELEVATOR_NO_MERGE) { __rq = q->last_merge; goto out_insert; } __rq = cfq_find_rq_hash(cfqd, bio->bi_sector); if (__rq) { BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector); if (elv_rq_merge_ok(__rq, bio)) { ret = ELEVATOR_BACK_MERGE; goto out; } } __rq = cfq_find_rq_rb(cfqd, bio->bi_sector + bio_sectors(bio)); if (__rq) { if (elv_rq_merge_ok(__rq, bio)) { ret = ELEVATOR_FRONT_MERGE; goto out; } } return ELEVATOR_NO_MERGE;out: q->last_merge = __rq;out_insert: *req = __rq; return ret;}static void cfq_merged_request(request_queue_t *q, struct request *req){ struct cfq_data *cfqd = q->elevator.elevator_data; struct cfq_rq *crq = RQ_DATA(req); cfq_del_crq_hash(crq); cfq_add_crq_hash(cfqd, crq); if (ON_RB(&crq->rb_node) && (rq_rb_key(req) != crq->rb_key)) { struct cfq_queue *cfqq = crq->cfq_queue; cfq_del_crq_rb(cfqq, crq); cfq_add_crq_rb(cfqd, cfqq, crq); } q->last_merge = req;}static voidcfq_merged_requests(request_queue_t *q, struct request *req, struct request *next){ cfq_merged_request(q, req); cfq_remove_request(q, next);}static voidcfq_dispatch_sort(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct cfq_rq *crq){ struct list_head *head = cfqd->dispatch, *entry = head; struct request *__rq; cfq_del_crq_rb(cfqq, crq); cfq_remove_merge_hints(cfqd->queue, crq); if (!list_empty(head)) { __rq = list_entry_rq(head->next); if (crq->request->sector < __rq->sector) { entry = head->prev; goto link; } } while ((entry = entry->prev) != head) { __rq = list_entry_rq(entry); if (crq->request->sector <= __rq->sector) break; }link: list_add_tail(&crq->request->queuelist, entry);}static inline void__cfq_dispatch_requests(request_queue_t *q, struct cfq_data *cfqd, struct cfq_queue *cfqq){ struct cfq_rq *crq = rb_entry_crq(rb_first(&cfqq->sort_list)); cfq_dispatch_sort(cfqd, cfqq, crq);}static int cfq_dispatch_requests(request_queue_t *q, struct cfq_data *cfqd){ struct cfq_queue *cfqq; struct list_head *entry, *tmp; int ret, queued, good_queues; if (list_empty(&cfqd->rr_list)) return 0; queued = ret = 0;restart: good_queues = 0; list_for_each_safe(entry, tmp, &cfqd->rr_list) { cfqq = list_entry_cfqq(cfqd->rr_list.next); BUG_ON(RB_EMPTY(&cfqq->sort_list)); __cfq_dispatch_requests(q, cfqd, cfqq); if (RB_EMPTY(&cfqq->sort_list)) cfq_put_queue(cfqd, cfqq); else good_queues++; queued++; ret = 1; } if ((queued < cfqd->cfq_quantum) && good_queues) goto restart; return ret;}static struct request *cfq_next_request(request_queue_t *q){ struct cfq_data *cfqd = q->elevator.elevator_data; struct request *rq; if (!list_empty(cfqd->dispatch)) { struct cfq_rq *crq;dispatch: rq = list_entry_rq(cfqd->dispatch->next); crq = RQ_DATA(rq); if (crq) cfq_remove_merge_hints(q, crq); return rq; } if (cfq_dispatch_requests(q, cfqd)) goto dispatch; return NULL;}static inline struct cfq_queue *__cfq_find_cfq_hash(struct cfq_data *cfqd, int pid, const int hashval){ struct list_head *hash_list = &cfqd->cfq_hash[hashval]; struct list_head *entry; list_for_each(entry, hash_list) { struct cfq_queue *__cfqq = list_entry_qhash(entry); if (__cfqq->pid == pid) return __cfqq; } return NULL;}static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *cfqd, int pid){ const int hashval = hash_long(current->tgid, CFQ_QHASH_SHIFT);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?