1 /*
2 * Copyright (c) 2008, XenSource Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of XenSource Inc. nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <sys/ioctl.h>
33 #include <signal.h>
34
35 #include "tapdisk-utils.h"
36 #include "tapdisk-server.h"
37 #include "tapdisk-driver.h"
38 #include "tapdisk-interface.h"
39
40 #define DBG(_level, _f, _a...) tlog_write(_level, _f, ##_a)
41 #define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
42
43 tapdisk_server_t server;
44
45 #define tapdisk_server_for_each_vbd(vbd, tmp) \
46 list_for_each_entry_safe(vbd, tmp, &server.vbds, next)
47
48 td_image_t *
tapdisk_server_get_shared_image(td_image_t * image)49 tapdisk_server_get_shared_image(td_image_t *image)
50 {
51 td_vbd_t *vbd, *tmpv;
52 td_image_t *img, *tmpi;
53
54 if (!td_flag_test(image->flags, TD_OPEN_SHAREABLE))
55 return NULL;
56
57 tapdisk_server_for_each_vbd(vbd, tmpv)
58 tapdisk_vbd_for_each_image(vbd, img, tmpi)
59 if (img->type == image->type &&
60 !strcmp(img->name, image->name))
61 return img;
62
63 return NULL;
64 }
65
66 struct list_head *
tapdisk_server_get_all_vbds(void)67 tapdisk_server_get_all_vbds(void)
68 {
69 return &server.vbds;
70 }
71
72 td_vbd_t *
tapdisk_server_get_vbd(uint16_t uuid)73 tapdisk_server_get_vbd(uint16_t uuid)
74 {
75 td_vbd_t *vbd, *tmp;
76
77 tapdisk_server_for_each_vbd(vbd, tmp)
78 if (vbd->uuid == uuid)
79 return vbd;
80
81 return NULL;
82 }
83
84 void
tapdisk_server_add_vbd(td_vbd_t * vbd)85 tapdisk_server_add_vbd(td_vbd_t *vbd)
86 {
87 list_add_tail(&vbd->next, &server.vbds);
88 }
89
90 void
tapdisk_server_remove_vbd(td_vbd_t * vbd)91 tapdisk_server_remove_vbd(td_vbd_t *vbd)
92 {
93 list_del(&vbd->next);
94 INIT_LIST_HEAD(&vbd->next);
95 tapdisk_server_check_state();
96 }
97
98 void
tapdisk_server_queue_tiocb(struct tiocb * tiocb)99 tapdisk_server_queue_tiocb(struct tiocb *tiocb)
100 {
101 tapdisk_queue_tiocb(&server.aio_queue, tiocb);
102 }
103
104 void
tapdisk_server_debug(void)105 tapdisk_server_debug(void)
106 {
107 td_vbd_t *vbd, *tmp;
108
109 tapdisk_debug_queue(&server.aio_queue);
110
111 tapdisk_server_for_each_vbd(vbd, tmp)
112 tapdisk_vbd_debug(vbd);
113
114 tlog_flush();
115 }
116
117 void
tapdisk_server_check_state(void)118 tapdisk_server_check_state(void)
119 {
120 if (list_empty(&server.vbds))
121 server.run = 0;
122 }
123
124 event_id_t
tapdisk_server_register_event(char mode,int fd,int timeout,event_cb_t cb,void * data)125 tapdisk_server_register_event(char mode, int fd,
126 int timeout, event_cb_t cb, void *data)
127 {
128 return scheduler_register_event(&server.scheduler,
129 mode, fd, timeout, cb, data);
130 }
131
132 void
tapdisk_server_unregister_event(event_id_t event)133 tapdisk_server_unregister_event(event_id_t event)
134 {
135 return scheduler_unregister_event(&server.scheduler, event);
136 }
137
138 void
tapdisk_server_set_max_timeout(int seconds)139 tapdisk_server_set_max_timeout(int seconds)
140 {
141 scheduler_set_max_timeout(&server.scheduler, seconds);
142 }
143
144 static void
tapdisk_server_assert_locks(void)145 tapdisk_server_assert_locks(void)
146 {
147
148 }
149
150 static void
tapdisk_server_set_retry_timeout(void)151 tapdisk_server_set_retry_timeout(void)
152 {
153 td_vbd_t *vbd, *tmp;
154
155 tapdisk_server_for_each_vbd(vbd, tmp)
156 if (tapdisk_vbd_retry_needed(vbd)) {
157 tapdisk_server_set_max_timeout(TD_VBD_RETRY_INTERVAL);
158 return;
159 }
160 }
161
162 static void
tapdisk_server_check_progress(void)163 tapdisk_server_check_progress(void)
164 {
165 struct timeval now;
166 td_vbd_t *vbd, *tmp;
167
168 gettimeofday(&now, NULL);
169
170 tapdisk_server_for_each_vbd(vbd, tmp)
171 tapdisk_vbd_check_progress(vbd);
172 }
173
174 static void
tapdisk_server_submit_tiocbs(void)175 tapdisk_server_submit_tiocbs(void)
176 {
177 tapdisk_submit_all_tiocbs(&server.aio_queue);
178 }
179
180 static void
tapdisk_server_kick_responses(void)181 tapdisk_server_kick_responses(void)
182 {
183 int n;
184 td_vbd_t *vbd, *tmp;
185
186 tapdisk_server_for_each_vbd(vbd, tmp)
187 tapdisk_vbd_kick(vbd);
188 }
189
190 static void
tapdisk_server_check_vbds(void)191 tapdisk_server_check_vbds(void)
192 {
193 td_vbd_t *vbd, *tmp;
194
195 tapdisk_server_for_each_vbd(vbd, tmp)
196 tapdisk_vbd_check_state(vbd);
197 }
198
199 static void
tapdisk_server_stop_vbds(void)200 tapdisk_server_stop_vbds(void)
201 {
202 td_vbd_t *vbd, *tmp;
203
204 tapdisk_server_for_each_vbd(vbd, tmp)
205 tapdisk_vbd_kill_queue(vbd);
206 }
207
208 static int
tapdisk_server_init_aio(void)209 tapdisk_server_init_aio(void)
210 {
211 return tapdisk_init_queue(&server.aio_queue, TAPDISK_TIOCBS,
212 TIO_DRV_LIO, NULL);
213 }
214
215 static void
tapdisk_server_close_aio(void)216 tapdisk_server_close_aio(void)
217 {
218 tapdisk_free_queue(&server.aio_queue);
219 }
220
221 static void
tapdisk_server_close(void)222 tapdisk_server_close(void)
223 {
224 tapdisk_server_close_aio();
225 }
226
227 void
tapdisk_server_iterate(void)228 tapdisk_server_iterate(void)
229 {
230 int ret;
231
232 tapdisk_server_assert_locks();
233 tapdisk_server_set_retry_timeout();
234 tapdisk_server_check_progress();
235
236 ret = scheduler_wait_for_events(&server.scheduler);
237 if (ret < 0)
238 DBG(TLOG_WARN, "server wait returned %d\n", ret);
239
240 tapdisk_server_check_vbds();
241 tapdisk_server_submit_tiocbs();
242 tapdisk_server_kick_responses();
243 }
244
245 static void
__tapdisk_server_run(void)246 __tapdisk_server_run(void)
247 {
248 while (server.run)
249 tapdisk_server_iterate();
250 }
251
252 static void
tapdisk_server_signal_handler(int signal)253 tapdisk_server_signal_handler(int signal)
254 {
255 td_vbd_t *vbd, *tmp;
256 static int xfsz_error_sent = 0;
257
258 switch (signal) {
259 case SIGBUS:
260 case SIGINT:
261 tapdisk_server_for_each_vbd(vbd, tmp)
262 tapdisk_vbd_close(vbd);
263 break;
264
265 case SIGXFSZ:
266 ERR(EFBIG, "received SIGXFSZ");
267 tapdisk_server_stop_vbds();
268 if (xfsz_error_sent)
269 break;
270
271 xfsz_error_sent = 1;
272 break;
273
274 case SIGUSR1:
275 tapdisk_server_debug();
276 break;
277 }
278 }
279
280 int
tapdisk_server_init(void)281 tapdisk_server_init(void)
282 {
283 memset(&server, 0, sizeof(server));
284 INIT_LIST_HEAD(&server.vbds);
285
286 scheduler_initialize(&server.scheduler);
287
288 return 0;
289 }
290
291 int
tapdisk_server_complete(void)292 tapdisk_server_complete(void)
293 {
294 int err;
295
296 err = tapdisk_server_init_aio();
297 if (err)
298 goto fail;
299
300 server.run = 1;
301
302 return 0;
303
304 fail:
305 tapdisk_server_close_aio();
306 return err;
307 }
308
309 int
tapdisk_server_initialize(void)310 tapdisk_server_initialize(void)
311 {
312 int err;
313
314 tapdisk_server_init();
315
316 err = tapdisk_server_complete();
317 if (err)
318 goto fail;
319
320 return 0;
321
322 fail:
323 tapdisk_server_close();
324 return err;
325 }
326
327 int
tapdisk_server_run()328 tapdisk_server_run()
329 {
330 int err;
331
332 err = tapdisk_set_resource_limits();
333 if (err)
334 return err;
335
336 signal(SIGBUS, tapdisk_server_signal_handler);
337 signal(SIGINT, tapdisk_server_signal_handler);
338 signal(SIGUSR1, tapdisk_server_signal_handler);
339 signal(SIGXFSZ, tapdisk_server_signal_handler);
340
341 __tapdisk_server_run();
342 tapdisk_server_close();
343
344 return 0;
345 }
346