DPRINTF("Secondary image closed\n");
}
+ if (vbd->retired) {
+ td_close(vbd->retired);
+ tapdisk_image_free(vbd->retired);
+ DPRINTF("Retired mirror image closed\n");
+ }
+
INIT_LIST_HEAD(&vbd->images);
td_flag_set(vbd->state, TD_VBD_CLOSED);
}
done:
vbd->secondary = second;
+ leaf->flags |= TD_IGNORE_ENOSPC;
if (td_flag_test(vbd->flags, TD_OPEN_STANDBY)) {
DPRINTF("In standby mode\n");
vbd->secondary_mode = TD_VBD_SECONDARY_STANDBY;
tapdisk_vbd_mark_progress(vbd);
- if (abs(res) == ENOSPC && image != vbd->secondary &&
- vbd->secondary_mode != TD_VBD_SECONDARY_DISABLED) {
- if (vbd->secondary_mode == TD_VBD_SECONDARY_MIRROR)
+ if (abs(res) == ENOSPC && td_flag_test(image->flags,
+ TD_IGNORE_ENOSPC)) {
+ res = 0;
+ leaf = tapdisk_vbd_first_image(vbd);
+ if (vbd->secondary_mode == TD_VBD_SECONDARY_MIRROR) {
DPRINTF("ENOSPC: disabling mirroring\n");
- else if (vbd->secondary_mode == TD_VBD_SECONDARY_STANDBY)
+ list_del_init(&leaf->next);
+ vbd->retired = leaf;
+ } else if (vbd->secondary_mode == TD_VBD_SECONDARY_STANDBY) {
DPRINTF("ENOSPC: failing over to secondary image\n");
- leaf = tapdisk_vbd_first_image(vbd);
- list_add(&vbd->secondary->next, leaf->next.prev);
- vbd->secondary = NULL;
- vbd->secondary_mode = TD_VBD_SECONDARY_DISABLED;
- signal_enospc(vbd);
+ list_add(&vbd->secondary->next, leaf->next.prev);
+ }
+ if (vbd->secondary_mode != TD_VBD_SECONDARY_DISABLED) {
+ vbd->secondary = NULL;
+ vbd->secondary_mode = TD_VBD_SECONDARY_DISABLED;
+ signal_enospc(vbd);
+ }
}
DBG(TLOG_DBG, "%s: req %d seg %d sec 0x%08llx "
switch (req->operation) {
case BLKIF_OP_WRITE:
treq.op = TD_OP_WRITE;
- td_queue_write(treq.image, treq);
+ /* it's important to queue the mirror request before queuing
+ * the main one. If the main image runs into ENOSPC, the
+ * mirroring could be disabled before td_queue_write returns,
+ * so if the mirror request was queued after (which would then
+ * not happen), we'd lose that write and cause the process to
+ * hang with unacknowledged writes */
if (vbd->secondary_mode == TD_VBD_SECONDARY_MIRROR)
queue_mirror_req(vbd, treq);
+ td_queue_write(treq.image, treq);
break;
case BLKIF_OP_READ:
"buf %p op %d\n", image->name, id, i, treq.sec, treq.secs,
treq.buf, (int)req->operation);
- if (i == req->nr_segments - 1) {
- tapdisk_vbd_submit_request(vbd, req, treq);
- treq_started = 0;
- }
-
vreq->secs_pending += nsects;
vbd->secs_pending += nsects;
if (vbd->secondary_mode == TD_VBD_SECONDARY_MIRROR &&
vbd->secs_pending += nsects;
}
+ if (i == req->nr_segments - 1) {
+ tapdisk_vbd_submit_request(vbd, req, treq);
+ treq_started = 0;
+ }
+
sector_nr += nsects;
}