Merge remote branch 'kwolf/for-anthony' into staging
This commit is contained in:
commit
aab2e8f79a
13
block.c
13
block.c
@ -745,6 +745,7 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res)
|
|||||||
int bdrv_commit(BlockDriverState *bs)
|
int bdrv_commit(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
|
BlockDriver *backing_drv;
|
||||||
int64_t sector, total_sectors;
|
int64_t sector, total_sectors;
|
||||||
int n, ro, open_flags;
|
int n, ro, open_flags;
|
||||||
int ret = 0, rw_ret = 0;
|
int ret = 0, rw_ret = 0;
|
||||||
@ -762,7 +763,8 @@ int bdrv_commit(BlockDriverState *bs)
|
|||||||
if (bs->backing_hd->keep_read_only) {
|
if (bs->backing_hd->keep_read_only) {
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
backing_drv = bs->backing_hd->drv;
|
||||||
ro = bs->backing_hd->read_only;
|
ro = bs->backing_hd->read_only;
|
||||||
strncpy(filename, bs->backing_hd->filename, sizeof(filename));
|
strncpy(filename, bs->backing_hd->filename, sizeof(filename));
|
||||||
open_flags = bs->backing_hd->open_flags;
|
open_flags = bs->backing_hd->open_flags;
|
||||||
@ -772,12 +774,14 @@ int bdrv_commit(BlockDriverState *bs)
|
|||||||
bdrv_delete(bs->backing_hd);
|
bdrv_delete(bs->backing_hd);
|
||||||
bs->backing_hd = NULL;
|
bs->backing_hd = NULL;
|
||||||
bs_rw = bdrv_new("");
|
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) {
|
if (rw_ret < 0) {
|
||||||
bdrv_delete(bs_rw);
|
bdrv_delete(bs_rw);
|
||||||
/* try to re-open read-only */
|
/* try to re-open read-only */
|
||||||
bs_ro = bdrv_new("");
|
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) {
|
if (ret < 0) {
|
||||||
bdrv_delete(bs_ro);
|
bdrv_delete(bs_ro);
|
||||||
/* drive not functional anymore */
|
/* drive not functional anymore */
|
||||||
@ -828,7 +832,8 @@ ro_cleanup:
|
|||||||
bdrv_delete(bs->backing_hd);
|
bdrv_delete(bs->backing_hd);
|
||||||
bs->backing_hd = NULL;
|
bs->backing_hd = NULL;
|
||||||
bs_ro = bdrv_new("");
|
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) {
|
if (ret < 0) {
|
||||||
bdrv_delete(bs_ro);
|
bdrv_delete(bs_ro);
|
||||||
/* drive not functional anymore */
|
/* drive not functional anymore */
|
||||||
|
2
block.h
2
block.h
@ -35,7 +35,7 @@ typedef struct QEMUSnapshotInfo {
|
|||||||
#define BDRV_O_NO_BACKING 0x0100 /* don't open the backing file */
|
#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_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_BITS 9
|
||||||
#define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS)
|
#define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS)
|
||||||
|
66
block/nbd.c
66
block/nbd.c
@ -33,6 +33,8 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define EN_OPTSTR ":exportname="
|
||||||
|
|
||||||
typedef struct BDRVNBDState {
|
typedef struct BDRVNBDState {
|
||||||
int sock;
|
int sock;
|
||||||
off_t size;
|
off_t size;
|
||||||
@ -42,55 +44,83 @@ typedef struct BDRVNBDState {
|
|||||||
static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
|
static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
|
||||||
{
|
{
|
||||||
BDRVNBDState *s = bs->opaque;
|
BDRVNBDState *s = bs->opaque;
|
||||||
|
uint32_t nbdflags;
|
||||||
|
|
||||||
|
char *file;
|
||||||
|
char *name;
|
||||||
const char *host;
|
const char *host;
|
||||||
const char *unixpath;
|
const char *unixpath;
|
||||||
int sock;
|
int sock;
|
||||||
off_t size;
|
off_t size;
|
||||||
size_t blocksize;
|
size_t blocksize;
|
||||||
int ret;
|
int ret;
|
||||||
|
int err = -EINVAL;
|
||||||
|
|
||||||
if (!strstart(filename, "nbd:", &host))
|
file = qemu_strdup(filename);
|
||||||
return -EINVAL;
|
|
||||||
|
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 (strstart(host, "unix:", &unixpath)) {
|
||||||
|
|
||||||
if (unixpath[0] != '/')
|
if (unixpath[0] != '/') {
|
||||||
return -EINVAL;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
sock = unix_socket_outgoing(unixpath);
|
sock = unix_socket_outgoing(unixpath);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
uint16_t port;
|
uint16_t port = NBD_DEFAULT_PORT;
|
||||||
char *p, *r;
|
char *p, *r;
|
||||||
char hostname[128];
|
char hostname[128];
|
||||||
|
|
||||||
pstrcpy(hostname, 128, host);
|
pstrcpy(hostname, 128, host);
|
||||||
|
|
||||||
p = strchr(hostname, ':');
|
p = strchr(hostname, ':');
|
||||||
if (p == NULL)
|
if (p != NULL) {
|
||||||
return -EINVAL;
|
*p = '\0';
|
||||||
|
p++;
|
||||||
|
|
||||||
*p = '\0';
|
port = strtol(p, &r, 0);
|
||||||
p++;
|
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);
|
sock = tcp_socket_outgoing(hostname, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sock == -1)
|
if (sock == -1) {
|
||||||
return -errno;
|
err = -errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = nbd_receive_negotiate(sock, &size, &blocksize);
|
ret = nbd_receive_negotiate(sock, name, &nbdflags, &size, &blocksize);
|
||||||
if (ret == -1)
|
if (ret == -1) {
|
||||||
return -errno;
|
err = -errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
s->sock = sock;
|
s->sock = sock;
|
||||||
s->size = size;
|
s->size = size;
|
||||||
s->blocksize = blocksize;
|
s->blocksize = blocksize;
|
||||||
|
err = 0;
|
||||||
|
|
||||||
return 0;
|
out:
|
||||||
|
qemu_free(file);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nbd_read(BlockDriverState *bs, int64_t sector_num,
|
static int nbd_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
|
@ -655,7 +655,7 @@ static int write_l2_entries(BlockDriverState *bs, uint64_t *l2_table,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
|
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);
|
&l2_table[l2_start_index], len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
@ -718,9 +718,17 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < j; i++)
|
/*
|
||||||
qcow2_free_any_clusters(bs,
|
* If this was a COW, we need to decrease the refcount of the old cluster.
|
||||||
be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1);
|
* 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;
|
ret = 0;
|
||||||
err:
|
err:
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/param.h>
|
||||||
#include <linux/cdrom.h>
|
#include <linux/cdrom.h>
|
||||||
#include <linux/fd.h>
|
#include <linux/fd.h>
|
||||||
#endif
|
#endif
|
||||||
@ -868,8 +869,13 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
|
|||||||
|
|
||||||
s->type = FTYPE_FILE;
|
s->type = FTYPE_FILE;
|
||||||
#if defined(__linux__)
|
#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
|
#endif
|
||||||
|
|
||||||
@ -1154,9 +1160,6 @@ static int cdrom_probe_device(const char *filename)
|
|||||||
int fd, ret;
|
int fd, ret;
|
||||||
int prio = 0;
|
int prio = 0;
|
||||||
|
|
||||||
if (strstart(filename, "/dev/cd", NULL))
|
|
||||||
prio = 50;
|
|
||||||
|
|
||||||
fd = open(filename, O_RDONLY | O_NONBLOCK);
|
fd = open(filename, O_RDONLY | O_NONBLOCK);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -8,16 +8,6 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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-common.h"
|
||||||
#include "qemu-error.h"
|
#include "qemu-error.h"
|
||||||
|
@ -512,7 +512,7 @@ static inline uint8_t fat_chksum(const direntry_t* entry)
|
|||||||
for(i=0;i<11;i++) {
|
for(i=0;i<11;i++) {
|
||||||
unsigned char c;
|
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;
|
chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +139,7 @@ static void ide_identify(IDEState *s)
|
|||||||
put_le16(p + 61, s->nb_sectors >> 16);
|
put_le16(p + 61, s->nb_sectors >> 16);
|
||||||
put_le16(p + 62, 0x07); /* single word dma0-2 supported */
|
put_le16(p + 62, 0x07); /* single word dma0-2 supported */
|
||||||
put_le16(p + 63, 0x07); /* mdma0-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 + 65, 120);
|
||||||
put_le16(p + 66, 120);
|
put_le16(p + 66, 120);
|
||||||
put_le16(p + 67, 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 + 53, 7); /* words 64-70, 54-58, 88 valid */
|
||||||
put_le16(p + 62, 7); /* single word dma0-2 supported */
|
put_le16(p + 62, 7); /* single word dma0-2 supported */
|
||||||
put_le16(p + 63, 7); /* mdma0-2 supported */
|
put_le16(p + 63, 7); /* mdma0-2 supported */
|
||||||
put_le16(p + 64, 0x3f); /* PIO modes supported */
|
|
||||||
#else
|
#else
|
||||||
put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
|
put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
|
||||||
put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
|
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 + 63, 0x103); /* DMA modes XXX: may be incorrect */
|
||||||
put_le16(p + 64, 1); /* PIO modes */
|
|
||||||
#endif
|
#endif
|
||||||
|
put_le16(p + 64, 3); /* pio3-4 supported */
|
||||||
put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
|
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 + 66, 0xb4); /* recommended DMA multiword tx cycle time */
|
||||||
put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
|
put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
|
||||||
|
@ -600,7 +600,7 @@ static void lsi_queue_command(LSIState *s)
|
|||||||
{
|
{
|
||||||
lsi_request *p = s->current;
|
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 != NULL);
|
||||||
assert(s->current->dma_len == 0);
|
assert(s->current->dma_len == 0);
|
||||||
QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
|
QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
|
||||||
@ -880,7 +880,7 @@ static void lsi_do_msgout(LSIState *s)
|
|||||||
break;
|
break;
|
||||||
case 0x20: /* SIMPLE queue */
|
case 0x20: /* SIMPLE queue */
|
||||||
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
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;
|
break;
|
||||||
case 0x21: /* HEAD of queue */
|
case 0x21: /* HEAD of queue */
|
||||||
BADF("HEAD queue not implemented\n");
|
BADF("HEAD queue not implemented\n");
|
||||||
|
130
hw/scsi-disk.c
130
hw/scsi-disk.c
@ -135,7 +135,7 @@ static void scsi_read_complete(void * opaque, int ret)
|
|||||||
scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
|
scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
|
||||||
return;
|
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);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (r->sector_count == (uint32_t)-1) {
|
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->sector_count = 0;
|
||||||
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
|
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
|
||||||
return;
|
return;
|
||||||
@ -486,16 +486,26 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
return buflen;
|
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);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||||
BlockDriverState *bdrv = s->bs;
|
BlockDriverState *bdrv = s->bs;
|
||||||
int cylinders, heads, secs;
|
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) {
|
switch (page) {
|
||||||
case 4: /* Rigid disk device geometry page. */
|
case 4: /* Rigid disk device geometry page. */
|
||||||
p[0] = 4;
|
p[0] = 4;
|
||||||
p[1] = 0x16;
|
p[1] = 0x16;
|
||||||
|
if (page_control == 1) { /* Changeable Values */
|
||||||
|
return p[1] + 2;
|
||||||
|
}
|
||||||
/* if a geometry hint is available, use it */
|
/* if a geometry hint is available, use it */
|
||||||
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
|
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
|
||||||
p[2] = (cylinders >> 16) & 0xff;
|
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 */
|
/* Medium rotation rate [rpm], 5400 rpm */
|
||||||
p[20] = (5400 >> 8) & 0xff;
|
p[20] = (5400 >> 8) & 0xff;
|
||||||
p[21] = 5400 & 0xff;
|
p[21] = 5400 & 0xff;
|
||||||
return 0x16;
|
return p[1] + 2;
|
||||||
|
|
||||||
case 5: /* Flexible disk device geometry page. */
|
case 5: /* Flexible disk device geometry page. */
|
||||||
p[0] = 5;
|
p[0] = 5;
|
||||||
p[1] = 0x1e;
|
p[1] = 0x1e;
|
||||||
|
if (page_control == 1) { /* Changeable Values */
|
||||||
|
return p[1] + 2;
|
||||||
|
}
|
||||||
/* Transfer rate [kbit/s], 5Mbit/s */
|
/* Transfer rate [kbit/s], 5Mbit/s */
|
||||||
p[2] = 5000 >> 8;
|
p[2] = 5000 >> 8;
|
||||||
p[3] = 5000 & 0xff;
|
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 */
|
/* Medium rotation rate [rpm], 5400 rpm */
|
||||||
p[28] = (5400 >> 8) & 0xff;
|
p[28] = (5400 >> 8) & 0xff;
|
||||||
p[29] = 5400 & 0xff;
|
p[29] = 5400 & 0xff;
|
||||||
return 0x1e;
|
return p[1] + 2;
|
||||||
|
|
||||||
case 8: /* Caching page. */
|
case 8: /* Caching page. */
|
||||||
p[0] = 8;
|
p[0] = 8;
|
||||||
p[1] = 0x12;
|
p[1] = 0x12;
|
||||||
|
if (page_control == 1) { /* Changeable Values */
|
||||||
|
return p[1] + 2;
|
||||||
|
}
|
||||||
if (bdrv_enable_write_cache(s->bs)) {
|
if (bdrv_enable_write_cache(s->bs)) {
|
||||||
p[2] = 4; /* WCE */
|
p[2] = 4; /* WCE */
|
||||||
}
|
}
|
||||||
return 20;
|
return p[1] + 2;
|
||||||
|
|
||||||
case 0x2a: /* CD Capabilities and Mechanical Status page. */
|
case 0x2a: /* CD Capabilities and Mechanical Status page. */
|
||||||
if (bdrv_get_type_hint(bdrv) != BDRV_TYPE_CDROM)
|
if (bdrv_get_type_hint(bdrv) != BDRV_TYPE_CDROM)
|
||||||
return 0;
|
return 0;
|
||||||
p[0] = 0x2a;
|
p[0] = 0x2a;
|
||||||
p[1] = 0x14;
|
p[1] = 0x14;
|
||||||
|
if (page_control == 1) { /* Changeable Values */
|
||||||
|
return p[1] + 2;
|
||||||
|
}
|
||||||
p[2] = 3; // CD-R & CD-RW read
|
p[2] = 3; // CD-R & CD-RW read
|
||||||
p[3] = 0; // Writing not supported
|
p[3] = 0; // Writing not supported
|
||||||
p[4] = 0x7f; /* Audio, composite, digital out,
|
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[19] = (16 * 176) & 0xff;
|
||||||
p[20] = (16 * 176) >> 8; // 16x write speed current
|
p[20] = (16 * 176) >> 8; // 16x write speed current
|
||||||
p[21] = (16 * 176) & 0xff;
|
p[21] = (16 * 176) & 0xff;
|
||||||
return 22;
|
return p[1] + 2;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
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);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||||
uint64_t nb_sectors;
|
uint64_t nb_sectors;
|
||||||
int page, dbd, buflen;
|
int page, dbd, buflen, page_control;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
|
uint8_t dev_specific_param;
|
||||||
|
|
||||||
dbd = req->cmd.buf[1] & 0x8;
|
dbd = req->cmd.buf[1] & 0x8;
|
||||||
page = req->cmd.buf[2] & 0x3f;
|
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);
|
memset(outbuf, 0, req->cmd.xfer);
|
||||||
p = outbuf;
|
p = outbuf;
|
||||||
|
|
||||||
p[1] = 0; /* Default media type. */
|
|
||||||
p[3] = 0; /* Block descriptor length. */
|
|
||||||
if (bdrv_is_read_only(s->bs)) {
|
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);
|
bdrv_get_geometry(s->bs, &nb_sectors);
|
||||||
if ((~dbd) & nb_sectors) {
|
if (!dbd && nb_sectors) {
|
||||||
outbuf[3] = 8; /* Block descriptor length */
|
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 /= s->cluster_size;
|
||||||
nb_sectors--;
|
|
||||||
if (nb_sectors > 0xffffff)
|
if (nb_sectors > 0xffffff)
|
||||||
nb_sectors = 0xffffff;
|
nb_sectors = 0;
|
||||||
p[0] = 0; /* media density code */
|
p[0] = 0; /* media density code */
|
||||||
p[1] = (nb_sectors >> 16) & 0xff;
|
p[1] = (nb_sectors >> 16) & 0xff;
|
||||||
p[2] = (nb_sectors >> 8) & 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;
|
p += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (page_control == 3) { /* Saved Values */
|
||||||
|
return -1; /* ILLEGAL_REQUEST */
|
||||||
|
}
|
||||||
|
|
||||||
switch (page) {
|
switch (page) {
|
||||||
case 0x04:
|
case 0x04:
|
||||||
case 0x05:
|
case 0x05:
|
||||||
case 0x08:
|
case 0x08:
|
||||||
case 0x2a:
|
case 0x2a:
|
||||||
p += mode_sense_page(req, page, p);
|
p += mode_sense_page(req, page, p, page_control);
|
||||||
break;
|
break;
|
||||||
case 0x3f:
|
case 0x3f:
|
||||||
p += mode_sense_page(req, 0x08, p);
|
p += mode_sense_page(req, 0x08, p, page_control);
|
||||||
p += mode_sense_page(req, 0x2a, p);
|
p += mode_sense_page(req, 0x2a, p, page_control);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
return -1; /* ILLEGAL_REQUEST */
|
||||||
}
|
}
|
||||||
|
|
||||||
buflen = p - outbuf;
|
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)
|
if (buflen > req->cmd.xfer)
|
||||||
buflen = req->cmd.xfer;
|
buflen = req->cmd.xfer;
|
||||||
return buflen;
|
return buflen;
|
||||||
@ -840,6 +892,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
break;
|
break;
|
||||||
case VERIFY:
|
case VERIFY:
|
||||||
break;
|
break;
|
||||||
|
case REZERO_UNIT:
|
||||||
|
DPRINTF("Rezero Unit\n");
|
||||||
|
if (!bdrv_is_inserted(s->bs)) {
|
||||||
|
goto not_ready;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
goto illegal_request;
|
goto illegal_request;
|
||||||
}
|
}
|
||||||
@ -959,6 +1017,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
|
|||||||
case SERVICE_ACTION_IN:
|
case SERVICE_ACTION_IN:
|
||||||
case REPORT_LUNS:
|
case REPORT_LUNS:
|
||||||
case VERIFY:
|
case VERIFY:
|
||||||
|
case REZERO_UNIT:
|
||||||
rc = scsi_disk_emulate_command(&r->req, outbuf);
|
rc = scsi_disk_emulate_command(&r->req, outbuf);
|
||||||
if (rc > 0) {
|
if (rc > 0) {
|
||||||
r->iov.iov_len = rc;
|
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_10:
|
||||||
case WRITE_12:
|
case WRITE_12:
|
||||||
case WRITE_16:
|
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)
|
if (lba > s->max_lba)
|
||||||
goto illegal_lba;
|
goto illegal_lba;
|
||||||
r->sector = lba * s->cluster_size;
|
r->sector = lba * s->cluster_size;
|
||||||
r->sector_count = len * s->cluster_size;
|
r->sector_count = len * s->cluster_size;
|
||||||
is_write = 1;
|
is_write = 1;
|
||||||
break;
|
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:
|
default:
|
||||||
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
||||||
fail:
|
fail:
|
||||||
|
@ -164,7 +164,7 @@ static void scsi_read_complete(void * opaque, int ret)
|
|||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DPRINTF("IO error\n");
|
DPRINTF("IO error ret %d\n", ret);
|
||||||
scsi_command_complete(r, ret);
|
scsi_command_complete(r, ret);
|
||||||
return;
|
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 &&
|
if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
|
||||||
s->qdev.type == TYPE_TAPE) {
|
s->qdev.type == TYPE_TAPE) {
|
||||||
s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
|
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);
|
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);
|
scsi_req_fixup(&r->req);
|
||||||
|
|
||||||
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag,
|
DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
|
||||||
cmd[0], r->req.cmd.xfer);
|
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->req.cmd.xfer == 0) {
|
||||||
if (r->buf != NULL)
|
if (r->buf != NULL)
|
||||||
|
@ -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));
|
qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
|
||||||
req->next = s->rq;
|
req->next = s->rq;
|
||||||
s->rq = req;
|
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;
|
return 0;
|
||||||
|
40
hw/virtio.c
40
hw/virtio.c
@ -360,11 +360,26 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
|
|||||||
return 0;
|
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)
|
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
|
||||||
{
|
{
|
||||||
unsigned int i, head, max;
|
unsigned int i, head, max;
|
||||||
target_phys_addr_t desc_pa = vq->vring.desc;
|
target_phys_addr_t desc_pa = vq->vring.desc;
|
||||||
target_phys_addr_t len;
|
|
||||||
|
|
||||||
if (!virtqueue_num_heads(vq, vq->last_avail_idx))
|
if (!virtqueue_num_heads(vq, vq->last_avail_idx))
|
||||||
return 0;
|
return 0;
|
||||||
@ -388,29 +403,20 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
|
|||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Collect all the descriptors */
|
||||||
do {
|
do {
|
||||||
struct iovec *sg;
|
struct iovec *sg;
|
||||||
int is_write = 0;
|
|
||||||
|
|
||||||
if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
|
if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
|
||||||
elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
|
elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
|
||||||
sg = &elem->in_sg[elem->in_num++];
|
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++];
|
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 we've got too many, that implies a descriptor loop. */
|
||||||
if ((elem->in_num + elem->out_num) > max) {
|
if ((elem->in_num + elem->out_num) > max) {
|
||||||
fprintf(stderr, "Looped descriptor");
|
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);
|
} 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;
|
elem->index = head;
|
||||||
|
|
||||||
vq->inuse++;
|
vq->inuse++;
|
||||||
|
@ -81,6 +81,7 @@ typedef struct VirtQueueElement
|
|||||||
unsigned int out_num;
|
unsigned int out_num;
|
||||||
unsigned int in_num;
|
unsigned int in_num;
|
||||||
target_phys_addr_t in_addr[VIRTQUEUE_MAX_SIZE];
|
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 in_sg[VIRTQUEUE_MAX_SIZE];
|
||||||
struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
|
struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
|
||||||
} VirtQueueElement;
|
} VirtQueueElement;
|
||||||
@ -142,6 +143,8 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count);
|
|||||||
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||||
unsigned int len, unsigned int idx);
|
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_pop(VirtQueue *vq, VirtQueueElement *elem);
|
||||||
int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes);
|
int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes);
|
||||||
|
|
||||||
|
118
nbd.c
118
nbd.c
@ -62,6 +62,8 @@
|
|||||||
#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7)
|
#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7)
|
||||||
#define NBD_DISCONNECT _IO(0xab, 8)
|
#define NBD_DISCONNECT _IO(0xab, 8)
|
||||||
|
|
||||||
|
#define NBD_OPT_EXPORT_NAME (1 << 0)
|
||||||
|
|
||||||
/* That's all folks */
|
/* That's all folks */
|
||||||
|
|
||||||
#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
|
#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;
|
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];
|
char buf[256];
|
||||||
uint64_t magic;
|
uint64_t magic, s;
|
||||||
|
uint16_t tmp;
|
||||||
|
|
||||||
TRACE("Receiving negotation.");
|
TRACE("Receiving negotation.");
|
||||||
|
|
||||||
if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
|
if (read_sync(csock, buf, 8) != 8) {
|
||||||
LOG("read failed");
|
LOG("read failed");
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
magic = be64_to_cpup((uint64_t*)(buf + 8));
|
buf[8] = '\0';
|
||||||
*size = be64_to_cpup((uint64_t*)(buf + 16));
|
if (strlen(buf) == 0) {
|
||||||
*blocksize = 1024;
|
LOG("server connection closed");
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
TRACE("Magic is %c%c%c%c%c%c%c%c",
|
TRACE("Magic is %c%c%c%c%c%c%c%c",
|
||||||
qemu_isprint(buf[0]) ? buf[0] : '.',
|
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[5]) ? buf[5] : '.',
|
||||||
qemu_isprint(buf[6]) ? buf[6] : '.',
|
qemu_isprint(buf[6]) ? buf[6] : '.',
|
||||||
qemu_isprint(buf[7]) ? buf[7] : '.');
|
qemu_isprint(buf[7]) ? buf[7] : '.');
|
||||||
TRACE("Magic is 0x%" PRIx64, magic);
|
|
||||||
TRACE("Size is %" PRIu64, *size);
|
|
||||||
|
|
||||||
if (memcmp(buf, "NBDMAGIC", 8) != 0) {
|
if (memcmp(buf, "NBDMAGIC", 8) != 0) {
|
||||||
LOG("Invalid magic received");
|
LOG("Invalid magic received");
|
||||||
@ -331,10 +336,99 @@ int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
|
|||||||
return -1;
|
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) {
|
if (name) {
|
||||||
LOG("Bad magic received");
|
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;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
5
nbd.h
5
nbd.h
@ -42,6 +42,8 @@ enum {
|
|||||||
NBD_CMD_DISC = 2
|
NBD_CMD_DISC = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define NBD_DEFAULT_PORT 10809
|
||||||
|
|
||||||
size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
|
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_outgoing(const char *address, uint16_t port);
|
||||||
int tcp_socket_incoming(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 unix_socket_incoming(const char *path);
|
||||||
|
|
||||||
int nbd_negotiate(int csock, off_t size);
|
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_init(int fd, int csock, off_t size, size_t blocksize);
|
||||||
int nbd_send_request(int csock, struct nbd_request *request);
|
int nbd_send_request(int csock, struct nbd_request *request);
|
||||||
int nbd_receive_reply(int csock, struct nbd_reply *reply);
|
int nbd_receive_reply(int csock, struct nbd_reply *reply);
|
||||||
|
@ -599,6 +599,7 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
|
|||||||
acb->aio_type = QEMU_AIO_IOCTL;
|
acb->aio_type = QEMU_AIO_IOCTL;
|
||||||
acb->aio_fildes = fd;
|
acb->aio_fildes = fd;
|
||||||
acb->ev_signo = SIGUSR2;
|
acb->ev_signo = SIGUSR2;
|
||||||
|
acb->async_context_id = get_async_context_id();
|
||||||
acb->aio_offset = 0;
|
acb->aio_offset = 0;
|
||||||
acb->aio_ioctl_buf = buf;
|
acb->aio_ioctl_buf = buf;
|
||||||
acb->aio_ioctl_cmd = req;
|
acb->aio_ioctl_cmd = req;
|
||||||
|
@ -620,6 +620,13 @@ qemu linux1.img -hdb nbd:unix:/tmp/my_socket
|
|||||||
qemu linux2.img -hdb nbd:unix:/tmp/my_socket
|
qemu linux2.img -hdb nbd:unix:/tmp/my_socket
|
||||||
@end example
|
@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
|
@node pcsys_network
|
||||||
@section Network emulation
|
@section Network emulation
|
||||||
|
|
||||||
|
@ -783,7 +783,8 @@ static int img_convert(int argc, char **argv)
|
|||||||
goto out;
|
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) {
|
if (!out_bs) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
@ -1286,7 +1287,7 @@ static int img_rebase(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bs_new_backing = bdrv_new("new_backing");
|
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);
|
new_backing_drv);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
error("Could not open new backing file '%s'", out_baseimg);
|
error("Could not open new backing file '%s'", out_baseimg);
|
||||||
|
@ -1427,11 +1427,8 @@ alloc_f(int argc, char **argv)
|
|||||||
|
|
||||||
cvtstr(offset, s1, sizeof(s1));
|
cvtstr(offset, s1, sizeof(s1));
|
||||||
|
|
||||||
if (nb_sectors == 1)
|
printf("%d/%d sectors allocated at offset %s\n",
|
||||||
printf("sector allocated at offset %s\n", s1);
|
sum_alloc, nb_sectors, s1);
|
||||||
else
|
|
||||||
printf("%d/%d sectors allocated at offset %s\n",
|
|
||||||
sum_alloc, nb_sectors, s1);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,6 +230,7 @@ int main(int argc, char **argv)
|
|||||||
int nb_fds = 0;
|
int nb_fds = 0;
|
||||||
int max_fd;
|
int max_fd;
|
||||||
int persistent = 0;
|
int persistent = 0;
|
||||||
|
uint32_t nbdflags;
|
||||||
|
|
||||||
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
|
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
@ -398,7 +399,8 @@ int main(int argc, char **argv)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = nbd_receive_negotiate(sock, &size, &blocksize);
|
ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
|
||||||
|
&size, &blocksize);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto out;
|
goto out;
|
||||||
|
90
savevm.c
90
savevm.c
@ -1837,8 +1837,10 @@ void do_savevm(Monitor *mon, const QDict *qdict)
|
|||||||
uint32_t vm_state_size;
|
uint32_t vm_state_size;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
struct _timeb tb;
|
struct _timeb tb;
|
||||||
|
struct tm *ptm;
|
||||||
#else
|
#else
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
struct tm tm;
|
||||||
#endif
|
#endif
|
||||||
const char *name = qdict_get_try_str(qdict, "name");
|
const char *name = qdict_get_try_str(qdict, "name");
|
||||||
|
|
||||||
@ -1869,15 +1871,6 @@ void do_savevm(Monitor *mon, const QDict *qdict)
|
|||||||
vm_stop(0);
|
vm_stop(0);
|
||||||
|
|
||||||
memset(sn, 0, sizeof(*sn));
|
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 */
|
/* fill auxiliary fields */
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -1891,6 +1884,24 @@ void do_savevm(Monitor *mon, const QDict *qdict)
|
|||||||
#endif
|
#endif
|
||||||
sn->vm_clock_nsec = qemu_get_clock(vm_clock);
|
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 */
|
/* Delete old snapshots of the same name */
|
||||||
if (name && del_existing_snapshots(mon, name) < 0) {
|
if (name && del_existing_snapshots(mon, name) < 0) {
|
||||||
goto the_end;
|
goto the_end;
|
||||||
@ -2039,8 +2050,10 @@ void do_delvm(Monitor *mon, const QDict *qdict)
|
|||||||
void do_info_snapshots(Monitor *mon)
|
void do_info_snapshots(Monitor *mon)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs, *bs1;
|
BlockDriverState *bs, *bs1;
|
||||||
QEMUSnapshotInfo *sn_tab, *sn;
|
QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
|
||||||
int nb_sns, i;
|
int nb_sns, i, ret, available;
|
||||||
|
int total;
|
||||||
|
int *available_snapshots;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
bs = bdrv_snapshots();
|
bs = bdrv_snapshots();
|
||||||
@ -2048,27 +2061,52 @@ void do_info_snapshots(Monitor *mon)
|
|||||||
monitor_printf(mon, "No available block device supports snapshots\n");
|
monitor_printf(mon, "No available block device supports snapshots\n");
|
||||||
return;
|
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);
|
nb_sns = bdrv_snapshot_list(bs, &sn_tab);
|
||||||
if (nb_sns < 0) {
|
if (nb_sns < 0) {
|
||||||
monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
|
monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
monitor_printf(mon, "Snapshot list (from %s):\n",
|
|
||||||
bdrv_get_device_name(bs));
|
if (nb_sns == 0) {
|
||||||
monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
|
monitor_printf(mon, "There is no snapshot available.\n");
|
||||||
for(i = 0; i < nb_sns; i++) {
|
return;
|
||||||
sn = &sn_tab[i];
|
|
||||||
monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(sn_tab);
|
||||||
|
qemu_free(available_snapshots);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user