debuggers.hg

view extras/mini-os/blkfront.c @ 20689:23bc248302df

mini-os: Fix memory leaks in blkfront, netfront, pcifront, etc.

The return value of Xenbus routines xenbus_transaction_start(),
xenbus_printf(), xenbus_transaction_end(), etc. is a pointer of error
message. This pointer should be passed to free() to release the
allocated memory when it is no longer needed.

Signed-off-by: Yu Zhiguo <yuzg@cn.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Dec 14 09:51:07 2009 +0000 (2009-12-14)
parents e10d641b413f
children b20f897d6010
line source
1 /* Minimal block driver for Mini-OS.
2 * Copyright (c) 2007-2008 Samuel Thibault.
3 * Based on netfront.c.
4 */
6 #include <stdint.h>
7 #include <mini-os/os.h>
8 #include <mini-os/xenbus.h>
9 #include <mini-os/events.h>
10 #include <errno.h>
11 #include <xen/io/blkif.h>
12 #include <xen/io/protocols.h>
13 #include <mini-os/gnttab.h>
14 #include <mini-os/xmalloc.h>
15 #include <time.h>
16 #include <mini-os/blkfront.h>
17 #include <mini-os/lib.h>
18 #include <fcntl.h>
20 #ifndef HAVE_LIBC
21 #define strtoul simple_strtoul
22 #endif
24 /* Note: we generally don't need to disable IRQs since we hardly do anything in
25 * the interrupt handler. */
27 /* Note: we really suppose non-preemptive threads. */
29 DECLARE_WAIT_QUEUE_HEAD(blkfront_queue);
34 #define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE)
35 #define GRANT_INVALID_REF 0
38 struct blk_buffer {
39 void* page;
40 grant_ref_t gref;
41 };
43 struct blkfront_dev {
44 domid_t dom;
46 struct blkif_front_ring ring;
47 grant_ref_t ring_ref;
48 evtchn_port_t evtchn;
49 blkif_vdev_t handle;
51 char *nodename;
52 char *backend;
53 struct blkfront_info info;
55 xenbus_event_queue events;
57 #ifdef HAVE_LIBC
58 int fd;
59 #endif
60 };
62 void blkfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
63 {
64 #ifdef HAVE_LIBC
65 struct blkfront_dev *dev = data;
66 int fd = dev->fd;
68 if (fd != -1)
69 files[fd].read = 1;
70 #endif
71 wake_up(&blkfront_queue);
72 }
74 static void free_blkfront(struct blkfront_dev *dev)
75 {
76 mask_evtchn(dev->evtchn);
78 free(dev->backend);
80 gnttab_end_access(dev->ring_ref);
81 free_page(dev->ring.sring);
83 unbind_evtchn(dev->evtchn);
85 free(dev->nodename);
86 free(dev);
87 }
89 struct blkfront_dev *init_blkfront(char *_nodename, struct blkfront_info *info)
90 {
91 xenbus_transaction_t xbt;
92 char* err;
93 char* message=NULL;
94 struct blkif_sring *s;
95 int retry=0;
96 char* msg = NULL;
97 char* c;
98 char* nodename = _nodename ? _nodename : "device/vbd/768";
100 struct blkfront_dev *dev;
102 char path[strlen(nodename) + 1 + 10 + 1];
104 printk("******************* BLKFRONT for %s **********\n\n\n", nodename);
106 dev = malloc(sizeof(*dev));
107 memset(dev, 0, sizeof(*dev));
108 dev->nodename = strdup(nodename);
109 #ifdef HAVE_LIBC
110 dev->fd = -1;
111 #endif
113 snprintf(path, sizeof(path), "%s/backend-id", nodename);
114 dev->dom = xenbus_read_integer(path);
115 evtchn_alloc_unbound(dev->dom, blkfront_handler, dev, &dev->evtchn);
117 s = (struct blkif_sring*) alloc_page();
118 memset(s,0,PAGE_SIZE);
121 SHARED_RING_INIT(s);
122 FRONT_RING_INIT(&dev->ring, s, PAGE_SIZE);
124 dev->ring_ref = gnttab_grant_access(dev->dom,virt_to_mfn(s),0);
126 dev->events = NULL;
128 again:
129 err = xenbus_transaction_start(&xbt);
130 if (err) {
131 printk("starting transaction\n");
132 free(err);
133 }
135 err = xenbus_printf(xbt, nodename, "ring-ref","%u",
136 dev->ring_ref);
137 if (err) {
138 message = "writing ring-ref";
139 goto abort_transaction;
140 }
141 err = xenbus_printf(xbt, nodename,
142 "event-channel", "%u", dev->evtchn);
143 if (err) {
144 message = "writing event-channel";
145 goto abort_transaction;
146 }
147 err = xenbus_printf(xbt, nodename,
148 "protocol", "%s", XEN_IO_PROTO_ABI_NATIVE);
149 if (err) {
150 message = "writing protocol";
151 goto abort_transaction;
152 }
154 snprintf(path, sizeof(path), "%s/state", nodename);
155 err = xenbus_switch_state(xbt, path, XenbusStateConnected);
156 if (err) {
157 message = "switching state";
158 goto abort_transaction;
159 }
162 err = xenbus_transaction_end(xbt, 0, &retry);
163 if (err) free(err);
164 if (retry) {
165 goto again;
166 printk("completing transaction\n");
167 }
169 goto done;
171 abort_transaction:
172 free(err);
173 err = xenbus_transaction_end(xbt, 1, &retry);
174 goto error;
176 done:
178 snprintf(path, sizeof(path), "%s/backend", nodename);
179 msg = xenbus_read(XBT_NIL, path, &dev->backend);
180 if (msg) {
181 printk("Error %s when reading the backend path %s\n", msg, path);
182 goto error;
183 }
185 printk("backend at %s\n", dev->backend);
187 dev->handle = strtoul(strrchr(nodename, '/')+1, NULL, 0);
189 {
190 XenbusState state;
191 char path[strlen(dev->backend) + 1 + 19 + 1];
192 snprintf(path, sizeof(path), "%s/mode", dev->backend);
193 msg = xenbus_read(XBT_NIL, path, &c);
194 if (msg) {
195 printk("Error %s when reading the mode\n", msg);
196 goto error;
197 }
198 if (*c == 'w')
199 dev->info.mode = O_RDWR;
200 else
201 dev->info.mode = O_RDONLY;
202 free(c);
204 snprintf(path, sizeof(path), "%s/state", dev->backend);
206 xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
208 msg = NULL;
209 state = xenbus_read_integer(path);
210 while (msg == NULL && state < XenbusStateConnected)
211 msg = xenbus_wait_for_state_change(path, &state, &dev->events);
212 if (msg != NULL || state != XenbusStateConnected) {
213 printk("backend not available, state=%d\n", state);
214 xenbus_unwatch_path_token(XBT_NIL, path, path);
215 goto error;
216 }
218 snprintf(path, sizeof(path), "%s/info", dev->backend);
219 dev->info.info = xenbus_read_integer(path);
221 snprintf(path, sizeof(path), "%s/sectors", dev->backend);
222 // FIXME: read_integer returns an int, so disk size limited to 1TB for now
223 dev->info.sectors = xenbus_read_integer(path);
225 snprintf(path, sizeof(path), "%s/sector-size", dev->backend);
226 dev->info.sector_size = xenbus_read_integer(path);
228 snprintf(path, sizeof(path), "%s/feature-barrier", dev->backend);
229 dev->info.barrier = xenbus_read_integer(path);
231 snprintf(path, sizeof(path), "%s/feature-flush-cache", dev->backend);
232 dev->info.flush = xenbus_read_integer(path);
234 *info = dev->info;
235 }
236 unmask_evtchn(dev->evtchn);
238 printk("%u sectors of %u bytes\n", dev->info.sectors, dev->info.sector_size);
239 printk("**************************\n");
241 return dev;
243 error:
244 free(msg);
245 free(err);
246 free_blkfront(dev);
247 return NULL;
248 }
250 void shutdown_blkfront(struct blkfront_dev *dev)
251 {
252 char* err = NULL;
253 XenbusState state;
255 char path[strlen(dev->backend) + 1 + 5 + 1];
256 char nodename[strlen(dev->nodename) + 1 + 5 + 1];
258 blkfront_sync(dev);
260 printk("close blk: backend=%s node=%s\n", dev->backend, dev->nodename);
262 snprintf(path, sizeof(path), "%s/state", dev->backend);
263 snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
265 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
266 printk("shutdown_blkfront: error changing state to %d: %s\n",
267 XenbusStateClosing, err);
268 goto close;
269 }
270 state = xenbus_read_integer(path);
271 while (err == NULL && state < XenbusStateClosing)
272 err = xenbus_wait_for_state_change(path, &state, &dev->events);
273 if (err) free(err);
275 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
276 printk("shutdown_blkfront: error changing state to %d: %s\n",
277 XenbusStateClosed, err);
278 goto close;
279 }
280 state = xenbus_read_integer(path);
281 if (state < XenbusStateClosed) {
282 err = xenbus_wait_for_state_change(path, &state, &dev->events);
283 if (err) free(err);
284 }
286 if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
287 printk("shutdown_blkfront: error changing state to %d: %s\n",
288 XenbusStateInitialising, err);
289 goto close;
290 }
291 err = NULL;
292 state = xenbus_read_integer(path);
293 while (err == NULL && (state < XenbusStateInitWait || state >= XenbusStateClosed))
294 err = xenbus_wait_for_state_change(path, &state, &dev->events);
296 close:
297 if (err) free(err);
298 xenbus_unwatch_path_token(XBT_NIL, path, path);
300 snprintf(path, sizeof(path), "%s/ring-ref", nodename);
301 xenbus_rm(XBT_NIL, path);
302 snprintf(path, sizeof(path), "%s/event-channel", nodename);
303 xenbus_rm(XBT_NIL, path);
305 free_blkfront(dev);
306 }
308 static void blkfront_wait_slot(struct blkfront_dev *dev)
309 {
310 /* Wait for a slot */
311 if (RING_FULL(&dev->ring)) {
312 unsigned long flags;
313 DEFINE_WAIT(w);
314 local_irq_save(flags);
315 while (1) {
316 blkfront_aio_poll(dev);
317 if (!RING_FULL(&dev->ring))
318 break;
319 /* Really no slot, go to sleep. */
320 add_waiter(w, blkfront_queue);
321 local_irq_restore(flags);
322 schedule();
323 local_irq_save(flags);
324 }
325 remove_waiter(w);
326 local_irq_restore(flags);
327 }
328 }
330 /* Issue an aio */
331 void blkfront_aio(struct blkfront_aiocb *aiocbp, int write)
332 {
333 struct blkfront_dev *dev = aiocbp->aio_dev;
334 struct blkif_request *req;
335 RING_IDX i;
336 int notify;
337 int n, j;
338 uintptr_t start, end;
340 // Can't io at non-sector-aligned location
341 ASSERT(!(aiocbp->aio_offset & (dev->info.sector_size-1)));
342 // Can't io non-sector-sized amounts
343 ASSERT(!(aiocbp->aio_nbytes & (dev->info.sector_size-1)));
344 // Can't io non-sector-aligned buffer
345 ASSERT(!((uintptr_t) aiocbp->aio_buf & (dev->info.sector_size-1)));
347 start = (uintptr_t)aiocbp->aio_buf & PAGE_MASK;
348 end = ((uintptr_t)aiocbp->aio_buf + aiocbp->aio_nbytes + PAGE_SIZE - 1) & PAGE_MASK;
349 aiocbp->n = n = (end - start) / PAGE_SIZE;
351 /* qemu's IDE max multsect is 16 (8KB) and SCSI max DMA was set to 32KB,
352 * so max 44KB can't happen */
353 ASSERT(n <= BLKIF_MAX_SEGMENTS_PER_REQUEST);
355 blkfront_wait_slot(dev);
356 i = dev->ring.req_prod_pvt;
357 req = RING_GET_REQUEST(&dev->ring, i);
359 req->operation = write ? BLKIF_OP_WRITE : BLKIF_OP_READ;
360 req->nr_segments = n;
361 req->handle = dev->handle;
362 req->id = (uintptr_t) aiocbp;
363 req->sector_number = aiocbp->aio_offset / 512;
365 for (j = 0; j < n; j++) {
366 req->seg[j].first_sect = 0;
367 req->seg[j].last_sect = PAGE_SIZE / 512 - 1;
368 }
369 req->seg[0].first_sect = ((uintptr_t)aiocbp->aio_buf & ~PAGE_MASK) / 512;
370 req->seg[n-1].last_sect = (((uintptr_t)aiocbp->aio_buf + aiocbp->aio_nbytes - 1) & ~PAGE_MASK) / 512;
371 for (j = 0; j < n; j++) {
372 uintptr_t data = start + j * PAGE_SIZE;
373 if (!write) {
374 /* Trigger CoW if needed */
375 *(char*)(data + (req->seg[j].first_sect << 9)) = 0;
376 barrier();
377 }
378 aiocbp->gref[j] = req->seg[j].gref =
379 gnttab_grant_access(dev->dom, virtual_to_mfn(data), write);
380 }
382 dev->ring.req_prod_pvt = i + 1;
384 wmb();
385 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->ring, notify);
387 if(notify) notify_remote_via_evtchn(dev->evtchn);
388 }
390 static void blkfront_aio_cb(struct blkfront_aiocb *aiocbp, int ret)
391 {
392 aiocbp->data = (void*) 1;
393 }
395 void blkfront_io(struct blkfront_aiocb *aiocbp, int write)
396 {
397 unsigned long flags;
398 DEFINE_WAIT(w);
400 ASSERT(!aiocbp->aio_cb);
401 aiocbp->aio_cb = blkfront_aio_cb;
402 blkfront_aio(aiocbp, write);
403 aiocbp->data = NULL;
405 local_irq_save(flags);
406 while (1) {
407 blkfront_aio_poll(aiocbp->aio_dev);
408 if (aiocbp->data)
409 break;
411 add_waiter(w, blkfront_queue);
412 local_irq_restore(flags);
413 schedule();
414 local_irq_save(flags);
415 }
416 remove_waiter(w);
417 local_irq_restore(flags);
418 }
420 static void blkfront_push_operation(struct blkfront_dev *dev, uint8_t op, uint64_t id)
421 {
422 int i;
423 struct blkif_request *req;
424 int notify;
426 blkfront_wait_slot(dev);
427 i = dev->ring.req_prod_pvt;
428 req = RING_GET_REQUEST(&dev->ring, i);
429 req->operation = op;
430 req->nr_segments = 0;
431 req->handle = dev->handle;
432 req->id = id;
433 /* Not needed anyway, but the backend will check it */
434 req->sector_number = 0;
435 dev->ring.req_prod_pvt = i + 1;
436 wmb();
437 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->ring, notify);
438 if (notify) notify_remote_via_evtchn(dev->evtchn);
439 }
441 void blkfront_aio_push_operation(struct blkfront_aiocb *aiocbp, uint8_t op)
442 {
443 struct blkfront_dev *dev = aiocbp->aio_dev;
444 blkfront_push_operation(dev, op, (uintptr_t) aiocbp);
445 }
447 void blkfront_sync(struct blkfront_dev *dev)
448 {
449 unsigned long flags;
450 DEFINE_WAIT(w);
452 if (dev->info.mode == O_RDWR) {
453 if (dev->info.barrier == 1)
454 blkfront_push_operation(dev, BLKIF_OP_WRITE_BARRIER, 0);
456 if (dev->info.flush == 1)
457 blkfront_push_operation(dev, BLKIF_OP_FLUSH_DISKCACHE, 0);
458 }
460 /* Note: This won't finish if another thread enqueues requests. */
461 local_irq_save(flags);
462 while (1) {
463 blkfront_aio_poll(dev);
464 if (RING_FREE_REQUESTS(&dev->ring) == RING_SIZE(&dev->ring))
465 break;
467 add_waiter(w, blkfront_queue);
468 local_irq_restore(flags);
469 schedule();
470 local_irq_save(flags);
471 }
472 remove_waiter(w);
473 local_irq_restore(flags);
474 }
476 int blkfront_aio_poll(struct blkfront_dev *dev)
477 {
478 RING_IDX rp, cons;
479 struct blkif_response *rsp;
480 int more;
481 int nr_consumed;
483 moretodo:
484 #ifdef HAVE_LIBC
485 if (dev->fd != -1) {
486 files[dev->fd].read = 0;
487 mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */
488 }
489 #endif
491 rp = dev->ring.sring->rsp_prod;
492 rmb(); /* Ensure we see queued responses up to 'rp'. */
493 cons = dev->ring.rsp_cons;
495 nr_consumed = 0;
496 while ((cons != rp))
497 {
498 struct blkfront_aiocb *aiocbp;
499 int status;
501 rsp = RING_GET_RESPONSE(&dev->ring, cons);
502 nr_consumed++;
504 aiocbp = (void*) (uintptr_t) rsp->id;
505 status = rsp->status;
507 if (status != BLKIF_RSP_OKAY)
508 printk("block error %d for op %d\n", status, rsp->operation);
510 switch (rsp->operation) {
511 case BLKIF_OP_READ:
512 case BLKIF_OP_WRITE:
513 {
514 int j;
516 for (j = 0; j < aiocbp->n; j++)
517 gnttab_end_access(aiocbp->gref[j]);
519 break;
520 }
522 case BLKIF_OP_WRITE_BARRIER:
523 case BLKIF_OP_FLUSH_DISKCACHE:
524 break;
526 default:
527 printk("unrecognized block operation %d response\n", rsp->operation);
528 }
530 dev->ring.rsp_cons = ++cons;
531 /* Nota: callback frees aiocbp itself */
532 if (aiocbp && aiocbp->aio_cb)
533 aiocbp->aio_cb(aiocbp, status ? -EIO : 0);
534 if (dev->ring.rsp_cons != cons)
535 /* We reentered, we must not continue here */
536 break;
537 }
539 RING_FINAL_CHECK_FOR_RESPONSES(&dev->ring, more);
540 if (more) goto moretodo;
542 return nr_consumed;
543 }
545 #ifdef HAVE_LIBC
546 int blkfront_open(struct blkfront_dev *dev)
547 {
548 dev->fd = alloc_fd(FTYPE_BLK);
549 printk("blk_open(%s) -> %d\n", dev->nodename, dev->fd);
550 files[dev->fd].blk.dev = dev;
551 return dev->fd;
552 }
553 #endif