Blame view

drivers/md/dm-round-robin.c 5.04 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
  /*
   * Copyright (C) 2003 Sistina Software.
   * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
   *
   * Module Author: Heinz Mauelshagen
   *
   * This file is released under the GPL.
   *
   * Round-robin path selector.
   */
586e80e6e   Mikulas Patocka   dm: remove dm hea...
11
  #include <linux/device-mapper.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
  #include "dm-path-selector.h"
  
  #include <linux/slab.h>
056075c76   Paul Gortmaker   md: Add module.h ...
15
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16

72d948616   Alasdair G Kergon   [PATCH] dm: impro...
17
  #define DM_MSG_PREFIX "multipath round-robin"
37a098e9d   Mike Snitzer   dm round robin: r...
18
19
  #define RR_MIN_IO     1
  #define RR_VERSION    "1.2.0"
72d948616   Alasdair G Kergon   [PATCH] dm: impro...
20

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
  /*-----------------------------------------------------------------
   * Path-handling code, paths are held in lists
   *---------------------------------------------------------------*/
  struct path_info {
  	struct list_head list;
c922d5f7f   Josef "Jeff" Sipek   [PATCH] struct pa...
26
  	struct dm_path *path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  	unsigned repeat_count;
  };
  
  static void free_paths(struct list_head *paths)
  {
  	struct path_info *pi, *next;
  
  	list_for_each_entry_safe(pi, next, paths, list) {
  		list_del(&pi->list);
  		kfree(pi);
  	}
  }
  
  /*-----------------------------------------------------------------
   * Round-robin selector
   *---------------------------------------------------------------*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
  struct selector {
  	struct list_head valid_paths;
  	struct list_head invalid_paths;
9659f8114   Mike Snitzer   dm mpath: push pa...
46
  	spinlock_t lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
  };
  
  static struct selector *alloc_selector(void)
  {
  	struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
37a098e9d   Mike Snitzer   dm round robin: r...
52
53
54
55
56
  	if (s) {
  		INIT_LIST_HEAD(&s->valid_paths);
  		INIT_LIST_HEAD(&s->invalid_paths);
  		spin_lock_init(&s->lock);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  
  	return s;
  }
  
  static int rr_create(struct path_selector *ps, unsigned argc, char **argv)
  {
  	struct selector *s;
  
  	s = alloc_selector();
  	if (!s)
  		return -ENOMEM;
  
  	ps->context = s;
  	return 0;
  }
  
  static void rr_destroy(struct path_selector *ps)
  {
9659f8114   Mike Snitzer   dm mpath: push pa...
75
  	struct selector *s = ps->context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
  
  	free_paths(&s->valid_paths);
  	free_paths(&s->invalid_paths);
  	kfree(s);
  	ps->context = NULL;
  }
c922d5f7f   Josef "Jeff" Sipek   [PATCH] struct pa...
82
  static int rr_status(struct path_selector *ps, struct dm_path *path,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  		     status_type_t type, char *result, unsigned int maxlen)
  {
  	struct path_info *pi;
  	int sz = 0;
  
  	if (!path)
  		DMEMIT("0 ");
  	else {
  		switch(type) {
  		case STATUSTYPE_INFO:
  			break;
  		case STATUSTYPE_TABLE:
  			pi = path->pscontext;
  			DMEMIT("%u ", pi->repeat_count);
  			break;
  		}
  	}
  
  	return sz;
  }
  
  /*
   * Called during initialisation to register each path with an
   * optional repeat_count.
   */
