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

This commit is contained in:
Anthony Liguori 2010-09-08 14:26:57 -05:00
commit aab2e8f79a
22 changed files with 428 additions and 135 deletions

13
block.c
View File

@ -745,6 +745,7 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res)
int bdrv_commit(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
BlockDriver *backing_drv;
int64_t sector, total_sectors;
int n, ro, open_flags;
int ret = 0, rw_ret = 0;
@ -762,7 +763,8 @@ int bdrv_commit(BlockDriverState *bs)
if (bs->backing_hd->keep_read_only) {
return -EACCES;
}
backing_drv = bs->backing_hd->drv;
ro = bs->backing_hd->read_only;
strncpy(filename, bs->backing_hd->filename, sizeof(filename));
open_flags = bs->backing_hd->open_flags;
@ -772,12 +774,14 @@ int bdrv_commit(BlockDriverState *bs)
bdrv_delete(bs->backing_hd);
bs->backing_hd = NULL;
bs_rw = bdrv_new("");
rw_ret = bdrv_open(bs_rw, filename, open_flags | BDRV_O_RDWR, drv);
rw_ret = bdrv_open(bs_rw, filename, open_flags | BDRV_O_RDWR,
backing_drv);
if (rw_ret < 0) {
bdrv_delete(bs_rw);
/* try to re-open read-only */
bs_ro = bdrv_new("");
ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR, drv);
ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR,
backing_drv);
if (ret < 0) {
bdrv_delete(bs_ro);
/* drive not functional anymore */
@ -828,7 +832,8 @@ ro_cleanup:
bdrv_delete(bs->backing_hd);
bs->backing_hd = NULL;
bs_ro = bdrv_new("");
ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR, drv);
ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR,
backing_drv);
if (ret < 0) {
bdrv_delete(bs_ro);
/* drive not functional anymore */

View File

@ -35,7 +35,7 @@ typedef struct QEMUSnapshotInfo {
#define BDRV_O_NO_BACKING 0x0100 /* don't open the backing file */
#define BDRV_O_NO_FLUSH 0x0200 /* disable flushing on this disk */
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB)
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
#define BDRV_SECTOR_BITS 9
#define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS)

View File

@ -33,6 +33,8 @@
#include <sys/types.h>
#include <unistd.h>
#define EN_OPTSTR ":exportname="
typedef struct BDRVNBDState {
int sock;
off_t size;
@ -42,55 +44,83 @@ typedef struct BDRVNBDState {
static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
{
BDRVNBDState *s = bs->opaque;
uint32_t nbdflags;
char *file;
char *name;
const char *host;
const char *unixpath;
int sock;
off_t size;
size_t blocksize;
int ret;
int err = -EINVAL;
if (!strstart(filename, "nbd:", &host))
return -EINVAL;
file = qemu_strdup(filename);
name = strstr(file, EN_OPTSTR);
if (name) {
if (name[strlen(EN_OPTSTR)] == 0) {
goto out;
}
name[0] = 0;
name += strlen(EN_OPTSTR);
}
if (!strstart(file, "nbd:", &host)) {
goto out;
}
if (strstart(host, "unix:", &unixpath)) {
if (unixpath[0] != '/')
return -EINVAL;
if (unixpath[0] != '/') {
goto out;
}
sock = unix_socket_outgoing(unixpath);
} else {
uint16_t port;
uint16_t port = NBD_DEFAULT_PORT;
char *p, *r;
char hostname[128];
pstrcpy(hostname, 128, host);
p = strchr(hostname, ':');
if (p == NULL)
return -EINVAL;
if (p != NULL) {
*p = '\0';
p++;
*p = '\0';
p++;
port = strtol(p, &r, 0);
if (r == p) {
goto out;
}
} else if (name == NULL) {
goto out;
}
port = strtol(p, &r, 0);
if (r == p)
return -EINVAL;
sock = tcp_socket_outgoing(hostname, port);
}
if (sock == -1)
return -errno;
if (sock == -1) {
err = -errno;
goto out;
}
ret = nbd_receive_negotiate(sock, &size, &blocksize);
if (ret == -1)
return -errno;
ret = nbd_receive_negotiate(sock, name, &nbdflags, &size, &blocksize);
if (ret == -1) {
err = -errno;
goto out;
}
s->sock = sock;
s->size = size;
s->blocksize = blocksize;
err = 0;
return 0;
out:
qemu_free(file);
return err;
}
static int nbd_read(BlockDriverState *bs, int64_t sector_num,

View File

@ -655,7 +655,7 @@ static int write_l2_entries(BlockDriverState *bs, uint64_t *l2_table,
int ret;
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
ret = bdrv_pwrite_sync(bs->file, l2_offset + start_offset,
ret = bdrv_pwrite(bs->file, l2_offset + start_offset,
&l2_table[l2_start_index], len);
if (ret < 0) {
return ret;
@ -718,9 +718,17 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
goto err;
}
for (i = 0; i < j; i++)
qcow2_free_any_clusters(bs,
be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1);
/*
* If this was a COW, we need to decrease the refcount of the old cluster.
* Also flush bs->file to get the right order for L2 and refcount update.
*/
if (j != 0) {
bdrv_flush(bs->file);
for (i = 0; i < j; i++) {
qcow2_free_any_clusters(bs,
be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1);
}
}
ret = 0;
err:

View File

@ -48,6 +48,7 @@
#endif
#ifdef __linux__
#include <sys/ioctl.h>
#include <sys/param.h>
#include <linux/cdrom.h>
#include <linux/fd.h>
#endif
@ -868,8 +869,13 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
s->type = FTYPE_FILE;
#if defined(__linux__)
if (strstart(filename, "/dev/sg", NULL)) {
bs->sg = 1;
{
char resolved_path[ MAXPATHLEN ], *temp;
temp = realpath(filename, resolved_path);
if (temp && strstart(temp, "/dev/sg", NULL)) {
bs->sg = 1;
}
}
#endif
@ -1154,9 +1160,6 @@ static int cdrom_probe_device(const char *filename)
int fd, ret;
int prio = 0;
if (strstart(filename, "/dev/cd", NULL))
prio = 50;
fd = open(filename, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
goto out;

View File

@ -8,16 +8,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <netdb.h>
#include <netinet/tcp.h>
#define closesocket(s) close(s)
#endif
#include "qemu-common.h"
#include "qemu-error.h"

View File

@ -512,7 +512,7 @@ static inline uint8_t fat_chksum(const direntry_t* entry)
for(i=0;i<11;i++) {
unsigned char c;
c = (i <= 8) ? entry->name[i] : entry->extension[i-8];
c = (i < 8) ? entry->name[i] : entry->extension[i-8];
chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
}

View File

@ -139,6 +139,7 @@ static void ide_identify(IDEState *s)
put_le16(p + 61, s->nb_sectors >> 16);
put_le16(p + 62, 0x07); /* single word dma0-2 supported */
put_le16(p + 63, 0x07); /* mdma0-2 supported */
put_le16(p + 64, 0x03); /* pio3-4 supported */
put_le16(p + 65, 120);
put_le16(p + 66, 120);
put_le16(p + 67, 120);
@ -199,13 +200,12 @@ static void ide_atapi_identify(IDEState *s)
put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */
put_le16(p + 62, 7); /* single word dma0-2 supported */
put_le16(p + 63, 7); /* mdma0-2 supported */
put_le16(p + 64, 0x3f); /* PIO modes supported */
#else
put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
put_le16(p + 64, 1); /* PIO modes */
#endif
put_le16(p + 64, 3); /* pio3-4 supported */
put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */

View File

@ -600,7 +600,7 @@ static void lsi_queue_command(LSIState *s)
{
lsi_request *p = s->current;
DPRINTF("Queueing tag=0x%x\n", s->current_tag);
DPRINTF("Queueing tag=0x%x\n", p->tag);
assert(s->current != NULL);
assert(s->current->dma_len == 0);
QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
@ -880,7 +880,7 @@ static void lsi_do_msgout(LSIState *s)
break;
case 0x20: /* SIMPLE queue */
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff);
DPRINTF("SIMPLE queue tag=0x%x\n", s->select_tag & 0xff);
break;
case 0x21: /* HEAD of queue */
BADF("HEAD queue not implemented\n");

View File

@ -135,7 +135,7 @@ static void scsi_read_complete(void * opaque, int ret)
scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
return;
}
DPRINTF("Data ready tag=0x%x len=%" PRId64 "\n", r->req.tag, r->iov.iov_len);
DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
}
@ -155,7 +155,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
return;
}
if (r->sector_count == (uint32_t)-1) {
DPRINTF("Read buf_len=%" PRId64 "\n", r->iov.iov_len);
DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
r->sector_count = 0;
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
return;
@ -486,16 +486,26 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
return buflen;
}
static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
int page_control)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
BlockDriverState *bdrv = s->bs;
int cylinders, heads, secs;
/*
* If Changeable Values are requested, a mask denoting those mode parameters
* that are changeable shall be returned. As we currently don't support
* parameter changes via MODE_SELECT all bits are returned set to zero.
* The buffer was already menset to zero by the caller of this function.
*/
switch (page) {
case 4: /* Rigid disk device geometry page. */
p[0] = 4;
p[1] = 0x16;
if (page_control == 1) { /* Changeable Values */
return p[1] + 2;
}
/* if a geometry hint is available, use it */
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
p[2] = (cylinders >> 16) & 0xff;
@ -520,11 +530,14 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
/* Medium rotation rate [rpm], 5400 rpm */
p[20] = (5400 >> 8) & 0xff;
p[21] = 5400 & 0xff;
return 0x16;
return p[1] + 2;
case 5: /* Flexible disk device geometry page. */
p[0] = 5;
p[1] = 0x1e;
if (page_control == 1) { /* Changeable Values */
return p[1] + 2;
}
/* Transfer rate [kbit/s], 5Mbit/s */
p[2] = 5000 >> 8;
p[3] = 5000 & 0xff;
@ -556,21 +569,27 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
/* Medium rotation rate [rpm], 5400 rpm */
p[28] = (5400 >> 8) & 0xff;
p[29] = 5400 & 0xff;
return 0x1e;
return p[1] + 2;
case 8: /* Caching page. */
p[0] = 8;
p[1] = 0x12;
if (page_control == 1) { /* Changeable Values */
return p[1] + 2;
}
if (bdrv_enable_write_cache(s->bs)) {
p[2] = 4; /* WCE */
}
return 20;
return p[1] + 2;
case 0x2a: /* CD Capabilities and Mechanical Status page. */
if (bdrv_get_type_hint(bdrv) != BDRV_TYPE_CDROM)
return 0;
p[0] = 0x2a;
p[1] = 0x14;
if (page_control == 1) { /* Changeable Values */
return p[1] + 2;
}
p[2] = 3; // CD-R & CD-RW read
p[3] = 0; // Writing not supported
p[4] = 0x7f; /* Audio, composite, digital out,
@ -594,7 +613,7 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
p[19] = (16 * 176) & 0xff;
p[20] = (16 * 176) >> 8; // 16x write speed current
p[21] = (16 * 176) & 0xff;
return 22;
return p[1] + 2;
default:
return 0;
@ -605,29 +624,46 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
uint64_t nb_sectors;
int page, dbd, buflen;
int page, dbd, buflen, page_control;
uint8_t *p;
uint8_t dev_specific_param;
dbd = req->cmd.buf[1] & 0x8;
page = req->cmd.buf[2] & 0x3f;
DPRINTF("Mode Sense (page %d, len %zd)\n", page, req->cmd.xfer);
page_control = (req->cmd.buf[2] & 0xc0) >> 6;
DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
(req->cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, req->cmd.xfer, page_control);
memset(outbuf, 0, req->cmd.xfer);
p = outbuf;
p[1] = 0; /* Default media type. */
p[3] = 0; /* Block descriptor length. */
if (bdrv_is_read_only(s->bs)) {
p[2] = 0x80; /* Readonly. */
dev_specific_param = 0x80; /* Readonly. */
} else {
dev_specific_param = 0x00;
}
if (req->cmd.buf[0] == MODE_SENSE) {
p[1] = 0; /* Default media type. */
p[2] = dev_specific_param;
p[3] = 0; /* Block descriptor length. */
p += 4;
} else { /* MODE_SENSE_10 */
p[2] = 0; /* Default media type. */
p[3] = dev_specific_param;
p[6] = p[7] = 0; /* Block descriptor length. */
p += 8;
}
p += 4;
bdrv_get_geometry(s->bs, &nb_sectors);
if ((~dbd) & nb_sectors) {
outbuf[3] = 8; /* Block descriptor length */
if (!dbd && nb_sectors) {
if (req->cmd.buf[0] == MODE_SENSE) {
outbuf[3] = 8; /* Block descriptor length */
} else { /* MODE_SENSE_10 */
outbuf[7] = 8; /* Block descriptor length */
}
nb_sectors /= s->cluster_size;
nb_sectors--;
if (nb_sectors > 0xffffff)
nb_sectors = 0xffffff;
nb_sectors = 0;
p[0] = 0; /* media density code */
p[1] = (nb_sectors >> 16) & 0xff;
p[2] = (nb_sectors >> 8) & 0xff;
@ -639,21 +675,37 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
p += 8;
}
if (page_control == 3) { /* Saved Values */
return -1; /* ILLEGAL_REQUEST */
}
switch (page) {
case 0x04:
case 0x05:
case 0x08:
case 0x2a:
p += mode_sense_page(req, page, p);
p += mode_sense_page(req, page, p, page_control);
break;
case 0x3f:
p += mode_sense_page(req, 0x08, p);
p += mode_sense_page(req, 0x2a, p);
p += mode_sense_page(req, 0x08, p, page_control);
p += mode_sense_page(req, 0x2a, p, page_control);
break;
default:
return -1; /* ILLEGAL_REQUEST */
}
buflen = p - outbuf;
outbuf[0] = buflen - 4;
/*
* The mode data length field specifies the length in bytes of the
* following data that is available to be transferred. The mode data
* length does not include itself.
*/
if (req->cmd.buf[0] == MODE_SENSE) {
outbuf[0] = buflen - 1;
} else { /* MODE_SENSE_10 */
outbuf[0] = ((buflen - 2) >> 8) & 0xff;
outbuf[1] = (buflen - 2) & 0xff;
}
if (buflen > req->cmd.xfer)
buflen = req->cmd.xfer;
return buflen;
@ -840,6 +892,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
break;
case VERIFY:
break;
case REZERO_UNIT:
DPRINTF("Rezero Unit\n");
if (!bdrv_is_inserted(s->bs)) {
goto not_ready;
}
break;
default:
goto illegal_request;
}
@ -959,6 +1017,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case SERVICE_ACTION_IN:
case REPORT_LUNS:
case VERIFY:
case REZERO_UNIT:
rc = scsi_disk_emulate_command(&r->req, outbuf);
if (rc > 0) {
r->iov.iov_len = rc;
@ -982,13 +1041,40 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case WRITE_10:
case WRITE_12:
case WRITE_16:
DPRINTF("Write (sector %" PRId64 ", count %d)\n", lba, len);
case WRITE_VERIFY:
case WRITE_VERIFY_12:
case WRITE_VERIFY_16:
DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
(command & 0xe) == 0xe ? "And Verify " : "", lba, len);
if (lba > s->max_lba)
goto illegal_lba;
r->sector = lba * s->cluster_size;
r->sector_count = len * s->cluster_size;
is_write = 1;
break;
case MODE_SELECT:
DPRINTF("Mode Select(6) (len %d)\n", len);
/* We don't support mode parameter changes.
Allow the mode parameter header + block descriptors only. */
if (len > 12) {
goto fail;
}
break;
case MODE_SELECT_10:
DPRINTF("Mode Select(10) (len %d)\n", len);
/* We don't support mode parameter changes.
Allow the mode parameter header + block descriptors only. */
if (len > 16) {
goto fail;
}
break;
case SEEK_6:
case SEEK_10:
DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10, lba);
if (lba > s->max_lba) {
goto illegal_lba;
}
break;
default:
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
fail:

View File

@ -164,7 +164,7 @@ static void scsi_read_complete(void * opaque, int ret)
int len;
if (ret) {
DPRINTF("IO error\n");
DPRINTF("IO error ret %d\n", ret);
scsi_command_complete(r, ret);
return;
}
@ -236,7 +236,7 @@ static void scsi_write_complete(void * opaque, int ret)
if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
s->qdev.type == TYPE_TAPE) {
s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
DPRINTF("block size %d\n", s->blocksize);
DPRINTF("block size %d\n", s->qdev.blocksize);
}
scsi_command_complete(r, ret);
@ -351,8 +351,18 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
}
scsi_req_fixup(&r->req);
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag,
cmd[0], r->req.cmd.xfer);
DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
r->req.cmd.xfer, cmd[0]);
#ifdef DEBUG_SCSI
{
int i;
for (i = 1; i < r->req.cmd.len; i++) {
printf(" 0x%02x", cmd[i]);
}
printf("\n");
}
#endif
if (r->req.cmd.xfer == 0) {
if (r->buf != NULL)

View File

@ -481,6 +481,11 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
req->next = s->rq;
s->rq = req;
virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
req->elem.in_num, 1);
virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
req->elem.out_num, 0);
}
return 0;

