mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* NBD bugfix (Changlong) * NBD write zeroes support (Eric) * Memory backend fixes (Haozhong) * Atomics fix (Alex) * New AVX512 features (Luwei) * "make check" logging fix (Paolo) * Chardev refactoring fallout (Paolo) * Small checkpatch improvements (Paolo, Jeff) # gpg: Signature made Wed 02 Nov 2016 08:31:11 AM GMT # gpg: using RSA key 0xBFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: (30 commits) main-loop: Suppress I/O thread warning under qtest docs/rcu.txt: Fix minor typo vl: exit qemu on guest panic if -no-shutdown is not set checkpatch: allow spaces before parenthesis for 'coroutine_fn' x86: add AVX512_4VNNIW and AVX512_4FMAPS features slirp: fix CharDriver breakage qemu-char: do not forward events through the mux until QEMU has started nbd: Implement NBD_CMD_WRITE_ZEROES on client nbd: Implement NBD_CMD_WRITE_ZEROES on server nbd: Improve server handling of shutdown requests nbd: Refactor conversion to errno to silence checkpatch nbd: Support shorter handshake nbd: Less allocation during NBD_OPT_LIST nbd: Let client skip portions of server reply nbd: Let server know when client gives up negotiation nbd: Share common option-sending code in client nbd: Send message along with server NBD_REP_ERR errors nbd: Share common reply-sending code in server nbd: Rename struct nbd_request and nbd_reply nbd: Rename NbdClientSession to NBDClientSession ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
+68
-36
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* QEMU Block driver for NBD
|
||||
*
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
* Copyright (C) 2008 Bull S.A.S.
|
||||
* Author: Laurent Vivier <Laurent.Vivier@bull.net>
|
||||
*
|
||||
@@ -32,7 +33,7 @@
|
||||
#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs))
|
||||
#define INDEX_TO_HANDLE(bs, index) ((index) ^ ((uint64_t)(intptr_t)bs))
|
||||
|
||||
static void nbd_recv_coroutines_enter_all(NbdClientSession *s)
|
||||
static void nbd_recv_coroutines_enter_all(NBDClientSession *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -45,7 +46,7 @@ static void nbd_recv_coroutines_enter_all(NbdClientSession *s)
|
||||
|
||||
static void nbd_teardown_connection(BlockDriverState *bs)
|
||||
{
|
||||
NbdClientSession *client = nbd_get_client_session(bs);
|
||||
NBDClientSession *client = nbd_get_client_session(bs);
|
||||
|
||||
if (!client->ioc) { /* Already closed */
|
||||
return;
|
||||
@@ -67,7 +68,7 @@ static void nbd_teardown_connection(BlockDriverState *bs)
|
||||
static void nbd_reply_ready(void *opaque)
|
||||
{
|
||||
BlockDriverState *bs = opaque;
|
||||
NbdClientSession *s = nbd_get_client_session(bs);
|
||||
NBDClientSession *s = nbd_get_client_session(bs);
|
||||
uint64_t i;
|
||||
int ret;
|
||||
|
||||
@@ -115,10 +116,10 @@ static void nbd_restart_write(void *opaque)
|
||||
}
|
||||
|
||||
static int nbd_co_send_request(BlockDriverState *bs,
|
||||
struct nbd_request *request,
|
||||
NBDRequest *request,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
NbdClientSession *s = nbd_get_client_session(bs);
|
||||
NBDClientSession *s = nbd_get_client_session(bs);
|
||||
AioContext *aio_context;
|
||||
int rc, ret, i;
|
||||
|
||||
@@ -166,9 +167,9 @@ static int nbd_co_send_request(BlockDriverState *bs,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void nbd_co_receive_reply(NbdClientSession *s,
|
||||
struct nbd_request *request,
|
||||
struct nbd_reply *reply,
|
||||
static void nbd_co_receive_reply(NBDClientSession *s,
|
||||
NBDRequest *request,
|
||||
NBDReply *reply,
|
||||
QEMUIOVector *qiov)
|
||||
{
|
||||
int ret;
|
||||
@@ -194,13 +195,13 @@ static void nbd_co_receive_reply(NbdClientSession *s,
|
||||
}
|
||||
}
|
||||
|
||||
static void nbd_coroutine_start(NbdClientSession *s,
|
||||
struct nbd_request *request)
|
||||
static void nbd_coroutine_start(NBDClientSession *s,
|
||||
NBDRequest *request)
|
||||
{
|
||||
/* Poor man semaphore. The free_sema is locked when no other request
|
||||
* can be accepted, and unlocked after receiving one reply. */
|
||||
if (s->in_flight >= MAX_NBD_REQUESTS - 1) {
|
||||
qemu_co_mutex_lock(&s->free_sema);
|
||||
if (s->in_flight == MAX_NBD_REQUESTS) {
|
||||
qemu_co_queue_wait(&s->free_sema);
|
||||
assert(s->in_flight < MAX_NBD_REQUESTS);
|
||||
}
|
||||
s->in_flight++;
|
||||
@@ -208,26 +209,26 @@ static void nbd_coroutine_start(NbdClientSession *s,
|
||||
/* s->recv_coroutine[i] is set as soon as we get the send_lock. */
|
||||
}
|
||||
|
||||
static void nbd_coroutine_end(NbdClientSession *s,
|
||||
struct nbd_request *request)
|
||||
static void nbd_coroutine_end(NBDClientSession *s,
|
||||
NBDRequest *request)
|
||||
{
|
||||
int i = HANDLE_TO_INDEX(s, request->handle);
|
||||
s->recv_coroutine[i] = NULL;
|
||||
if (s->in_flight-- == MAX_NBD_REQUESTS) {
|
||||
qemu_co_mutex_unlock(&s->free_sema);
|
||||
qemu_co_queue_next(&s->free_sema);
|
||||
}
|
||||
}
|
||||
|
||||
int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
NbdClientSession *client = nbd_get_client_session(bs);
|
||||
struct nbd_request request = {
|
||||
NBDClientSession *client = nbd_get_client_session(bs);
|
||||
NBDRequest request = {
|
||||
.type = NBD_CMD_READ,
|
||||
.from = offset,
|
||||
.len = bytes,
|
||||
};
|
||||
struct nbd_reply reply;
|
||||
NBDReply reply;
|
||||
ssize_t ret;
|
||||
|
||||
assert(bytes <= NBD_MAX_BUFFER_SIZE);
|
||||
@@ -247,18 +248,18 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
NbdClientSession *client = nbd_get_client_session(bs);
|
||||
struct nbd_request request = {
|
||||
NBDClientSession *client = nbd_get_client_session(bs);
|
||||
NBDRequest request = {
|
||||
.type = NBD_CMD_WRITE,
|
||||
.from = offset,
|
||||
.len = bytes,
|
||||
};
|
||||
struct nbd_reply reply;
|
||||
NBDReply reply;
|
||||
ssize_t ret;
|
||||
|
||||
if (flags & BDRV_REQ_FUA) {
|
||||
assert(client->nbdflags & NBD_FLAG_SEND_FUA);
|
||||
request.type |= NBD_CMD_FLAG_FUA;
|
||||
request.flags |= NBD_CMD_FLAG_FUA;
|
||||
}
|
||||
|
||||
assert(bytes <= NBD_MAX_BUFFER_SIZE);
|
||||
@@ -274,11 +275,46 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
return -reply.error;
|
||||
}
|
||||
|
||||
int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
int count, BdrvRequestFlags flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
NBDClientSession *client = nbd_get_client_session(bs);
|
||||
NBDRequest request = {
|
||||
.type = NBD_CMD_WRITE_ZEROES,
|
||||
.from = offset,
|
||||
.len = count,
|
||||
};
|
||||
NBDReply reply;
|
||||
|
||||
if (!(client->nbdflags & NBD_FLAG_SEND_WRITE_ZEROES)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (flags & BDRV_REQ_FUA) {
|
||||
assert(client->nbdflags & NBD_FLAG_SEND_FUA);
|
||||
request.flags |= NBD_CMD_FLAG_FUA;
|
||||
}
|
||||
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
|
||||
request.flags |= NBD_CMD_FLAG_NO_HOLE;
|
||||
}
|
||||
|
||||
nbd_coroutine_start(client, &request);
|
||||
ret = nbd_co_send_request(bs, &request, NULL);
|
||||
if (ret < 0) {
|
||||
reply.error = -ret;
|
||||
} else {
|
||||
nbd_co_receive_reply(client, &request, &reply, NULL);
|
||||
}
|
||||
nbd_coroutine_end(client, &request);
|
||||
return -reply.error;
|
||||
}
|
||||
|
||||
int nbd_client_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
NbdClientSession *client = nbd_get_client_session(bs);
|
||||
struct nbd_request request = { .type = NBD_CMD_FLUSH };
|
||||
struct nbd_reply reply;
|
||||
NBDClientSession *client = nbd_get_client_session(bs);
|
||||
NBDRequest request = { .type = NBD_CMD_FLUSH };
|
||||
NBDReply reply;
|
||||
ssize_t ret;
|
||||
|
||||
if (!(client->nbdflags & NBD_FLAG_SEND_FLUSH)) {
|
||||
@@ -301,13 +337,13 @@ int nbd_client_co_flush(BlockDriverState *bs)
|
||||
|
||||
int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
|
||||
{
|
||||
NbdClientSession *client = nbd_get_client_session(bs);
|
||||
struct nbd_request request = {
|
||||
NBDClientSession *client = nbd_get_client_session(bs);
|
||||
NBDRequest request = {
|
||||
.type = NBD_CMD_TRIM,
|
||||
.from = offset,
|
||||
.len = count,
|
||||
};
|
||||
struct nbd_reply reply;
|
||||
NBDReply reply;
|
||||
ssize_t ret;
|
||||
|
||||
if (!(client->nbdflags & NBD_FLAG_SEND_TRIM)) {
|
||||
@@ -342,12 +378,8 @@ void nbd_client_attach_aio_context(BlockDriverState *bs,
|
||||
|
||||
void nbd_client_close(BlockDriverState *bs)
|
||||
{
|
||||
NbdClientSession *client = nbd_get_client_session(bs);
|
||||
struct nbd_request request = {
|
||||
.type = NBD_CMD_DISC,
|
||||
.from = 0,
|
||||
.len = 0
|
||||
};
|
||||
NBDClientSession *client = nbd_get_client_session(bs);
|
||||
NBDRequest request = { .type = NBD_CMD_DISC };
|
||||
|
||||
if (client->ioc == NULL) {
|
||||
return;
|
||||
@@ -365,7 +397,7 @@ int nbd_client_init(BlockDriverState *bs,
|
||||
const char *hostname,
|
||||
Error **errp)
|
||||
{
|
||||
NbdClientSession *client = nbd_get_client_session(bs);
|
||||
NBDClientSession *client = nbd_get_client_session(bs);
|
||||
int ret;
|
||||
|
||||
/* NBD handshake */
|
||||
@@ -386,7 +418,7 @@ int nbd_client_init(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
qemu_co_mutex_init(&client->send_mutex);
|
||||
qemu_co_mutex_init(&client->free_sema);
|
||||
qemu_co_queue_init(&client->free_sema);
|
||||
client->sioc = sioc;
|
||||
object_ref(OBJECT(client->sioc));
|
||||
|
||||
|
||||
+7
-5
@@ -17,24 +17,24 @@
|
||||
|
||||
#define MAX_NBD_REQUESTS 16
|
||||
|
||||
typedef struct NbdClientSession {
|
||||
typedef struct NBDClientSession {
|
||||
QIOChannelSocket *sioc; /* The master data channel */
|
||||
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
|
||||
uint16_t nbdflags;
|
||||
off_t size;
|
||||
|
||||
CoMutex send_mutex;
|
||||
CoMutex free_sema;
|
||||
CoQueue free_sema;
|
||||
Coroutine *send_coroutine;
|
||||
int in_flight;
|
||||
|
||||
Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
|
||||
struct nbd_reply reply;
|
||||
NBDReply reply;
|
||||
|
||||
bool is_unix;
|
||||
} NbdClientSession;
|
||||
} NBDClientSession;
|
||||
|
||||
NbdClientSession *nbd_get_client_session(BlockDriverState *bs);
|
||||
NBDClientSession *nbd_get_client_session(BlockDriverState *bs);
|
||||
|
||||
int nbd_client_init(BlockDriverState *bs,
|
||||
QIOChannelSocket *sock,
|
||||
@@ -48,6 +48,8 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count);
|
||||
int nbd_client_co_flush(BlockDriverState *bs);
|
||||
int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags);
|
||||
int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
int count, BdrvRequestFlags flags);
|
||||
int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags);
|
||||
|
||||
|
||||
+6
-2
@@ -44,7 +44,7 @@
|
||||
#define EN_OPTSTR ":exportname="
|
||||
|
||||
typedef struct BDRVNBDState {
|
||||
NbdClientSession client;
|
||||
NBDClientSession client;
|
||||
|
||||
/* For nbd_refresh_filename() */
|
||||
SocketAddress *saddr;
|
||||
@@ -294,7 +294,7 @@ done:
|
||||
return saddr;
|
||||
}
|
||||
|
||||
NbdClientSession *nbd_get_client_session(BlockDriverState *bs)
|
||||
NBDClientSession *nbd_get_client_session(BlockDriverState *bs)
|
||||
{
|
||||
BDRVNBDState *s = bs->opaque;
|
||||
return &s->client;
|
||||
@@ -466,6 +466,7 @@ static int nbd_co_flush(BlockDriverState *bs)
|
||||
static void nbd_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
bs->bl.max_pdiscard = NBD_MAX_BUFFER_SIZE;
|
||||
bs->bl.max_pwrite_zeroes = NBD_MAX_BUFFER_SIZE;
|
||||
bs->bl.max_transfer = NBD_MAX_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
@@ -558,6 +559,7 @@ static BlockDriver bdrv_nbd = {
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_preadv = nbd_client_co_preadv,
|
||||
.bdrv_co_pwritev = nbd_client_co_pwritev,
|
||||
.bdrv_co_pwrite_zeroes = nbd_client_co_pwrite_zeroes,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_pdiscard = nbd_client_co_pdiscard,
|
||||
@@ -576,6 +578,7 @@ static BlockDriver bdrv_nbd_tcp = {
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_preadv = nbd_client_co_preadv,
|
||||
.bdrv_co_pwritev = nbd_client_co_pwritev,
|
||||
.bdrv_co_pwrite_zeroes = nbd_client_co_pwrite_zeroes,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_pdiscard = nbd_client_co_pdiscard,
|
||||
@@ -594,6 +597,7 @@ static BlockDriver bdrv_nbd_unix = {
|
||||
.bdrv_file_open = nbd_open,
|
||||
.bdrv_co_preadv = nbd_client_co_preadv,
|
||||
.bdrv_co_pwritev = nbd_client_co_pwritev,
|
||||
.bdrv_co_pwrite_zeroes = nbd_client_co_pwrite_zeroes,
|
||||
.bdrv_close = nbd_close,
|
||||
.bdrv_co_flush_to_os = nbd_co_flush,
|
||||
.bdrv_co_pdiscard = nbd_client_co_pdiscard,
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ The core RCU API is small:
|
||||
and then read from there.
|
||||
|
||||
RCU read-side critical sections must use atomic_rcu_read() to
|
||||
read data, unless concurrent writes are presented by another
|
||||
read data, unless concurrent writes are prevented by another
|
||||
synchronization mechanism.
|
||||
|
||||
Furthermore, RCU read-side critical sections should traverse the
|
||||
|
||||
@@ -493,7 +493,7 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
|
||||
hwaddr *xlat, hwaddr *plen)
|
||||
{
|
||||
MemoryRegionSection *section;
|
||||
AddressSpaceDispatch *d = cpu->cpu_ases[asidx].memory_dispatch;
|
||||
AddressSpaceDispatch *d = atomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch);
|
||||
|
||||
section = address_space_translate_internal(d, addr, xlat, plen, false);
|
||||
|
||||
@@ -1231,6 +1231,15 @@ void qemu_mutex_unlock_ramlist(void)
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static int64_t get_file_size(int fd)
|
||||
{
|
||||
int64_t size = lseek(fd, 0, SEEK_END);
|
||||
if (size < 0) {
|
||||
return -errno;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static void *file_ram_alloc(RAMBlock *block,
|
||||
ram_addr_t memory,
|
||||
const char *path,
|
||||
@@ -1242,6 +1251,7 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
char *c;
|
||||
void *area = MAP_FAILED;
|
||||
int fd = -1;
|
||||
int64_t file_size;
|
||||
|
||||
if (kvm_enabled() && !kvm_has_sync_mmu()) {
|
||||
error_setg(errp,
|
||||
@@ -1304,6 +1314,8 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
}
|
||||
#endif
|
||||
|
||||
file_size = get_file_size(fd);
|
||||
|
||||
if (memory < block->page_size) {
|
||||
error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "
|
||||
"or larger than page size 0x%zx",
|
||||
@@ -1311,6 +1323,13 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (file_size > 0 && file_size < memory) {
|
||||
error_setg(errp, "backing store %s size 0x%" PRIx64
|
||||
" does not match 'size' option 0x" RAM_ADDR_FMT,
|
||||
path, file_size, memory);
|
||||
goto error;
|
||||
}
|
||||
|
||||
memory = ROUND_UP(memory, block->page_size);
|
||||
|
||||
/*
|
||||
@@ -1318,8 +1337,16 @@ static void *file_ram_alloc(RAMBlock *block,
|
||||
* hosts, so don't bother bailing out on errors.
|
||||
* If anything goes wrong with it under other filesystems,
|
||||
* mmap will fail.
|
||||
*
|
||||
* Do not truncate the non-empty backend file to avoid corrupting
|
||||
* the existing data in the file. Disabling shrinking is not
|
||||
* enough. For example, the current vNVDIMM implementation stores
|
||||
* the guest NVDIMM labels at the end of the backend file. If the
|
||||
* backend file is later extended, QEMU will not be able to find
|
||||
* those labels. Therefore, extending the non-empty backend file
|
||||
* is disabled as well.
|
||||
*/
|
||||
if (ftruncate(fd, memory)) {
|
||||
if (!file_size && ftruncate(fd, memory)) {
|
||||
perror("ftruncate");
|
||||
}
|
||||
|
||||
@@ -2378,7 +2405,7 @@ static void tcg_commit(MemoryListener *listener)
|
||||
* may have split the RCU critical section.
|
||||
*/
|
||||
d = atomic_rcu_read(&cpuas->as->dispatch);
|
||||
cpuas->memory_dispatch = d;
|
||||
atomic_rcu_set(&cpuas->memory_dispatch, d);
|
||||
tlb_flush(cpuas->cpu, 1);
|
||||
}
|
||||
|
||||
|
||||
+56
-17
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
|
||||
*
|
||||
* Network Block Device
|
||||
@@ -25,52 +26,89 @@
|
||||
#include "io/channel-socket.h"
|
||||
#include "crypto/tlscreds.h"
|
||||
|
||||
/* Note: these are _NOT_ the same as the network representation of an NBD
|
||||
/* Handshake phase structs - this struct is passed on the wire */
|
||||
|
||||
struct nbd_option {
|
||||
uint64_t magic; /* NBD_OPTS_MAGIC */
|
||||
uint32_t option; /* NBD_OPT_* */
|
||||
uint32_t length;
|
||||
} QEMU_PACKED;
|
||||
typedef struct nbd_option nbd_option;
|
||||
|
||||
struct nbd_opt_reply {
|
||||
uint64_t magic; /* NBD_REP_MAGIC */
|
||||
uint32_t option; /* NBD_OPT_* */
|
||||
uint32_t type; /* NBD_REP_* */
|
||||
uint32_t length;
|
||||
} QEMU_PACKED;
|
||||
typedef struct nbd_opt_reply nbd_opt_reply;
|
||||
|
||||
/* Transmission phase structs
|
||||
*
|
||||
* Note: these are _NOT_ the same as the network representation of an NBD
|
||||
* request and reply!
|
||||
*/
|
||||
struct nbd_request {
|
||||
struct NBDRequest {
|
||||
uint64_t handle;
|
||||
uint64_t from;
|
||||
uint32_t len;
|
||||
uint32_t type;
|
||||
uint16_t flags; /* NBD_CMD_FLAG_* */
|
||||
uint16_t type; /* NBD_CMD_* */
|
||||
};
|
||||
typedef struct NBDRequest NBDRequest;
|
||||
|
||||
struct nbd_reply {
|
||||
struct NBDReply {
|
||||
uint64_t handle;
|
||||
uint32_t error;
|
||||
};
|
||||
typedef struct NBDReply NBDReply;
|
||||
|
||||
/* Transmission (export) flags: sent from server to client during handshake,
|
||||
but describe what will happen during transmission */
|
||||
#define NBD_FLAG_HAS_FLAGS (1 << 0) /* Flags are there */
|
||||
#define NBD_FLAG_READ_ONLY (1 << 1) /* Device is read-only */
|
||||
#define NBD_FLAG_SEND_FLUSH (1 << 2) /* Send FLUSH */
|
||||
#define NBD_FLAG_SEND_FUA (1 << 3) /* Send FUA (Force Unit Access) */
|
||||
#define NBD_FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */
|
||||
#define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */
|
||||
#define NBD_FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send WRITE_ZEROES */
|
||||
|
||||
/* New-style global flags. */
|
||||
#define NBD_FLAG_FIXED_NEWSTYLE (1 << 0) /* Fixed newstyle protocol. */
|
||||
/* New-style handshake (global) flags, sent from server to client, and
|
||||
control what will happen during handshake phase. */
|
||||
#define NBD_FLAG_FIXED_NEWSTYLE (1 << 0) /* Fixed newstyle protocol. */
|
||||
#define NBD_FLAG_NO_ZEROES (1 << 1) /* End handshake without zeroes. */
|
||||
|
||||
/* New-style client flags. */
|
||||
#define NBD_FLAG_C_FIXED_NEWSTYLE (1 << 0) /* Fixed newstyle protocol. */
|
||||
/* New-style client flags, sent from client to server to control what happens
|
||||
during handshake phase. */
|
||||
#define NBD_FLAG_C_FIXED_NEWSTYLE (1 << 0) /* Fixed newstyle protocol. */
|
||||
#define NBD_FLAG_C_NO_ZEROES (1 << 1) /* End handshake without zeroes. */
|
||||
|
||||
/* Reply types. */
|
||||
#define NBD_REP_ERR(value) ((UINT32_C(1) << 31) | (value))
|
||||
|
||||
#define NBD_REP_ACK (1) /* Data sending finished. */
|
||||
#define NBD_REP_SERVER (2) /* Export description. */
|
||||
#define NBD_REP_ERR_UNSUP ((UINT32_C(1) << 31) | 1) /* Unknown option. */
|
||||
#define NBD_REP_ERR_POLICY ((UINT32_C(1) << 31) | 2) /* Server denied */
|
||||
#define NBD_REP_ERR_INVALID ((UINT32_C(1) << 31) | 3) /* Invalid length. */
|
||||
#define NBD_REP_ERR_TLS_REQD ((UINT32_C(1) << 31) | 5) /* TLS required */
|
||||
|
||||
#define NBD_REP_ERR_UNSUP NBD_REP_ERR(1) /* Unknown option */
|
||||
#define NBD_REP_ERR_POLICY NBD_REP_ERR(2) /* Server denied */
|
||||
#define NBD_REP_ERR_INVALID NBD_REP_ERR(3) /* Invalid length */
|
||||
#define NBD_REP_ERR_PLATFORM NBD_REP_ERR(4) /* Not compiled in */
|
||||
#define NBD_REP_ERR_TLS_REQD NBD_REP_ERR(5) /* TLS required */
|
||||
#define NBD_REP_ERR_SHUTDOWN NBD_REP_ERR(7) /* Server shutting down */
|
||||
|
||||
#define NBD_CMD_MASK_COMMAND 0x0000ffff
|
||||
#define NBD_CMD_FLAG_FUA (1 << 16)
|
||||
/* Request flags, sent from client to server during transmission phase */
|
||||
#define NBD_CMD_FLAG_FUA (1 << 0) /* 'force unit access' during write */
|
||||
#define NBD_CMD_FLAG_NO_HOLE (1 << 1) /* don't punch hole on zero run */
|
||||
|
||||
/* Supported request types */
|
||||
enum {
|
||||
NBD_CMD_READ = 0,
|
||||
NBD_CMD_WRITE = 1,
|
||||
NBD_CMD_DISC = 2,
|
||||
NBD_CMD_FLUSH = 3,
|
||||
NBD_CMD_TRIM = 4
|
||||
NBD_CMD_TRIM = 4,
|
||||
/* 5 reserved for failed experiment NBD_CMD_CACHE */
|
||||
NBD_CMD_WRITE_ZEROES = 6,
|
||||
};
|
||||
|
||||
#define NBD_DEFAULT_PORT 10809
|
||||
@@ -95,8 +133,8 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
|
||||
QIOChannel **outioc,
|
||||
off_t *size, Error **errp);
|
||||
int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size);
|
||||
ssize_t nbd_send_request(QIOChannel *ioc, struct nbd_request *request);
|
||||
ssize_t nbd_receive_reply(QIOChannel *ioc, struct nbd_reply *reply);
|
||||
ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request);
|
||||
ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply);
|
||||
int nbd_client(int fd);
|
||||
int nbd_disconnect(int fd);
|
||||
|
||||
@@ -115,6 +153,7 @@ BlockBackend *nbd_export_get_blockdev(NBDExport *exp);
|
||||
|
||||
NBDExport *nbd_export_find(const char *name);
|
||||
void nbd_export_set_name(NBDExport *exp, const char *name);
|
||||
void nbd_export_set_description(NBDExport *exp, const char *description);
|
||||
void nbd_export_close_all(void);
|
||||
|
||||
void nbd_client_new(NBDExport *exp,
|
||||
|
||||
@@ -315,4 +315,17 @@ static inline void g_source_set_name_by_id(guint tag, const char *name)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2, 36, 0)
|
||||
/* Always fail. This will not include error_report output in the test log,
|
||||
* sending it instead to stderr.
|
||||
*/
|
||||
#define g_test_initialized() (0)
|
||||
#endif
|
||||
#if !GLIB_CHECK_VERSION(2, 38, 0)
|
||||
#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
|
||||
#error schizophrenic detection of glib subprocess testing
|
||||
#endif
|
||||
#define g_test_subprocess() (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,7 @@ void loc_set_file(const char *fname, int lno);
|
||||
|
||||
void error_vprintf(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
|
||||
void error_printf(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
|
||||
void error_vprintf_unless_qmp(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
|
||||
void error_printf_unless_qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
|
||||
void error_set_progname(const char *argv0);
|
||||
void error_vreport(const char *fmt, va_list ap) GCC_FMT_ATTR(1, 0);
|
||||
|
||||
@@ -128,6 +128,9 @@ extern int daemon(int, int);
|
||||
#if !defined(EMEDIUMTYPE)
|
||||
#define EMEDIUMTYPE 4098
|
||||
#endif
|
||||
#if !defined(ESHUTDOWN)
|
||||
#define ESHUTDOWN 4099
|
||||
#endif
|
||||
#ifndef TIME_MAX
|
||||
#define TIME_MAX LONG_MAX
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -234,7 +234,7 @@ static int os_host_main_loop_wait(int64_t timeout)
|
||||
if (!timeout && (spin_counter > MAX_MAIN_LOOP_SPIN)) {
|
||||
static bool notified;
|
||||
|
||||
if (!notified && !qtest_driver()) {
|
||||
if (!notified && !qtest_enabled() && !qtest_driver()) {
|
||||
fprintf(stderr,
|
||||
"main-loop: WARNING: I/O thread spun for %d iterations\n",
|
||||
MAX_MAIN_LOOP_SPIN);
|
||||
|
||||
@@ -3955,6 +3955,27 @@ static void monitor_readline_flush(void *opaque)
|
||||
monitor_flush(opaque);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print to current monitor if we have one, else to stderr.
|
||||
* TODO should return int, so callers can calculate width, but that
|
||||
* requires surgery to monitor_vprintf(). Left for another day.
|
||||
*/
|
||||
void error_vprintf(const char *fmt, va_list ap)
|
||||
{
|
||||
if (cur_mon && !monitor_cur_is_qmp()) {
|
||||
monitor_vprintf(cur_mon, fmt, ap);
|
||||
} else {
|
||||
vfprintf(stderr, fmt, ap);
|
||||
}
|
||||
}
|
||||
|
||||
void error_vprintf_unless_qmp(const char *fmt, va_list ap)
|
||||
{
|
||||
if (cur_mon && !monitor_cur_is_qmp()) {
|
||||
monitor_vprintf(cur_mon, fmt, ap);
|
||||
}
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) monitor_lock_init(void)
|
||||
{
|
||||
qemu_mutex_init(&monitor_lock);
|
||||
|
||||
+272
-232
File diff suppressed because it is too large
Load Diff
+7
-5
@@ -53,16 +53,16 @@
|
||||
/* This is all part of the "official" NBD API.
|
||||
*
|
||||
* The most up-to-date documentation is available at:
|
||||
* https://github.com/yoe/nbd/blob/master/doc/proto.txt
|
||||
* https://github.com/yoe/nbd/blob/master/doc/proto.md
|
||||
*/
|
||||
|
||||
#define NBD_REQUEST_SIZE (4 + 4 + 8 + 8 + 4)
|
||||
#define NBD_REQUEST_SIZE (4 + 2 + 2 + 8 + 8 + 4)
|
||||
#define NBD_REPLY_SIZE (4 + 4 + 8)
|
||||
#define NBD_REQUEST_MAGIC 0x25609513
|
||||
#define NBD_REPLY_MAGIC 0x67446698
|
||||
#define NBD_OPTS_MAGIC 0x49484156454F5054LL
|
||||
#define NBD_CLIENT_MAGIC 0x0000420281861253LL
|
||||
#define NBD_REP_MAGIC 0x3e889045565a9LL
|
||||
#define NBD_REP_MAGIC 0x0003e889045565a9LL
|
||||
|
||||
#define NBD_SET_SOCK _IO(0xab, 0)
|
||||
#define NBD_SET_BLKSIZE _IO(0xab, 1)
|
||||
@@ -92,6 +92,7 @@
|
||||
#define NBD_ENOMEM 12
|
||||
#define NBD_EINVAL 22
|
||||
#define NBD_ENOSPC 28
|
||||
#define NBD_ESHUTDOWN 108
|
||||
|
||||
static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size)
|
||||
{
|
||||
@@ -104,9 +105,10 @@ static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size)
|
||||
return nbd_wr_syncv(ioc, &iov, 1, size, true);
|
||||
}
|
||||
|
||||
static inline ssize_t write_sync(QIOChannel *ioc, void *buffer, size_t size)
|
||||
static inline ssize_t write_sync(QIOChannel *ioc, const void *buffer,
|
||||
size_t size)
|
||||
{
|
||||
struct iovec iov = { .iov_base = buffer, .iov_len = size };
|
||||
struct iovec iov = { .iov_base = (void *) buffer, .iov_len = size };
|
||||
|
||||
return nbd_wr_syncv(ioc, &iov, 1, size, false);
|
||||
}
|
||||
|
||||
+204
-90
File diff suppressed because it is too large
Load Diff
+1
-2
@@ -763,8 +763,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (slirp_add_exec(s->slirp, 3, qemu_chr_fe_get_driver(&fwd->hd),
|
||||
&server, port) < 0) {
|
||||
if (slirp_add_exec(s->slirp, 3, &fwd->hd, &server, port) < 0) {
|
||||
error_report("conflicting/invalid host:port in guest forwarding "
|
||||
"rule '%s'", config_str);
|
||||
g_free(fwd);
|
||||
|
||||
+2
-2
@@ -4621,10 +4621,10 @@
|
||||
#
|
||||
# @pause: system pauses
|
||||
#
|
||||
# Since: 2.1
|
||||
# Since: 2.1 (poweroff since 2.8)
|
||||
##
|
||||
{ 'enum': 'GuestPanicAction',
|
||||
'data': [ 'pause' ] }
|
||||
'data': [ 'pause', 'poweroff' ] }
|
||||
|
||||
##
|
||||
# @rtc-reset-reinjection
|
||||
|
||||
+6
-2
@@ -735,19 +735,23 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
|
||||
}
|
||||
}
|
||||
|
||||
static bool muxes_realized;
|
||||
|
||||
static void mux_chr_event(void *opaque, int event)
|
||||
{
|
||||
CharDriverState *chr = opaque;
|
||||
MuxDriver *d = chr->opaque;
|
||||
int i;
|
||||
|
||||
if (!muxes_realized) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send the event to all registered listeners */
|
||||
for (i = 0; i < d->mux_cnt; i++)
|
||||
mux_chr_send_event(d, i, event);
|
||||
}
|
||||
|
||||
static bool muxes_realized;
|
||||
|
||||
/**
|
||||
* Called after processing of default and command-line-specified
|
||||
* chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
|
||||
|
||||
+11
-1
@@ -83,6 +83,7 @@ static void usage(const char *name)
|
||||
" -t, --persistent don't exit on the last connection\n"
|
||||
" -v, --verbose display extra debugging information\n"
|
||||
" -x, --export-name=NAME expose export by name\n"
|
||||
" -D, --description=TEXT with -x, also export a human-readable description\n"
|
||||
"\n"
|
||||
"Exposing part of the image:\n"
|
||||
" -o, --offset=OFFSET offset into the image\n"
|
||||
@@ -477,7 +478,7 @@ int main(int argc, char **argv)
|
||||
off_t fd_size;
|
||||
QemuOpts *sn_opts = NULL;
|
||||
const char *sn_id_or_name = NULL;
|
||||
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:";
|
||||
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:";
|
||||
struct option lopt[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
@@ -503,6 +504,7 @@ int main(int argc, char **argv)
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "object", required_argument, NULL, QEMU_NBD_OPT_OBJECT },
|
||||
{ "export-name", required_argument, NULL, 'x' },
|
||||
{ "description", required_argument, NULL, 'D' },
|
||||
{ "tls-creds", required_argument, NULL, QEMU_NBD_OPT_TLSCREDS },
|
||||
{ "image-opts", no_argument, NULL, QEMU_NBD_OPT_IMAGE_OPTS },
|
||||
{ "trace", required_argument, NULL, 'T' },
|
||||
@@ -524,6 +526,7 @@ int main(int argc, char **argv)
|
||||
BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
|
||||
QDict *options = NULL;
|
||||
const char *export_name = NULL;
|
||||
const char *export_description = NULL;
|
||||
const char *tlscredsid = NULL;
|
||||
bool imageOpts = false;
|
||||
bool writethrough = true;
|
||||
@@ -689,6 +692,9 @@ int main(int argc, char **argv)
|
||||
case 'x':
|
||||
export_name = optarg;
|
||||
break;
|
||||
case 'D':
|
||||
export_description = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
@@ -937,7 +943,11 @@ int main(int argc, char **argv)
|
||||
}
|
||||
if (export_name) {
|
||||
nbd_export_set_name(exp, export_name);
|
||||
nbd_export_set_description(exp, export_description);
|
||||
newproto = true;
|
||||
} else if (export_description) {
|
||||
error_report("Export description requires an export name");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
server_ioc = qio_channel_socket_new();
|
||||
|
||||
+4
-1
@@ -79,9 +79,12 @@ Disconnect the device @var{dev}
|
||||
Allow up to @var{num} clients to share the device (default @samp{1})
|
||||
@item -t, --persistent
|
||||
Don't exit on the last connection
|
||||
@item -x NAME, --export-name=NAME
|
||||
@item -x, --export-name=@var{name}
|
||||
Set the NBD volume export name. This switches the server to use
|
||||
the new style NBD protocol negotiation
|
||||
@item -D, --description=@var{description}
|
||||
Set the NBD volume export description, as a human-readable
|
||||
string. Requires the use of @option{-x}
|
||||
@item --tls-creds=ID
|
||||
Enable mandatory TLS encryption for the server by setting the ID
|
||||
of the TLS credentials object previously created with the --object
|
||||
|
||||
@@ -1754,7 +1754,7 @@ sub process {
|
||||
# Ignore those directives where spaces _are_ permitted.
|
||||
if ($name =~ /^(?:
|
||||
if|for|while|switch|return|case|
|
||||
volatile|__volatile__|
|
||||
volatile|__volatile__|coroutine_fn|
|
||||
__attribute__|format|__extension__|
|
||||
asm|__asm__)$/x)
|
||||
{
|
||||
@@ -2498,8 +2498,8 @@ sub process {
|
||||
VMStateDescription|
|
||||
VMStateInfo}x;
|
||||
if ($line !~ /\bconst\b/ &&
|
||||
$line =~ /\b($struct_ops)\b/) {
|
||||
ERROR("struct $1 should normally be const\n" .
|
||||
$line =~ /\b($struct_ops)\b.*=/) {
|
||||
ERROR("initializer for struct $1 should normally be const\n" .
|
||||
$herecurr);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user