0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/device-mapper.h>
0013
0014 #include "dm-path-selector.h"
0015
0016 #include <linux/slab.h>
0017 #include <linux/module.h>
0018
0019 #define DM_MSG_PREFIX "multipath round-robin"
0020 #define RR_MIN_IO 1
0021 #define RR_VERSION "1.2.0"
0022
0023
0024
0025
0026 struct path_info {
0027 struct list_head list;
0028 struct dm_path *path;
0029 unsigned repeat_count;
0030 };
0031
0032 static void free_paths(struct list_head *paths)
0033 {
0034 struct path_info *pi, *next;
0035
0036 list_for_each_entry_safe(pi, next, paths, list) {
0037 list_del(&pi->list);
0038 kfree(pi);
0039 }
0040 }
0041
0042
0043
0044
0045
0046 struct selector {
0047 struct list_head valid_paths;
0048 struct list_head invalid_paths;
0049 spinlock_t lock;
0050 };
0051
0052 static struct selector *alloc_selector(void)
0053 {
0054 struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
0055
0056 if (s) {
0057 INIT_LIST_HEAD(&s->valid_paths);
0058 INIT_LIST_HEAD(&s->invalid_paths);
0059 spin_lock_init(&s->lock);
0060 }
0061
0062 return s;
0063 }
0064
0065 static int rr_create(struct path_selector *ps, unsigned argc, char **argv)
0066 {
0067 struct selector *s;
0068
0069 s = alloc_selector();
0070 if (!s)
0071 return -ENOMEM;
0072
0073 ps->context = s;
0074 return 0;
0075 }
0076
0077 static void rr_destroy(struct path_selector *ps)
0078 {
0079 struct selector *s = ps->context;
0080
0081 free_paths(&s->valid_paths);
0082 free_paths(&s->invalid_paths);
0083 kfree(s);
0084 ps->context = NULL;
0085 }
0086
0087 static int rr_status(struct path_selector *ps, struct dm_path *path,
0088 status_type_t type, char *result, unsigned int maxlen)
0089 {
0090 struct path_info *pi;
0091 int sz = 0;
0092
0093 if (!path)
0094 DMEMIT("0 ");
0095 else {
0096 switch(type) {
0097 case STATUSTYPE_INFO:
0098 break;
0099 case STATUSTYPE_TABLE:
0100 pi = path->pscontext;
0101 DMEMIT("%u ", pi->repeat_count);
0102 break;
0103
0104 case STATUSTYPE_IMA:
0105 *result = '\0';
0106 break;
0107 }
0108 }
0109
0110 return sz;
0111 }
0112
0113
0114
0115
0116
0117 static int rr_add_path(struct path_selector *ps, struct dm_path *path,
0118 int argc, char **argv, char **error)
0119 {
0120 struct selector *s = ps->context;
0121 struct path_info *pi;
0122 unsigned repeat_count = RR_MIN_IO;
0123 char dummy;
0124 unsigned long flags;
0125
0126 if (argc > 1) {
0127 *error = "round-robin ps: incorrect number of arguments";
0128 return -EINVAL;
0129 }
0130
0131
0132 if ((argc == 1) && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
0133 *error = "round-robin ps: invalid repeat count";
0134 return -EINVAL;
0135 }
0136
0137 if (repeat_count > 1) {
0138 DMWARN_LIMIT("repeat_count > 1 is deprecated, using 1 instead");
0139 repeat_count = 1;
0140 }
0141
0142
0143 pi = kmalloc(sizeof(*pi), GFP_KERNEL);
0144 if (!pi) {
0145 *error = "round-robin ps: Error allocating path context";
0146 return -ENOMEM;
0147 }
0148
0149 pi->path = path;
0150 pi->repeat_count = repeat_count;
0151
0152 path->pscontext = pi;
0153
0154 spin_lock_irqsave(&s->lock, flags);
0155 list_add_tail(&pi->list, &s->valid_paths);
0156 spin_unlock_irqrestore(&s->lock, flags);
0157
0158 return 0;
0159 }
0160
0161 static void rr_fail_path(struct path_selector *ps, struct dm_path *p)
0162 {
0163 unsigned long flags;
0164 struct selector *s = ps->context;
0165 struct path_info *pi = p->pscontext;
0166
0167 spin_lock_irqsave(&s->lock, flags);
0168 list_move(&pi->list, &s->invalid_paths);
0169 spin_unlock_irqrestore(&s->lock, flags);
0170 }
0171
0172 static int rr_reinstate_path(struct path_selector *ps, struct dm_path *p)
0173 {
0174 unsigned long flags;
0175 struct selector *s = ps->context;
0176 struct path_info *pi = p->pscontext;
0177
0178 spin_lock_irqsave(&s->lock, flags);
0179 list_move(&pi->list, &s->valid_paths);
0180 spin_unlock_irqrestore(&s->lock, flags);
0181
0182 return 0;
0183 }
0184
0185 static struct dm_path *rr_select_path(struct path_selector *ps, size_t nr_bytes)
0186 {
0187 unsigned long flags;
0188 struct selector *s = ps->context;
0189 struct path_info *pi = NULL;
0190
0191 spin_lock_irqsave(&s->lock, flags);
0192 if (!list_empty(&s->valid_paths)) {
0193 pi = list_entry(s->valid_paths.next, struct path_info, list);
0194 list_move_tail(&pi->list, &s->valid_paths);
0195 }
0196 spin_unlock_irqrestore(&s->lock, flags);
0197
0198 return pi ? pi->path : NULL;
0199 }
0200
0201 static struct path_selector_type rr_ps = {
0202 .name = "round-robin",
0203 .module = THIS_MODULE,
0204 .table_args = 1,
0205 .info_args = 0,
0206 .create = rr_create,
0207 .destroy = rr_destroy,
0208 .status = rr_status,
0209 .add_path = rr_add_path,
0210 .fail_path = rr_fail_path,
0211 .reinstate_path = rr_reinstate_path,
0212 .select_path = rr_select_path,
0213 };
0214
0215 static int __init dm_rr_init(void)
0216 {
0217 int r = dm_register_path_selector(&rr_ps);
0218
0219 if (r < 0)
0220 DMERR("register failed %d", r);
0221
0222 DMINFO("version " RR_VERSION " loaded");
0223
0224 return r;
0225 }
0226
0227 static void __exit dm_rr_exit(void)
0228 {
0229 int r = dm_unregister_path_selector(&rr_ps);
0230
0231 if (r < 0)
0232 DMERR("unregister failed %d", r);
0233 }
0234
0235 module_init(dm_rr_init);
0236 module_exit(dm_rr_exit);
0237
0238 MODULE_DESCRIPTION(DM_NAME " round-robin multipath path selector");
0239 MODULE_AUTHOR("Sistina Software <dm-devel@redhat.com>");
0240 MODULE_LICENSE("GPL");