View File

@ -360,11 +360,26 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
return 0;
}
void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr,
size_t num_sg, int is_write)
{
unsigned int i;
target_phys_addr_t len;
for (i = 0; i < num_sg; i++) {
len = sg[i].iov_len;
sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
if (sg[i].iov_base == NULL || len != sg[i].iov_len) {
fprintf(stderr, "virtio: trying to map MMIO memory\n");
exit(1);
}
}
}
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
{
unsigned int i, head, max;
target_phys_addr_t desc_pa = vq->vring.desc;
target_phys_addr_t len;
if (!virtqueue_num_heads(vq, vq->last_avail_idx))
return 0;
@ -388,29 +403,20 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
i = 0;
}
/* Collect all the descriptors */
do {
struct iovec *sg;
int is_write = 0;
if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
sg = &elem->in_sg[elem->in_num++];
is_write = 1;
} else
} else {
elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
sg = &elem->out_sg[elem->out_num++];
/* Grab the first descriptor, and check it's OK. */
sg->iov_len = vring_desc_len(desc_pa, i);
len = sg->iov_len;
sg->iov_base = cpu_physical_memory_map(vring_desc_addr(desc_pa, i),
&len, is_write);
if (sg->iov_base == NULL || len != sg->iov_len) {
fprintf(stderr, "virtio: trying to map MMIO memory\n");
exit(1);
}
sg->iov_len = vring_desc_len(desc_pa, i);
/* If we've got too many, that implies a descriptor loop. */
if ((elem->in_num + elem->out_num) > max) {
fprintf(stderr, "Looped descriptor");
@ -418,6 +424,10 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
}
} while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
/* Now map what we have collected */
virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0);
elem->index = head;
vq->inuse++;

