X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=block%2Felevator.c;h=980f8ae147b4c396b15886be25bd9b2342322472;hb=39ab9ddeb3e9573a1ea9a17a1431ea5c81681964;hp=b9c518afe1f8bf61907999f56844c5583a9d0a43;hpb=4937ce87959629d31e9b09cf5bdf1e12a305c805;p=linux-2.6-omap-h63xx.git diff --git a/block/elevator.c b/block/elevator.c index b9c518afe1f..980f8ae147b 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; @@ -185,9 +201,7 @@ static elevator_t *elevator_alloc(struct request_queue *q, eq->ops = &e->ops; eq->elevator_type = e; - kobject_init(&eq->kobj); - kobject_set_name(&eq->kobj, "%s", "iosched"); - eq->kobj.ktype = &elv_ktype; + kobject_init(&eq->kobj, &elv_ktype); mutex_init(&eq->sysfs_lock); eq->hash = kmalloc_node(sizeof(struct hlist_head) * ELV_HASH_ENTRIES, @@ -226,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); @@ -250,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) @@ -263,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) @@ -355,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) @@ -364,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) @@ -385,18 +407,18 @@ struct request *elv_rb_find(struct rb_root *root, sector_t sector) return NULL; } - EXPORT_SYMBOL(elv_rb_find); /* * Insert rq into dispatch queue of q. Queue lock must be held on - * entry. rq is sort insted into the dispatch queue. To be used by + * entry. rq is sort instead into the dispatch queue. To be used by * specific elevators. */ 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; @@ -406,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) @@ -427,7 +449,6 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq) list_add(&rq->queuelist, entry); } - EXPORT_SYMBOL(elv_dispatch_sort); /* @@ -448,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) @@ -468,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. */ @@ -627,7 +650,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where) default: printk(KERN_ERR "%s: bad insertion point %d\n", - __FUNCTION__, where); + __func__, where); BUG(); } @@ -667,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) @@ -675,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, @@ -687,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) @@ -712,6 +734,14 @@ struct request *elv_next_request(struct request_queue *q) int ret; while ((rq = __elv_next_request(q)) != NULL) { + /* + * Kill the empty barrier place holder, the driver must + * not ever see it. + */ + if (blk_empty_barrier(rq)) { + end_queued_request(rq, 1); + continue; + } if (!(rq->cmd_flags & REQ_STARTED)) { /* * This is the first time the device driver @@ -735,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); @@ -748,28 +792,29 @@ 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) { - int nr_bytes = rq->hard_nr_sectors << 9; - - if (!nr_bytes) - nr_bytes = rq->data_len; - - blkdev_dequeue_request(rq); rq->cmd_flags |= REQ_QUIET; - end_that_request_chunk(rq, 0, nr_bytes); - end_that_request_last(rq, 0); + end_queued_request(rq, 0); } else { - printk(KERN_ERR "%s: bad return=%d\n", __FUNCTION__, - ret); + printk(KERN_ERR "%s: bad return=%d\n", __func__, ret); break; } } return rq; } - EXPORT_SYMBOL(elv_next_request); void elv_dequeue_request(struct request_queue *q, struct request *rq) @@ -787,7 +832,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) @@ -802,7 +846,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) @@ -930,9 +973,7 @@ int elv_register_queue(struct request_queue *q) elevator_t *e = q->elevator; int error; - e->kobj.parent = &q->kobj; - - error = kobject_add(&e->kobj); + error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched"); if (!error) { struct elv_fs_entry *attr = e->elevator_type->elevator_attrs; if (attr) { @@ -959,7 +1000,7 @@ void elv_unregister_queue(struct request_queue *q) __elv_unregister_queue(q->elevator); } -int elv_register(struct elevator_type *e) +void elv_register(struct elevator_type *e) { char *def = ""; @@ -973,8 +1014,8 @@ int 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); - return 0; + printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name, + def); } EXPORT_SYMBOL_GPL(elv_register); @@ -1031,7 +1072,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); @@ -1065,7 +1106,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: @@ -1076,7 +1120,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; } @@ -1106,7 +1154,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; } @@ -1140,7 +1189,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, @@ -1153,5 +1201,4 @@ struct request *elv_rb_latter_request(struct request_queue *q, return NULL; } - EXPORT_SYMBOL(elv_rb_latter_request);