📄 block-vhd.c
字号:
static void
vhd_queue_write(td_driver_t *driver, td_request_t treq)
{
struct vhd_state *s = (struct vhd_state *)driver->data;
DBG(TLOG_DBG, "%s: lsec: 0x%08"PRIx64", secs: 0x%04x, (seg: %d)\n",
s->vhd.file, treq.sec, treq.secs, treq.sidx);
while (treq.secs) {
int err;
uint8_t flags;
td_request_t clone;
err = 0;
flags = 0;
clone = treq;
switch (read_bitmap_cache(s, clone.sec, VHD_OP_DATA_WRITE)) {
case -EINVAL:
err = -EINVAL;
goto fail;
case VHD_BM_BAT_LOCKED:
err = -EBUSY;
clone.blocked = 1;
goto fail;
case VHD_BM_BAT_CLEAR:
flags = (VHD_FLAG_REQ_UPDATE_BAT |
VHD_FLAG_REQ_UPDATE_BITMAP);
clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
err = schedule_data_write(s, clone, flags);
if (err)
goto fail;
break;
case VHD_BM_BIT_CLEAR:
flags = VHD_FLAG_REQ_UPDATE_BITMAP;
clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 0);
err = schedule_data_write(s, clone, flags);
if (err)
goto fail;
break;
case VHD_BM_BIT_SET:
clone.secs = read_bitmap_cache_span(s, clone.sec, clone.secs, 1);
err = schedule_data_write(s, clone, 0);
if (err)
goto fail;
break;
case VHD_BM_NOT_CACHED:
clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
err = schedule_bitmap_read(s, clone.sec / s->spb);
if (err)
goto fail;
err = __vhd_queue_request(s, VHD_OP_DATA_WRITE, clone);
if (err)
goto fail;
break;
case VHD_BM_READ_PENDING:
clone.secs = MIN(clone.secs, s->spb - (clone.sec % s->spb));
err = __vhd_queue_request(s, VHD_OP_DATA_WRITE, clone);
if (err)
goto fail;
break;
default:
ASSERT(0);
break;
}
treq.sec += clone.secs;
treq.secs -= clone.secs;
treq.buf += vhd_sectors_to_bytes(clone.secs);
continue;
fail:
clone.secs = treq.secs;
td_complete_request(clone, err);
break;
}
}
static inline void
signal_completion(struct vhd_request *list, int error)
{
struct vhd_state *s;
struct vhd_request *r, *next;
if (!list)
return;
r = list;
s = list->state;
while (r) {
int err;
err = (error ? error : r->error);
next = r->next;
td_complete_request(r->treq, err);
DBG(TLOG_DBG, "lsec: 0x%08"PRIx64", blk: 0x%04"PRIx64", "
"err: %d\n", r->treq.sec, r->treq.sec / s->spb, err);
free_vhd_request(s, r);
r = next;
s->returned++;
TRACE(s);
}
}
static void
start_new_bitmap_transaction(struct vhd_state *s, struct vhd_bitmap *bm)
{
int i, error = 0;
struct vhd_transaction *tx;
struct vhd_request *r, *next;
if (!bm->queue.head)
return;
DBG(TLOG_DBG, "blk: 0x%04x\n", bm->blk);
r = bm->queue.head;
tx = &bm->tx;
clear_req_list(&bm->queue);
if (r && bat_entry(s, bm->blk) == DD_BLK_UNUSED)
tx->error = -EIO;
while (r) {
next = r->next;
r->next = NULL;
clear_vhd_flag(r->flags, VHD_FLAG_REQ_QUEUED);
add_to_transaction(tx, r);
if (test_vhd_flag(r->flags, VHD_FLAG_REQ_FINISHED)) {
tx->finished++;
if (!r->error) {
u32 sec = r->treq.sec % s->spb;
for (i = 0; i < r->treq.secs; i++)
vhd_bitmap_set(&s->vhd,
bm->shadow, sec + i);
}
}
r = next;
}
/* perhaps all the queued writes already completed? */
if (tx->started && transaction_completed(tx))
finish_data_transaction(s, bm);
}
static void
finish_bat_transaction(struct vhd_state *s, struct vhd_bitmap *bm)
{
struct vhd_transaction *tx = &bm->tx;
if (!bat_locked(s))
return;
if (s->bat.pbw_blk != bm->blk)
return;
if (!s->bat.req.error)
goto release;
if (!test_vhd_flag(tx->status, VHD_FLAG_TX_LIVE))
goto release;
tx->closed = 1;
return;
release:
DBG(TLOG_DBG, "blk: 0x%04x\n", bm->blk);
unlock_bat(s);
init_bat(s);
}
static void
finish_bitmap_transaction(struct vhd_state *s,
struct vhd_bitmap *bm, int error)
{
int map_size;
struct vhd_transaction *tx = &bm->tx;
DBG(TLOG_DBG, "blk: 0x%04x, err: %d\n", bm->blk, error);
tx->error = (tx->error ? tx->error : error);
map_size = vhd_sectors_to_bytes(s->bm_secs);
if (!test_vhd_flag(s->flags, VHD_FLAG_OPEN_PREALLOCATE)) {
if (test_vhd_flag(tx->status, VHD_FLAG_TX_UPDATE_BAT)) {
/* still waiting for bat write */
ASSERT(bm->blk == s->bat.pbw_blk);
ASSERT(test_vhd_flag(s->bat.status,
VHD_FLAG_BAT_WRITE_STARTED));
s->bat.req.tx = tx;
return;
}
}
if (tx->error) {
/* undo changes to shadow */
memcpy(bm->shadow, bm->map, map_size);
} else {
/* complete atomic write */
memcpy(bm->map, bm->shadow, map_size);
if (!test_batmap(s, bm->blk) && bitmap_full(s, bm))
set_batmap(s, bm->blk);
}
/* transaction done; signal completions */
signal_completion(tx->requests.head, tx->error);
init_tx(tx);
start_new_bitmap_transaction(s, bm);
if (!bitmap_in_use(bm))
unlock_bitmap(bm);
finish_bat_transaction(s, bm);
}
static void
finish_data_transaction(struct vhd_state *s, struct vhd_bitmap *bm)
{
struct vhd_transaction *tx = &bm->tx;
DBG(TLOG_DBG, "blk: 0x%04x\n", bm->blk);
tx->closed = 1;
if (!tx->error)
return schedule_bitmap_write(s, bm->blk);
return finish_bitmap_transaction(s, bm, 0);
}
static void
finish_bat_write(struct vhd_request *req)
{
struct vhd_bitmap *bm;
struct vhd_transaction *tx;
struct vhd_state *s = req->state;
s->returned++;
TRACE(s);
bm = get_bitmap(s, s->bat.pbw_blk);
DBG(TLOG_DBG, "blk 0x%04x, pbwo: 0x%08"PRIx64", err %d\n",
s->bat.pbw_blk, s->bat.pbw_offset, req->error);
ASSERT(bm && bitmap_valid(bm));
ASSERT(bat_locked(s) &&
test_vhd_flag(s->bat.status, VHD_FLAG_BAT_WRITE_STARTED));
tx = &bm->tx;
ASSERT(test_vhd_flag(tx->status, VHD_FLAG_TX_LIVE));
if (!req->error) {
bat_entry(s, s->bat.pbw_blk) = s->bat.pbw_offset;
s->next_db = s->bat.pbw_offset + s->spb + s->bm_secs;
} else
tx->error = req->error;
if (test_vhd_flag(s->flags, VHD_FLAG_OPEN_PREALLOCATE)) {
tx->finished++;
remove_from_req_list(&tx->requests, req);
if (transaction_completed(tx))
finish_data_transaction(s, bm);
} else {
clear_vhd_flag(tx->status, VHD_FLAG_TX_UPDATE_BAT);
if (s->bat.req.tx)
finish_bitmap_transaction(s, bm, req->error);
}
finish_bat_transaction(s, bm);
}
static void
finish_zero_bm_write(struct vhd_request *req)
{
u32 blk;
struct vhd_bitmap *bm;
struct vhd_transaction *tx = req->tx;
struct vhd_state *s = req->state;
s->returned++;
TRACE(s);
blk = req->treq.sec / s->spb;
bm = get_bitmap(s, blk);
DBG(TLOG_DBG, "blk: 0x%04x\n", blk);
ASSERT(bat_locked(s));
ASSERT(s->bat.pbw_blk == blk);
ASSERT(bm && bitmap_valid(bm) && bitmap_locked(bm));
tx->finished++;
remove_from_req_list(&tx->requests, req);
if (req->error) {
unlock_bat(s);
init_bat(s);
tx->error = req->error;
clear_vhd_flag(tx->status, VHD_FLAG_TX_UPDATE_BAT);
} else
schedule_bat_write(s);
if (transaction_completed(tx))
finish_data_transaction(s, bm);
}
static void
finish_bitmap_read(struct vhd_request *req)
{
u32 blk;
struct vhd_bitmap *bm;
struct vhd_request *r, *next;
struct vhd_state *s = req->state;
s->returned++;
TRACE(s);
blk = req->treq.sec / s->spb;
bm = get_bitmap(s, blk);
DBG(TLOG_DBG, "blk: 0x%04x\n", blk);
ASSERT(bm && test_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING));
r = bm->waiting.head;
clear_req_list(&bm->waiting);
clear_vhd_flag(bm->status, VHD_FLAG_BM_READ_PENDING);
if (!req->error) {
memcpy(bm->shadow, bm->map, vhd_sectors_to_bytes(s->bm_secs));
while (r) {
struct vhd_request tmp;
tmp = *r;
next = r->next;
free_vhd_request(s, r);
ASSERT(tmp.op == VHD_OP_DATA_READ ||
tmp.op == VHD_OP_DATA_WRITE);
if (tmp.op == VHD_OP_DATA_READ)
vhd_queue_read(s->driver, tmp.treq);
else if (tmp.op == VHD_OP_DATA_WRITE)
vhd_queue_write(s->driver, tmp.treq);
r = next;
}
} else {
int err = req->error;
unlock_bitmap(bm);
free_vhd_bitmap(s, bm);
return signal_completion(r, err);
}
if (!bitmap_in_use(bm))
unlock_bitmap(bm);
}
static void
finish_bitmap_write(struct vhd_request *req)
{
u32 blk;
struct vhd_bitmap *bm;
struct vhd_transaction *tx;
struct vhd_state *s = req->state;
s->returned++;
TRACE(s);
blk = req->treq.sec / s->spb;
bm = get_bitmap(s, blk);
tx = &bm->tx;
DBG(TLOG_DBG, "blk: 0x%04x, started: %d, finished: %d\n",
blk, tx->started, tx->finished);
ASSERT(tx->closed);
ASSERT(bm && bitmap_valid(bm));
ASSERT(test_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING));
clear_vhd_flag(bm->status, VHD_FLAG_BM_WRITE_PENDING);
finish_bitmap_transaction(s, bm, req->error);
}
static void
finish_data_read(struct vhd_request *req)
{
struct vhd_state *s = req->state;
DBG(TLOG_DBG, "lsec 0x%08"PRIx64", blk: 0x%04"PRIx64"\n",
req->treq.sec, req->treq.sec / s->spb);
signal_completion(req, 0);
}
static void
finish_data_write(struct vhd_request *req)
{
int i;
struct vhd_transaction *tx = req->tx;
struct vhd_state *s = (struct vhd_state *)req->state;
set_vhd_flag(req->flags, VHD_FLAG_REQ_FINISHED);
if (tx) {
u32 blk, sec;
struct vhd_bitmap *bm;
blk = req->treq.sec / s->spb;
sec = req->treq.sec % s->spb;
bm = get_bitmap(s, blk);
ASSERT(bm && bitmap_valid(bm) && bitmap_locked(bm));
tx->finished++;
DBG(TLOG_DBG, "lsec: 0x%08"PRIx64", blk: 0x04%"PRIx64", "
"tx->started: %d, tx->finished: %d\n", req->treq.sec,
req->treq.sec / s->spb, tx->started, tx->finished);
if (!req->error)
for (i = 0; i < req->treq.secs; i++)
vhd_bitmap_set(&s->vhd, bm->shadow, sec + i);
if (transaction_completed(tx))
finish_data_transaction(s, bm);
} else if (!test_vhd_flag(req->flags, VHD_FLAG_REQ_QUEUED)) {
ASSERT(!req->next);
DBG(TLOG_DBG, "lsec: 0x%08"PRIx64", blk: 0x%04"PRIx64"\n",
req->treq.sec, req->treq.sec / s->spb);
signal_completion(req, 0);
}
}
void
vhd_complete(void *arg, struct tiocb *tiocb, int err)
{
struct vhd_request *req = (struct vhd_request *)arg;
struct vhd_state *s = req->state;
struct iocb *io = &tiocb->iocb;
s->completed++;
TRACE(s);
req->error = err;
if (req->error)
ERR(req->error, "%s: op: %u, lsec: %"PRIu64", secs: %u, "
"nbytes: %lu, blk: %"PRIu64", blk_offset: %u",
s->vhd.file, req->op, req->treq.sec, req->treq.secs,
io->u.c.nbytes, req->treq.sec / s->spb,
bat_entry(s, req->treq.sec / s->spb));
switch (req->op) {
case VHD_OP_DATA_READ:
finish_data_read(req);
break;
case VHD_OP_DATA_WRITE:
finish_data_write(req);
break;
case VHD_OP_BITMAP_READ:
finish_bitmap_read(req);
break;
case VHD_OP_BITMAP_WRITE:
finish_bitmap_write(req);
break;
case VHD_OP_ZERO_BM_WRITE:
finish_zero_bm_write(req);
break;
case VHD_OP_BAT_WRITE:
finish_bat_write(req);
break;
default:
ASSERT(0);
break;
}
}
void
vhd_debug(td_driver_t *driver)
{
int i;
struct vhd_state *s = (struct vhd_state *)driver->data;
DBG(TLOG_WARN, "%s: QUEUED: 0x%08"PRIx64", COMPLETED: 0x%08"PRIx64", "
"RETURNED: 0x%08"PRIx64"\n", s->vhd.file, s->queued, s->completed,
s->returned);
DBG(TLOG_WARN, "WRITES: 0x%08"PRIx64", AVG_WRITE_SIZE: %f\n",
s->writes, (s->writes ? ((float)s->write_size / s->writes) : 0.0));
DBG(TLOG_WARN, "READS: 0x%08"PRIx64", AVG_READ_SIZE: %f\n",
s->reads, (s->reads ? ((float)s->read_size / s->reads) : 0.0));
DBG(TLOG_WARN, "ALLOCATED REQUESTS: (%lu total)\n", VHD_REQS_DATA);
for (i = 0; i < VHD_REQS_DATA; i++) {
struct vhd_request *r = &s->vreq_list[i];
td_request_t *t = &r->treq;
if (t->secs)
DBG(TLOG_WARN, "%d: id: 0x%04"PRIx64", err: %d, op: %d,"
" lsec: 0x%08"PRIx64", flags: %d, this: %p, "
"next: %p, tx: %p\n", i, t->id, r->error, r->op,
t->sec, r->flags, r, r->next, r->tx);
}
DBG(TLOG_WARN, "BITMAP CACHE:\n");
for (i = 0; i < VHD_CACHE_SIZE; i++) {
int qnum = 0, wnum = 0, rnum = 0;
struct vhd_bitmap *bm = s->bitmap[i];
struct vhd_transaction *tx;
struct vhd_request *r;
if (!bm)
continue;
tx = &bm->tx;
r = bm->queue.head;
while (r) {
qnum++;
r = r->next;
}
r = bm->waiting.head;
while (r) {
wnum++;
r = r->next;
}
r = tx->requests.head;
while (r) {
rnum++;
r = r->next;
}
DBG(TLOG_WARN, "%d: blk: 0x%04x, status: 0x%08x, q: %p, qnum: %d, w: %p, "
"wnum: %d, locked: %d, in use: %d, tx: %p, tx_error: %d, "
"started: %d, finished: %d, status: %u, reqs: %p, nreqs: %d\n",
i, bm->blk, bm->status, bm->queue.head, qnum, bm->waiting.head,
wnum, bitmap_locked(bm), bitmap_in_use(bm), tx, tx->error,
tx->started, tx->finished, tx->status, tx->requests.head, rnum);
}
DBG(TLOG_WARN, "BAT: status: 0x%08x, pbw_blk: 0x%04x, "
"pbw_off: 0x%08"PRIx64", tx: %p\n", s->bat.status, s->bat.pbw_blk,
s->bat.pbw_offset, s->bat.req.tx);
/*
for (i = 0; i < s->hdr.max_bat_size; i++)
DPRINTF("%d: %u\n", i, s->bat.bat[i]);
*/
}
struct tap_disk tapdisk_vhd = {
.disk_type = "tapdisk_vhd",
.flags = 0,
.private_data_size = sizeof(struct vhd_state),
.td_open = _vhd_open,
.td_close = _vhd_close,
.td_queue_read = vhd_queue_read,
.td_queue_write = vhd_queue_write,
.td_get_parent_id = vhd_get_parent_id,
.td_validate_parent = vhd_validate_parent,
.td_debug = vhd_debug,
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -