Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/md/dm-round-robin.c
15109 views
1
/*
2
* Copyright (C) 2003 Sistina Software.
3
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
4
*
5
* Module Author: Heinz Mauelshagen
6
*
7
* This file is released under the GPL.
8
*
9
* Round-robin path selector.
10
*/
11
12
#include <linux/device-mapper.h>
13
14
#include "dm-path-selector.h"
15
16
#include <linux/slab.h>
17
18
#define DM_MSG_PREFIX "multipath round-robin"
19
20
/*-----------------------------------------------------------------
21
* Path-handling code, paths are held in lists
22
*---------------------------------------------------------------*/
23
struct path_info {
24
struct list_head list;
25
struct dm_path *path;
26
unsigned repeat_count;
27
};
28
29
static void free_paths(struct list_head *paths)
30
{
31
struct path_info *pi, *next;
32
33
list_for_each_entry_safe(pi, next, paths, list) {
34
list_del(&pi->list);
35
kfree(pi);
36
}
37
}
38
39
/*-----------------------------------------------------------------
40
* Round-robin selector
41
*---------------------------------------------------------------*/
42
43
#define RR_MIN_IO 1000
44
45
struct selector {
46
struct list_head valid_paths;
47
struct list_head invalid_paths;
48
};
49
50
static struct selector *alloc_selector(void)
51
{
52
struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
53
54
if (s) {
55
INIT_LIST_HEAD(&s->valid_paths);
56
INIT_LIST_HEAD(&s->invalid_paths);
57
}
58
59
return s;
60
}
61
62
static int rr_create(struct path_selector *ps, unsigned argc, char **argv)
63
{
64
struct selector *s;
65
66
s = alloc_selector();
67
if (!s)
68
return -ENOMEM;
69
70
ps->context = s;
71
return 0;
72
}
73
74
static void rr_destroy(struct path_selector *ps)
75
{
76
struct selector *s = (struct selector *) ps->context;
77
78
free_paths(&s->valid_paths);
79
free_paths(&s->invalid_paths);
80
kfree(s);
81
ps->context = NULL;
82
}
83
84
static int rr_status(struct path_selector *ps, struct dm_path *path,
85
status_type_t type, char *result, unsigned int maxlen)
86
{
87
struct path_info *pi;
88
int sz = 0;
89
90
if (!path)
91
DMEMIT("0 ");
92
else {
93
switch(type) {
94
case STATUSTYPE_INFO:
95
break;
96
case STATUSTYPE_TABLE:
97
pi = path->pscontext;
98
DMEMIT("%u ", pi->repeat_count);
99
break;
100
}
101
}
102
103
return sz;
104
}
105
106
/*
107
* Called during initialisation to register each path with an
108
* optional repeat_count.
109
*/
110
static int rr_add_path(struct path_selector *ps, struct dm_path *path,
111
int argc, char **argv, char **error)
112
{
113
struct selector *s = (struct selector *) ps->context;
114
struct path_info *pi;
115
unsigned repeat_count = RR_MIN_IO;
116
117
if (argc > 1) {
118
*error = "round-robin ps: incorrect number of arguments";
119
return -EINVAL;
120
}
121
122
/* First path argument is number of I/Os before switching path */
123
if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
124
*error = "round-robin ps: invalid repeat count";
125
return -EINVAL;
126
}
127
128
/* allocate the path */
129
pi = kmalloc(sizeof(*pi), GFP_KERNEL);
130
if (!pi) {
131
*error = "round-robin ps: Error allocating path context";
132
return -ENOMEM;
133
}
134
135
pi->path = path;
136
pi->repeat_count = repeat_count;
137
138
path->pscontext = pi;
139
140
list_add_tail(&pi->list, &s->valid_paths);
141
142
return 0;
143
}
144
145
static void rr_fail_path(struct path_selector *ps, struct dm_path *p)
146
{
147
struct selector *s = (struct selector *) ps->context;
148
struct path_info *pi = p->pscontext;
149
150
list_move(&pi->list, &s->invalid_paths);
151
}
152
153
static int rr_reinstate_path(struct path_selector *ps, struct dm_path *p)
154
{
155
struct selector *s = (struct selector *) ps->context;
156
struct path_info *pi = p->pscontext;
157
158
list_move(&pi->list, &s->valid_paths);
159
160
return 0;
161
}
162
163
static struct dm_path *rr_select_path(struct path_selector *ps,
164
unsigned *repeat_count, size_t nr_bytes)
165
{
166
struct selector *s = (struct selector *) ps->context;
167
struct path_info *pi = NULL;
168
169
if (!list_empty(&s->valid_paths)) {
170
pi = list_entry(s->valid_paths.next, struct path_info, list);
171
list_move_tail(&pi->list, &s->valid_paths);
172
*repeat_count = pi->repeat_count;
173
}
174
175
return pi ? pi->path : NULL;
176
}
177
178
static struct path_selector_type rr_ps = {
179
.name = "round-robin",
180
.module = THIS_MODULE,
181
.table_args = 1,
182
.info_args = 0,
183
.create = rr_create,
184
.destroy = rr_destroy,
185
.status = rr_status,
186
.add_path = rr_add_path,
187
.fail_path = rr_fail_path,
188
.reinstate_path = rr_reinstate_path,
189
.select_path = rr_select_path,
190
};
191
192
static int __init dm_rr_init(void)
193
{
194
int r = dm_register_path_selector(&rr_ps);
195
196
if (r < 0)
197
DMERR("register failed %d", r);
198
199
DMINFO("version 1.0.0 loaded");
200
201
return r;
202
}
203
204
static void __exit dm_rr_exit(void)
205
{
206
int r = dm_unregister_path_selector(&rr_ps);
207
208
if (r < 0)
209
DMERR("unregister failed %d", r);
210
}
211
212
module_init(dm_rr_init);
213
module_exit(dm_rr_exit);
214
215
MODULE_DESCRIPTION(DM_NAME " round-robin multipath path selector");
216
MODULE_AUTHOR("Sistina Software <[email protected]>");
217
MODULE_LICENSE("GPL");
218
219