View File

@ -81,6 +81,7 @@ typedef struct VirtQueueElement
unsigned int out_num;
unsigned int in_num;
target_phys_addr_t in_addr[VIRTQUEUE_MAX_SIZE];
target_phys_addr_t out_addr[VIRTQUEUE_MAX_SIZE];
struct iovec in_sg[VIRTQUEUE_MAX_SIZE];
struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
} VirtQueueElement;
@ -142,6 +143,8 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count);
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
unsigned int len, unsigned int idx);
void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr,
size_t num_sg, int is_write);
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem);
int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes);

118
nbd.c
View File

@ -62,6 +62,8 @@
#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7)
#define NBD_DISCONNECT _IO(0xab, 8)
#define NBD_OPT_EXPORT_NAME (1 << 0)
/* That's all folks */
#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
@ -296,22 +298,27 @@ int nbd_negotiate(int csock, off_t size)
return 0;
}
int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
off_t *size, size_t *blocksize)
{
char buf[8 + 8 + 8 + 128];
uint64_t magic;
char buf[256];
uint64_t magic, s;
uint16_t tmp;
TRACE("Receiving negotation.");
if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
if (read_sync(csock, buf, 8) != 8) {
LOG("read failed");
errno = EINVAL;
return -1;
}
magic = be64_to_cpup((uint64_t*)(buf + 8));
*size = be64_to_cpup((uint64_t*)(buf + 16));
*blocksize = 1024;
buf[8] = '\0';
if (strlen(buf) == 0) {
LOG("server connection closed");
errno = EINVAL;
return -1;
}
TRACE("Magic is %c%c%c%c%c%c%c%c",
qemu_isprint(buf[0]) ? buf[0] : '.',
@ -322,8 +329,6 @@ int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
qemu_isprint(buf[5]) ? buf[5] : '.',
qemu_isprint(buf[6]) ? buf[6] : '.',
qemu_isprint(buf[7]) ? buf[7] : '.');
TRACE("Magic is 0x%" PRIx64, magic);
TRACE("Size is %" PRIu64, *size);
if (memcmp(buf, "NBDMAGIC", 8) != 0) {
LOG("Invalid magic received");
@ -331,10 +336,99 @@ int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
return -1;
}
TRACE("Checking magic");
if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
LOG("read failed");
errno = EINVAL;
return -1;
}
magic = be64_to_cpu(magic);
TRACE("Magic is 0x%" PRIx64, magic);
if (magic != 0x00420281861253LL) {
LOG("Bad magic received");
if (name) {
uint32_t reserved = 0;
uint32_t opt;
uint32_t namesize;
TRACE("Checking magic (opts_magic)");
if (magic != 0x49484156454F5054LL) {
LOG("Bad magic received");
errno = EINVAL;
return -1;
}
if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
LOG("flags read failed");
errno = EINVAL;
return -1;
}
*flags = be16_to_cpu(tmp) << 16;
/* reserved for future use */
if (write_sync(csock, &reserved, sizeof(reserved)) !=
sizeof(reserved)) {
LOG("write failed (reserved)");
errno = EINVAL;
return -1;
}
/* write the export name */
magic = cpu_to_be64(magic);
if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
LOG("write failed (magic)");
errno = EINVAL;
return -1;
}
opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
LOG("write failed (opt)");
errno = EINVAL;
return -1;
}
namesize = cpu_to_be32(strlen(name));
if (write_sync(csock, &namesize, sizeof(namesize)) !=
sizeof(namesize)) {
LOG("write failed (namesize)");
errno = EINVAL;
return -1;
}
if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
LOG("write failed (name)");
errno = EINVAL;
return -1;
}
} else {
TRACE("Checking magic (cli_magic)");
if (magic != 0x00420281861253LL) {
LOG("Bad magic received");
errno = EINVAL;
return -1;
}
}
if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
LOG("read failed");
errno = EINVAL;
return -1;
}
*size = be64_to_cpu(s);
*blocksize = 1024;
TRACE("Size is %" PRIu64, *size);
if (!name) {
if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
LOG("read failed (flags)");
errno = EINVAL;
return -1;
}
*flags = be32_to_cpup(flags);
} else {
if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
LOG("read failed (tmp)");
errno = EINVAL;
return -1;
}
*flags |= be32_to_cpu(tmp);
}
if (read_sync(csock, &buf, 124) != 124) {
LOG("read failed (buf)");
errno = EINVAL;
return -1;
}