c922d5f7f   Josef "Jeff" Sipek   [PATCH] struct pa...
108
  static int rr_add_path(struct path_selector *ps, struct dm_path *path,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
  		       int argc, char **argv, char **error)
  {
9659f8114   Mike Snitzer   dm mpath: push pa...
111
  	struct selector *s = ps->context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
  	struct path_info *pi;
  	unsigned repeat_count = RR_MIN_IO;
31998ef19   Mikulas Patocka   dm: reject traili...
114
  	char dummy;
9659f8114   Mike Snitzer   dm mpath: push pa...
115
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
121
122
  
  	if (argc > 1) {
  		*error = "round-robin ps: incorrect number of arguments";
  		return -EINVAL;
  	}
  
  	/* First path argument is number of I/Os before switching path */
31998ef19   Mikulas Patocka   dm: reject traili...
123
  	if ((argc == 1) && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
  		*error = "round-robin ps: invalid repeat count";
  		return -EINVAL;
  	}
37a098e9d   Mike Snitzer   dm round robin: r...
127
128
129
130
  	if (repeat_count > 1) {
  		DMWARN_LIMIT("repeat_count > 1 is deprecated, using 1 instead");
  		repeat_count = 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
135
136
137
138
139
140
141
  	/* allocate the path */
  	pi = kmalloc(sizeof(*pi), GFP_KERNEL);
  	if (!pi) {
  		*error = "round-robin ps: Error allocating path context";
  		return -ENOMEM;
  	}
  
  	pi->path = path;
  	pi->repeat_count = repeat_count;
  
  	path->pscontext = pi;
9659f8114   Mike Snitzer   dm mpath: push pa...
142
  	spin_lock_irqsave(&s->lock, flags);
5d55fdf94   Jonathan E Brassow   [PATCH] dm: multi...
143
  	list_add_tail(&pi->list, &s->valid_paths);
9659f8114   Mike Snitzer   dm mpath: push pa...
144
  	spin_unlock_irqrestore(&s->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
  
  	return 0;
  }
c922d5f7f   Josef "Jeff" Sipek   [PATCH] struct pa...
148
  static void rr_fail_path(struct path_selector *ps, struct dm_path *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  {
9659f8114   Mike Snitzer   dm mpath: push pa...
150
151
  	unsigned long flags;
  	struct selector *s = ps->context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  	struct path_info *pi = p->pscontext;
9659f8114   Mike Snitzer   dm mpath: push pa...
153
  	spin_lock_irqsave(&s->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  	list_move(&pi->list, &s->invalid_paths);
9659f8114   Mike Snitzer   dm mpath: push pa...
155
  	spin_unlock_irqrestore(&s->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  }
c922d5f7f   Josef "Jeff" Sipek   [PATCH] struct pa...
157
  static int rr_reinstate_path(struct path_selector *ps, struct dm_path *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  {
9659f8114   Mike Snitzer   dm mpath: push pa...
159
160
  	unsigned long flags;
  	struct selector *s = ps->context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  	struct path_info *pi = p->pscontext;
9659f8114   Mike Snitzer   dm mpath: push pa...
162
  	spin_lock_irqsave(&s->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  	list_move(&pi->list, &s->valid_paths);
9659f8114   Mike Snitzer   dm mpath: push pa...
164
  	spin_unlock_irqrestore(&s->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
  
  	return 0;
  }
90a4323cc   Mike Snitzer   dm path selector:...
168
  static struct dm_path *rr_select_path(struct path_selector *ps, size_t nr_bytes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  {
9659f8114   Mike Snitzer   dm mpath: push pa...
170
171
  	unsigned long flags;
  	struct selector *s = ps->context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  	struct path_info *pi = NULL;
37a098e9d   Mike Snitzer   dm round robin: r...
173
  	spin_lock_irqsave(&s->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
  	if (!list_empty(&s->valid_paths)) {
  		pi = list_entry(s->valid_paths.next, struct path_info, list);
  		list_move_tail(&pi->list, &s->valid_paths);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  	}
9659f8114   Mike Snitzer   dm mpath: push pa...
178
  	spin_unlock_irqrestore(&s->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179

37a098e9d   Mike Snitzer   dm round robin: r...
180
  	return pi ? pi->path : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  }
  
  static struct path_selector_type rr_ps = {
  	.name = "round-robin",
  	.module = THIS_MODULE,
  	.table_args = 1,
  	.info_args = 0,
  	.create = rr_create,
  	.destroy = rr_destroy,
  	.status = rr_status,
  	.add_path = rr_add_path,
  	.fail_path = rr_fail_path,
  	.reinstate_path = rr_reinstate_path,
  	.select_path = rr_select_path,
  };
  
  static int __init dm_rr_init(void)
  {
  	int r = dm_register_path_selector(&rr_ps);
  
  	if (r < 0)
72d948616   Alasdair G Kergon   [PATCH] dm: impro...
202
  		DMERR("register failed %d", r);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203

21136f89d   Mike Snitzer   dm mpath: remove ...
204
  	DMINFO("version " RR_VERSION " loaded");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
208
209
210
211
212
213
  
  	return r;
  }
  
  static void __exit dm_rr_exit(void)
  {
  	int r = dm_unregister_path_selector(&rr_ps);
  
  	if (r < 0)
0cd331243   Alasdair G Kergon   dm: remove duplic...
214
  		DMERR("unregister failed %d", r);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
219
220
221
222
  }
  
  module_init(dm_rr_init);
  module_exit(dm_rr_exit);
  
  MODULE_DESCRIPTION(DM_NAME " round-robin multipath path selector");
  MODULE_AUTHOR("Sistina Software <dm-devel@redhat.com>");
  MODULE_LICENSE("GPL");