/** * send one request to device, it validate there is no problem with the * * @header IN request to do * OUT last request done * @return EXA_RDEV_REQUEST_END_OK new request submitted successfully and header * contains an old request succesfully done * EXA_RDEV_REQUEST_END_ERROR new request submitted successfully * and header contains an old request that fail * RDEV_REQUEST_NOT_ENOUGH_FREE_REQ not enough resources to submit a new request */ static int exa_td_process_one_request(header_t **header, device_t *disk_device) { void * buffer; int sector_nb; uint64_t sector; int retval; header_t *req_header = *header; /* FIXME this is a ugly hack to prevent compiler to complain about * uninitialized variable. Actually, this is because the request type * itself is f***ed up (no type and the funky use os bit masks...) * Please remove this whe reworking header_t content... */ rdev_op_t op = (rdev_op_t)-1; /* submit this new request to exa_rdev and so to the disk driver */ sector_nb = req_header->io.desc.sector_nb; buffer = req_header->io.buf; sector = req_header->io.desc.sector; EXA_ASSERT(NBD_REQ_TYPE_IS_VALID(req_header->io.desc.request_type)); switch (req_header->io.desc.request_type) { case NBD_REQ_TYPE_READ: EXA_ASSERT(!req_header->io.desc.flush_cache); op = RDEV_OP_READ; break; case NBD_REQ_TYPE_WRITE: if (req_header->io.desc.flush_cache) op = RDEV_OP_WRITE_BARRIER; else op = RDEV_OP_WRITE; break; } /* Be carefull the 'header' pointer can be modified */ retval = exa_rdev_make_request_new(op, (void *)header, sector + RDEV_RESERVED_AREA_IN_SECTORS, sector_nb, buffer, disk_device->handle); if (retval == RDEV_REQUEST_NOT_ENOUGH_FREE_REQ) return RDEV_REQUEST_NOT_ENOUGH_FREE_REQ; if (*header != NULL) (*header)->io.desc.result = retval == RDEV_REQUEST_END_OK ? 0 : -EIO; if (retval < 0) return RDEV_REQUEST_END_ERROR; return retval; }
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; } } }