diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/ipv4/ipvs/ip_vs_sched.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'net/ipv4/ipvs/ip_vs_sched.c')
-rw-r--r-- | net/ipv4/ipvs/ip_vs_sched.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/net/ipv4/ipvs/ip_vs_sched.c b/net/ipv4/ipvs/ip_vs_sched.c new file mode 100644 index 000000000000..0f7c56a225bd --- /dev/null +++ b/net/ipv4/ipvs/ip_vs_sched.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /* | ||
2 | * IPVS An implementation of the IP virtual server support for the | ||
3 | * LINUX operating system. IPVS is now implemented as a module | ||
4 | * over the Netfilter framework. IPVS can be used to build a | ||
5 | * high-performance and highly available server based on a | ||
6 | * cluster of servers. | ||
7 | * | ||
8 | * Version: $Id: ip_vs_sched.c,v 1.13 2003/05/10 03:05:23 wensong Exp $ | ||
9 | * | ||
10 | * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> | ||
11 | * Peter Kese <peter.kese@ijs.si> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version | ||
16 | * 2 of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * Changes: | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <asm/string.h> | ||
26 | #include <linux/kmod.h> | ||
27 | |||
28 | #include <net/ip_vs.h> | ||
29 | |||
30 | /* | ||
31 | * IPVS scheduler list | ||
32 | */ | ||
33 | static LIST_HEAD(ip_vs_schedulers); | ||
34 | |||
35 | /* lock for service table */ | ||
36 | static DEFINE_RWLOCK(__ip_vs_sched_lock); | ||
37 | |||
38 | |||
39 | /* | ||
40 | * Bind a service with a scheduler | ||
41 | */ | ||
42 | int ip_vs_bind_scheduler(struct ip_vs_service *svc, | ||
43 | struct ip_vs_scheduler *scheduler) | ||
44 | { | ||
45 | int ret; | ||
46 | |||
47 | if (svc == NULL) { | ||
48 | IP_VS_ERR("ip_vs_bind_scheduler(): svc arg NULL\n"); | ||
49 | return -EINVAL; | ||
50 | } | ||
51 | if (scheduler == NULL) { | ||
52 | IP_VS_ERR("ip_vs_bind_scheduler(): scheduler arg NULL\n"); | ||
53 | return -EINVAL; | ||
54 | } | ||
55 | |||
56 | svc->scheduler = scheduler; | ||
57 | |||
58 | if (scheduler->init_service) { | ||
59 | ret = scheduler->init_service(svc); | ||
60 | if (ret) { | ||
61 | IP_VS_ERR("ip_vs_bind_scheduler(): init error\n"); | ||
62 | return ret; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | |||
70 | /* | ||
71 | * Unbind a service with its scheduler | ||
72 | */ | ||
73 | int ip_vs_unbind_scheduler(struct ip_vs_service *svc) | ||
74 | { | ||
75 | struct ip_vs_scheduler *sched; | ||
76 | |||
77 | if (svc == NULL) { | ||
78 | IP_VS_ERR("ip_vs_unbind_scheduler(): svc arg NULL\n"); | ||
79 | return -EINVAL; | ||
80 | } | ||
81 | |||
82 | sched = svc->scheduler; | ||
83 | if (sched == NULL) { | ||
84 | IP_VS_ERR("ip_vs_unbind_scheduler(): svc isn't bound\n"); | ||
85 | return -EINVAL; | ||
86 | } | ||
87 | |||
88 | if (sched->done_service) { | ||
89 | if (sched->done_service(svc) != 0) { | ||
90 | IP_VS_ERR("ip_vs_unbind_scheduler(): done error\n"); | ||
91 | return -EINVAL; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | svc->scheduler = NULL; | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | |||
100 | /* | ||
101 | * Get scheduler in the scheduler list by name | ||
102 | */ | ||
103 | static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name) | ||
104 | { | ||
105 | struct ip_vs_scheduler *sched; | ||
106 | |||
107 | IP_VS_DBG(2, "ip_vs_sched_getbyname(): sched_name \"%s\"\n", | ||
108 | sched_name); | ||
109 | |||
110 | read_lock_bh(&__ip_vs_sched_lock); | ||
111 | |||
112 | list_for_each_entry(sched, &ip_vs_schedulers, n_list) { | ||
113 | /* | ||
114 | * Test and get the modules atomically | ||
115 | */ | ||
116 | if (sched->module && !try_module_get(sched->module)) { | ||
117 | /* | ||
118 | * This scheduler is just deleted | ||
119 | */ | ||
120 | continue; | ||
121 | } | ||
122 | if (strcmp(sched_name, sched->name)==0) { | ||
123 | /* HIT */ | ||
124 | read_unlock_bh(&__ip_vs_sched_lock); | ||
125 | return sched; | ||
126 | } | ||
127 | if (sched->module) | ||
128 | module_put(sched->module); | ||
129 | } | ||
130 | |||
131 | read_unlock_bh(&__ip_vs_sched_lock); | ||
132 | return NULL; | ||
133 | } | ||
134 | |||
135 | |||
136 | /* | ||
137 | * Lookup scheduler and try to load it if it doesn't exist | ||
138 | */ | ||
139 | struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name) | ||
140 | { | ||
141 | struct ip_vs_scheduler *sched; | ||
142 | |||
143 | /* | ||
144 | * Search for the scheduler by sched_name | ||
145 | */ | ||
146 | sched = ip_vs_sched_getbyname(sched_name); | ||
147 | |||
148 | /* | ||
149 | * If scheduler not found, load the module and search again | ||
150 | */ | ||
151 | if (sched == NULL) { | ||
152 | request_module("ip_vs_%s", sched_name); | ||
153 | sched = ip_vs_sched_getbyname(sched_name); | ||
154 | } | ||
155 | |||
156 | return sched; | ||
157 | } | ||
158 | |||
159 | void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler) | ||
160 | { | ||
161 | if (scheduler->module) | ||
162 | module_put(scheduler->module); | ||
163 | } | ||
164 | |||
165 | |||
166 | /* | ||
167 | * Register a scheduler in the scheduler list | ||
168 | */ | ||
169 | int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler) | ||
170 | { | ||
171 | struct ip_vs_scheduler *sched; | ||
172 | |||
173 | if (!scheduler) { | ||
174 | IP_VS_ERR("register_ip_vs_scheduler(): NULL arg\n"); | ||
175 | return -EINVAL; | ||
176 | } | ||
177 | |||
178 | if (!scheduler->name) { | ||
179 | IP_VS_ERR("register_ip_vs_scheduler(): NULL scheduler_name\n"); | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | |||
183 | /* increase the module use count */ | ||
184 | ip_vs_use_count_inc(); | ||
185 | |||
186 | /* | ||
187 | * Make sure that the scheduler with this name doesn't exist | ||
188 | * in the scheduler list. | ||
189 | */ | ||
190 | sched = ip_vs_sched_getbyname(scheduler->name); | ||
191 | if (sched) { | ||
192 | ip_vs_scheduler_put(sched); | ||
193 | ip_vs_use_count_dec(); | ||
194 | IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler " | ||
195 | "already existed in the system\n", scheduler->name); | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | |||
199 | write_lock_bh(&__ip_vs_sched_lock); | ||
200 | |||
201 | if (scheduler->n_list.next != &scheduler->n_list) { | ||
202 | write_unlock_bh(&__ip_vs_sched_lock); | ||
203 | ip_vs_use_count_dec(); | ||
204 | IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler " | ||
205 | "already linked\n", scheduler->name); | ||
206 | return -EINVAL; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * Add it into the d-linked scheduler list | ||
211 | */ | ||
212 | list_add(&scheduler->n_list, &ip_vs_schedulers); | ||
213 | write_unlock_bh(&__ip_vs_sched_lock); | ||
214 | |||
215 | IP_VS_INFO("[%s] scheduler registered.\n", scheduler->name); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | |||
221 | /* | ||
222 | * Unregister a scheduler from the scheduler list | ||
223 | */ | ||
224 | int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler) | ||
225 | { | ||
226 | if (!scheduler) { | ||
227 | IP_VS_ERR( "unregister_ip_vs_scheduler(): NULL arg\n"); | ||
228 | return -EINVAL; | ||
229 | } | ||
230 | |||
231 | write_lock_bh(&__ip_vs_sched_lock); | ||
232 | if (scheduler->n_list.next == &scheduler->n_list) { | ||
233 | write_unlock_bh(&__ip_vs_sched_lock); | ||
234 | IP_VS_ERR("unregister_ip_vs_scheduler(): [%s] scheduler " | ||
235 | "is not in the list. failed\n", scheduler->name); | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * Remove it from the d-linked scheduler list | ||
241 | */ | ||
242 | list_del(&scheduler->n_list); | ||
243 | write_unlock_bh(&__ip_vs_sched_lock); | ||
244 | |||
245 | /* decrease the module use count */ | ||
246 | ip_vs_use_count_dec(); | ||
247 | |||
248 | IP_VS_INFO("[%s] scheduler unregistered.\n", scheduler->name); | ||
249 | |||
250 | return 0; | ||
251 | } | ||