Merge remote-tracking branch 'kwolf/for-anthony' into staging

This commit is contained in:
Anthony Liguori 2011-07-22 09:23:43 -05:00
commit bf1cd9b4f5
28 changed files with 2427 additions and 1778 deletions

19
block.c
View File

@ -1146,6 +1146,25 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
return ret; return ret;
} }
/**
* Length of a allocated file in bytes. Sparse files are counted by actual
* allocated space. Return < 0 if error or unknown.
*/
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
if (!drv) {
return -ENOMEDIUM;
}
if (drv->bdrv_get_allocated_file_size) {
return drv->bdrv_get_allocated_file_size(bs);
}
if (bs->file) {
return bdrv_get_allocated_file_size(bs->file);
}
return -ENOTSUP;
}
/** /**
* Length of a file in bytes. Return < 0 if error or unknown. * Length of a file in bytes. Return < 0 if error or unknown.
*/ */

View File

@ -89,6 +89,7 @@ int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors); const uint8_t *buf, int nb_sectors);
int bdrv_truncate(BlockDriverState *bs, int64_t offset); int bdrv_truncate(BlockDriverState *bs, int64_t offset);
int64_t bdrv_getlength(BlockDriverState *bs); int64_t bdrv_getlength(BlockDriverState *bs);
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs); void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
int bdrv_commit(BlockDriverState *bs); int bdrv_commit(BlockDriverState *bs);

View File

@ -312,3 +312,15 @@ found:
c->entries[i].dirty = true; c->entries[i].dirty = true;
} }
bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
bool enable)
{
bool old = c->writethrough;
if (!old && enable) {
qcow2_cache_flush(bs, c);
}
c->writethrough = enable;
return old;
}

View File

@ -705,8 +705,15 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
BDRVQcowState *s = bs->opaque; BDRVQcowState *s = bs->opaque;
uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated; uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
int64_t old_offset, old_l2_offset; int64_t old_offset, old_l2_offset;
int i, j, l1_modified, nb_csectors, refcount; int i, j, l1_modified = 0, nb_csectors, refcount;
int ret; int ret;
bool old_l2_writethrough, old_refcount_writethrough;
/* Switch caches to writeback mode during update */
old_l2_writethrough =
qcow2_cache_set_writethrough(bs, s->l2_table_cache, false);
old_refcount_writethrough =
qcow2_cache_set_writethrough(bs, s->refcount_block_cache, false);
l2_table = NULL; l2_table = NULL;
l1_table = NULL; l1_table = NULL;
@ -720,7 +727,11 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
l1_allocated = 1; l1_allocated = 1;
if (bdrv_pread(bs->file, l1_table_offset, if (bdrv_pread(bs->file, l1_table_offset,
l1_table, l1_size2) != l1_size2) l1_table, l1_size2) != l1_size2)
{
ret = -EIO;
goto fail; goto fail;
}
for(i = 0;i < l1_size; i++) for(i = 0;i < l1_size; i++)
be64_to_cpus(&l1_table[i]); be64_to_cpus(&l1_table[i]);
} else { } else {
@ -729,7 +740,6 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
l1_allocated = 0; l1_allocated = 0;
} }
l1_modified = 0;
for(i = 0; i < l1_size; i++) { for(i = 0; i < l1_size; i++) {
l2_offset = l1_table[i]; l2_offset = l1_table[i];
if (l2_offset) { if (l2_offset) {
@ -773,6 +783,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
} }
if (refcount < 0) { if (refcount < 0) {
ret = -EIO;
goto fail; goto fail;
} }
} }
@ -803,6 +814,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
refcount = get_refcount(bs, l2_offset >> s->cluster_bits); refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
} }
if (refcount < 0) { if (refcount < 0) {
ret = -EIO;
goto fail; goto fail;
} else if (refcount == 1) { } else if (refcount == 1) {
l2_offset |= QCOW_OFLAG_COPIED; l2_offset |= QCOW_OFLAG_COPIED;
@ -813,6 +825,18 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
} }
} }
} }
ret = 0;
fail:
if (l2_table) {
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
}
/* Enable writethrough cache mode again */
qcow2_cache_set_writethrough(bs, s->l2_table_cache, old_l2_writethrough);
qcow2_cache_set_writethrough(bs, s->refcount_block_cache,
old_refcount_writethrough);
if (l1_modified) { if (l1_modified) {
for(i = 0; i < l1_size; i++) for(i = 0; i < l1_size; i++)
cpu_to_be64s(&l1_table[i]); cpu_to_be64s(&l1_table[i]);
@ -824,15 +848,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
} }
if (l1_allocated) if (l1_allocated)
qemu_free(l1_table); qemu_free(l1_table);
return 0; return ret;
fail:
if (l2_table) {
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
}
if (l1_allocated)
qemu_free(l1_table);
return -EIO;
} }

View File

@ -228,6 +228,8 @@ int qcow2_read_snapshots(BlockDriverState *bs);
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables, Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
bool writethrough); bool writethrough);
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c); int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
bool enable);
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table); void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c); int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);

View File

@ -793,6 +793,17 @@ static int64_t raw_getlength(BlockDriverState *bs)
} }
#endif #endif
static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
{
struct stat st;
BDRVRawState *s = bs->opaque;
if (fstat(s->fd, &st) < 0) {
return -errno;
}
return (int64_t)st.st_blocks * 512;
}
static int raw_create(const char *filename, QEMUOptionParameter *options) static int raw_create(const char *filename, QEMUOptionParameter *options)
{ {
int fd; int fd;
@ -888,6 +899,8 @@ static BlockDriver bdrv_file = {
.bdrv_truncate = raw_truncate, .bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
.create_options = raw_create_options, .create_options = raw_create_options,
}; };
@ -1156,6 +1169,8 @@ static BlockDriver bdrv_host_device = {
.bdrv_read = raw_read, .bdrv_read = raw_read,
.bdrv_write = raw_write, .bdrv_write = raw_write,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
/* generic scsi device */ /* generic scsi device */
#ifdef __linux__ #ifdef __linux__
@ -1277,6 +1292,8 @@ static BlockDriver bdrv_host_floppy = {
.bdrv_read = raw_read, .bdrv_read = raw_read,
.bdrv_write = raw_write, .bdrv_write = raw_write,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
/* removable device support */ /* removable device support */
.bdrv_is_inserted = floppy_is_inserted, .bdrv_is_inserted = floppy_is_inserted,
@ -1380,6 +1397,8 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_read = raw_read, .bdrv_read = raw_read,
.bdrv_write = raw_write, .bdrv_write = raw_write,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
/* removable device support */ /* removable device support */
.bdrv_is_inserted = cdrom_is_inserted, .bdrv_is_inserted = cdrom_is_inserted,
@ -1503,6 +1522,8 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_read = raw_read, .bdrv_read = raw_read,
.bdrv_write = raw_write, .bdrv_write = raw_write,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
/* removable device support */ /* removable device support */
.bdrv_is_inserted = cdrom_is_inserted, .bdrv_is_inserted = cdrom_is_inserted,

View File

@ -213,6 +213,31 @@ static int64_t raw_getlength(BlockDriverState *bs)
return l.QuadPart; return l.QuadPart;
} }
static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
{
typedef DWORD (WINAPI * get_compressed_t)(const char *filename,
DWORD * high);
get_compressed_t get_compressed;
struct _stati64 st;
const char *filename = bs->filename;
/* WinNT support GetCompressedFileSize to determine allocate size */
get_compressed =
(get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"),
"GetCompressedFileSizeA");
if (get_compressed) {
DWORD high, low;
low = get_compressed(filename, &high);
if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) {
return (((int64_t) high) << 32) + low;
}
}
if (_stati64(filename, &st) < 0) {
return -1;
}
return st.st_size;
}
static int raw_create(const char *filename, QEMUOptionParameter *options) static int raw_create(const char *filename, QEMUOptionParameter *options)
{ {
int fd; int fd;
@ -257,6 +282,8 @@ static BlockDriver bdrv_file = {
.bdrv_write = raw_write, .bdrv_write = raw_write,
.bdrv_truncate = raw_truncate, .bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
.create_options = raw_create_options, .create_options = raw_create_options,
}; };
@ -419,6 +446,8 @@ static BlockDriver bdrv_host_device = {
.bdrv_read = raw_read, .bdrv_read = raw_read,
.bdrv_write = raw_write, .bdrv_write = raw_write,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
}; };
static void bdrv_file_init(void) static void bdrv_file_init(void)