5
nbd.h
View File

@ -42,6 +42,8 @@ enum {
NBD_CMD_DISC = 2
};
#define NBD_DEFAULT_PORT 10809
size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
int tcp_socket_outgoing(const char *address, uint16_t port);
int tcp_socket_incoming(const char *address, uint16_t port);
@ -49,7 +51,8 @@ int unix_socket_outgoing(const char *path);
int unix_socket_incoming(const char *path);
int nbd_negotiate(int csock, off_t size);
int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize);
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
off_t *size, size_t *blocksize);
int nbd_init(int fd, int csock, off_t size, size_t blocksize);
int nbd_send_request(int csock, struct nbd_request *request);
int nbd_receive_reply(int csock, struct nbd_reply *reply);

View File

@ -599,6 +599,7 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
acb->aio_type = QEMU_AIO_IOCTL;
acb->aio_fildes = fd;
acb->ev_signo = SIGUSR2;
acb->async_context_id = get_async_context_id();
acb->aio_offset = 0;
acb->aio_ioctl_buf = buf;
acb->aio_ioctl_cmd = req;

View File

@ -620,6 +620,13 @@ qemu linux1.img -hdb nbd:unix:/tmp/my_socket
qemu linux2.img -hdb nbd:unix:/tmp/my_socket
@end example
If the nbd-server uses named exports (since NBD 2.9.18), you must use the
"exportname" option:
@example
qemu -cdrom nbd:localhost:exportname=debian-500-ppc-netinst
qemu -cdrom nbd:localhost:exportname=openSUSE-11.1-ppc-netinst
@end example
@node pcsys_network
@section Network emulation

