X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=block%2Felevator.c;h=ac5310ef8270984e32799e0524917abf4246853a;hb=a1c1f281b84a751fdb5ff919da3b09df7297619f;hp=f9736fbdab0308f7121694df2faa3ffa68258994;hpb=b47711bfbcd4eb77ca61ef0162487b20e023ae55;p=linux-2.6-omap-h63xx.git diff --git a/block/elevator.c b/block/elevator.c index f9736fbdab0..ac5310ef827 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -45,7 +45,8 @@ static LIST_HEAD(elv_list); */ static const int elv_hash_shift = 6; #define ELV_HASH_BLOCK(sec) ((sec) >> 3) -#define ELV_HASH_FN(sec) (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift)) +#define ELV_HASH_FN(sec) \ + (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift)) #define ELV_HASH_ENTRIES (1 << elv_hash_shift) #define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) #define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash)) @@ -68,7 +69,7 @@ static int elv_iosched_allow_merge(struct request *rq, struct bio *bio) /* * can we safely merge with this request? */ -inline int elv_rq_merge_ok(struct request *rq, struct bio *bio) +int elv_rq_merge_ok(struct request *rq, struct bio *bio) { if (!rq_mergeable(rq)) return 0; @@ -133,6 +134,21 @@ static struct elevator_type *elevator_get(const char *name) spin_lock(&elv_list_lock); e = elevator_find(name); + if (!e) { + char elv[ELV_NAME_MAX + strlen("-iosched")]; + + spin_unlock(&elv_list_lock); + + if (!strcmp(name, "anticipatory")) + sprintf(elv, "as-iosched"); + else + sprintf(elv, "%s-iosched", name); + + request_module(elv); + spin_lock(&elv_list_lock); + e = elevator_find(name); + } + if (e && !try_module_get(e->elevator_owner)) e = NULL; @@ -224,15 +240,27 @@ int elevator_init(struct request_queue *q, char *name) q->end_sector = 0; q->boundary_rq = NULL; - if (name && !(e = elevator_get(name))) - return -EINVAL; + if (name) { + e = elevator_get(name); + if (!e) + return -EINVAL; + } - if (!e && *chosen_elevator && !(e = elevator_get(chosen_elevator))) - printk("I/O scheduler %s not found\n", chosen_elevator); + if (!e && *chosen_elevator) { + e = elevator_get(chosen_elevator); + if (!e) + printk(KERN_ERR "I/O scheduler %s not found\n", + chosen_elevator); + } - if (!e && !(e = elevator_get(CONFIG_DEFAULT_IOSCHED))) { - printk("Default I/O scheduler not found, using no-op\n"); - e = elevator_get("noop"); + if (!e) { + e = elevator_get(CONFIG_DEFAULT_IOSCHED); + if (!e) { + printk(KERN_ERR + "Default I/O scheduler not found. " \ + "Using noop.\n"); + e = elevator_get("noop"); + } } eq = elevator_alloc(q, e); @@ -248,7 +276,6 @@ int elevator_init(struct request_queue *q, char *name) elevator_attach(q, eq, data); return ret; } - EXPORT_SYMBOL(elevator_init); void elevator_exit(elevator_t *e) @@ -261,7 +288,6 @@ void elevator_exit(elevator_t *e) kobject_put(&e->kobj); } - EXPORT_SYMBOL(elevator_exit); static void elv_activate_rq(struct request_queue *q, struct request *rq) @@ -353,7 +379,6 @@ struct request *elv_rb_add(struct rb_root *root, struct request *rq) rb_insert_color(&rq->rb_node, root); return NULL; } - EXPORT_SYMBOL(elv_rb_add); void elv_rb_del(struct rb_root *root, struct request *rq) @@ -362,7 +387,6 @@ void elv_rb_del(struct rb_root *root, struct request *rq) rb_erase(&rq->rb_node, root); RB_CLEAR_NODE(&rq->rb_node); } - EXPORT_SYMBOL(elv_rb_del); struct request *elv_rb_find(struct rb_root *root, sector_t sector) @@ -383,7 +407,6 @@ struct request *elv_rb_find(struct rb_root *root, sector_t sector) return NULL; } - EXPORT_SYMBOL(elv_rb_find); /* @@ -395,6 +418,7 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq) { sector_t boundary; struct list_head *entry; + int stop_flags; if (q->last_merge == rq) q->last_merge = NULL; @@ -404,13 +428,13 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq) q->nr_sorted--; boundary = q->end_sector; - + stop_flags = REQ_SOFTBARRIER | REQ_HARDBARRIER | REQ_STARTED; list_for_each_prev(entry, &q->queue_head) { struct request *pos = list_entry_rq(entry); if (rq_data_dir(rq) != rq_data_dir(pos)) break; - if (pos->cmd_flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED)) + if (pos->cmd_flags & stop_flags) break; if (rq->sector >= boundary) { if (pos->sector < boundary) @@ -425,7 +449,6 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq) list_add(&rq->queuelist, entry); } - EXPORT_SYMBOL(elv_dispatch_sort); /* @@ -446,7 +469,6 @@ void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) q->boundary_rq = rq; list_add_tail(&rq->queuelist, &q->queue_head); } - EXPORT_SYMBOL(elv_dispatch_add_tail); int elv_merge(struct request_queue *q, struct request **req, struct bio *bio) @@ -466,6 +488,9 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio) } } + if (blk_queue_nomerges(q)) + return ELEVATOR_NO_MERGE; + /* * See if our hash lookup can find a potential backmerge. */ @@ -665,7 +690,8 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where, q->end_sector = rq_end_sector(rq); q->boundary_rq = rq; } - } else if (!(rq->cmd_flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT) + } else if (!(rq->cmd_flags & REQ_ELVPRIV) && + where == ELEVATOR_INSERT_SORT) where = ELEVATOR_INSERT_BACK; if (plug) @@ -673,7 +699,6 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where, elv_insert(q, rq, where); } - EXPORT_SYMBOL(__elv_add_request); void elv_add_request(struct request_queue *q, struct request *rq, int where, @@ -685,7 +710,6 @@ void elv_add_request(struct request_queue *q, struct request *rq, int where, __elv_add_request(q, rq, where, plug); spin_unlock_irqrestore(q->queue_lock, flags); } - EXPORT_SYMBOL(elv_add_request); static inline struct request *__elv_next_request(struct request_queue *q) @@ -741,7 +765,21 @@ struct request *elv_next_request(struct request_queue *q) q->boundary_rq = NULL; } - if ((rq->cmd_flags & REQ_DONTPREP) || !q->prep_rq_fn) + if (rq->cmd_flags & REQ_DONTPREP) + break; + + if (q->dma_drain_size && rq->data_len) { + /* + * make sure space for the drain appears we + * know we can do this because max_hw_segments + * has been adjusted to be one fewer than the + * device can handle + */ + rq->nr_phys_segments++; + rq->nr_hw_segments++; + } + + if (!q->prep_rq_fn) break; ret = q->prep_rq_fn(q, rq); @@ -754,6 +792,16 @@ struct request *elv_next_request(struct request_queue *q) * avoid resource deadlock. REQ_STARTED will * prevent other fs requests from passing this one. */ + if (q->dma_drain_size && rq->data_len && + !(rq->cmd_flags & REQ_DONTPREP)) { + /* + * remove the space for the drain we added + * so that we don't add it again + */ + --rq->nr_phys_segments; + --rq->nr_hw_segments; + } + rq = NULL; break; } else if (ret == BLKPREP_KILL) { @@ -768,7 +816,6 @@ struct request *elv_next_request(struct request_queue *q) return rq; } - EXPORT_SYMBOL(elv_next_request); void elv_dequeue_request(struct request_queue *q, struct request *rq) @@ -786,7 +833,6 @@ void elv_dequeue_request(struct request_queue *q, struct request *rq) if (blk_account_rq(rq)) q->in_flight++; } - EXPORT_SYMBOL(elv_dequeue_request); int elv_queue_empty(struct request_queue *q) @@ -801,7 +847,6 @@ int elv_queue_empty(struct request_queue *q) return 1; } - EXPORT_SYMBOL(elv_queue_empty); struct request *elv_latter_request(struct request_queue *q, struct request *rq) @@ -970,7 +1015,8 @@ void elv_register(struct elevator_type *e) !strcmp(e->elevator_name, CONFIG_DEFAULT_IOSCHED))) def = " (default)"; - printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name, def); + printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name, + def); } EXPORT_SYMBOL_GPL(elv_register); @@ -1027,7 +1073,7 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) */ spin_lock_irq(q->queue_lock); - set_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); + queue_flag_set(QUEUE_FLAG_ELVSWITCH, q); elv_drain_elevator(q); @@ -1061,7 +1107,10 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) * finally exit old elevator and turn off BYPASS. */ elevator_exit(old_elevator); - clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); + spin_lock_irq(q->queue_lock); + queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q); + spin_unlock_irq(q->queue_lock); + return 1; fail_register: @@ -1072,7 +1121,11 @@ fail_register: elevator_exit(e); q->elevator = old_elevator; elv_register_queue(q); - clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); + + spin_lock_irq(q->queue_lock); + queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q); + spin_unlock_irq(q->queue_lock); + return 0; } @@ -1102,7 +1155,8 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name, } if (!elevator_switch(q, e)) - printk(KERN_ERR "elevator: switch to %s failed\n",elevator_name); + printk(KERN_ERR "elevator: switch to %s failed\n", + elevator_name); return count; } @@ -1136,7 +1190,6 @@ struct request *elv_rb_former_request(struct request_queue *q, return NULL; } - EXPORT_SYMBOL(elv_rb_former_request); struct request *elv_rb_latter_request(struct request_queue *q, @@ -1149,5 +1202,4 @@ struct request *elv_rb_latter_request(struct request_queue *q, return NULL; } - EXPORT_SYMBOL(elv_rb_latter_request);