View File

@ -1286,6 +1286,49 @@ static int do_sd_create(char *filename, int64_t vdi_size,
return 0; return 0;
} }
static int sd_prealloc(const char *filename)
{
BlockDriverState *bs = NULL;
uint32_t idx, max_idx;
int64_t vdi_size;
void *buf = qemu_mallocz(SD_DATA_OBJ_SIZE);
int ret;
ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR);
if (ret < 0) {
goto out;
}
vdi_size = bdrv_getlength(bs);
if (vdi_size < 0) {
ret = vdi_size;
goto out;
}
max_idx = DIV_ROUND_UP(vdi_size, SD_DATA_OBJ_SIZE);
for (idx = 0; idx < max_idx; idx++) {
/*
* The created image can be a cloned image, so we need to read
* a data from the source image.
*/
ret = bdrv_pread(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
if (ret < 0) {
goto out;
}
ret = bdrv_pwrite(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
if (ret < 0) {
goto out;
}
}
out:
if (bs) {
bdrv_delete(bs);
}
qemu_free(buf);
return ret;
}
static int sd_create(const char *filename, QEMUOptionParameter *options) static int sd_create(const char *filename, QEMUOptionParameter *options)
{ {
int ret; int ret;
@ -1295,13 +1338,15 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
BDRVSheepdogState s; BDRVSheepdogState s;
char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN]; char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
uint32_t snapid; uint32_t snapid;
int prealloc = 0;
const char *vdiname;
strstart(filename, "sheepdog:", (const char **)&filename); strstart(filename, "sheepdog:", &vdiname);
memset(&s, 0, sizeof(s)); memset(&s, 0, sizeof(s));
memset(vdi, 0, sizeof(vdi)); memset(vdi, 0, sizeof(vdi));
memset(tag, 0, sizeof(tag)); memset(tag, 0, sizeof(tag));
if (parse_vdiname(&s, filename, vdi, &snapid, tag) < 0) { if (parse_vdiname(&s, vdiname, vdi, &snapid, tag) < 0) {
error_report("invalid filename"); error_report("invalid filename");
return -EINVAL; return -EINVAL;
} }
@ -1311,6 +1356,16 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
vdi_size = options->value.n; vdi_size = options->value.n;
} else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
backing_file = options->value.s; backing_file = options->value.s;
} else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
if (!options->value.s || !strcmp(options->value.s, "off")) {
prealloc = 0;
} else if (!strcmp(options->value.s, "full")) {
prealloc = 1;
} else {
error_report("Invalid preallocation mode: '%s'",
options->value.s);
return -EINVAL;
}
} }
options++; options++;
} }
@ -1348,7 +1403,12 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
bdrv_delete(bs); bdrv_delete(bs);
} }
return do_sd_create((char *)vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port); ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
if (!prealloc || ret) {
return ret;
}
return sd_prealloc(filename);
} }
static void sd_close(BlockDriverState *bs) static void sd_close(BlockDriverState *bs)
@ -1984,6 +2044,11 @@ static QEMUOptionParameter sd_create_options[] = {
.type = OPT_STRING, .type = OPT_STRING,
.help = "File name of a base image" .help = "File name of a base image"
}, },
{
.name = BLOCK_OPT_PREALLOC,
.type = OPT_STRING,
.help = "Preallocation mode (allowed values: off, full)"
},
{ NULL } { NULL }
}; };

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,7 @@
#define BLOCK_OPT_CLUSTER_SIZE "cluster_size" #define BLOCK_OPT_CLUSTER_SIZE "cluster_size"
#define BLOCK_OPT_TABLE_SIZE "table_size" #define BLOCK_OPT_TABLE_SIZE "table_size"
#define BLOCK_OPT_PREALLOC "preallocation" #define BLOCK_OPT_PREALLOC "preallocation"
#define BLOCK_OPT_SUBFMT "subformat"
typedef struct AIOPool { typedef struct AIOPool {
void (*cancel)(BlockDriverAIOCB *acb); void (*cancel)(BlockDriverAIOCB *acb);
@ -85,6 +86,7 @@ struct BlockDriver {
const char *protocol_name; const char *protocol_name;
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset); int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
int64_t (*bdrv_getlength)(BlockDriverState *bs); int64_t (*bdrv_getlength)(BlockDriverState *bs);
int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs);
int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors); const uint8_t *buf, int nb_sectors);

View File

