Commit 3d3c2379feb177a5fd55bb0ed76776dc9d4f3243

Authored by Tejun Heo
Committed by Jens Axboe
1 parent 47fdd4ca96

block, cfq: move icq cache management to block core

Let elevators set ->icq_size and ->icq_align in elevator_type and
elv_register() and elv_unregister() respectively create and destroy
kmem_cache for icq.

* elv_register() now can return failure.  All callers updated.

* icq caches are automatically named "ELVNAME_io_cq".

* cfq_slab_setup/kill() are collapsed into cfq_init/exit().

* While at it, minor indentation change for iosched_cfq.elevator_name
  for consistency.

This will help moving icq management to block core.  This doesn't
introduce any functional change.

Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

Showing 5 changed files with 62 additions and 42 deletions Side-by-side Diff

... ... @@ -3914,34 +3914,6 @@
3914 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 3918 * sysfs parts below -->
3947 3919 */
3948 3920  
... ... @@ -4053,8 +4025,10 @@
4053 4025 .elevator_init_fn = cfq_init_queue,
4054 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 4030 .elevator_attrs = cfq_attrs,
4057   - .elevator_name = "cfq",
  4031 + .elevator_name = "cfq",
4058 4032 .elevator_owner = THIS_MODULE,
4059 4033 };
4060 4034  
... ... @@ -4072,6 +4046,8 @@
4072 4046  
4073 4047 static int __init cfq_init(void)
4074 4048 {
  4049 + int ret;
  4050 +
4075 4051 /*
4076 4052 * could be 0 on HZ < 1000 setups
4077 4053 */
4078 4054  
... ... @@ -4086,10 +4062,17 @@
4086 4062 #else
4087 4063 cfq_group_idle = 0;
4088 4064 #endif
4089   - if (cfq_slab_setup())
  4065 + cfq_pool = KMEM_CACHE(cfq_queue, 0);
  4066 + if (!cfq_pool)
4090 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 4076 blkio_policy_register(&blkio_policy_cfq);
4094 4077  
4095 4078 return 0;
... ... @@ -4099,8 +4082,7 @@
4099 4082 {
4100 4083 blkio_policy_unregister(&blkio_policy_cfq);
4101 4084 elv_unregister(&iosched_cfq);
4102   - rcu_barrier(); /* make sure all cic RCU frees are complete */
4103   - cfq_slab_kill();
  4085 + kmem_cache_destroy(cfq_pool);
4104 4086 }
4105 4087  
4106 4088 module_init(cfq_init);
block/deadline-iosched.c
... ... @@ -448,9 +448,7 @@
448 448  
449 449 static int __init deadline_init(void)
450 450 {
451   - elv_register(&iosched_deadline);
452   -
453   - return 0;
  451 + return elv_register(&iosched_deadline);
454 452 }
455 453  
456 454 static void __exit deadline_exit(void)
... ... @@ -886,15 +886,36 @@
886 886 }
887 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 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 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 915 list_add_tail(&e->list, &elv_list);
896 916 spin_unlock(&elv_list_lock);
897 917  
  918 + /* print pretty message */
898 919 if (!strcmp(e->elevator_name, chosen_elevator) ||
899 920 (!*chosen_elevator &&
900 921 !strcmp(e->elevator_name, CONFIG_DEFAULT_IOSCHED)))
901 922  
902 923  
... ... @@ -902,14 +923,26 @@
902 923  
903 924 printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name,
904 925 def);
  926 + return 0;
905 927 }
906 928 EXPORT_SYMBOL_GPL(elv_register);
907 929  
908 930 void elv_unregister(struct elevator_type *e)
909 931 {
  932 + /* unregister */
910 933 spin_lock(&elv_list_lock);
911 934 list_del_init(&e->list);
912 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 947 EXPORT_SYMBOL_GPL(elv_unregister);
915 948  
block/noop-iosched.c
... ... @@ -94,9 +94,7 @@
94 94  
95 95 static int __init noop_init(void)
96 96 {
97   - elv_register(&elevator_noop);
98   -
99   - return 0;
  97 + return elv_register(&elevator_noop);
100 98 }
101 99  
102 100 static void __exit noop_exit(void)
include/linux/elevator.h
... ... @@ -78,10 +78,19 @@
78 78 */
79 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 85 struct elevator_ops ops;
  86 + size_t icq_size;
  87 + size_t icq_align;
82 88 struct elv_fs_entry *elevator_attrs;
83 89 char elevator_name[ELV_NAME_MAX];
84 90 struct module *elevator_owner;
  91 +
  92 + /* managed by elevator core */
  93 + char icq_cache_name[ELV_NAME_MAX + 5]; /* elvname + "_io_cq" */
85 94 struct list_head list;
86 95 };
87 96  
... ... @@ -127,7 +136,7 @@
127 136 /*
128 137 * io scheduler registration
129 138 */
130   -extern void elv_register(struct elevator_type *);
  139 +extern int elv_register(struct elevator_type *);
131 140 extern void elv_unregister(struct elevator_type *);
132 141  
133 142 /*