sheepdog: resend write requests when SD_RES_READONLY is received
When a snapshot is taken from out side of qemu (e.g. qemu-img snapshot), write requests to the current vdi return SD_RES_READONLY. In this case, the sheepdog block driver needs to update the current inode to the latest one and resend the write requests. Signed-off-by: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
9ff53a0eb8
commit
13c31de2fd
@ -605,6 +605,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data,
|
|||||||
static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||||
struct iovec *iov, int niov, bool create,
|
struct iovec *iov, int niov, bool create,
|
||||||
enum AIOCBState aiocb_type);
|
enum AIOCBState aiocb_type);
|
||||||
|
static int coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req);
|
||||||
|
|
||||||
|
|
||||||
static AIOReq *find_pending_req(BDRVSheepdogState *s, uint64_t oid)
|
static AIOReq *find_pending_req(BDRVSheepdogState *s, uint64_t oid)
|
||||||
@ -749,9 +750,19 @@ static void coroutine_fn aio_read_response(void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rsp.result != SD_RES_SUCCESS) {
|
switch (rsp.result) {
|
||||||
|
case SD_RES_SUCCESS:
|
||||||
|
break;
|
||||||
|
case SD_RES_READONLY:
|
||||||
|
ret = resend_aioreq(s, aio_req);
|
||||||
|
if (ret == SD_RES_SUCCESS) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
acb->ret = -EIO;
|
acb->ret = -EIO;
|
||||||
error_report("%s", sd_strerror(rsp.result));
|
error_report("%s", sd_strerror(rsp.result));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_aio_req(s, aio_req);
|
free_aio_req(s, aio_req);
|
||||||
@ -1186,6 +1197,53 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req)
|
||||||
|
{
|
||||||
|
SheepdogAIOCB *acb = aio_req->aiocb;
|
||||||
|
bool create = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = reload_inode(s, 0, "");
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
aio_req->oid = vid_to_data_oid(s->inode.vdi_id,
|
||||||
|
data_oid_to_idx(aio_req->oid));
|
||||||
|
|
||||||
|
/* check whether this request becomes a CoW one */
|
||||||
|
if (acb->aiocb_type == AIOCB_WRITE_UDATA) {
|
||||||
|
int idx = data_oid_to_idx(aio_req->oid);
|
||||||
|
AIOReq *areq;
|
||||||
|
|
||||||
|
if (s->inode.data_vdi_id[idx] == 0) {
|
||||||
|
create = true;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (is_data_obj_writable(&s->inode, idx)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* link to the pending list if there is another CoW request to
|
||||||
|
* the same object */
|
||||||
|
QLIST_FOREACH(areq, &s->inflight_aio_head, aio_siblings) {
|
||||||
|
if (areq != aio_req && areq->oid == aio_req->oid) {
|
||||||
|
dprintf("simultaneous CoW to %" PRIx64 "\n", aio_req->oid);
|
||||||
|
QLIST_REMOVE(aio_req, aio_siblings);
|
||||||
|
QLIST_INSERT_HEAD(&s->pending_aio_head, aio_req, aio_siblings);
|
||||||
|
return SD_RES_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aio_req->base_oid = vid_to_data_oid(s->inode.data_vdi_id[idx], idx);
|
||||||
|
aio_req->flags |= SD_FLAG_CMD_COW;
|
||||||
|
create = true;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
|
||||||
|
create, acb->aiocb_type);
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO Convert to fine grained options */
|
/* TODO Convert to fine grained options */
|
||||||
static QemuOptsList runtime_opts = {
|
static QemuOptsList runtime_opts = {
|
||||||
.name = "sheepdog",
|
.name = "sheepdog",
|
||||||
|
Loading…
Reference in New Issue
Block a user