2 * (C) Copyright 2008 Hewlett-Packard Development Company, L.P
4 * This file is released under the GPL.
7 #include "dm-path-selector.h"
9 #include <linux/slab.h>
10 #include <linux/module.h>
12 #define DM_MSG_PREFIX "multipath least-pending"
14 /*-----------------------------------------------------------------
15 * Path-handling code, paths are held in lists
16 *---------------------------------------------------------------*/
18 struct list_head list;
20 unsigned repeat_count;
24 static void free_paths(struct list_head *paths)
26 struct path_info *pi, *next;
28 list_for_each_entry_safe(pi, next, paths, list) {
34 /*-----------------------------------------------------------------
35 * Least-pending selector
36 *---------------------------------------------------------------*/
41 struct list_head valid_paths;
42 struct list_head invalid_paths;
45 static struct selector *alloc_selector(void)
47 struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
50 INIT_LIST_HEAD(&s->valid_paths);
51 INIT_LIST_HEAD(&s->invalid_paths);
57 static int lpp_create(struct path_selector *ps, unsigned argc, char **argv)
69 static void lpp_destroy(struct path_selector *ps)
71 struct selector *s = ps->context;
73 free_paths(&s->valid_paths);
74 free_paths(&s->invalid_paths);
79 static int lpp_status(struct path_selector *ps, struct dm_path *path,
80 status_type_t type, char *result, unsigned int maxlen)
90 case STATUSTYPE_TABLE:
98 DMEMIT("%u:%u ", pi->repeat_count,
99 atomic_read(&pi->io_count));
101 case STATUSTYPE_TABLE:
110 * Called during initialisation to register each path with an
111 * optional repeat_count.
113 static int lpp_add_path(struct path_selector *ps, struct dm_path *path,
114 int argc, char **argv, char **error)
116 struct selector *s = ps->context;
117 struct path_info *pi;
118 unsigned repeat_count = LPP_MIN_IO;
121 *error = "least-pending ps: incorrect number of arguments";
125 /* First path argument is number of I/Os before switching path */
126 if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
127 *error = "least-pending ps: invalid repeat count";
131 /* allocate the path */
132 pi = kmalloc(sizeof(*pi), GFP_KERNEL);
134 *error = "least-pending ps: Error allocating path context";
139 pi->repeat_count = repeat_count;
140 atomic_set(&pi->io_count, 0);
142 path->pscontext = pi;
144 list_add(&pi->list, &s->valid_paths);
149 static void lpp_fail_path(struct path_selector *ps, struct dm_path *p)
151 struct selector *s = ps->context;
152 struct path_info *pi = p->pscontext;
157 atomic_set(&pi->io_count, 0);
159 list_move(&pi->list, &s->invalid_paths);
162 static int lpp_reinstate_path(struct path_selector *ps, struct dm_path *p)
164 struct selector *s = ps->context;
165 struct path_info *pi = p->pscontext;
170 list_move(&pi->list, &s->valid_paths);
175 static struct dm_path *lpp_select_path(struct path_selector *ps,
176 unsigned *repeat_count,
179 struct selector *s = ps->context;
180 struct path_info *pi, *next, *least_io_path = NULL;
181 struct list_head *paths;
183 if (list_empty(&s->valid_paths))
186 paths = &s->valid_paths;
188 list_for_each_entry_safe(pi, next, paths, list) {
189 if (!least_io_path || atomic_read(&least_io_path->io_count) < atomic_read(&pi->io_count))
191 if (!atomic_read(&least_io_path->io_count))
198 atomic_inc(&least_io_path->io_count);
199 *repeat_count = least_io_path->repeat_count;
201 return least_io_path->path;
204 static int lpp_end_io(struct path_selector *ps, struct dm_path *path,
207 struct path_info *pi = NULL;
209 pi = path->pscontext;
213 atomic_dec(&pi->io_count);
218 static struct path_selector_type lpp_ps = {
219 .name = "least-pending",
220 .module = THIS_MODULE,
223 .create = lpp_create,
224 .destroy = lpp_destroy,
225 .status = lpp_status,
226 .add_path = lpp_add_path,
227 .fail_path = lpp_fail_path,
228 .reinstate_path = lpp_reinstate_path,
229 .select_path = lpp_select_path,
230 .end_io = lpp_end_io,
233 static int __init dm_lpp_init(void)
235 int r = dm_register_path_selector(&lpp_ps);
238 DMERR("register failed %d", r);
240 DMINFO("version 1.0.0 loaded");
245 static void __exit dm_lpp_exit(void)
247 int r = dm_unregister_path_selector(&lpp_ps);
250 DMERR("unregister failed %d", r);
253 module_init(dm_lpp_init);
254 module_exit(dm_lpp_exit);
256 MODULE_DESCRIPTION(DM_NAME " least-pending multipath path selector");
257 MODULE_AUTHOR("Sakshi Chaitanya Veni <vsakshi@hp.com>");
258 MODULE_LICENSE("GPL");