@ -244,7 +244,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
DPRINTF("do_busid_cmd: busid 0x%x\n", busid); DPRINTF("do_busid_cmd: busid 0x%x\n", busid);
lun = busid & 7; lun = busid & 7;
s->current_req = scsi_req_new(s->current_dev, 0, lun); s->current_req = scsi_req_new(s->current_dev, 0, lun, NULL);
datalen = scsi_req_enqueue(s->current_req, buf); datalen = scsi_req_enqueue(s->current_req, buf);
s->ti_size = datalen; s->ti_size = datalen;
if (datalen != 0) { if (datalen != 0) {

View File

@ -661,7 +661,7 @@ static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
static void lsi_request_cancelled(SCSIRequest *req) static void lsi_request_cancelled(SCSIRequest *req)
{ {
LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
lsi_request *p; lsi_request *p = req->hba_private;
if (s->current && req == s->current->req) { if (s->current && req == s->current->req) {
scsi_req_unref(req); scsi_req_unref(req);
@ -670,7 +670,6 @@ static void lsi_request_cancelled(SCSIRequest *req)
return; return;
} }
p = lsi_find_by_tag(s, req->tag);
if (p) { if (p) {
QTAILQ_REMOVE(&s->queue, p, next); QTAILQ_REMOVE(&s->queue, p, next);
scsi_req_unref(req); scsi_req_unref(req);
@ -680,18 +679,12 @@ static void lsi_request_cancelled(SCSIRequest *req)
/* Record that data is available for a queued command. Returns zero if /* Record that data is available for a queued command. Returns zero if
the device was reselected, nonzero if the IO is deferred. */ the device was reselected, nonzero if the IO is deferred. */
static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t len) static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
{ {
lsi_request *p; lsi_request *p = req->hba_private;
p = lsi_find_by_tag(s, tag);
if (!p) {
BADF("IO with unknown tag %d\n", tag);
return 1;
}
if (p->pending) { if (p->pending) {
BADF("Multiple IO pending for tag %d\n", tag); BADF("Multiple IO pending for request %p\n", p);
} }
p->pending = len; p->pending = len;
/* Reselect if waiting for it, or if reselection triggers an IRQ /* Reselect if waiting for it, or if reselection triggers an IRQ
@ -743,9 +736,9 @@ static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
int out; int out;
if (s->waiting == 1 || !s->current || req->tag != s->current->tag || if (s->waiting == 1 || !s->current || req->hba_private != s->current ||
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) { (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
if (lsi_queue_tag(s, req->tag, len)) { if (lsi_queue_req(s, req, len)) {
return; return;
} }
} }
@ -789,7 +782,8 @@ static void lsi_do_command(LSIState *s)
assert(s->current == NULL); assert(s->current == NULL);
s->current = qemu_mallocz(sizeof(lsi_request)); s->current = qemu_mallocz(sizeof(lsi_request));
s->current->tag = s->select_tag; s->current->tag = s->select_tag;
s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun); s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun,
s->current);
n = scsi_req_enqueue(s->current->req, buf); n = scsi_req_enqueue(s->current->req, buf);
if (n) { if (n) {

View File

@ -131,7 +131,8 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
return res; return res;
} }
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun) SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag,
uint32_t lun, void *hba_private)
{ {
SCSIRequest *req; SCSIRequest *req;
@ -141,14 +142,16 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l
req->dev = d; req->dev = d;
req->tag = tag; req->tag = tag;
req->lun = lun; req->lun = lun;
req->hba_private = hba_private;
req->status = -1; req->status = -1;
trace_scsi_req_alloc(req->dev->id, req->lun, req->tag); trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
return req; return req;
} }
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun) SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
void *hba_private)
{ {
return d->info->alloc_req(d, tag, lun); return d->info->alloc_req(d, tag, lun, hba_private);
} }
uint8_t *scsi_req_get_buf(SCSIRequest *req) uint8_t *scsi_req_get_buf(SCSIRequest *req)

View File

@ -81,13 +81,13 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf); static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
uint32_t lun) uint32_t lun, void *hba_private)
{ {
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIRequest *req; SCSIRequest *req;
SCSIDiskReq *r; SCSIDiskReq *r;
req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun); req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun, hba_private);
r = DO_UPCAST(SCSIDiskReq, req, req); r = DO_UPCAST(SCSIDiskReq, req, req);
r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE); r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
return req; return req;
@ -398,6 +398,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
"buffer size %zd\n", req->cmd.xfer); "buffer size %zd\n", req->cmd.xfer);
pages = buflen++; pages = buflen++;
outbuf[buflen++] = 0x00; // list of supported pages (this page) outbuf[buflen++] = 0x00; // list of supported pages (this page)
if (s->serial)
outbuf[buflen++] = 0x80; // unit serial number outbuf[buflen++] = 0x80; // unit serial number
outbuf[buflen++] = 0x83; // device identification outbuf[buflen++] = 0x83; // device identification
if (s->drive_kind == SCSI_HD) { if (s->drive_kind == SCSI_HD) {
@ -409,8 +410,14 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
} }
case 0x80: /* Device serial number, optional */ case 0x80: /* Device serial number, optional */
{ {
int l = strlen(s->serial); int l;
if (!s->serial) {
DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
return -1;
}
l = strlen(s->serial);
if (l > req->cmd.xfer) if (l > req->cmd.xfer)
l = req->cmd.xfer; l = req->cmd.xfer;
if (l > 20) if (l > 20)
@ -1007,7 +1014,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
command = buf[0]; command = buf[0];
outbuf = (uint8_t *)r->iov.iov_base; outbuf = (uint8_t *)r->iov.iov_base;
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
if (scsi_req_parse(&r->req, buf) != 0) { if (scsi_req_parse(&r->req, buf) != 0) {
BADF("Unsupported command length, command %x\n", command); BADF("Unsupported command length, command %x\n", command);
@ -1203,7 +1210,9 @@ static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
if (!s->serial) { if (!s->serial) {
/* try to fall back to value set with legacy -drive serial=... */ /* try to fall back to value set with legacy -drive serial=... */
dinfo = drive_get_by_blockdev(s->bs); dinfo = drive_get_by_blockdev(s->bs);
s->serial = qemu_strdup(*dinfo->serial ? dinfo->serial : "0"); if (*dinfo->serial) {
s->serial = qemu_strdup(dinfo->serial);
}
} }
if (!s->version) { if (!s->version) {

View File

@ -96,11 +96,12 @@ static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len)
return size; return size;
} }
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
void *hba_private)
{ {
SCSIRequest *req; SCSIRequest *req;
req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun); req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun, hba_private);
return req; return req;
} }

View File

@ -43,6 +43,7 @@ struct SCSIRequest {
} cmd; } cmd;
BlockDriverAIOCB *aiocb; BlockDriverAIOCB *aiocb;
bool enqueued; bool enqueued;
void *hba_private;
QTAILQ_ENTRY(SCSIRequest) next; QTAILQ_ENTRY(SCSIRequest) next;
}; };
@ -67,7 +68,8 @@ struct SCSIDeviceInfo {
DeviceInfo qdev; DeviceInfo qdev;
scsi_qdev_initfn init; scsi_qdev_initfn init;
void (*destroy)(SCSIDevice *s); void (*destroy)(SCSIDevice *s);
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun); SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
void *hba_private);
void (*free_req)(SCSIRequest *req); void (*free_req)(SCSIRequest *req);
int32_t (*send_command)(SCSIRequest *req, uint8_t *buf); int32_t (*send_command)(SCSIRequest *req, uint8_t *buf);
void (*read_data)(SCSIRequest *req); void (*read_data)(SCSIRequest *req);
@ -138,8 +140,10 @@ extern const struct SCSISense sense_code_LUN_FAILURE;
int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed); int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed);
int scsi_sense_valid(SCSISense sense); int scsi_sense_valid(SCSISense sense);
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag,
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun); uint32_t lun, void *hba_private);
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
void *hba_private);
int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf); int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf);
void scsi_req_free(SCSIRequest *req); void scsi_req_free(SCSIRequest *req);
SCSIRequest *scsi_req_ref(SCSIRequest *req); SCSIRequest *scsi_req_ref(SCSIRequest *req);

View File

@ -121,7 +121,7 @@ static struct vscsi_req *vscsi_get_req(VSCSIState *s)
return NULL; return NULL;
} }
static void vscsi_put_req(VSCSIState *s, vscsi_req *req) static void vscsi_put_req(vscsi_req *req)
{ {
if (req->sreq != NULL) { if (req->sreq != NULL) {
scsi_req_unref(req->sreq); scsi_req_unref(req->sreq);
@ -130,15 +130,6 @@ static void vscsi_put_req(VSCSIState *s, vscsi_req *req)
req->active = 0; req->active = 0;
} }
static vscsi_req *vscsi_find_req(VSCSIState *s, SCSIRequest *req)
{
uint32_t tag = req->tag;
if (tag >= VSCSI_REQ_LIMIT || !s->reqs[tag].active) {
return NULL;
}
return &s->reqs[tag];
}
static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun) static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun)
{ {
/* XXX Figure that one out properly ! This is crackpot */ /* XXX Figure that one out properly ! This is crackpot */
@ -454,7 +445,7 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
if (n) { if (n) {
req->senselen = n; req->senselen = n;
vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
vscsi_put_req(s, req); vscsi_put_req(req);
return; return;
} }
@ -483,7 +474,7 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
{ {
VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
vscsi_req *req = vscsi_find_req(s, sreq); vscsi_req *req = sreq->hba_private;
uint8_t *buf; uint8_t *buf;
int rc = 0; int rc = 0;
@ -531,7 +522,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status) static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
{ {
VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
vscsi_req *req = vscsi_find_req(s, sreq); vscsi_req *req = sreq->hba_private;
int32_t res_in = 0, res_out = 0; int32_t res_in = 0, res_out = 0;
dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n", dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n",
@ -563,15 +554,14 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
} }
} }
vscsi_send_rsp(s, req, 0, res_in, res_out); vscsi_send_rsp(s, req, 0, res_in, res_out);
vscsi_put_req(s, req); vscsi_put_req(req);
} }
static void vscsi_request_cancelled(SCSIRequest *sreq) static void vscsi_request_cancelled(SCSIRequest *sreq)
{ {
VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); vscsi_req *req = sreq->hba_private;
vscsi_req *req = vscsi_find_req(s, sreq);
vscsi_put_req(s, req); vscsi_put_req(req);
} }
static void vscsi_process_login(VSCSIState *s, vscsi_req *req) static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
@ -659,7 +649,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
} }
req->lun = lun; req->lun = lun;
req->sreq = scsi_req_new(sdev, req->qtag, lun); req->sreq = scsi_req_new(sdev, req->qtag, lun, req);
n = scsi_req_enqueue(req->sreq, srp->cmd.cdb); n = scsi_req_enqueue(req->sreq, srp->cmd.cdb);
dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n", dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n",
@ -858,7 +848,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
} }
if (done) { if (done) {
vscsi_put_req(s, req); vscsi_put_req(req);
} }
} }

