debuggers.hg

view tools/blktap2/daemon/tapdisk-daemon.c @ 19706:56d00bbc21e2

blktap2: fix tapdisk-channel.c

This patch fixes the following error.
cc1: warnings being treated as errors
In file included from usr/include/sys/resource.h:25,
from tapdisk-daemon.c:559:
usr/include/bits/resource.h: In function 'main':
usr/include/bits/resource.h:33: warning: ISO C90 forbids mixed
declarations and code

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Keir Fraser <keir.fraser@citrix.com>
date Thu May 28 10:03:29 2009 +0100 (2009-05-28)
parents 1c627434605e
children
line source
1 /* Copyright (c) 2008, XenSource Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of XenSource Inc. nor the names of its contributors
12 * may be used to endorse or promote products derived from this software
13 * without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <stdio.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/ioctl.h>
34 #include <sys/resource.h>
36 #include <xs.h>
37 #include "disktypes.h"
38 #include "tapdisk-dispatch.h"
40 #define TAPDISK_DAEMON_DOMID_WATCH "domid-watch"
41 #define TAPDISK_DAEMON_PIDFILE "/var/run/blktapctrl.pid"
43 typedef struct tapdisk_daemon {
44 char *node;
45 int blktap_fd;
46 uint16_t cookie;
48 struct xs_handle *xsh;
49 struct list_head channels;
50 struct xenbus_watch watch;
51 } tapdisk_daemon_t;
53 static tapdisk_daemon_t tapdisk_daemon;
55 #define tapdisk_daemon_for_each_channel(c, tmp) \
56 list_for_each_entry_safe(c, tmp, &tapdisk_daemon.channels, list)
58 #define MAX(a, b) ((a) >= (b) ? (a) : (b))
60 static void
61 tapdisk_daemon_print_drivers(void)
62 {
63 int i, size;
65 DPRINTF("blktap-daemon: v1.0.2\n");
67 size = sizeof(dtypes) / sizeof(disk_info_t *);
68 for (i = 0; i < size; i++)
69 DPRINTF("Found driver: [%s]\n", dtypes[i]->name);
70 }
72 static int
73 tapdisk_daemon_write_pidfile(long pid)
74 {
75 char buf[100];
76 int len, fd, flags, err;
78 fd = open(TAPDISK_DAEMON_PIDFILE, O_RDWR | O_CREAT, 0600);
79 if (fd == -1) {
80 EPRINTF("Opening pid file failed (%d)\n", errno);
81 return -errno;
82 }
84 /* We exit silently if daemon already running */
85 err = lockf(fd, F_TLOCK, 0);
86 if (err == -1)
87 exit(0);
89 /* Set FD_CLOEXEC, so that tapdisk doesn't get this file descriptor */
90 flags = fcntl(fd, F_GETFD);
91 if (flags == -1) {
92 EPRINTF("F_GETFD failed (%d)\n", errno);
93 return -errno;
94 }
96 flags |= FD_CLOEXEC;
97 err = fcntl(fd, F_SETFD, flags);
98 if (err == -1) {
99 EPRINTF("F_SETFD failed (%d)\n", errno);
100 return -errno;
101 }
103 len = sprintf(buf, "%ld\n", pid);
104 err = write(fd, buf, len);
105 if (err != len) {
106 EPRINTF("Writing pid file failed (%d)\n", errno);
107 return -errno;
108 }
110 return 0;
111 }
113 static int
114 tapdisk_daemon_init(void)
115 {
116 char *devname;
117 int i, err, blktap_major;
119 memset(&tapdisk_daemon, 0, sizeof(tapdisk_daemon_t));
121 err = asprintf(&devname, "%s/%s0", BLKTAP_DEV_DIR, BLKTAP_DEV_NAME);
122 if (err == -1) {
123 devname = NULL;
124 err = -ENOMEM;
125 goto fail;
126 }
128 err = xc_find_device_number("blktap0");
129 if (err < 0)
130 goto fail;
132 blktap_major = major(err);
133 err = make_blktap_device(devname, blktap_major, 0, S_IFCHR | 0600);
134 if (err)
135 goto fail;
137 tapdisk_daemon.blktap_fd = open(devname, O_RDWR);
138 if (tapdisk_daemon.blktap_fd == -1) {
139 err = -errno;
140 EPRINTF("blktap0 open failed\n");
141 goto fail;
142 }
144 for (i = 0; i < 2; i++) {
145 tapdisk_daemon.xsh = xs_daemon_open();
146 if (!tapdisk_daemon.xsh) {
147 EPRINTF("xs_daemon_open failed -- is xenstore running?\n");
148 sleep(2);
149 } else
150 break;
151 }
153 if (!tapdisk_daemon.xsh) {
154 err = -ENOSYS;
155 goto fail;
156 }
158 INIT_LIST_HEAD(&tapdisk_daemon.channels);
160 free(devname);
161 return 0;
163 fail:
164 if (tapdisk_daemon.blktap_fd > 0)
165 close(tapdisk_daemon.blktap_fd);
166 free(devname);
167 memset(&tapdisk_daemon, 0, sizeof(tapdisk_daemon_t));
168 EPRINTF("%s: %d\n", __func__, err);
170 return err;
171 }
173 static int
174 tapdisk_daemon_set_node(void)
175 {
176 int err;
177 char *domid;
179 domid = get_dom_domid(tapdisk_daemon.xsh);
180 if (!domid)
181 return -EAGAIN;
183 err = asprintf(&tapdisk_daemon.node,
184 "/local/domain/%s/backend/tap", domid);
185 if (err == -1) {
186 tapdisk_daemon.node = NULL;
187 err = -ENOMEM;
188 goto out;
189 }
191 err = 0;
193 out:
194 free(domid);
195 return err;
196 }
198 static int
199 tapdisk_daemon_get_domid(void)
200 {
201 int err;
202 unsigned int num;
203 char **res, *node, *token, *domid;
205 res = xs_read_watch(tapdisk_daemon.xsh, &num);
206 if (!res)
207 return -EAGAIN;
209 err = 0;
210 node = res[XS_WATCH_PATH];
211 token = res[XS_WATCH_TOKEN];
213 if (strcmp(token, TAPDISK_DAEMON_DOMID_WATCH)) {
214 err = -EINVAL;
215 goto out;
216 }
218 err = tapdisk_daemon_set_node();
220 out:
221 free(res);
222 return err;
223 }
225 static int
226 tapdisk_daemon_wait_for_domid(void)
227 {
228 int err;
229 char *domid;
230 fd_set readfds;
232 err = tapdisk_daemon_set_node();
233 if (!err)
234 return 0;
236 if (!xs_watch(tapdisk_daemon.xsh, "/local/domain",
237 TAPDISK_DAEMON_DOMID_WATCH)) {
238 EPRINTF("unable to set domain id watch\n");
239 return -EINVAL;
240 }
242 do {
243 FD_ZERO(&readfds);
244 FD_SET(xs_fileno(tapdisk_daemon.xsh), &readfds);
246 select(xs_fileno(tapdisk_daemon.xsh) + 1,
247 &readfds, NULL, NULL, NULL);
249 if (FD_ISSET(xs_fileno(tapdisk_daemon.xsh), &readfds))
250 err = tapdisk_daemon_get_domid();
251 else
252 err = -EAGAIN;
253 } while (err == -EAGAIN);
255 xs_unwatch(tapdisk_daemon.xsh,
256 "/local/domain", TAPDISK_DAEMON_DOMID_WATCH);
257 return err;
258 }
260 static inline int
261 tapdisk_daemon_new_vbd_event(const char *node)
262 {
263 return (!strcmp(node, "start-tapdisk"));
264 }
266 static int
267 tapdisk_daemon_write_uuid(char *path, uint32_t uuid)
268 {
269 int err;
270 char *cpath, uuid_str[12];
272 snprintf(uuid_str, sizeof(uuid_str), "%u", uuid);
274 err = asprintf(&cpath, "%s/tapdisk-uuid", path);
275 if (err == -1)
276 return -ENOMEM;
278 err = xs_write(tapdisk_daemon.xsh, XBT_NULL,
279 cpath, uuid_str, strlen(uuid_str));
280 free(cpath);
282 return (err ? 0 : -errno);
283 }
285 static void
286 tapdisk_daemon_probe(struct xs_handle *xsh,
287 struct xenbus_watch *watch, const char *path)
288 {
289 char *cpath;
290 int len, err;
291 uint32_t cookie;
292 const char *node;
293 tapdisk_channel_t *channel;
295 len = strsep_len(path, '/', 7);
296 if (len < 0)
297 return;
299 node = path + len + 1;
301 if (!tapdisk_daemon_new_vbd_event(node))
302 return;
304 if (!xs_exists(xsh, path))
305 return;
307 cpath = strdup(path);
308 if (!cpath) {
309 EPRINTF("failed to allocate control path for %s\n", path);
310 return;
311 }
312 cpath[len] = '\0';
314 cookie = tapdisk_daemon.cookie++;
315 err = tapdisk_daemon_write_uuid(cpath, cookie);
316 if (err)
317 goto out;
319 DPRINTF("%s: got watch on %s, uuid = %u\n", __func__, path, cookie);
321 err = tapdisk_channel_open(&channel, cpath,
322 tapdisk_daemon.xsh,
323 tapdisk_daemon.blktap_fd,
324 cookie);
325 if (!err)
326 list_add(&channel->list, &tapdisk_daemon.channels);
327 else
328 EPRINTF("failed to open tapdisk channel for %s: %d\n",
329 path, err);
331 out:
332 free(cpath);
333 }
335 static int
336 tapdisk_daemon_start(void)
337 {
338 int err;
340 err = tapdisk_daemon_wait_for_domid();
341 if (err)
342 return err;
344 tapdisk_daemon.watch.node = tapdisk_daemon.node;
345 tapdisk_daemon.watch.callback = tapdisk_daemon_probe;
347 err = register_xenbus_watch(tapdisk_daemon.xsh, &tapdisk_daemon.watch);
348 if (err)
349 goto fail;
351 ioctl(tapdisk_daemon.blktap_fd,
352 BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_INTERPOSE);
353 ioctl(tapdisk_daemon.blktap_fd, BLKTAP_IOCTL_SENDPID, getpid());
355 return 0;
357 fail:
358 free(tapdisk_daemon.node);
359 tapdisk_daemon.node = NULL;
360 tapdisk_daemon.watch.node = NULL;
361 EPRINTF("%s: %d\n", __func__, err);
362 return err;
363 }
365 static int
366 tapdisk_daemon_stop(void)
367 {
368 unregister_xenbus_watch(tapdisk_daemon.xsh, &tapdisk_daemon.watch);
370 ioctl(tapdisk_daemon.blktap_fd,
371 BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_PASSTHROUGH);
372 close(tapdisk_daemon.blktap_fd);
374 return 0;
375 }
377 static void
378 tapdisk_daemon_free(void)
379 {
380 free(tapdisk_daemon.node);
381 xs_daemon_close(tapdisk_daemon.xsh);
382 memset(&tapdisk_daemon, 0, sizeof(tapdisk_daemon_t));
383 }
385 static int
386 tapdisk_daemon_read_message(int fd, tapdisk_message_t *message, int timeout)
387 {
388 fd_set readfds;
389 struct timeval tv;
390 int ret, len, offset;
392 tv.tv_sec = timeout;
393 tv.tv_usec = 0;
394 offset = 0;
395 len = sizeof(tapdisk_message_t);
397 memset(message, 0, sizeof(tapdisk_message_t));
399 while (offset < len) {
400 FD_ZERO(&readfds);
401 FD_SET(fd, &readfds);
403 /* we don't bother reinitializing tv. at worst, it will wait a
404 * bit more time than expected. */
406 ret = select(fd + 1, &readfds, NULL, NULL, &tv);
407 if (ret == -1)
408 break;
409 else if (FD_ISSET(fd, &readfds)) {
410 ret = read(fd, message + offset, len - offset);
411 if (ret <= 0)
412 break;
413 offset += ret;
414 } else
415 break;
416 }
418 return (offset == len ? 0 : -EIO);
419 }
421 static int
422 tapdisk_daemon_receive_message(int fd)
423 {
424 int err;
425 tapdisk_message_t m;
426 tapdisk_channel_t *c, *tmp;
428 err = tapdisk_daemon_read_message(fd, &m, 2);
429 if (err) {
430 EPRINTF("failed reading message on %d: %d\n", fd, err);
431 return err;
432 }
434 tapdisk_daemon_for_each_channel(c, tmp)
435 if (c->cookie == m.cookie && c->read_fd == fd) {
436 DPRINTF("got '%s' message from %d:%d\n",
437 tapdisk_message_name(m.type),
438 c->channel_id, c->cookie);
440 return tapdisk_channel_receive_message(c, &m);
441 }
443 EPRINTF("unrecognized message on %d: '%s' (uuid = %u)\n",
444 fd, tapdisk_message_name(m.type), m.cookie);
446 return -EINVAL;
447 }
449 static int
450 tapdisk_daemon_set_fds(fd_set *readfds)
451 {
452 int max, fd;
453 tapdisk_channel_t *channel, *tmp;
455 max = xs_fileno(tapdisk_daemon.xsh);
457 FD_ZERO(readfds);
458 FD_SET(max, readfds);
460 tapdisk_daemon_for_each_channel(channel, tmp) {
461 fd = channel->read_fd;
462 max = MAX(fd, max);
463 FD_SET(fd, readfds);
464 }
466 return max;
467 }
469 static int
470 tapdisk_daemon_check_fds(fd_set *readfds)
471 {
472 int err;
473 tapdisk_channel_t *channel, *tmp;
475 if (FD_ISSET(xs_fileno(tapdisk_daemon.xsh), readfds))
476 xs_fire_next_watch(tapdisk_daemon.xsh);
478 tapdisk_daemon_for_each_channel(channel, tmp)
479 if (FD_ISSET(channel->read_fd, readfds))
480 return tapdisk_daemon_receive_message(channel->read_fd);
482 return 0;
483 }
485 static int
486 tapdisk_daemon_run(void)
487 {
488 int err, max;
489 fd_set readfds;
491 while (1) {
492 max = tapdisk_daemon_set_fds(&readfds);
494 err = select(max + 1, &readfds, NULL, NULL, NULL);
495 if (err < 0)
496 continue;
498 err = tapdisk_daemon_check_fds(&readfds);
499 }
501 return err;
502 }
504 void
505 tapdisk_daemon_find_channel(tapdisk_channel_t *channel)
506 {
507 tapdisk_channel_t *c, *tmp;
509 channel->read_fd = 0;
510 channel->write_fd = 0;
511 channel->tapdisk_pid = 0;
513 /* do we want multiple vbds per tapdisk? */
514 if (!xs_exists(tapdisk_daemon.xsh, channel->share_tapdisk_str)) {
515 channel->shared = 0;
516 return;
517 }
519 channel->shared = 1;
521 /* check if we already have a process started */
522 tapdisk_daemon_for_each_channel(c, tmp)
523 if (c->drivertype == channel->drivertype) {
524 channel->write_fd = c->write_fd;
525 channel->read_fd = c->read_fd;
526 channel->channel_id = c->channel_id;
527 channel->tapdisk_pid = c->tapdisk_pid;
528 return;
529 }
530 }
532 void
533 tapdisk_daemon_close_channel(tapdisk_channel_t *channel)
534 {
535 tapdisk_channel_t *c, *tmp;
537 list_del(&channel->list);
539 tapdisk_daemon_for_each_channel(c, tmp)
540 if (c->channel_id == channel->channel_id)
541 return;
543 close(channel->read_fd);
544 close(channel->write_fd);
545 }
547 int
548 main(int argc, char *argv[])
549 {
550 int err;
551 char buf[128];
553 if (daemon(0, 0)) {
554 EPRINTF("daemon() failed (%d)\n", errno);
555 return -errno;
556 }
558 #define CORE_DUMP
559 #if defined(CORE_DUMP)
560 {
561 /* set up core-dumps*/
562 struct rlimit rlim;
563 rlim.rlim_cur = RLIM_INFINITY;
564 rlim.rlim_max = RLIM_INFINITY;
565 if (setrlimit(RLIMIT_CORE, &rlim) < 0)
566 EPRINTF("setrlimit failed: %d\n", errno);
567 }
568 #endif
570 snprintf(buf, sizeof(buf), "BLKTAP-DAEMON[%d]", getpid());
571 openlog(buf, LOG_CONS | LOG_ODELAY, LOG_DAEMON);
573 err = tapdisk_daemon_write_pidfile(getpid());
574 if (err)
575 goto out;
577 tapdisk_daemon_print_drivers();
579 err = tapdisk_daemon_init();
580 if (err)
581 goto out;
583 err = tapdisk_daemon_start();
584 if (err)
585 goto out;
587 tapdisk_daemon_run();
589 tapdisk_daemon_stop();
590 tapdisk_daemon_free();
592 err = 0;
594 out:
595 if (err)
596 EPRINTF("failed to start %s: %d\n", argv[0], err);
597 closelog();
598 return err;
599 }