int
tapdisk_image_check_td_request(td_image_t *image, td_request_t treq)
{
- int rdonly;
+ int rdonly, err;
td_driver_t *driver;
td_disk_info_t *info;
+ err = -EINVAL;
+
driver = image->driver;
if (!driver)
return -ENODEV;
if (treq.op != TD_OP_READ && treq.op != TD_OP_WRITE)
goto fail;
- if (treq.op == TD_OP_WRITE && rdonly)
+ if (treq.op == TD_OP_WRITE && rdonly) {
+ err = -EPERM;
goto fail;
+ }
if (treq.secs <= 0 || treq.sec + treq.secs > info->size)
goto fail;
return 0;
fail:
- ERR(-EINVAL, "bad td request on %s (%s, %llu): %d at %llu",
+ ERR(err, "bad td request on %s (%s, %llu): %d at %llu",
image->name, (rdonly ? "ro" : "rw"), info->size, treq.op,
treq.sec + treq.secs);
- return -EINVAL;
+ return err;
}
{
td_driver_t *driver;
td_disk_info_t *info;
- int i, psize, rdonly;
uint64_t nsects, total;
+ int i, err, psize, rdonly;
driver = image->driver;
if (!driver)
return -ENODEV;
+ err = -EINVAL;
nsects = 0;
total = 0;
info = &driver->info;
req->operation != BLKIF_OP_WRITE)
goto fail;
- if (req->operation == BLKIF_OP_WRITE && rdonly)
+ if (req->operation == BLKIF_OP_WRITE && rdonly) {
+ err = -EPERM;
goto fail;
+ }
if (!req->nr_segments || req->nr_segments > MAX_SEGMENTS_PER_REQ)
goto fail;
return 0;
fail:
- ERR(-EINVAL, "bad request on %s (%s, %llu): id: %llu: %d at %llu",
+ ERR(err, "bad request on %s (%s, %llu): id: %llu: %d at %llu",
image->name, (rdonly ? "ro" : "rw"), info->size, req->id,
req->operation, req->sector_number + total);
- return -EINVAL;
+ return err;
}
void
int
tapdisk_vbd_retry_needed(td_vbd_t *vbd)
{
- return !list_empty(&vbd->failed_requests);
+ return !(list_empty(&vbd->failed_requests) ||
+ list_empty(&vbd->new_requests));
}
int
return 0;
}
+static int
+tapdisk_vbd_request_should_retry(td_vbd_t *vbd, td_vbd_request_t *vreq)
+{
+ if (td_flag_test(vbd->state, TD_VBD_DEAD) ||
+ td_flag_test(vbd->state, TD_VBD_SHUTDOWN_REQUESTED))
+ return 0;
+
+ switch (abs(vreq->error)) {
+ case EPERM:
+ case ENOSYS:
+ case ESTALE:
+ case ENOSPC:
+ return 0;
+ }
+
+ if (tapdisk_vbd_request_timeout(vreq))
+ return 0;
+
+ return 1;
+}
+
static void
tapdisk_vbd_complete_vbd_request(td_vbd_t *vbd, td_vbd_request_t *vreq)
{
if (!vreq->submitting && !vreq->secs_pending) {
if (vreq->status == BLKIF_RSP_ERROR &&
- !tapdisk_vbd_request_timeout(vreq) &&
- !td_flag_test(vbd->state, TD_VBD_DEAD) &&
- !td_flag_test(vbd->state, TD_VBD_SHUTDOWN_REQUESTED))
+ tapdisk_vbd_request_should_retry(vbd, vreq))
tapdisk_vbd_move_request(vreq, &vbd->failed_requests);
else
tapdisk_vbd_move_request(vreq, &vbd->completed_requests);
tapdisk_vbd_move_request(vreq, &vbd->pending_requests);
err = tapdisk_vbd_check_queue(vbd);
- if (err)
+ if (err) {
+ vreq->error = err;
goto fail;
+ }
err = tapdisk_image_check_ring_request(image, req);
- if (err)
+ if (err) {
+ vreq->error = err;
goto fail;
+ }
memset(&treq, 0, sizeof(td_request_t));
for (i = 0; i < req->nr_segments; i++) {
goto out;
}
+static int
+tapdisk_vbd_request_completed(td_vbd_t *vbd, td_vbd_request_t *vreq)
+{
+ return vreq->list_head == &vbd->completed_requests;
+}
+
static int
tapdisk_vbd_reissue_failed_requests(td_vbd_t *vbd)
{
vreq->req.nr_segments);
err = tapdisk_vbd_issue_request(vbd, vreq);
- if (err)
+ /*
+ * if this request failed, but was not completed,
+ * we'll back off for a while.
+ */
+ if (err && !tapdisk_vbd_request_completed(vbd, vreq))
break;
}
- return err;
+ return 0;
}
static void
tapdisk_vbd_for_each_request(vreq, tmp, &vbd->new_requests) {
err = tapdisk_vbd_issue_request(vbd, vreq);
- if (err)
+ /*
+ * if this request failed, but was not completed,
+ * we'll back off for a while.
+ */
+ if (err && !tapdisk_vbd_request_completed(vbd, vreq))
return err;
tapdisk_vbd_count_new_request(vbd, vreq);