2013-12-02 05:23:41 +08:00
|
|
|
#ifndef NBD_CLIENT_H
|
|
|
|
#define NBD_CLIENT_H
|
|
|
|
|
|
|
|
#include "qemu-common.h"
|
|
|
|
#include "block/nbd.h"
|
|
|
|
#include "block/block_int.h"
|
2016-02-11 02:41:01 +08:00
|
|
|
#include "io/channel-socket.h"
|
2013-12-02 05:23:41 +08:00
|
|
|
|
|
|
|
/* #define DEBUG_NBD */
|
|
|
|
|
|
|
|
#if defined(DEBUG_NBD)
|
|
|
|
#define logout(fmt, ...) \
|
|
|
|
fprintf(stderr, "nbd\t%-24s" fmt, __func__, ##__VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define logout(fmt, ...) ((void)0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define MAX_NBD_REQUESTS 16
|
|
|
|
|
2016-10-15 02:33:06 +08:00
|
|
|
typedef struct NBDClientSession {
|
2016-02-11 02:41:01 +08:00
|
|
|
QIOChannelSocket *sioc; /* The master data channel */
|
|
|
|
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
|
2016-07-22 03:34:46 +08:00
|
|
|
uint16_t nbdflags;
|
2013-12-02 05:23:41 +08:00
|
|
|
off_t size;
|
|
|
|
|
|
|
|
CoMutex send_mutex;
|
nbd: Use CoQueue for free_sema instead of CoMutex
NBD is using the CoMutex in a way that wasn't anticipated. For example, if there are
N(N=26, MAX_NBD_REQUESTS=16) nbd write requests, so we will invoke nbd_client_co_pwritev
N times.
----------------------------------------------------------------------------------------
time request Actions
1 1 in_flight=1, Coroutine=C1
2 2 in_flight=2, Coroutine=C2
...
15 15 in_flight=15, Coroutine=C15
16 16 in_flight=16, Coroutine=C16, free_sema->holder=C16, mutex->locked=true
17 17 in_flight=16, Coroutine=C17, queue C17 into free_sema->queue
18 18 in_flight=16, Coroutine=C18, queue C18 into free_sema->queue
...
26 N in_flight=16, Coroutine=C26, queue C26 into free_sema->queue
----------------------------------------------------------------------------------------
Once nbd client recieves request No.16' reply, we will re-enter C16. It's ok, because
it's equal to 'free_sema->holder'.
----------------------------------------------------------------------------------------
time request Actions
27 16 in_flight=15, Coroutine=C16, free_sema->holder=C16, mutex->locked=false
----------------------------------------------------------------------------------------
Then nbd_coroutine_end invokes qemu_co_mutex_unlock what will pop coroutines from
free_sema->queue's head and enter C17. More free_sema->holder is C17 now.
----------------------------------------------------------------------------------------
time request Actions
28 17 in_flight=16, Coroutine=C17, free_sema->holder=C17, mutex->locked=true
----------------------------------------------------------------------------------------
In above scenario, we only recieves request No.16' reply. As time goes by, nbd client will
almostly recieves replies from requests 1 to 15 rather than request 17 who owns C17. In this
case, we will encounter assert "mutex->holder == self" failed since Kevin's commit 0e438cdc
"coroutine: Let CoMutex remember who holds it". For example, if nbd client recieves request
No.15' reply, qemu will stop unexpectedly:
----------------------------------------------------------------------------------------
time request Actions
29 15(most case) in_flight=15, Coroutine=C15, free_sema->holder=C17, mutex->locked=false
----------------------------------------------------------------------------------------
Per Paolo's suggestion "The simplest fix is to change it to CoQueue, which is like a condition
variable", this patch replaces CoMutex with CoQueue.
Cc: Wen Congyang <wency@cn.fujitsu.com>
Reported-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Changlong Xie <xiecl.fnst@cn.fujitsu.com>
Message-Id: <1476267508-19499-1-git-send-email-xiecl.fnst@cn.fujitsu.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-10-12 18:18:28 +08:00
|
|
|
CoQueue free_sema;
|
2017-02-13 21:52:24 +08:00
|
|
|
Coroutine *read_reply_co;
|
2013-12-02 05:23:41 +08:00
|
|
|
int in_flight;
|
|
|
|
|
|
|
|
Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
|
2016-10-15 02:33:07 +08:00
|
|
|
NBDReply reply;
|
2016-10-15 02:33:06 +08:00
|
|
|
} NBDClientSession;
|
2013-12-02 05:23:41 +08:00
|
|
|
|
2016-10-15 02:33:06 +08:00
|
|
|
NBDClientSession *nbd_get_client_session(BlockDriverState *bs);
|
2015-02-07 05:06:16 +08:00
|
|
|
|
2016-02-11 02:41:01 +08:00
|
|
|
int nbd_client_init(BlockDriverState *bs,
|
|
|
|
QIOChannelSocket *sock,
|
|
|
|
const char *export_name,
|
2016-02-11 02:41:12 +08:00
|
|
|
QCryptoTLSCreds *tlscreds,
|
|
|
|
const char *hostname,
|
2015-02-07 05:06:16 +08:00
|
|
|
Error **errp);
|
|
|
|
void nbd_client_close(BlockDriverState *bs);
|
|
|
|
|
2016-07-16 07:23:02 +08:00
|
|
|
int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count);
|
2015-02-07 05:06:16 +08:00
|
|
|
int nbd_client_co_flush(BlockDriverState *bs);
|
2016-07-16 07:23:07 +08:00
|
|
|
int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
|
|
|
uint64_t bytes, QEMUIOVector *qiov, int flags);
|
2016-10-15 02:33:18 +08:00
|
|
|
int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
|
|
|
int count, BdrvRequestFlags flags);
|
2016-07-16 07:23:07 +08:00
|
|
|
int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
|
|
|
|
uint64_t bytes, QEMUIOVector *qiov, int flags);
|
2015-02-07 05:06:16 +08:00
|
|
|
|
|
|
|
void nbd_client_detach_aio_context(BlockDriverState *bs);
|
|
|
|
void nbd_client_attach_aio_context(BlockDriverState *bs,
|
|
|
|
AioContext *new_context);
|
2014-05-08 22:34:43 +08:00
|
|
|
|
2013-12-02 05:23:41 +08:00
|
|
|
#endif /* NBD_CLIENT_H */
|