View File

@ -783,7 +783,8 @@ static int img_convert(int argc, char **argv)
goto out;
}
out_bs = bdrv_new_open(out_filename, out_fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
out_bs = bdrv_new_open(out_filename, out_fmt,
BDRV_O_FLAGS | BDRV_O_RDWR | BDRV_O_NO_FLUSH);
if (!out_bs) {
ret = -1;
goto out;
@ -1286,7 +1287,7 @@ static int img_rebase(int argc, char **argv)
}
bs_new_backing = bdrv_new("new_backing");
ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS | BDRV_O_RDWR,
ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS,
new_backing_drv);
if (ret) {
error("Could not open new backing file '%s'", out_baseimg);

View File

@ -1427,11 +1427,8 @@ alloc_f(int argc, char **argv)
cvtstr(offset, s1, sizeof(s1));
if (nb_sectors == 1)
printf("sector allocated at offset %s\n", s1);
else
printf("%d/%d sectors allocated at offset %s\n",
sum_alloc, nb_sectors, s1);
printf("%d/%d sectors allocated at offset %s\n",
sum_alloc, nb_sectors, s1);
return 0;
}

View File

@ -230,6 +230,7 @@ int main(int argc, char **argv)
int nb_fds = 0;
int max_fd;
int persistent = 0;
uint32_t nbdflags;
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
switch (ch) {
@ -398,7 +399,8 @@ int main(int argc, char **argv)
goto out;
}
ret = nbd_receive_negotiate(sock, &size, &blocksize);
ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
&size, &blocksize);
if (ret == -1) {
ret = 1;
goto out;

View File

@ -1837,8 +1837,10 @@ void do_savevm(Monitor *mon, const QDict *qdict)
uint32_t vm_state_size;
#ifdef _WIN32
struct _timeb tb;
struct tm *ptm;
#else
struct timeval tv;
struct tm tm;
#endif
const char *name = qdict_get_try_str(qdict, "name");
@ -1869,15 +1871,6 @@ void do_savevm(Monitor *mon, const QDict *qdict)
vm_stop(0);
memset(sn, 0, sizeof(*sn));
if (name) {
ret = bdrv_snapshot_find(bs, old_sn, name);
if (ret >= 0) {
pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
} else {
pstrcpy(sn->name, sizeof(sn->name), name);
}
}
/* fill auxiliary fields */
#ifdef _WIN32
@ -1891,6 +1884,24 @@ void do_savevm(Monitor *mon, const QDict *qdict)
#endif
sn->vm_clock_nsec = qemu_get_clock(vm_clock);
if (name) {
ret = bdrv_snapshot_find(bs, old_sn, name);
if (ret >= 0) {
pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
} else {
pstrcpy(sn->name, sizeof(sn->name), name);
}
} else {
#ifdef _WIN32
ptm = localtime(&tb.time);
strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", ptm);
#else
localtime_r(&tv.tv_sec, &tm);
strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", &tm);
#endif
}
/* Delete old snapshots of the same name */
if (name && del_existing_snapshots(mon, name) < 0) {
goto the_end;
@ -2039,8 +2050,10 @@ void do_delvm(Monitor *mon, const QDict *qdict)
void do_info_snapshots(Monitor *mon)
{
BlockDriverState *bs, *bs1;
QEMUSnapshotInfo *sn_tab, *sn;
int nb_sns, i;
QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
int nb_sns, i, ret, available;
int total;
int *available_snapshots;
char buf[256];
bs = bdrv_snapshots();
@ -2048,27 +2061,52 @@ void do_info_snapshots(Monitor *mon)
monitor_printf(mon, "No available block device supports snapshots\n");
return;
}
monitor_printf(mon, "Snapshot devices:");
bs1 = NULL;
while ((bs1 = bdrv_next(bs1))) {
if (bdrv_can_snapshot(bs1)) {
if (bs == bs1)
monitor_printf(mon, " %s", bdrv_get_device_name(bs1));
}
}
monitor_printf(mon, "\n");
nb_sns = bdrv_snapshot_list(bs, &sn_tab);
if (nb_sns < 0) {
monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
return;
}
monitor_printf(mon, "Snapshot list (from %s):\n",
bdrv_get_device_name(bs));
monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
for(i = 0; i < nb_sns; i++) {
sn = &sn_tab[i];
monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
if (nb_sns == 0) {
monitor_printf(mon, "There is no snapshot available.\n");
return;
}
available_snapshots = qemu_mallocz(sizeof(int) * nb_sns);
total = 0;
for (i = 0; i < nb_sns; i++) {
sn = &sn_tab[i];
available = 1;
bs1 = NULL;
while ((bs1 = bdrv_next(bs1))) {
if (bdrv_can_snapshot(bs1) && bs1 != bs) {
ret = bdrv_snapshot_find(bs1, sn_info, sn->id_str);
if (ret < 0) {
available = 0;
break;
}
}
}
if (available) {
available_snapshots[total] = i;
total++;
}
}
if (total > 0) {
monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
for (i = 0; i < total; i++) {
sn = &sn_tab[available_snapshots[i]];
monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
}
} else {
monitor_printf(mon, "There is no suitable snapshot available\n");
}
qemu_free(sn_tab);
qemu_free(available_snapshots);
}