]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | Subject: Update least-pending-IO dynamic load balancer |
2 | From: Hannes Reinecke <hare@suse.de> | |
3 | Date: Wed Jan 7 09:26:30 2009 +0100: | |
4 | References: bnc#444199 | |
5 | ||
6 | Attached patch provides "Least pending IO" dynamic load balancing policy for | |
7 | bio based device mapper multipath. This load balancing policy considers the | |
8 | number of unserviced requests pending on a path and selects the path with least | |
9 | count for pending service request. | |
10 | ||
11 | We find this policy more useful especially when the SAN environment has | |
12 | heterogeneous components. Ex, when there is one 8GB HBA and one 2GB HBA | |
13 | connected to the same server, 8GB HBA could be utilized better with this | |
14 | algorithm. | |
15 | ||
16 | This patch includes the update as posted in the bugzilla, | |
17 | based on the review comments received in the dm-devel mailing list. | |
18 | ||
19 | Signed-off-by: Sakshi Chaitanya Veni <vsakshi@hp.com> | |
20 | Signed-off-by: Vijayakumar Balasubramanian <vijayakumar@hp.com> | |
21 | Signed-off-by: Senthil Kumar V <senthil-kumar.veluswamy@hp.com> | |
22 | Signed-off-by: Hannes Reinecke <hare@suse.de> | |
23 | ||
24 | diff --git a/drivers/md/Makefile b/drivers/md/Makefile | |
25 | index 42c35fb..24cfd6a 100644 | |
26 | --- a/drivers/md/Makefile | |
27 | +++ b/drivers/md/Makefile | |
28 | @@ -32,7 +32,7 @@ obj-$(CONFIG_BLK_DEV_MD) += md-mod.o | |
29 | obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o | |
30 | obj-$(CONFIG_DM_CRYPT) += dm-crypt.o | |
31 | obj-$(CONFIG_DM_DELAY) += dm-delay.o | |
32 | -obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o | |
33 | +obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o dm-least-pending.o | |
34 | obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o | |
35 | obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-regions.o dm-log.o | |
36 | obj-$(CONFIG_DM_RAID45) += dm-raid45.o dm-log.o dm-memcache.o \ | |
37 | diff --git a/drivers/md/dm-least-pending.c b/drivers/md/dm-least-pending.c | |
38 | new file mode 100644 | |
39 | index 0000000..a7aea6d | |
40 | --- /dev/null | |
41 | +++ b/drivers/md/dm-least-pending.c | |
42 | @@ -0,0 +1,256 @@ | |
43 | +/* | |
44 | + * (C) Copyright 2008 Hewlett-Packard Development Company, L.P | |
45 | + * | |
46 | + * This file is released under the GPL. | |
47 | + */ | |
48 | + | |
49 | +#include "dm-path-selector.h" | |
50 | + | |
51 | +#include <linux/slab.h> | |
52 | + | |
53 | +#define DM_MSG_PREFIX "multipath least-pending" | |
54 | + | |
55 | +/*----------------------------------------------------------------- | |
56 | +* Path-handling code, paths are held in lists | |
57 | +*---------------------------------------------------------------*/ | |
58 | +struct path_info { | |
59 | + struct list_head list; | |
60 | + struct dm_path *path; | |
61 | + unsigned repeat_count; | |
62 | + atomic_t io_count; | |
63 | +}; | |
64 | + | |
65 | +static void free_paths(struct list_head *paths) | |
66 | +{ | |
67 | + struct path_info *pi, *next; | |
68 | + | |
69 | + list_for_each_entry_safe(pi, next, paths, list) { | |
70 | + list_del(&pi->list); | |
71 | + kfree(pi); | |
72 | + } | |
73 | +} | |
74 | + | |
75 | +/*----------------------------------------------------------------- | |
76 | + * Least-pending selector | |
77 | + *---------------------------------------------------------------*/ | |
78 | + | |
79 | +#define LPP_MIN_IO 1 | |
80 | + | |
81 | +struct selector { | |
82 | + struct list_head valid_paths; | |
83 | + struct list_head invalid_paths; | |
84 | +}; | |
85 | + | |
86 | +static struct selector *alloc_selector(void) | |
87 | +{ | |
88 | + struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL); | |
89 | + | |
90 | + if (s) { | |
91 | + INIT_LIST_HEAD(&s->valid_paths); | |
92 | + INIT_LIST_HEAD(&s->invalid_paths); | |
93 | + } | |
94 | + | |
95 | + return s; | |
96 | +} | |
97 | + | |
98 | +static int lpp_create(struct path_selector *ps, unsigned argc, char **argv) | |
99 | +{ | |
100 | + struct selector *s; | |
101 | + | |
102 | + s = alloc_selector(); | |
103 | + if (!s) | |
104 | + return -ENOMEM; | |
105 | + | |
106 | + ps->context = s; | |
107 | + return 0; | |
108 | +} | |
109 | + | |
110 | +static void lpp_destroy(struct path_selector *ps) | |
111 | +{ | |
112 | + struct selector *s = ps->context; | |
113 | + | |
114 | + free_paths(&s->valid_paths); | |
115 | + free_paths(&s->invalid_paths); | |
116 | + kfree(s); | |
117 | + ps->context = NULL; | |
118 | +} | |
119 | + | |
120 | +static int lpp_status(struct path_selector *ps, struct dm_path *path, | |
121 | + status_type_t type, char *result, unsigned int maxlen) | |
122 | +{ | |
123 | + struct path_info *pi; | |
124 | + int sz = 0; | |
125 | + | |
126 | + if (!path) | |
127 | + switch (type) { | |
128 | + case STATUSTYPE_INFO: | |
129 | + DMEMIT("1 "); | |
130 | + break; | |
131 | + case STATUSTYPE_TABLE: | |
132 | + DMEMIT("0 "); | |
133 | + break; | |
134 | + } | |
135 | + else { | |
136 | + pi = path->pscontext; | |
137 | + switch (type) { | |
138 | + case STATUSTYPE_INFO: | |
139 | + DMEMIT("%u:%u ", pi->repeat_count, | |
140 | + atomic_read(&pi->io_count)); | |
141 | + break; | |
142 | + case STATUSTYPE_TABLE: | |
143 | + break; | |
144 | + } | |
145 | + } | |
146 | + | |
147 | + return sz; | |
148 | +} | |
149 | + | |
150 | +/* | |
151 | + * Called during initialisation to register each path with an | |
152 | + * optional repeat_count. | |
153 | + */ | |
154 | +static int lpp_add_path(struct path_selector *ps, struct dm_path *path, | |
155 | + int argc, char **argv, char **error) | |
156 | +{ | |
157 | + struct selector *s = ps->context; | |
158 | + struct path_info *pi; | |
159 | + unsigned repeat_count = LPP_MIN_IO; | |
160 | + | |
161 | + if (argc > 1) { | |
162 | + *error = "least-pending ps: incorrect number of arguments"; | |
163 | + return -EINVAL; | |
164 | + } | |
165 | + | |
166 | + /* First path argument is number of I/Os before switching path */ | |
167 | + if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) { | |
168 | + *error = "least-pending ps: invalid repeat count"; | |
169 | + return -EINVAL; | |
170 | + } | |
171 | + | |
172 | + /* allocate the path */ | |
173 | + pi = kmalloc(sizeof(*pi), GFP_KERNEL); | |
174 | + if (!pi) { | |
175 | + *error = "least-pending ps: Error allocating path context"; | |
176 | + return -ENOMEM; | |
177 | + } | |
178 | + | |
179 | + pi->path = path; | |
180 | + pi->repeat_count = repeat_count; | |
181 | + atomic_set(&pi->io_count, 0); | |
182 | + | |
183 | + path->pscontext = pi; | |
184 | + | |
185 | + list_add(&pi->list, &s->valid_paths); | |
186 | + | |
187 | + return 0; | |
188 | +} | |
189 | + | |
190 | +static void lpp_fail_path(struct path_selector *ps, struct dm_path *p) | |
191 | +{ | |
192 | + struct selector *s = ps->context; | |
193 | + struct path_info *pi = p->pscontext; | |
194 | + | |
195 | + if (!pi) | |
196 | + return; | |
197 | + | |
198 | + atomic_set(&pi->io_count, 0); | |
199 | + | |
200 | + list_move(&pi->list, &s->invalid_paths); | |
201 | +} | |
202 | + | |
203 | +static int lpp_reinstate_path(struct path_selector *ps, struct dm_path *p) | |
204 | +{ | |
205 | + struct selector *s = ps->context; | |
206 | + struct path_info *pi = p->pscontext; | |
207 | + | |
208 | + if (!pi) | |
209 | + return 1; | |
210 | + | |
211 | + list_move(&pi->list, &s->valid_paths); | |
212 | + | |
213 | + return 0; | |
214 | +} | |
215 | + | |
216 | +static struct dm_path *lpp_select_path(struct path_selector *ps, | |
217 | + unsigned *repeat_count) | |
218 | +{ | |
219 | + struct selector *s = ps->context; | |
220 | + struct path_info *pi, *next, *least_io_path = NULL; | |
221 | + struct list_head *paths; | |
222 | + | |
223 | + if (list_empty(&s->valid_paths)) | |
224 | + return NULL; | |
225 | + | |
226 | + paths = &s->valid_paths; | |
227 | + | |
228 | + list_for_each_entry_safe(pi, next, paths, list) { | |
229 | + if (!least_io_path || atomic_read(&least_io_path->io_count) < atomic_read(&pi->io_count)) | |
230 | + least_io_path = pi; | |
231 | + if (!atomic_read(&least_io_path->io_count)) | |
232 | + break; | |
233 | + } | |
234 | + | |
235 | + if (!least_io_path) | |
236 | + return NULL; | |
237 | + | |
238 | + atomic_inc(&least_io_path->io_count); | |
239 | + *repeat_count = pi->repeat_count; | |
240 | + | |
241 | + return least_io_path->path; | |
242 | +} | |
243 | + | |
244 | +static int lpp_end_io(struct path_selector *ps, struct dm_path *path) | |
245 | +{ | |
246 | + struct path_info *pi = NULL; | |
247 | + | |
248 | + pi = path->pscontext; | |
249 | + if (!pi) | |
250 | + return 1; | |
251 | + | |
252 | + atomic_dec(&pi->io_count); | |
253 | + | |
254 | + return 0; | |
255 | +} | |
256 | + | |
257 | +static struct path_selector_type lpp_ps = { | |
258 | + .name = "least-pending", | |
259 | + .module = THIS_MODULE, | |
260 | + .table_args = 0, | |
261 | + .info_args = 1, | |
262 | + .create = lpp_create, | |
263 | + .destroy = lpp_destroy, | |
264 | + .status = lpp_status, | |
265 | + .add_path = lpp_add_path, | |
266 | + .fail_path = lpp_fail_path, | |
267 | + .reinstate_path = lpp_reinstate_path, | |
268 | + .select_path = lpp_select_path, | |
269 | + .end_io = lpp_end_io, | |
270 | +}; | |
271 | + | |
272 | +static int __init dm_lpp_init(void) | |
273 | +{ | |
274 | + int r = dm_register_path_selector(&lpp_ps); | |
275 | + | |
276 | + if (r < 0) | |
277 | + DMERR("register failed %d", r); | |
278 | + | |
279 | + DMINFO("version 1.0.0 loaded"); | |
280 | + | |
281 | + return r; | |
282 | +} | |
283 | + | |
284 | +static void __exit dm_lpp_exit(void) | |
285 | +{ | |
286 | + int r = dm_unregister_path_selector(&lpp_ps); | |
287 | + | |
288 | + if (r < 0) | |
289 | + DMERR("unregister failed %d", r); | |
290 | +} | |
291 | + | |
292 | +module_init(dm_lpp_init); | |
293 | +module_exit(dm_lpp_exit); | |
294 | + | |
295 | +MODULE_DESCRIPTION(DM_NAME " least-pending multipath path selector"); | |
296 | +MODULE_AUTHOR("Sakshi Chaitanya Veni <vsakshi@hp.com>"); | |
297 | +MODULE_LICENSE("GPL"); | |
298 | + |