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");