aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block/cfq-iosched.c48
-rw-r--r--block/deadline-iosched.c4
-rw-r--r--block/elevator.c37
-rw-r--r--block/noop-iosched.c4
-rw-r--r--include/linux/elevator.h11
5 files changed, 62 insertions, 42 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 048fa699adf9..06e59abcb57f 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -3914,34 +3914,6 @@ static void *cfq_init_queue(struct request_queue *q)
3914 return cfqd; 3914 return cfqd;
3915} 3915}
3916 3916
3917static void cfq_slab_kill(void)
3918{
3919 /*
3920 * Caller already ensured that pending RCU callbacks are completed,
3921 * so we should have no busy allocations at this point.
3922 */
3923 if (cfq_pool)
3924 kmem_cache_destroy(cfq_pool);
3925 if (cfq_icq_pool)
3926 kmem_cache_destroy(cfq_icq_pool);
3927}
3928
3929static int __init cfq_slab_setup(void)
3930{
3931 cfq_pool = KMEM_CACHE(cfq_queue, 0);
3932 if (!cfq_pool)
3933 goto fail;
3934
3935 cfq_icq_pool = KMEM_CACHE(cfq_io_cq, 0);
3936 if (!cfq_icq_pool)
3937 goto fail;
3938
3939 return 0;
3940fail:
3941 cfq_slab_kill();
3942 return -ENOMEM;
3943}
3944
3945/* 3917/*
3946 * sysfs parts below --> 3918 * sysfs parts below -->
3947 */ 3919 */
@@ -4053,8 +4025,10 @@ static struct elevator_type iosched_cfq = {
4053 .elevator_init_fn = cfq_init_queue, 4025 .elevator_init_fn = cfq_init_queue,
4054 .elevator_exit_fn = cfq_exit_queue, 4026 .elevator_exit_fn = cfq_exit_queue,
4055 }, 4027 },
4028 .icq_size = sizeof(struct cfq_io_cq),
4029 .icq_align = __alignof__(struct cfq_io_cq),
4056 .elevator_attrs = cfq_attrs, 4030 .elevator_attrs = cfq_attrs,
4057 .elevator_name = "cfq", 4031 .elevator_name = "cfq",
4058 .elevator_owner = THIS_MODULE, 4032 .elevator_owner = THIS_MODULE,
4059}; 4033};
4060 4034
@@ -4072,6 +4046,8 @@ static struct blkio_policy_type blkio_policy_cfq;
4072 4046
4073static int __init cfq_init(void) 4047static int __init cfq_init(void)
4074{ 4048{
4049 int ret;
4050
4075 /* 4051 /*
4076 * could be 0 on HZ < 1000 setups 4052 * could be 0 on HZ < 1000 setups
4077 */ 4053 */
@@ -4086,10 +4062,17 @@ static int __init cfq_init(void)
4086#else 4062#else
4087 cfq_group_idle = 0; 4063 cfq_group_idle = 0;
4088#endif 4064#endif
4089 if (cfq_slab_setup()) 4065 cfq_pool = KMEM_CACHE(cfq_queue, 0);
4066 if (!cfq_pool)
4090 return -ENOMEM; 4067 return -ENOMEM;
4091 4068
4092 elv_register(&iosched_cfq); 4069 ret = elv_register(&iosched_cfq);
4070 if (ret) {
4071 kmem_cache_destroy(cfq_pool);
4072 return ret;
4073 }
4074 cfq_icq_pool = iosched_cfq.icq_cache;
4075
4093 blkio_policy_register(&blkio_policy_cfq); 4076 blkio_policy_register(&blkio_policy_cfq);
4094 4077
4095 return 0; 4078 return 0;
@@ -4099,8 +4082,7 @@ static void __exit cfq_exit(void)
4099{ 4082{
4100 blkio_policy_unregister(&blkio_policy_cfq); 4083 blkio_policy_unregister(&blkio_policy_cfq);
4101 elv_unregister(&iosched_cfq); 4084 elv_unregister(&iosched_cfq);
4102 rcu_barrier(); /* make sure all cic RCU frees are complete */ 4085 kmem_cache_destroy(cfq_pool);
4103 cfq_slab_kill();
4104} 4086}
4105 4087
4106module_init(cfq_init); 4088module_init(cfq_init);
diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c
index c644137d9cd6..7bf12d793fcd 100644
--- a/block/deadline-iosched.c
+++ b/block/deadline-iosched.c
@@ -448,9 +448,7 @@ static struct elevator_type iosched_deadline = {
448 448
449static int __init deadline_init(void) 449static int __init deadline_init(void)
450{ 450{
451 elv_register(&iosched_deadline); 451 return elv_register(&iosched_deadline);
452
453 return 0;
454} 452}
455 453
456static void __exit deadline_exit(void) 454static void __exit deadline_exit(void)
diff --git a/block/elevator.c b/block/elevator.c
index c5c6214829cb..cca049fb45c8 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -886,15 +886,36 @@ void elv_unregister_queue(struct request_queue *q)
886} 886}
887EXPORT_SYMBOL(elv_unregister_queue); 887EXPORT_SYMBOL(elv_unregister_queue);
888 888
889void elv_register(struct elevator_type *e) 889int elv_register(struct elevator_type *e)
890{ 890{
891 char *def = ""; 891 char *def = "";
892 892
893 /* create icq_cache if requested */
894 if (e->icq_size) {
895 if (WARN_ON(e->icq_size < sizeof(struct io_cq)) ||
896 WARN_ON(e->icq_align < __alignof__(struct io_cq)))
897 return -EINVAL;
898
899 snprintf(e->icq_cache_name, sizeof(e->icq_cache_name),
900 "%s_io_cq", e->elevator_name);
901 e->icq_cache = kmem_cache_create(e->icq_cache_name, e->icq_size,
902 e->icq_align, 0, NULL);
903 if (!e->icq_cache)
904 return -ENOMEM;
905 }
906
907 /* register, don't allow duplicate names */
893 spin_lock(&elv_list_lock); 908 spin_lock(&elv_list_lock);
894 BUG_ON(elevator_find(e->elevator_name)); 909 if (elevator_find(e->elevator_name)) {
910 spin_unlock(&elv_list_lock);
911 if (e->icq_cache)
912 kmem_cache_destroy(e->icq_cache);
913 return -EBUSY;
914 }
895 list_add_tail(&e->list, &elv_list); 915 list_add_tail(&e->list, &elv_list);
896 spin_unlock(&elv_list_lock); 916 spin_unlock(&elv_list_lock);
897 917
918 /* print pretty message */
898 if (!strcmp(e->elevator_name, chosen_elevator) || 919 if (!strcmp(e->elevator_name, chosen_elevator) ||
899 (!*chosen_elevator && 920 (!*chosen_elevator &&
900 !strcmp(e->elevator_name, CONFIG_DEFAULT_IOSCHED))) 921 !strcmp(e->elevator_name, CONFIG_DEFAULT_IOSCHED)))
@@ -902,14 +923,26 @@ void elv_register(struct elevator_type *e)
902 923
903 printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name, 924 printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name,
904 def); 925 def);
926 return 0;
905} 927}
906EXPORT_SYMBOL_GPL(elv_register); 928EXPORT_SYMBOL_GPL(elv_register);
907 929
908void elv_unregister(struct elevator_type *e) 930void elv_unregister(struct elevator_type *e)
909{ 931{
932 /* unregister */
910 spin_lock(&elv_list_lock); 933 spin_lock(&elv_list_lock);
911 list_del_init(&e->list); 934 list_del_init(&e->list);
912 spin_unlock(&elv_list_lock); 935 spin_unlock(&elv_list_lock);
936
937 /*
938 * Destroy icq_cache if it exists. icq's are RCU managed. Make
939 * sure all RCU operations are complete before proceeding.
940 */
941 if (e->icq_cache) {
942 rcu_barrier();
943 kmem_cache_destroy(e->icq_cache);
944 e->icq_cache = NULL;
945 }
913} 946}
914EXPORT_SYMBOL_GPL(elv_unregister); 947EXPORT_SYMBOL_GPL(elv_unregister);
915 948
diff --git a/block/noop-iosched.c b/block/noop-iosched.c
index 06389e9ef96d..413a0b1d788c 100644
--- a/block/noop-iosched.c
+++ b/block/noop-iosched.c
@@ -94,9 +94,7 @@ static struct elevator_type elevator_noop = {
94 94
95static int __init noop_init(void) 95static int __init noop_init(void)
96{ 96{
97 elv_register(&elevator_noop); 97 return elv_register(&elevator_noop);
98
99 return 0;
100} 98}
101 99
102static void __exit noop_exit(void) 100static void __exit noop_exit(void)
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 04958ef53e62..d3d3e28cbfd4 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -78,10 +78,19 @@ struct elv_fs_entry {
78 */ 78 */
79struct elevator_type 79struct elevator_type
80{ 80{
81 /* managed by elevator core */
82 struct kmem_cache *icq_cache;
83
84 /* fields provided by elevator implementation */
81 struct elevator_ops ops; 85 struct elevator_ops ops;
86 size_t icq_size;
87 size_t icq_align;
82 struct elv_fs_entry *elevator_attrs; 88 struct elv_fs_entry *elevator_attrs;
83 char elevator_name[ELV_NAME_MAX]; 89 char elevator_name[ELV_NAME_MAX];
84 struct module *elevator_owner; 90 struct module *elevator_owner;
91
92 /* managed by elevator core */
93 char icq_cache_name[ELV_NAME_MAX + 5]; /* elvname + "_io_cq" */
85 struct list_head list; 94 struct list_head list;
86}; 95};
87 96
@@ -127,7 +136,7 @@ extern void elv_drain_elevator(struct request_queue *);
127/* 136/*
128 * io scheduler registration 137 * io scheduler registration
129 */ 138 */
130extern void elv_register(struct elevator_type *); 139extern int elv_register(struct elevator_type *);
131extern void elv_unregister(struct elevator_type *); 140extern void elv_unregister(struct elevator_type *);
132 141
133/* 142/*