aboutsummaryrefslogtreecommitdiffstats
path: root/block/elevator.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/elevator.c')
-rw-r--r--block/elevator.c146
1 files changed, 108 insertions, 38 deletions
diff --git a/block/elevator.c b/block/elevator.c
index 0232df2b16e6..0d2db536c6a7 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -120,15 +120,10 @@ static struct elevator_type *elevator_get(const char *name)
120 return e; 120 return e;
121} 121}
122 122
123static int elevator_attach(request_queue_t *q, struct elevator_type *e, 123static int elevator_attach(request_queue_t *q, struct elevator_queue *eq)
124 struct elevator_queue *eq)
125{ 124{
126 int ret = 0; 125 int ret = 0;
127 126
128 memset(eq, 0, sizeof(*eq));
129 eq->ops = &e->ops;
130 eq->elevator_type = e;
131
132 q->elevator = eq; 127 q->elevator = eq;
133 128
134 if (eq->ops->elevator_init_fn) 129 if (eq->ops->elevator_init_fn)
@@ -154,6 +149,32 @@ static int __init elevator_setup(char *str)
154 149
155__setup("elevator=", elevator_setup); 150__setup("elevator=", elevator_setup);
156 151
152static struct kobj_type elv_ktype;
153
154static elevator_t *elevator_alloc(struct elevator_type *e)
155{
156 elevator_t *eq = kmalloc(sizeof(elevator_t), GFP_KERNEL);
157 if (eq) {
158 memset(eq, 0, sizeof(*eq));
159 eq->ops = &e->ops;
160 eq->elevator_type = e;
161 kobject_init(&eq->kobj);
162 snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched");
163 eq->kobj.ktype = &elv_ktype;
164 mutex_init(&eq->sysfs_lock);
165 } else {
166 elevator_put(e);
167 }
168 return eq;
169}
170
171static void elevator_release(struct kobject *kobj)
172{
173 elevator_t *e = container_of(kobj, elevator_t, kobj);
174 elevator_put(e->elevator_type);
175 kfree(e);
176}
177
157int elevator_init(request_queue_t *q, char *name) 178int elevator_init(request_queue_t *q, char *name)
158{ 179{
159 struct elevator_type *e = NULL; 180 struct elevator_type *e = NULL;
@@ -176,29 +197,26 @@ int elevator_init(request_queue_t *q, char *name)
176 e = elevator_get("noop"); 197 e = elevator_get("noop");
177 } 198 }
178 199
179 eq = kmalloc(sizeof(struct elevator_queue), GFP_KERNEL); 200 eq = elevator_alloc(e);
180 if (!eq) { 201 if (!eq)
181 elevator_put(e);
182 return -ENOMEM; 202 return -ENOMEM;
183 }
184 203
185 ret = elevator_attach(q, e, eq); 204 ret = elevator_attach(q, eq);
186 if (ret) { 205 if (ret)
187 kfree(eq); 206 kobject_put(&eq->kobj);
188 elevator_put(e);
189 }
190 207
191 return ret; 208 return ret;
192} 209}
193 210
194void elevator_exit(elevator_t *e) 211void elevator_exit(elevator_t *e)
195{ 212{
213 mutex_lock(&e->sysfs_lock);
196 if (e->ops->elevator_exit_fn) 214 if (e->ops->elevator_exit_fn)
197 e->ops->elevator_exit_fn(e); 215 e->ops->elevator_exit_fn(e);
216 e->ops = NULL;
217 mutex_unlock(&e->sysfs_lock);
198 218
199 elevator_put(e->elevator_type); 219 kobject_put(&e->kobj);
200 e->elevator_type = NULL;
201 kfree(e);
202} 220}
203 221
204/* 222/*
@@ -627,26 +645,78 @@ void elv_completed_request(request_queue_t *q, struct request *rq)
627 } 645 }
628} 646}
629 647
630int elv_register_queue(struct request_queue *q) 648#define to_elv(atr) container_of((atr), struct elv_fs_entry, attr)
649
650static ssize_t
651elv_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
631{ 652{
632 elevator_t *e = q->elevator; 653 elevator_t *e = container_of(kobj, elevator_t, kobj);
654 struct elv_fs_entry *entry = to_elv(attr);
655 ssize_t error;
656
657 if (!entry->show)
658 return -EIO;
659
660 mutex_lock(&e->sysfs_lock);
661 error = e->ops ? entry->show(e, page) : -ENOENT;
662 mutex_unlock(&e->sysfs_lock);
663 return error;
664}
633 665
634 e->kobj.parent = kobject_get(&q->kobj); 666static ssize_t
635 if (!e->kobj.parent) 667elv_attr_store(struct kobject *kobj, struct attribute *attr,
636 return -EBUSY; 668 const char *page, size_t length)
669{
670 elevator_t *e = container_of(kobj, elevator_t, kobj);
671 struct elv_fs_entry *entry = to_elv(attr);
672 ssize_t error;
637 673
638 snprintf(e->kobj.name, KOBJ_NAME_LEN, "%s", "iosched"); 674 if (!entry->store)
639 e->kobj.ktype = e->elevator_type->elevator_ktype; 675 return -EIO;
640 676
641 return kobject_register(&e->kobj); 677 mutex_lock(&e->sysfs_lock);
678 error = e->ops ? entry->store(e, page, length) : -ENOENT;
679 mutex_unlock(&e->sysfs_lock);
680 return error;
681}
682
683static struct sysfs_ops elv_sysfs_ops = {
684 .show = elv_attr_show,
685 .store = elv_attr_store,
686};
687
688static struct kobj_type elv_ktype = {
689 .sysfs_ops = &elv_sysfs_ops,
690 .release = elevator_release,
691};
692
693int elv_register_queue(struct request_queue *q)
694{
695 elevator_t *e = q->elevator;
696 int error;
697
698 e->kobj.parent = &q->kobj;
699
700 error = kobject_add(&e->kobj);
701 if (!error) {
702 struct attribute **attr = e->elevator_type->elevator_attrs;
703 if (attr) {
704 while (*attr) {
705 if (sysfs_create_file(&e->kobj,*attr++))
706 break;
707 }
708 }
709 kobject_uevent(&e->kobj, KOBJ_ADD);
710 }
711 return error;
642} 712}
643 713
644void elv_unregister_queue(struct request_queue *q) 714void elv_unregister_queue(struct request_queue *q)
645{ 715{
646 if (q) { 716 if (q) {
647 elevator_t *e = q->elevator; 717 elevator_t *e = q->elevator;
648 kobject_unregister(&e->kobj); 718 kobject_uevent(&e->kobj, KOBJ_REMOVE);
649 kobject_put(&q->kobj); 719 kobject_del(&e->kobj);
650 } 720 }
651} 721}
652 722
@@ -697,16 +767,16 @@ EXPORT_SYMBOL_GPL(elv_unregister);
697 * need for the new one. this way we have a chance of going back to the old 767 * need for the new one. this way we have a chance of going back to the old
698 * one, if the new one fails init for some reason. 768 * one, if the new one fails init for some reason.
699 */ 769 */
700static void elevator_switch(request_queue_t *q, struct elevator_type *new_e) 770static int elevator_switch(request_queue_t *q, struct elevator_type *new_e)
701{ 771{
702 elevator_t *old_elevator, *e; 772 elevator_t *old_elevator, *e;
703 773
704 /* 774 /*
705 * Allocate new elevator 775 * Allocate new elevator
706 */ 776 */
707 e = kmalloc(sizeof(elevator_t), GFP_KERNEL); 777 e = elevator_alloc(new_e);
708 if (!e) 778 if (!e)
709 goto error; 779 return 0;
710 780
711 /* 781 /*
712 * Turn on BYPASS and drain all requests w/ elevator private data 782 * Turn on BYPASS and drain all requests w/ elevator private data
@@ -737,7 +807,7 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e)
737 /* 807 /*
738 * attach and start new elevator 808 * attach and start new elevator
739 */ 809 */
740 if (elevator_attach(q, new_e, e)) 810 if (elevator_attach(q, e))
741 goto fail; 811 goto fail;
742 812
743 if (elv_register_queue(q)) 813 if (elv_register_queue(q))
@@ -748,7 +818,7 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e)
748 */ 818 */
749 elevator_exit(old_elevator); 819 elevator_exit(old_elevator);
750 clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); 820 clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
751 return; 821 return 1;
752 822
753fail_register: 823fail_register:
754 /* 824 /*
@@ -761,10 +831,9 @@ fail:
761 q->elevator = old_elevator; 831 q->elevator = old_elevator;
762 elv_register_queue(q); 832 elv_register_queue(q);
763 clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); 833 clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
764 kfree(e); 834 if (e)
765error: 835 kobject_put(&e->kobj);
766 elevator_put(new_e); 836 return 0;
767 printk(KERN_ERR "elevator: switch to %s failed\n",new_e->elevator_name);
768} 837}
769 838
770ssize_t elv_iosched_store(request_queue_t *q, const char *name, size_t count) 839ssize_t elv_iosched_store(request_queue_t *q, const char *name, size_t count)
@@ -791,7 +860,8 @@ ssize_t elv_iosched_store(request_queue_t *q, const char *name, size_t count)
791 return count; 860 return count;
792 } 861 }
793 862
794 elevator_switch(q, e); 863 if (!elevator_switch(q, e))
864 printk(KERN_ERR "elevator: switch to %s failed\n",elevator_name);
795 return count; 865 return count;
796} 866}
797 867