/** * Wait for the completion of a request and acknowledges upper layer it was * done. This function is blocking in case there are actually pending IO. If * not, it immediatly returns RDEV_REQUEST_ALL_ENDED. * * @param disk_device disk on which the request is. * * return RDEV_REQUEST_END_ERROR, RDEV_REQUEST_END_OK or RDEV_REQUEST_ALL_ENDED */ static int wait_and_complete_one_io(device_t *disk_device) { header_t *req; int err = exa_rdev_wait_one_request((void *)&req, disk_device->handle); EXA_ASSERT(err == RDEV_REQUEST_ALL_ENDED || err == RDEV_REQUEST_END_ERROR || err == RDEV_REQUEST_END_OK); if (!means_finished(err)) return err; req->io.desc.result = err == RDEV_REQUEST_END_OK ? 0 : -EIO; handle_completed_io(disk_device, req); return err; }
static void async_op(rdev_op_t op, uint64_t offset, uint64_t size_in_bytes, exa_rdev_handle_t *dev_req) { int retval; void *nbd_private; char *buffer; uint64_t chunk_size; uint64_t size_in_sectors; bool quit = false; size_in_sectors = (size_in_bytes / SECTOR_SIZE) + 1; chunk_size = (size_in_bytes > EXA_RDEV_READ_WRITE_FRAGMENT) ? EXA_RDEV_READ_WRITE_FRAGMENT : size_in_bytes; chunk_size /= SECTOR_SIZE; if (chunk_size == 0) chunk_size = 1; /* Prepare buffer to do requests, exa_rdev requires it to be aligned */ buffer = os_aligned_malloc(size_in_sectors * SECTOR_SIZE, PAGE_SIZE, NULL); memset(buffer, 0, size_in_sectors * SECTOR_SIZE); retval = RDEV_REQUEST_ALL_ENDED; while (!quit) { switch (retval) { case RDEV_REQUEST_ALL_ENDED: if (size_in_sectors <= 0) quit = true; /* fallthrough */ case RDEV_REQUEST_NONE_ENDED: if (size_in_sectors > 0) { if (op == RDEV_OP_WRITE) memset(buffer, 'E', size_in_bytes); else memset(buffer, 0, chunk_size); nbd_private = buffer; /* Be carefull the 'nbd_private' pointer can be modified */ retval = exa_rdev_make_request_new(op, &nbd_private, offset, chunk_size, buffer, dev_req); if (retval == RDEV_REQUEST_NOT_ENOUGH_FREE_REQ) { fprintf(stderr, "Overflow of exa_rdev, try later\n"); /* retry */ break; } if (retval < 0) { fprintf(stderr, "Error %d\n", retval); retval = RDEV_REQUEST_END_ERROR; break; } size_in_sectors -= chunk_size; if ((size_in_sectors > 0) && (size_in_sectors < chunk_size)) chunk_size = size_in_sectors; offset += (chunk_size * SECTOR_SIZE); buffer = (char *)buffer + (chunk_size * SECTOR_SIZE); } else { retval = RDEV_REQUEST_NOT_ENOUGH_FREE_REQ; } break; case RDEV_REQUEST_NOT_ENOUGH_FREE_REQ: buffer = NULL; retval = exa_rdev_wait_one_request((void **)&buffer, dev_req); break; case RDEV_REQUEST_END_OK: case RDEV_REQUEST_END_ERROR: if (retval == RDEV_REQUEST_END_ERROR) fprintf(stderr, "Request ended with error\n"); retval = RDEV_REQUEST_NONE_ENDED; break; } } }