diff options
-rw-r--r-- | block/cfq-iosched.c | 48 | ||||
-rw-r--r-- | block/deadline-iosched.c | 4 | ||||
-rw-r--r-- | block/elevator.c | 37 | ||||
-rw-r--r-- | block/noop-iosched.c | 4 | ||||
-rw-r--r-- | include/linux/elevator.h | 11 |
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 | ||
3917 | static 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 | |||
3929 | static 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; | ||
3940 | fail: | ||
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 | ||
4073 | static int __init cfq_init(void) | 4047 | static 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 | ||
4106 | module_init(cfq_init); | 4088 | module_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 | ||
449 | static int __init deadline_init(void) | 449 | static 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 | ||
456 | static void __exit deadline_exit(void) | 454 | static 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 | } |
887 | EXPORT_SYMBOL(elv_unregister_queue); | 887 | EXPORT_SYMBOL(elv_unregister_queue); |
888 | 888 | ||
889 | void elv_register(struct elevator_type *e) | 889 | int 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 | } |
906 | EXPORT_SYMBOL_GPL(elv_register); | 928 | EXPORT_SYMBOL_GPL(elv_register); |
907 | 929 | ||
908 | void elv_unregister(struct elevator_type *e) | 930 | void 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 | } |
914 | EXPORT_SYMBOL_GPL(elv_unregister); | 947 | EXPORT_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 | ||
95 | static int __init noop_init(void) | 95 | static 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 | ||
102 | static void __exit noop_exit(void) | 100 | static 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 | */ |
79 | struct elevator_type | 79 | struct 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 | */ |
130 | extern void elv_register(struct elevator_type *); | 139 | extern int elv_register(struct elevator_type *); |
131 | extern void elv_unregister(struct elevator_type *); | 140 | extern void elv_unregister(struct elevator_type *); |
132 | 141 | ||
133 | /* | 142 | /* |