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