View File

@ -216,10 +216,6 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet; USBPacket *p = s->packet;
if (req->tag != s->tag) {
fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag);
}
assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV)); assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
s->scsi_len = len; s->scsi_len = len;
s->scsi_buf = scsi_req_get_buf(req); s->scsi_buf = scsi_req_get_buf(req);
@ -241,9 +237,6 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet; USBPacket *p = s->packet;
if (req->tag != s->tag) {
fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag);
}
DPRINTF("Command complete %d\n", status); DPRINTF("Command complete %d\n", status);
s->residue = s->data_len; s->residue = s->data_len;
s->result = status != 0; s->result = status != 0;
@ -387,7 +380,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
s->tag, cbw.flags, cbw.cmd_len, s->data_len); s->tag, cbw.flags, cbw.cmd_len, s->data_len);
s->residue = 0; s->residue = 0;
s->scsi_len = 0; s->scsi_len = 0;
s->req = scsi_req_new(s->scsi_dev, s->tag, 0); s->req = scsi_req_new(s->scsi_dev, s->tag, 0, NULL);
scsi_req_enqueue(s->req, cbw.cmd); scsi_req_enqueue(s->req, cbw.cmd);
/* ??? Should check that USB and SCSI data transfer /* ??? Should check that USB and SCSI data transfer
directions match. */ directions match. */

View File

@ -657,7 +657,7 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
/* copy in packet. ugh */ /* copy in packet. ugh */
len = iov_from_buf(sg, elem.in_num, len = iov_from_buf(sg, elem.in_num,
buf + offset, size - offset); buf + offset, 0, size - offset);
total += len; total += len;
offset += len; offset += len;
/* If buffers can't be merged, at this point we /* If buffers can't be merged, at this point we

View File

@ -104,7 +104,7 @@ static size_t write_to_port(VirtIOSerialPort *port,
} }
len = iov_from_buf(elem.in_sg, elem.in_num, len = iov_from_buf(elem.in_sg, elem.in_num,
buf + offset, size - offset); buf + offset, 0, size - offset);
offset += len; offset += len;
virtqueue_push(vq, &elem, len); virtqueue_push(vq, &elem, len);

69
iov.c
View File

@ -14,56 +14,61 @@
#include "iov.h" #include "iov.h"
size_t iov_from_buf(struct iovec *iov, unsigned int iovcnt, size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
const void *buf, size_t size) const void *buf, size_t iov_off, size_t size)
{ {
size_t offset; size_t iovec_off, buf_off;
unsigned int i; unsigned int i;
offset = 0; iovec_off = 0;
for (i = 0; offset < size && i < iovcnt; i++) {
size_t len;
len = MIN(iov[i].iov_len, size - offset);
memcpy(iov[i].iov_base, buf + offset, len);
offset += len;
}
return offset;
}
size_t iov_to_buf(const struct iovec *iov, const unsigned int iovcnt,
void *buf, size_t offset, size_t size)
{
uint8_t *ptr;
size_t iov_off, buf_off;
unsigned int i;
ptr = buf;
iov_off = 0;
buf_off = 0; buf_off = 0;
for (i = 0; i < iovcnt && size; i++) { for (i = 0; i < iov_cnt && size; i++) {
if (offset < (iov_off + iov[i].iov_len)) { if (iov_off < (iovec_off + iov[i].iov_len)) {
size_t len = MIN((iov_off + iov[i].iov_len) - offset , size); size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off, size);
memcpy(ptr + buf_off, iov[i].iov_base + (offset - iov_off), len); memcpy(iov[i].iov_base + (iov_off - iovec_off), buf + buf_off, len);
buf_off += len; buf_off += len;
offset += len; iov_off += len;
size -= len; size -= len;
} }
iov_off += iov[i].iov_len; iovec_off += iov[i].iov_len;
} }
return buf_off; return buf_off;
} }
size_t iov_size(const struct iovec *iov, const unsigned int iovcnt) size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
void *buf, size_t iov_off, size_t size)
{
uint8_t *ptr;
size_t iovec_off, buf_off;
unsigned int i;
ptr = buf;
iovec_off = 0;
buf_off = 0;
for (i = 0; i < iov_cnt && size; i++) {
if (iov_off < (iovec_off + iov[i].iov_len)) {
size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size);
memcpy(ptr + buf_off, iov[i].iov_base + (iov_off - iovec_off), len);
buf_off += len;
iov_off += len;
size -= len;
}
iovec_off += iov[i].iov_len;
}
return buf_off;
}
size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
{ {
size_t len; size_t len;
unsigned int i; unsigned int i;
len = 0; len = 0;
for (i = 0; i < iovcnt; i++) { for (i = 0; i < iov_cnt; i++) {
len += iov[i].iov_len; len += iov[i].iov_len;
} }
return len; return len;

10
iov.h
View File

@ -12,8 +12,8 @@
#include "qemu-common.h" #include "qemu-common.h"
size_t iov_from_buf(struct iovec *iov, unsigned int iovcnt, size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
const void *buf, size_t size); const void *buf, size_t iov_off, size_t size);
size_t iov_to_buf(const struct iovec *iov, const unsigned int iovcnt, size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
void *buf, size_t offset, size_t size); void *buf, size_t iov_off, size_t size);
size_t iov_size(const struct iovec *iov, const unsigned int iovcnt); size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);

View File

@ -23,6 +23,7 @@ static QemuOptsList qemu_drive_opts = {
},{ },{
.name = "index", .name = "index",
.type = QEMU_OPT_NUMBER, .type = QEMU_OPT_NUMBER,
.help = "index number",
},{ },{
.name = "cyls", .name = "cyls",
.type = QEMU_OPT_NUMBER, .type = QEMU_OPT_NUMBER,
@ -46,6 +47,7 @@ static QemuOptsList qemu_drive_opts = {
},{ },{
.name = "snapshot", .name = "snapshot",
.type = QEMU_OPT_BOOL, .type = QEMU_OPT_BOOL,
.help = "enable/disable snapshot mode",
},{ },{
.name = "file", .name = "file",
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
@ -65,12 +67,15 @@ static QemuOptsList qemu_drive_opts = {
},{ },{
.name = "serial", .name = "serial",
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
.help = "disk serial number",
},{ },{
.name = "rerror", .name = "rerror",
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
.help = "read error action",
},{ },{
.name = "werror", .name = "werror",
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
.help = "write error action",
},{ },{
.name = "addr", .name = "addr",
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
@ -78,6 +83,7 @@ static QemuOptsList qemu_drive_opts = {
},{ },{
.name = "readonly", .name = "readonly",
.type = QEMU_OPT_BOOL, .type = QEMU_OPT_BOOL,
.help = "open drive file as read-only",
}, },
{ /* end of list */ } { /* end of list */ }
}, },

