ia64/xen-unstable

view tools/blktap2/drivers/tapdisk-client.c @ 19817:b7f73a7f3078

blktap2: portability fixes for NetBSD

- Use standard off_t and lseek() instead of non-portable off64_t and
lseek64()
- Use uuid API as documented in DCE 1.1 RPC specification
- Add NetBSD implementation for blk_getimagesize() and
blk_getsectorsize()
- Use blk_getimagesize() and blk_getsectorsize()
- Fix uuid header check

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 23 17:24:14 2009 +0100 (2009-06-23)
parents 1c627434605e
children
line source
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 */
29 /* client harness for tapdisk log */
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <sys/mman.h>
39 #include <sys/socket.h>
40 #include <sys/types.h>
41 #include <sys/un.h>
43 #include "log.h"
45 #define BDPRINTF(_f, _a...) fprintf (stderr, "log: " _f "\n", ## _a)
47 #define BWPRINTF(_f, _a...) fprintf (stderr, "log: " _f "\n", ## _a)
49 struct writelog {
50 char* shmpath;
51 uint32_t shmsize;
52 void* shm;
54 /* next unprocessed item in the writelog */
55 void* cur;
56 unsigned int inflight;
58 /* pointer to start and end of free data space for requests */
59 void* dhd;
60 void* dtl;
62 log_sring_t* sring;
63 log_front_ring_t fring;
64 };
66 /* bytes free on the data ring */
67 static inline unsigned int dring_avail(struct writelog* wl)
68 {
69 /* one byte reserved to distinguish empty from full */
70 if (wl->dhd == wl->dtl)
71 return sdataend(wl->shm) - sdatastart(wl->shm) - 1;
73 if (wl->dhd < wl->dtl)
74 return wl->dtl - wl->dhd - 1;
76 return (sdataend(wl->shm) - wl->dhd) + (wl->dtl - sdatastart(wl->shm)) - 1;
77 }
79 /* advance ring pointer by len bytes */
80 static inline void* dring_advance(struct writelog* wl, void* start, size_t len)
81 {
82 void* next;
83 int dsz = sdataend(wl->shm) - sdatastart(wl->shm);
85 next = start + (len % dsz);
86 if (next > sdataend(wl->shm))
87 next -= dsz;
89 return next;
90 }
92 static void usage(void)
93 {
94 fprintf(stderr, "usage: tapdisk-client <sock>\n");
95 }
97 /* returns socket file descriptor */
98 static int tdctl_open(const char* sockpath)
99 {
100 struct sockaddr_un saddr;
101 int fd;
103 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
104 BWPRINTF("error creating socket: %s", strerror(errno));
105 return -1;
106 }
108 memset(&saddr, 0, sizeof(saddr));
109 saddr.sun_family = AF_UNIX;
110 memcpy(saddr.sun_path, sockpath, strlen(sockpath));
112 if (connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
113 BWPRINTF("error connecting to socket %s: %s", sockpath, strerror(errno));
114 close(fd);
115 return -1;
116 }
118 return fd;
119 }
121 static int ctl_talk(int fd, struct log_ctlmsg* msg, char* rsp, int rsplen)
122 {
123 int rc;
125 if ((rc = write(fd, msg, sizeof(*msg))) < 0) {
126 BWPRINTF("error sending ctl request: %s", strerror(errno));
127 return -1;
128 } else if (rc < sizeof(*msg)) {
129 BWPRINTF("short ctl write (%d/%zd bytes)", rc, sizeof(*msg));
130 return -1;
131 }
133 if (!rsplen)
134 return 0;
136 if ((rc = read(fd, rsp, rsplen)) < 0) {
137 BWPRINTF("error reading ctl response: %s", strerror(errno));
138 return -1;
139 } else if (rc < rsplen) {
140 BWPRINTF("short ctl read (%d/%d bytes)", rc, rsplen);
141 return -1;
142 }
144 return 0;
145 }
147 static int ctl_get_shmem(int fd, struct writelog* wl)
148 {
149 struct log_ctlmsg req;
150 char rsp[CTLRSPLEN_SHMP + 1];
151 int rc;
153 memset(&req, 0, sizeof(req));
154 memset(rsp, 0, sizeof(rsp));
156 memcpy(req.msg, LOGCMD_SHMP, 4);
157 if ((rc = ctl_talk(fd, &req, rsp, CTLRSPLEN_SHMP)) < 0) {
158 BWPRINTF("error getting shared memory parameters");
159 return -1;
160 }
162 memcpy(&wl->shmsize, rsp, sizeof(wl->shmsize));
163 wl->shmpath = strdup(rsp + sizeof(wl->shmsize));
165 BDPRINTF("shared memory parameters: size: %u, path: %s",
166 wl->shmsize, wl->shmpath);
168 return 0;
169 }
171 static void ctlmsg_init(struct log_ctlmsg* msg, const char* cmd)
172 {
173 memset(msg, 0, sizeof(*msg));
174 memcpy(msg->msg, cmd, 4);
175 }
177 static int ctl_get_writes(int fd)
178 {
179 struct log_ctlmsg req;
180 char rsp[CTLRSPLEN_GET];
181 int rc;
183 ctlmsg_init(&req, LOGCMD_GET);
185 if ((rc = ctl_talk(fd, &req, rsp, CTLRSPLEN_GET)) < 0) {
186 BWPRINTF("error getting writes");
187 return -1;
188 }
190 return 0;
191 }
193 static int ctl_peek_writes(int fd)
194 {
195 struct log_ctlmsg req;
196 char rsp[CTLRSPLEN_PEEK];
197 int rc;
199 ctlmsg_init(&req, LOGCMD_PEEK);
201 if ((rc = ctl_talk(fd, &req, rsp, CTLRSPLEN_PEEK)) < 0) {
202 BWPRINTF("error peeking writes");
203 return -1;
204 }
206 return 0;
207 }
209 /* submit pending requests */
210 static int ctl_kick(int fd)
211 {
212 struct log_ctlmsg req;
213 int rc;
215 ctlmsg_init(&req, LOGCMD_KICK);
217 if ((rc = ctl_talk(fd, &req, NULL, 0)) < 0) {
218 BWPRINTF("error kicking ring");
219 return -1;
220 }
222 return 0;
223 }
225 static int ctl_clear_writes(int fd)
226 {
227 struct log_ctlmsg req;
228 char rsp[CTLRSPLEN_CLEAR];
229 int rc;
231 ctlmsg_init(&req, LOGCMD_CLEAR);
233 if ((rc = ctl_talk(fd, &req, rsp, CTLRSPLEN_CLEAR)) < 0) {
234 BWPRINTF("error clearing writes");
235 return -1;
236 }
238 return 0;
239 }
241 static int writelog_map(struct writelog* wl)
242 {
243 int fd;
244 void* shm;
246 if ((fd = shm_open(wl->shmpath, O_RDWR, 0750)) < 0) {
247 BWPRINTF("could not open shared memory at %s: %s", wl->shmpath,
248 strerror(errno));
249 return -1;
250 }
252 wl->shm = mmap(NULL, wl->shmsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
253 close(fd);
254 if (wl->shm == MAP_FAILED) {
255 BWPRINTF("could not mmap write log shm: %s", strerror(errno));
256 return -1;
257 }
258 wl->cur = wl->shm;
259 wl->inflight = 0;
260 wl->dhd = wl->dtl = sdatastart(wl->shm);
262 BDPRINTF("shm cookie: 0x%x, data size: %u", *((uint32_t*)wl->shm),
263 dring_avail(wl));
265 wl->sring = sringstart(wl->shm);
266 /* need some thought about what to do on reconnect */
267 FRONT_RING_INIT(&wl->fring, wl->sring, SRINGSIZE);
269 return 0;
270 }
272 static int writelog_dump(struct writelog* wl)
273 {
274 struct disk_range* range = wl->shm;
276 for (range = wl->shm; (void*)range < bmend(wl->shm); range++) {
277 if (!range->count)
278 break;
280 BDPRINTF("dirty extent: %"PRIu64":%u",
281 range->sector, range->count);
282 }
284 return 0;
285 }
287 /* walk dirty map and enqueue read requests.
288 * returns: 0 when entire bitmap has been enqueued,
289 * 1 when the ring is full
290 * -1 on error
291 */
292 static int writelog_enqueue_requests(struct writelog* wl)
293 {
294 struct disk_range* range = wl->shm;
295 log_request_t* req;
297 for (range = wl->cur; (void*)range < bmend(wl->shm); range++) {
298 if (!range->count)
299 break;
301 if (RING_FULL(&wl->fring))
302 break;
304 /* insert range into request stream */
305 /* 1. get next request slot from ring */
306 /* 2. ensure enough shm space is available */
308 BDPRINTF("enqueueing dirty extent: %"PRIu64":%u (ring space: %d/%d)",
309 range->sector, range->count, RING_FREE_REQUESTS(&wl->fring),
310 RING_SIZE(&wl->fring));
312 req = RING_GET_REQUEST(&wl->fring, wl->fring.req_prod_pvt);
314 req->sector = range->sector;
315 req->count = range->count;
316 /* ... */
317 req->offset = 0;
319 wl->fring.req_prod_pvt++;
320 wl->inflight++;
321 }
323 wl->cur = range;
325 if (range->count)
326 return 1;
328 return 0;
329 }
331 static int writelog_dequeue_responses(struct writelog* wl)
332 {
333 RING_IDX rstart, rend;
334 log_response_t rsp;
336 rstart = wl->fring.rsp_cons;
337 rend = wl->sring->rsp_prod;
339 BDPRINTF("ring kicked (start = %u, end = %u)", rstart, rend);
341 while (rstart != rend) {
342 memcpy(&rsp, RING_GET_RESPONSE(&wl->fring, rstart), sizeof(rsp));
343 BDPRINTF("ctl: read response %"PRIu64":%u", rsp.sector, rsp.count);
344 wl->fring.rsp_cons = ++rstart;
345 wl->inflight--;
346 }
348 return 0;
349 }
351 static int writelog_free(struct writelog* wl)
352 {
353 if (wl->shmpath) {
354 free(wl->shmpath);
355 wl->shmpath = NULL;
356 }
357 if (wl->shm) {
358 munmap(wl->shm, wl->shmsize);
359 wl->shm = NULL;
360 }
362 return 0;
363 }
365 int get_writes(struct writelog* wl, int fd, int peek)
366 {
367 int rc;
369 if (peek)
370 rc = ctl_peek_writes(fd);
371 else
372 rc = ctl_get_writes(fd);
374 if (rc < 0)
375 return rc;
377 wl->cur = wl->shm;
379 return 0;
380 }
382 int await_responses(struct writelog* wl, int fd)
383 {
384 struct log_ctlmsg msg;
385 int rc;
387 /* sit on socket waiting for kick */
388 if ((rc = read(fd, &msg, sizeof(msg))) < 0) {
389 BWPRINTF("error reading from control socket: %s", strerror(errno));
390 return -1;
391 } else if (!rc) {
392 BWPRINTF("EOF on control socket");
393 return -1;
394 } else if (rc < sizeof(msg)) {
395 BWPRINTF("short reply (%d/%d bytes)", rc, (int) sizeof(msg));
396 return -1;
397 }
399 if (strncmp(msg.msg, LOGCMD_KICK, 4)) {
400 BWPRINTF("Unknown message received: %.4s", msg.msg);
401 return -1;
402 }
404 if (writelog_dequeue_responses(wl) < 0)
405 return -1;
407 return 0;
408 }
410 /* read_loop:
411 * 1. extract dirty bitmap
412 * 2. feed as much as possible onto ring
413 * 3. kick
414 * 4. as responses come back, feed more of the dirty bitmap
415 * into the ring
416 * 5. when entire bitmap has been queued, go to 1?
417 */
418 int read_loop(struct writelog* wl, int fd)
419 {
420 int rc;
422 if (get_writes(wl, fd, 1) < 0)
423 return -1;
424 writelog_dump(wl);
426 do {
427 rc = writelog_enqueue_requests(wl);
429 if (RING_FREE_REQUESTS(&wl->fring) < RING_SIZE(&wl->fring))
430 RING_PUSH_REQUESTS(&wl->fring);
431 if (ctl_kick(fd) < 0)
432 return -1;
434 /* collect responses */
435 if (wl->inflight && await_responses(wl, fd) < 0)
436 return -1;
437 } while (rc > 0);
439 return rc;
440 }
442 int main(int argc, char* argv[])
443 {
444 int fd;
445 struct writelog wl;
446 char cmd;
448 if (argc < 2) {
449 usage();
450 return 1;
451 }
453 if (argc < 3)
454 cmd = 'p';
455 else
456 cmd = argv[2][0];
458 fd = tdctl_open(argv[1]);
460 if (ctl_get_shmem(fd, &wl) < 0)
461 return 1;
463 if (writelog_map(&wl) < 0) {
464 BWPRINTF("Error mapping write log: %s", strerror(errno));
465 return 1;
466 }
468 switch (cmd) {
469 case 'p':
470 if (get_writes(&wl, fd, 1) < 0)
471 return 1;
472 writelog_dump(&wl);
473 break;
474 case 'c':
475 if (ctl_clear_writes(fd) < 0)
476 return 1;
477 break;
478 case 'g':
479 if (get_writes(&wl, fd, 0) < 0)
480 return 1;
481 writelog_dump(&wl);
482 break;
483 case 'r':
484 if (read_loop(&wl, fd) < 0)
485 return 1;
486 break;
487 default:
488 usage();
489 return 1;
490 }
492 writelog_free(&wl);
493 close(fd);
495 return 0;
496 }