View File

@ -30,7 +30,7 @@ ETEXI
DEF("convert", img_convert, DEF("convert", img_convert,
"convert [-c] [-p] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename") "convert [-c] [-p] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename")
STEXI STEXI
@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename} @item convert [-c] [-p] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
ETEXI ETEXI
DEF("info", img_info, DEF("info", img_info,
@ -48,7 +48,7 @@ ETEXI
DEF("rebase", img_rebase, DEF("rebase", img_rebase,
"rebase [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename") "rebase [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
STEXI STEXI
@item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} @item rebase [-f @var{fmt}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
ETEXI ETEXI
DEF("resize", img_resize, DEF("resize", img_resize,

View File

@ -1024,35 +1024,6 @@ out:
return 0; return 0;
} }
#ifdef _WIN32
static int64_t get_allocated_file_size(const char *filename)
{
typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
get_compressed_t get_compressed;
struct _stati64 st;
/* WinNT support GetCompressedFileSize to determine allocate size */
get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
if (get_compressed) {
DWORD high, low;
low = get_compressed(filename, &high);
if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
return (((int64_t) high) << 32) + low;
}
if (_stati64(filename, &st) < 0)
return -1;
return st.st_size;
}
#else
static int64_t get_allocated_file_size(const char *filename)
{
struct stat st;
if (stat(filename, &st) < 0)
return -1;
return (int64_t)st.st_blocks * 512;
}
#endif
static void dump_snapshots(BlockDriverState *bs) static void dump_snapshots(BlockDriverState *bs)
{ {
@ -1112,7 +1083,7 @@ static int img_info(int argc, char **argv)
bdrv_get_format(bs, fmt_name, sizeof(fmt_name)); bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
bdrv_get_geometry(bs, &total_sectors); bdrv_get_geometry(bs, &total_sectors);
get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512); get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
allocated_size = get_allocated_file_size(filename); allocated_size = bdrv_get_allocated_file_size(bs);
if (allocated_size < 0) { if (allocated_size < 0) {
snprintf(dsize_buf, sizeof(dsize_buf), "unavailable"); snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
} else { } else {

View File

@ -38,6 +38,8 @@ by the used format or see the format descriptions below for details.
indicates that target image must be compressed (qcow format only) indicates that target image must be compressed (qcow format only)
@item -h @item -h
with or without a command shows help and lists the supported formats with or without a command shows help and lists the supported formats
@item -p
display progress bar (convert and rebase commands only)
@end table @end table
Parameters to snapshot subcommand: Parameters to snapshot subcommand:
@ -84,7 +86,7 @@ it doesn't need to be specified separately in this case.
Commit the changes recorded in @var{filename} in its base image. Commit the changes recorded in @var{filename} in its base image.
@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename} @item convert [-c] [-p] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename} Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename}
using format @var{output_fmt}. It can be optionally compressed (@code{-c} using format @var{output_fmt}. It can be optionally compressed (@code{-c}
@ -114,7 +116,7 @@ they are displayed too.
List, apply, create or delete snapshots in image @var{filename}. List, apply, create or delete snapshots in image @var{filename}.
@item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} @item rebase [-f @var{fmt}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
Changes the backing file of an image. Only the formats @code{qcow2} and Changes the backing file of an image. Only the formats @code{qcow2} and
@code{qed} support changing the backing file. @code{qed} support changing the backing file.

261
qemu-io.c
View File

@ -59,24 +59,26 @@ static void *qemu_io_alloc(size_t len, int pattern)
{ {
void *buf; void *buf;
if (misalign) if (misalign) {
len += MISALIGN_OFFSET; len += MISALIGN_OFFSET;
}
buf = qemu_blockalign(bs, len); buf = qemu_blockalign(bs, len);
memset(buf, pattern, len); memset(buf, pattern, len);
if (misalign) if (misalign) {
buf += MISALIGN_OFFSET; buf += MISALIGN_OFFSET;
}
return buf; return buf;
} }
static void qemu_io_free(void *p) static void qemu_io_free(void *p)
{ {
if (misalign) if (misalign) {
p -= MISALIGN_OFFSET; p -= MISALIGN_OFFSET;
}
qemu_vfree(p); qemu_vfree(p);
} }
static void static void dump_buffer(const void *buffer, int64_t offset, int len)
dump_buffer(const void *buffer, int64_t offset, int len)
{ {
int i, j; int i, j;
const uint8_t *p; const uint8_t *p;
@ -85,21 +87,22 @@ dump_buffer(const void *buffer, int64_t offset, int len)
const uint8_t *s = p; const uint8_t *s = p;
printf("%08" PRIx64 ": ", offset + i); printf("%08" PRIx64 ": ", offset + i);
for (j = 0; j < 16 && i + j < len; j++, p++) for (j = 0; j < 16 && i + j < len; j++, p++) {
printf("%02x ", *p); printf("%02x ", *p);
}
printf(" "); printf(" ");
for (j = 0; j < 16 && i + j < len; j++, s++) { for (j = 0; j < 16 && i + j < len; j++, s++) {
if (isalnum(*s)) if (isalnum(*s)) {
printf("%c", *s); printf("%c", *s);
else } else {
printf("."); printf(".");
} }
}
printf("\n"); printf("\n");
} }
} }
static void static void print_report(const char *op, struct timeval *t, int64_t offset,
print_report(const char *op, struct timeval *t, int64_t offset,
int count, int total, int cnt, int Cflag) int count, int total, int cnt, int Cflag)
{ {
char s1[64], s2[64], ts[64]; char s1[64], s2[64], ts[64];
@ -178,8 +181,9 @@ static int do_read(char *buf, int64_t offset, int count, int *total)
int ret; int ret;
ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9); ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
if (ret < 0) if (ret < 0) {
return ret; return ret;
}
*total = count; *total = count;
return 1; return 1;
} }
@ -189,8 +193,9 @@ static int do_write(char *buf, int64_t offset, int count, int *total)
int ret; int ret;
ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9); ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
if (ret < 0) if (ret < 0) {
return ret; return ret;
}
*total = count; *total = count;
return 1; return 1;
} }
@ -198,32 +203,36 @@ static int do_write(char *buf, int64_t offset, int count, int *total)
static int do_pread(char *buf, int64_t offset, int count, int *total) static int do_pread(char *buf, int64_t offset, int count, int *total)
{ {
*total = bdrv_pread(bs, offset, (uint8_t *)buf, count); *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
if (*total < 0) if (*total < 0) {
return *total; return *total;
}
return 1; return 1;
} }
static int do_pwrite(char *buf, int64_t offset, int count, int *total) static int do_pwrite(char *buf, int64_t offset, int count, int *total)
{ {
*total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
if (*total < 0) if (*total < 0) {
return *total; return *total;
}
return 1; return 1;
} }
static int do_load_vmstate(char *buf, int64_t offset, int count, int *total) static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
{ {
*total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count); *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
if (*total < 0) if (*total < 0) {
return *total; return *total;
}
return 1; return 1;
} }
static int do_save_vmstate(char *buf, int64_t offset, int count, int *total) static int do_save_vmstate(char *buf, int64_t offset, int count, int *total)
{ {
*total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count); *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
if (*total < 0) if (*total < 0) {
return *total; return *total;
}
return 1; return 1;
} }
@ -240,11 +249,12 @@ static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9, acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
aio_rw_done, &async_ret); aio_rw_done, &async_ret);
if (!acb) if (!acb) {
return -EIO; return -EIO;
}
while (async_ret == NOT_DONE) while (async_ret == NOT_DONE) {
qemu_aio_wait(); qemu_aio_wait();
}
*total = qiov->size; *total = qiov->size;
return async_ret < 0 ? async_ret : 1; return async_ret < 0 ? async_ret : 1;
@ -257,11 +267,13 @@ static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9, acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
aio_rw_done, &async_ret); aio_rw_done, &async_ret);
if (!acb) if (!acb) {
return -EIO; return -EIO;
}
while (async_ret == NOT_DONE) while (async_ret == NOT_DONE) {
qemu_aio_wait(); qemu_aio_wait();
}
*total = qiov->size; *total = qiov->size;
return async_ret < 0 ? async_ret : 1; return async_ret < 0 ? async_ret : 1;
@ -309,8 +321,7 @@ static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
return async_ret.error < 0 ? async_ret.error : 1; return async_ret.error < 0 ? async_ret.error : 1;
} }
static void static void read_help(void)
read_help(void)
{ {
printf( printf(
"\n" "\n"
@ -345,8 +356,7 @@ static const cmdinfo_t read_cmd = {
.help = read_help, .help = read_help,
}; };
static int static int read_f(int argc, char **argv)
read_f(int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
@ -381,8 +391,9 @@ read_f(int argc, char **argv)
case 'P': case 'P':
Pflag = 1; Pflag = 1;
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) if (pattern < 0) {
return 0; return 0;
}
break; break;
case 'q': case 'q':
qflag = 1; qflag = 1;
@ -403,8 +414,9 @@ read_f(int argc, char **argv)
} }
} }
if (optind != argc - 2) if (optind != argc - 2) {
return command_usage(&read_cmd); return command_usage(&read_cmd);
}
if (bflag && pflag) { if (bflag && pflag) {
printf("-b and -p cannot be specified at the same time\n"); printf("-b and -p cannot be specified at the same time\n");
@ -437,12 +449,12 @@ read_f(int argc, char **argv)
return 0; return 0;
} }
if (!pflag) if (!pflag) {
if (offset & 0x1ff) { if (offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n", printf("offset %" PRId64 " is not sector aligned\n",
offset); offset);
return 0; return 0;
}
if (count & 0x1ff) { if (count & 0x1ff) {
printf("count %d is not sector aligned\n", printf("count %d is not sector aligned\n",
count); count);
@ -453,12 +465,13 @@ read_f(int argc, char **argv)
buf = qemu_io_alloc(count, 0xab); buf = qemu_io_alloc(count, 0xab);
gettimeofday(&t1, NULL); gettimeofday(&t1, NULL);
if (pflag) if (pflag) {
cnt = do_pread(buf, offset, count, &total); cnt = do_pread(buf, offset, count, &total);
else if (bflag) } else if (bflag) {
cnt = do_load_vmstate(buf, offset, count, &total); cnt = do_load_vmstate(buf, offset, count, &total);
else } else {
cnt = do_read(buf, offset, count, &total); cnt = do_read(buf, offset, count, &total);
}
gettimeofday(&t2, NULL); gettimeofday(&t2, NULL);
if (cnt < 0) { if (cnt < 0) {
@ -467,7 +480,7 @@ read_f(int argc, char **argv)
} }
if (Pflag) { if (Pflag) {
void* cmp_buf = malloc(pattern_count); void *cmp_buf = malloc(pattern_count);
memset(cmp_buf, pattern, pattern_count); memset(cmp_buf, pattern, pattern_count);
if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
printf("Pattern verification failed at offset %" printf("Pattern verification failed at offset %"
@ -477,11 +490,13 @@ read_f(int argc, char **argv)
free(cmp_buf); free(cmp_buf);
} }
if (qflag) if (qflag) {
goto out; goto out;
}
if (vflag) if (vflag) {
dump_buffer(buf, offset, count); dump_buffer(buf, offset, count);
}
/* Finally, report back -- -C gives a parsable format */ /* Finally, report back -- -C gives a parsable format */
t2 = tsub(t2, t1); t2 = tsub(t2, t1);
@ -493,8 +508,7 @@ out:
return 0; return 0;
} }
static void static void readv_help(void)
readv_help(void)
{ {
printf( printf(
"\n" "\n"
@ -525,8 +539,7 @@ static const cmdinfo_t readv_cmd = {
.help = readv_help, .help = readv_help,
}; };
static int static int readv_f(int argc, char **argv)
readv_f(int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0, vflag = 0; int Cflag = 0, qflag = 0, vflag = 0;
@ -548,8 +561,9 @@ readv_f(int argc, char **argv)
case 'P': case 'P':
Pflag = 1; Pflag = 1;
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) if (pattern < 0) {
return 0; return 0;
}
break; break;
case 'q': case 'q':
qflag = 1; qflag = 1;
@ -562,8 +576,9 @@ readv_f(int argc, char **argv)
} }
} }
if (optind > argc - 2) if (optind > argc - 2) {
return command_usage(&readv_cmd); return command_usage(&readv_cmd);
}
offset = cvtnum(argv[optind]); offset = cvtnum(argv[optind]);
@ -592,21 +607,22 @@ readv_f(int argc, char **argv)
} }
if (Pflag) { if (Pflag) {
void* cmp_buf = malloc(qiov.size); void *cmp_buf = malloc(qiov.size);
memset(cmp_buf, pattern, qiov.size); memset(cmp_buf, pattern, qiov.size);
if (memcmp(buf, cmp_buf, qiov.size)) { if (memcmp(buf, cmp_buf, qiov.size)) {
printf("Pattern verification failed at offset %" printf("Pattern verification failed at offset %"
PRId64 ", %zd bytes\n", PRId64 ", %zd bytes\n", offset, qiov.size);
offset, qiov.size);
} }
free(cmp_buf); free(cmp_buf);
} }
if (qflag) if (qflag) {
goto out; goto out;
}
if (vflag) if (vflag) {
dump_buffer(buf, offset, qiov.size); dump_buffer(buf, offset, qiov.size);
}
/* Finally, report back -- -C gives a parsable format */ /* Finally, report back -- -C gives a parsable format */
t2 = tsub(t2, t1); t2 = tsub(t2, t1);
@ -617,8 +633,7 @@ out:
return 0; return 0;
} }
static void static void write_help(void)
write_help(void)
{ {
printf( printf(
"\n" "\n"
@ -650,8 +665,7 @@ static const cmdinfo_t write_cmd = {
.help = write_help, .help = write_help,
}; };
static int static int write_f(int argc, char **argv)
write_f(int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, pflag = 0, qflag = 0, bflag = 0; int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
@ -676,8 +690,9 @@ write_f(int argc, char **argv)
break; break;
case 'P': case 'P':
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) if (pattern < 0) {
return 0; return 0;
}
break; break;
case 'q': case 'q':
qflag = 1; qflag = 1;
@ -687,8 +702,9 @@ write_f(int argc, char **argv)
} }
} }
if (optind != argc - 2) if (optind != argc - 2) {
return command_usage(&write_cmd); return command_usage(&write_cmd);
}
if (bflag && pflag) { if (bflag && pflag) {
printf("-b and -p cannot be specified at the same time\n"); printf("-b and -p cannot be specified at the same time\n");
@ -725,12 +741,13 @@ write_f(int argc, char **argv)
buf = qemu_io_alloc(count, pattern); buf = qemu_io_alloc(count, pattern);
gettimeofday(&t1, NULL); gettimeofday(&t1, NULL);
if (pflag) if (pflag) {
cnt = do_pwrite(buf, offset, count, &total); cnt = do_pwrite(buf, offset, count, &total);
else if (bflag) } else if (bflag) {
cnt = do_save_vmstate(buf, offset, count, &total); cnt = do_save_vmstate(buf, offset, count, &total);
else } else {
cnt = do_write(buf, offset, count, &total); cnt = do_write(buf, offset, count, &total);
}
gettimeofday(&t2, NULL); gettimeofday(&t2, NULL);
if (cnt < 0) { if (cnt < 0) {
@ -738,8 +755,9 @@ write_f(int argc, char **argv)
goto out; goto out;
} }
if (qflag) if (qflag) {
goto out; goto out;
}
/* Finally, report back -- -C gives a parsable format */ /* Finally, report back -- -C gives a parsable format */
t2 = tsub(t2, t1); t2 = tsub(t2, t1);
@ -781,8 +799,7 @@ static const cmdinfo_t writev_cmd = {
.help = writev_help, .help = writev_help,
}; };
static int static int writev_f(int argc, char **argv)
writev_f(int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0; int Cflag = 0, qflag = 0;
@ -805,16 +822,18 @@ writev_f(int argc, char **argv)
break; break;
case 'P': case 'P':
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) if (pattern < 0) {
return 0; return 0;
}
break; break;
default: default:
return command_usage(&writev_cmd); return command_usage(&writev_cmd);
} }
} }
if (optind > argc - 2) if (optind > argc - 2) {
return command_usage(&writev_cmd); return command_usage(&writev_cmd);
}
offset = cvtnum(argv[optind]); offset = cvtnum(argv[optind]);
if (offset < 0) { if (offset < 0) {
@ -841,8 +860,9 @@ writev_f(int argc, char **argv)
goto out; goto out;
} }
if (qflag) if (qflag) {
goto out; goto out;
}
/* Finally, report back -- -C gives a parsable format */ /* Finally, report back -- -C gives a parsable format */
t2 = tsub(t2, t1); t2 = tsub(t2, t1);
@ -852,8 +872,7 @@ out:
return 0; return 0;
} }
static void static void multiwrite_help(void)
multiwrite_help(void)
{ {
printf( printf(
"\n" "\n"
@ -885,8 +904,7 @@ static const cmdinfo_t multiwrite_cmd = {
.help = multiwrite_help, .help = multiwrite_help,
}; };
static int static int multiwrite_f(int argc, char **argv)
multiwrite_f(int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0; int Cflag = 0, qflag = 0;
@ -912,16 +930,18 @@ multiwrite_f(int argc, char **argv)
break; break;
case 'P': case 'P':
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) if (pattern < 0) {
return 0; return 0;
}
break; break;
default: default:
return command_usage(&writev_cmd); return command_usage(&writev_cmd);
} }
} }
if (optind > argc - 2) if (optind > argc - 2) {
return command_usage(&writev_cmd); return command_usage(&writev_cmd);
}
nr_reqs = 1; nr_reqs = 1;
for (i = optind; i < argc; i++) { for (i = optind; i < argc; i++) {
@ -985,8 +1005,9 @@ multiwrite_f(int argc, char **argv)
goto out; goto out;
} }
if (qflag) if (qflag) {
goto out; goto out;
}
/* Finally, report back -- -C gives a parsable format */ /* Finally, report back -- -C gives a parsable format */
t2 = tsub(t2, t1); t2 = tsub(t2, t1);
@ -1014,8 +1035,7 @@ struct aio_ctx {
struct timeval t1; struct timeval t1;
}; };
static void static void aio_write_done(void *opaque, int ret)
aio_write_done(void *opaque, int ret)
{ {
struct aio_ctx *ctx = opaque; struct aio_ctx *ctx = opaque;
struct timeval t2; struct timeval t2;
@ -1041,8 +1061,7 @@ out:
free(ctx); free(ctx);
} }
static void static void aio_read_done(void *opaque, int ret)
aio_read_done(void *opaque, int ret)
{ {
struct aio_ctx *ctx = opaque; struct aio_ctx *ctx = opaque;
struct timeval t2; struct timeval t2;
@ -1060,8 +1079,7 @@ aio_read_done(void *opaque, int ret)
memset(cmp_buf, ctx->pattern, ctx->qiov.size); memset(cmp_buf, ctx->pattern, ctx->qiov.size);
if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) { if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
printf("Pattern verification failed at offset %" printf("Pattern verification failed at offset %"
PRId64 ", %zd bytes\n", PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
ctx->offset, ctx->qiov.size);
} }
free(cmp_buf); free(cmp_buf);
} }
@ -1083,8 +1101,7 @@ out:
free(ctx); free(ctx);
} }
static void static void aio_read_help(void)
aio_read_help(void)
{ {
printf( printf(
"\n" "\n"
@ -1116,8 +1133,7 @@ static const cmdinfo_t aio_read_cmd = {
.help = aio_read_help, .help = aio_read_help,
}; };
static int static int aio_read_f(int argc, char **argv)
aio_read_f(int argc, char **argv)
{ {
int nr_iov, c; int nr_iov, c;
struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx)); struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
@ -1183,12 +1199,11 @@ aio_read_f(int argc, char **argv)
return 0; return 0;
} }
static void static void aio_write_help(void)
aio_write_help(void)
{ {
printf( printf(
"\n" "\n"
" asynchronously writes a range of bytes from the given offset source \n" " asynchronously writes a range of bytes from the given offset source\n"
" from multiple buffers\n" " from multiple buffers\n"
"\n" "\n"
" Example:\n" " Example:\n"
@ -1216,8 +1231,7 @@ static const cmdinfo_t aio_write_cmd = {
.help = aio_write_help, .help = aio_write_help,
}; };
static int static int aio_write_f(int argc, char **argv)
aio_write_f(int argc, char **argv)
{ {
int nr_iov, c; int nr_iov, c;
int pattern = 0xcd; int pattern = 0xcd;
@ -1234,8 +1248,9 @@ aio_write_f(int argc, char **argv)
break; break;
case 'P': case 'P':
pattern = parse_pattern(optarg); pattern = parse_pattern(optarg);
if (pattern < 0) if (pattern < 0) {
return 0; return 0;
}
break; break;
default: default:
free(ctx); free(ctx);
@ -1278,8 +1293,7 @@ aio_write_f(int argc, char **argv)
return 0; return 0;
} }
static int static int aio_flush_f(int argc, char **argv)
aio_flush_f(int argc, char **argv)
{ {
qemu_aio_flush(); qemu_aio_flush();
return 0; return 0;
@ -1291,8 +1305,7 @@ static const cmdinfo_t aio_flush_cmd = {
.oneline = "completes all outstanding aio requests" .oneline = "completes all outstanding aio requests"
}; };
static int static int flush_f(int argc, char **argv)
flush_f(int argc, char **argv)
{ {
bdrv_flush(bs); bdrv_flush(bs);
return 0; return 0;
@ -1305,8 +1318,7 @@ static const cmdinfo_t flush_cmd = {
.oneline = "flush all in-core file state to disk", .oneline = "flush all in-core file state to disk",
}; };
static int static int truncate_f(int argc, char **argv)
truncate_f(int argc, char **argv)
{ {
int64_t offset; int64_t offset;
int ret; int ret;
@ -1336,8 +1348,7 @@ static const cmdinfo_t truncate_cmd = {
.oneline = "truncates the current file at the given offset", .oneline = "truncates the current file at the given offset",
}; };
static int static int length_f(int argc, char **argv)
length_f(int argc, char **argv)
{ {
int64_t size; int64_t size;
char s1[64]; char s1[64];
@ -1362,21 +1373,23 @@ static const cmdinfo_t length_cmd = {
}; };
static int static int info_f(int argc, char **argv)
info_f(int argc, char **argv)
{ {
BlockDriverInfo bdi; BlockDriverInfo bdi;
char s1[64], s2[64]; char s1[64], s2[64];
int ret; int ret;
if (bs->drv && bs->drv->format_name) if (bs->drv && bs->drv->format_name) {
printf("format name: %s\n", bs->drv->format_name); printf("format name: %s\n", bs->drv->format_name);
if (bs->drv && bs->drv->protocol_name) }
if (bs->drv && bs->drv->protocol_name) {
printf("format name: %s\n", bs->drv->protocol_name); printf("format name: %s\n", bs->drv->protocol_name);
}
ret = bdrv_get_info(bs, &bdi); ret = bdrv_get_info(bs, &bdi);
if (ret) if (ret) {
return 0; return 0;
}
cvtstr(bdi.cluster_size, s1, sizeof(s1)); cvtstr(bdi.cluster_size, s1, sizeof(s1));
cvtstr(bdi.vm_state_offset, s2, sizeof(s2)); cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
@ -1396,8 +1409,7 @@ static const cmdinfo_t info_cmd = {
.oneline = "prints information about the current file", .oneline = "prints information about the current file",
}; };
static void static void discard_help(void)
discard_help(void)
{ {
printf( printf(
"\n" "\n"
@ -1425,8 +1437,7 @@ static const cmdinfo_t discard_cmd = {
.help = discard_help, .help = discard_help,
}; };
static int static int discard_f(int argc, char **argv)
discard_f(int argc, char **argv)
{ {
struct timeval t1, t2; struct timeval t1, t2;
int Cflag = 0, qflag = 0; int Cflag = 0, qflag = 0;
@ -1465,7 +1476,8 @@ discard_f(int argc, char **argv)
} }
gettimeofday(&t1, NULL); gettimeofday(&t1, NULL);
ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS, count >> BDRV_SECTOR_BITS); ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS,
count >> BDRV_SECTOR_BITS);
gettimeofday(&t2, NULL); gettimeofday(&t2, NULL);
if (ret < 0) { if (ret < 0) {
@ -1483,8 +1495,7 @@ out:
return 0; return 0;
} }
static int static int alloc_f(int argc, char **argv)
alloc_f(int argc, char **argv)
{ {
int64_t offset; int64_t offset;
int nb_sectors, remaining; int nb_sectors, remaining;
@ -1499,10 +1510,11 @@ alloc_f(int argc, char **argv)
return 0; return 0;
} }
if (argc == 3) if (argc == 3) {
nb_sectors = cvtnum(argv[2]); nb_sectors = cvtnum(argv[2]);
else } else {
nb_sectors = 1; nb_sectors = 1;
}
remaining = nb_sectors; remaining = nb_sectors;
sum_alloc = 0; sum_alloc = 0;
@ -1531,8 +1543,7 @@ static const cmdinfo_t alloc_cmd = {
.oneline = "checks if a sector is present in the file", .oneline = "checks if a sector is present in the file",
}; };
static int static int map_f(int argc, char **argv)
map_f(int argc, char **argv)
{ {
int64_t offset; int64_t offset;
int64_t nb_sectors; int64_t nb_sectors;
@ -1554,7 +1565,7 @@ map_f(int argc, char **argv)
offset += num; offset += num;
nb_sectors -= num; nb_sectors -= num;
} while(offset < bs->total_sectors); } while (offset < bs->total_sectors);
return 0; return 0;
} }
@ -1569,8 +1580,7 @@ static const cmdinfo_t map_cmd = {
}; };
static int static int close_f(int argc, char **argv)
close_f(int argc, char **argv)
{ {
bdrv_close(bs); bdrv_close(bs);
bs = NULL; bs = NULL;
@ -1609,8 +1619,7 @@ static int openfile(char *name, int flags, int growable)
return 0; return 0;
} }
static void static void open_help(void)
open_help(void)
{ {
printf( printf(
"\n" "\n"
@ -1641,8 +1650,7 @@ static const cmdinfo_t open_cmd = {
.help = open_help, .help = open_help,
}; };
static int static int open_f(int argc, char **argv)
open_f(int argc, char **argv)
{ {
int flags = 0; int flags = 0;
int readonly = 0; int readonly = 0;
@ -1672,28 +1680,27 @@ open_f(int argc, char **argv)
flags |= BDRV_O_RDWR; flags |= BDRV_O_RDWR;
} }
if (optind != argc - 1) if (optind != argc - 1) {
return command_usage(&open_cmd); return command_usage(&open_cmd);
}
return openfile(argv[optind], flags, growable); return openfile(argv[optind], flags, growable);
} }
static int static int init_args_command(int index)
init_args_command(
int index)
{ {
/* only one device allowed so far */ /* only one device allowed so far */
if (index >= 1) if (index >= 1) {
return 0; return 0;
}
return ++index; return ++index;
} }
static int static int init_check_command(const cmdinfo_t *ct)
init_check_command(
const cmdinfo_t *ct)
{ {
if (ct->flags & CMD_FLAG_GLOBAL) if (ct->flags & CMD_FLAG_GLOBAL) {
return 1; return 1;
}
if (!(ct->flags & CMD_NOFILE_OK) && !bs) { if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
fprintf(stderr, "no file open, try 'help open'\n"); fprintf(stderr, "no file open, try 'help open'\n");
return 0; return 0;
@ -1816,8 +1823,9 @@ int main(int argc, char **argv)
flags |= BDRV_O_RDWR; flags |= BDRV_O_RDWR;
} }
if ((argc - optind) == 1) if ((argc - optind) == 1) {
openfile(argv[optind], flags, growable); openfile(argv[optind], flags, growable);
}
command_loop(); command_loop();
/* /*
@ -1825,7 +1833,8 @@ int main(int argc, char **argv)
*/ */
qemu_aio_flush(); qemu_aio_flush();
if (bs) if (bs) {
bdrv_close(bs); bdrv_close(bs);
}
return 0; return 0;
} }

View File

@ -160,6 +160,14 @@ an untrusted format header.
This option specifies the serial number to assign to the device. This option specifies the serial number to assign to the device.
@item addr=@var{addr} @item addr=@var{addr}
Specify the controller's PCI address (if=virtio only). Specify the controller's PCI address (if=virtio only).
@item werror=@var{action},rerror=@var{action}
Specify which @var{action} to take on write and read errors. Valid actions are:
"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
"report" (report the error to the guest), "enospc" (pause QEMU only if the
host disk is full; report the error to the guest otherwise).
The default setting is @option{werror=enospc} and @option{rerror=report}.
@item readonly
Open drive @option{file} as read-only. Guest write attempts will fail.
@end table @end table
By default, writethrough caching is used for all block device. This means that By default, writethrough caching is used for all block device. This means that