nbd patches for 2019-06-13
- add 'qemu-nbd --pid-file' - NBD-related iotest improvements - NBD code refactoring in preparation for reconnect -----BEGIN PGP SIGNATURE----- iQEcBAABCAAGBQJdAm3WAAoJEKeha0olJ0NqEdMH/iXo+ps7bZNkO9JwEh15VUqQ tMDt+lZi3hi1p9u2V8uF6flWsnUWurIQ55r6WXRQj7r2LgZfRzeLCcgbsFA+6cXM ChA4HI9Q/3NdXhdNcyGcXfoZ3jPLJZYkUzaE5CbsRxsOm2Wi5xxDsXf4lcp4aJdm R2sfccPOFuwIQp09d/6NEA0TCxmfJLEw6KRbcAZ5UKSMnK0VXKF7ZMegM6meDQn8 mIjjkBAKhGN7q/8FOvluUmnkmGCp0uWfsAtmYCr8/qOSRoKaBFBlfzbAZu6jY9dZ yrEPs2RActPUHdYvFeLVOaEXlYTVOYG8NLdXM6Ilp0XDLuUAPkjZYP/VKPj/GzI= =JixR -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2019-06-13' into staging nbd patches for 2019-06-13 - add 'qemu-nbd --pid-file' - NBD-related iotest improvements - NBD code refactoring in preparation for reconnect # gpg: Signature made Thu 13 Jun 2019 16:37:58 BST # gpg: using RSA key A7A16B4A2527436A # gpg: Good signature from "Eric Blake <eblake@redhat.com>" [full] # gpg: aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" [full] # gpg: aka "[jpeg image of size 6874]" [full] # Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2 F3AA A7A1 6B4A 2527 436A * remotes/ericb/tags/pull-nbd-2019-06-13: block/nbd: merge NBDClientSession struct back to BDRVNBDState block/nbd: merge nbd-client.* to nbd.c block/nbd-client: drop stale logout nbd/server: Nicer spelling of max BLOCK_STATUS reply length iotests: Let 233 run concurrently iotests: Use qemu-nbd's --pid-file qemu-nbd: Do not close stderr iotests.py: Add qemu_nbd_early_pipe() qemu-nbd: Add --pid-file option Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
d1bf88e56f
|
@ -22,7 +22,7 @@ block-obj-y += null.o mirror.o commit.o io.o create.o
|
|||
block-obj-y += throttle-groups.o
|
||||
block-obj-$(CONFIG_LINUX) += nvme.o
|
||||
|
||||
block-obj-y += nbd.o nbd-client.o
|
||||
block-obj-y += nbd.o
|
||||
block-obj-$(CONFIG_SHEEPDOG) += sheepdog.o
|
||||
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
||||
block-obj-$(if $(CONFIG_LIBISCSI),y,n) += iscsi-opts.o
|
||||
|
|
1226
block/nbd-client.c
1226
block/nbd-client.c
File diff suppressed because it is too large
Load diff
|
@ -1,71 +0,0 @@
|
|||
#ifndef NBD_CLIENT_H
|
||||
#define NBD_CLIENT_H
|
||||
|
||||
#include "block/nbd.h"
|
||||
#include "block/block_int.h"
|
||||
#include "io/channel-socket.h"
|
||||
|
||||
/* #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
|
||||
|
||||
typedef struct {
|
||||
Coroutine *coroutine;
|
||||
uint64_t offset; /* original offset of the request */
|
||||
bool receiving; /* waiting for connection_co? */
|
||||
} NBDClientRequest;
|
||||
|
||||
typedef struct NBDClientSession {
|
||||
QIOChannelSocket *sioc; /* The master data channel */
|
||||
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
|
||||
NBDExportInfo info;
|
||||
|
||||
CoMutex send_mutex;
|
||||
CoQueue free_sema;
|
||||
Coroutine *connection_co;
|
||||
int in_flight;
|
||||
|
||||
NBDClientRequest requests[MAX_NBD_REQUESTS];
|
||||
NBDReply reply;
|
||||
BlockDriverState *bs;
|
||||
bool quit;
|
||||
} NBDClientSession;
|
||||
|
||||
NBDClientSession *nbd_get_client_session(BlockDriverState *bs);
|
||||
|
||||
int nbd_client_init(BlockDriverState *bs,
|
||||
SocketAddress *saddr,
|
||||
const char *export_name,
|
||||
QCryptoTLSCreds *tlscreds,
|
||||
const char *hostname,
|
||||
const char *x_dirty_bitmap,
|
||||
Error **errp);
|
||||
void nbd_client_close(BlockDriverState *bs);
|
||||
|
||||
int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes);
|
||||
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 bytes, BdrvRequestFlags flags);
|
||||
int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags);
|
||||
|
||||
void nbd_client_detach_aio_context(BlockDriverState *bs);
|
||||
void nbd_client_attach_aio_context(BlockDriverState *bs,
|
||||
AioContext *new_context);
|
||||
|
||||
int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs,
|
||||
bool want_zero,
|
||||
int64_t offset, int64_t bytes,
|
||||
int64_t *pnum, int64_t *map,
|
||||
BlockDriverState **file);
|
||||
|
||||
#endif /* NBD_CLIENT_H */
|
1284
block/nbd.c
1284
block/nbd.c
File diff suppressed because it is too large
Load diff
|
@ -160,11 +160,13 @@ nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pa
|
|||
# iscsi.c
|
||||
iscsi_xcopy(void *src_lun, uint64_t src_off, void *dst_lun, uint64_t dst_off, uint64_t bytes, int ret) "src_lun %p offset %"PRIu64" dst_lun %p offset %"PRIu64" bytes %"PRIu64" ret %d"
|
||||
|
||||
# nbd-client.c
|
||||
# nbd.c
|
||||
nbd_parse_blockstatus_compliance(const char *err) "ignoring extra data from non-compliant server: %s"
|
||||
nbd_structured_read_compliance(const char *type) "server sent non-compliant unaligned read %s chunk"
|
||||
nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s"
|
||||
nbd_co_request_fail(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s"
|
||||
nbd_client_connect(const char *export_name) "export '%s'"
|
||||
nbd_client_connect_success(const char *export_name) "export '%s'"
|
||||
|
||||
# ssh.c
|
||||
ssh_restart_coroutine(void *co) "co=%p"
|
||||
|
|
13
nbd/server.c
13
nbd/server.c
|
@ -21,15 +21,18 @@
|
|||
#include "qapi/error.h"
|
||||
#include "trace.h"
|
||||
#include "nbd-internal.h"
|
||||
#include "qemu/units.h"
|
||||
|
||||
#define NBD_META_ID_BASE_ALLOCATION 0
|
||||
#define NBD_META_ID_DIRTY_BITMAP 1
|
||||
|
||||
/* NBD_MAX_BITMAP_EXTENTS: 1 mb of extents data. An empirical
|
||||
/*
|
||||
* NBD_MAX_BLOCK_STATUS_EXTENTS: 1 MiB of extents data. An empirical
|
||||
* constant. If an increase is needed, note that the NBD protocol
|
||||
* recommends no larger than 32 mb, so that the client won't consider
|
||||
* the reply as a denial of service attack. */
|
||||
#define NBD_MAX_BITMAP_EXTENTS (0x100000 / 8)
|
||||
* the reply as a denial of service attack.
|
||||
*/
|
||||
#define NBD_MAX_BLOCK_STATUS_EXTENTS (1 * MiB / 8)
|
||||
|
||||
static int system_errno_to_nbd_errno(int err)
|
||||
{
|
||||
|
@ -1960,7 +1963,7 @@ static int nbd_co_send_block_status(NBDClient *client, uint64_t handle,
|
|||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BITMAP_EXTENTS;
|
||||
unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS;
|
||||
NBDExtent *extents = g_new(NBDExtent, nb_extents);
|
||||
uint64_t final_length = length;
|
||||
|
||||
|
@ -2045,7 +2048,7 @@ static int nbd_co_send_bitmap(NBDClient *client, uint64_t handle,
|
|||
uint32_t context_id, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BITMAP_EXTENTS;
|
||||
unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS;
|
||||
NBDExtent *extents = g_new(NBDExtent, nb_extents);
|
||||
uint64_t final_length = length;
|
||||
|
||||
|
|
14
qemu-nbd.c
14
qemu-nbd.c
|
@ -61,6 +61,7 @@
|
|||
#define QEMU_NBD_OPT_IMAGE_OPTS 262
|
||||
#define QEMU_NBD_OPT_FORK 263
|
||||
#define QEMU_NBD_OPT_TLSAUTHZ 264
|
||||
#define QEMU_NBD_OPT_PID_FILE 265
|
||||
|
||||
#define MBR_SIZE 512
|
||||
|
||||
|
@ -113,6 +114,7 @@ static void usage(const char *name)
|
|||
" specify tracing options\n"
|
||||
" --fork fork off the server process and exit the parent\n"
|
||||
" once the server is running\n"
|
||||
" --pid-file=PATH store the server's process ID in the given file\n"
|
||||
#if HAVE_NBD_DEVICE
|
||||
"\n"
|
||||
"Kernel NBD client support:\n"
|
||||
|
@ -641,6 +643,7 @@ int main(int argc, char **argv)
|
|||
{ "image-opts", no_argument, NULL, QEMU_NBD_OPT_IMAGE_OPTS },
|
||||
{ "trace", required_argument, NULL, 'T' },
|
||||
{ "fork", no_argument, NULL, QEMU_NBD_OPT_FORK },
|
||||
{ "pid-file", required_argument, NULL, QEMU_NBD_OPT_PID_FILE },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
int ch;
|
||||
|
@ -667,6 +670,7 @@ int main(int argc, char **argv)
|
|||
bool list = false;
|
||||
int old_stderr = -1;
|
||||
unsigned socket_activation;
|
||||
const char *pid_file_name = NULL;
|
||||
|
||||
/* The client thread uses SIGTERM to interrupt the server. A signal
|
||||
* handler ensures that "qemu-nbd -v -c" exits with a nice status code.
|
||||
|
@ -866,6 +870,9 @@ int main(int argc, char **argv)
|
|||
case 'L':
|
||||
list = true;
|
||||
break;
|
||||
case QEMU_NBD_OPT_PID_FILE:
|
||||
pid_file_name = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -997,10 +1004,11 @@ int main(int argc, char **argv)
|
|||
exit(EXIT_FAILURE);
|
||||
} else if (pid == 0) {
|
||||
close(stderr_fd[0]);
|
||||
|
||||
old_stderr = dup(STDERR_FILENO);
|
||||
ret = qemu_daemon(1, 0);
|
||||
|
||||
/* Temporarily redirect stderr to the parent's pipe... */
|
||||
old_stderr = dup(STDERR_FILENO);
|
||||
dup2(stderr_fd[1], STDERR_FILENO);
|
||||
if (ret < 0) {
|
||||
error_report("Failed to daemonize: %s", strerror(errno));
|
||||
|
@ -1186,6 +1194,10 @@ int main(int argc, char **argv)
|
|||
|
||||
nbd_update_server_watch();
|
||||
|
||||
if (pid_file_name) {
|
||||
qemu_write_pidfile(pid_file_name, &error_fatal);
|
||||
}
|
||||
|
||||
/* now when the initialization is (almost) complete, chdir("/")
|
||||
* to free any busy filesystems */
|
||||
if (chdir("/") < 0) {
|
||||
|
|
|
@ -117,6 +117,8 @@ option; or provide the credentials needed for connecting as a client
|
|||
in list mode.
|
||||
@item --fork
|
||||
Fork off the server process and exit the parent once the server is running.
|
||||
@item --pid-file=PATH
|
||||
Store the server's process ID in the given file.
|
||||
@item --tls-authz=ID
|
||||
Specify the ID of a qauthz object previously created with the
|
||||
--object option. This will be used to authorize connecting users
|
||||
|
|
|
@ -24,7 +24,7 @@ import socket
|
|||
import stat
|
||||
import time
|
||||
import iotests
|
||||
from iotests import cachemode, imgfmt, qemu_img, qemu_nbd, qemu_nbd_pipe
|
||||
from iotests import cachemode, imgfmt, qemu_img, qemu_nbd, qemu_nbd_early_pipe
|
||||
|
||||
NBD_PORT_START = 32768
|
||||
NBD_PORT_END = NBD_PORT_START + 1024
|
||||
|
@ -93,7 +93,7 @@ class QemuNBD(NBDBlockdevAddBase):
|
|||
pass
|
||||
|
||||
def _try_server_up(self, *args):
|
||||
status, msg = qemu_nbd_pipe('-f', imgfmt, test_img, *args)
|
||||
status, msg = qemu_nbd_early_pipe('-f', imgfmt, test_img, *args)
|
||||
if status == 0:
|
||||
return True
|
||||
if 'Address already in use' in msg:
|
||||
|
|
|
@ -49,7 +49,6 @@ _supported_proto file
|
|||
# If porting to non-Linux, consider using socat instead of ss in common.nbd
|
||||
_require_command QEMU_NBD
|
||||
|
||||
nbd_server_set_tcp_port
|
||||
tls_x509_init
|
||||
|
||||
echo
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
nbd_unix_socket="${TEST_DIR}/qemu-nbd.sock"
|
||||
nbd_tcp_addr="127.0.0.1"
|
||||
nbd_pid_file="${TEST_DIR}/qemu-nbd.pid"
|
||||
nbd_stderr_fifo="${TEST_DIR}/qemu-nbd.fifo"
|
||||
|
||||
# If bash version is >= 4.1, this will be overwritten by a dynamically
|
||||
# assigned file descriptor value.
|
||||
nbd_fifo_fd=10
|
||||
|
||||
nbd_server_stop()
|
||||
{
|
||||
|
@ -33,77 +38,62 @@ nbd_server_stop()
|
|||
kill "$NBD_PID"
|
||||
fi
|
||||
fi
|
||||
rm -f "$nbd_unix_socket"
|
||||
}
|
||||
|
||||
nbd_server_wait_for_unix_socket()
|
||||
{
|
||||
pid=$1
|
||||
|
||||
for ((i = 0; i < 300; i++))
|
||||
do
|
||||
if [ -r "$nbd_unix_socket" ]; then
|
||||
return
|
||||
fi
|
||||
kill -s 0 $pid 2>/dev/null
|
||||
if test $? != 0
|
||||
then
|
||||
echo "qemu-nbd unexpectedly quit"
|
||||
exit 1
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
echo "Failed in check of unix socket created by qemu-nbd"
|
||||
exit 1
|
||||
rm -f "$nbd_unix_socket" "$nbd_stderr_fifo"
|
||||
}
|
||||
|
||||
nbd_server_start_unix_socket()
|
||||
{
|
||||
nbd_server_stop
|
||||
$QEMU_NBD -v -t -k "$nbd_unix_socket" "$@" &
|
||||
nbd_server_wait_for_unix_socket $!
|
||||
}
|
||||
|
||||
nbd_server_set_tcp_port()
|
||||
{
|
||||
(ss --help) >/dev/null 2>&1 || _notrun "ss utility not found, skipping test"
|
||||
|
||||
for ((port = 10809; port <= 10909; port++))
|
||||
do
|
||||
if ! ss -tln | grep -sqE ":$port\b"; then
|
||||
nbd_tcp_port=$port
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Cannot find free TCP port for nbd in range 10809-10909"
|
||||
exit 1
|
||||
}
|
||||
|
||||
nbd_server_wait_for_tcp_socket()
|
||||
{
|
||||
pid=$1
|
||||
|
||||
for ((i = 0; i < 300; i++))
|
||||
do
|
||||
if ss -tln | grep -sqE ":$nbd_tcp_port\b"; then
|
||||
return
|
||||
fi
|
||||
kill -s 0 $pid 2>/dev/null
|
||||
if test $? != 0
|
||||
then
|
||||
echo "qemu-nbd unexpectedly quit"
|
||||
exit 1
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
echo "Failed in check of TCP socket created by qemu-nbd"
|
||||
exit 1
|
||||
$QEMU_NBD -v -t -k "$nbd_unix_socket" --fork "$@"
|
||||
}
|
||||
|
||||
nbd_server_start_tcp_socket()
|
||||
{
|
||||
nbd_server_stop
|
||||
$QEMU_NBD -v -t -b $nbd_tcp_addr -p $nbd_tcp_port "$@" &
|
||||
nbd_server_wait_for_tcp_socket $!
|
||||
|
||||
mkfifo "$nbd_stderr_fifo"
|
||||
for ((port = 10809; port <= 10909; port++))
|
||||
do
|
||||
# Redirect stderr to FIFO, so we can later decide whether we
|
||||
# want to read it or to redirect it to our stderr, depending
|
||||
# on whether the command fails or not
|
||||
$QEMU_NBD -v -t -b $nbd_tcp_addr -p $port --fork "$@" \
|
||||
2> "$nbd_stderr_fifo" &
|
||||
|
||||
# Taken from common.qemu
|
||||
if [[ "${BASH_VERSINFO[0]}" -ge "5" ||
|
||||
("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]]
|
||||
then
|
||||
exec {nbd_fifo_fd}<"$nbd_stderr_fifo"
|
||||
else
|
||||
let _nbd_fifo_fd++
|
||||
eval "exec ${_nbd_fifo_fd}<'$nbd_stderr_fifo'"
|
||||
fi
|
||||
wait $!
|
||||
|
||||
if test $? == 0
|
||||
then
|
||||
# Success, redirect qemu-nbd's stderr to our stderr
|
||||
nbd_tcp_port=$port
|
||||
(cat <&$nbd_fifo_fd >&2) &
|
||||
eval "exec $nbd_fifo_fd>&-"
|
||||
return
|
||||
fi
|
||||
|
||||
# Failure, read the output
|
||||
output=$(cat <&$nbd_fifo_fd)
|
||||
eval "exec $nbd_fifo_fd>&-"
|
||||
|
||||
if ! echo "$output" | grep -q "Address already in use"
|
||||
then
|
||||
# Unknown error, print it
|
||||
echo "$output" >&2
|
||||
rm -f "$nbd_stderr_fifo"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Cannot find free TCP port for nbd in range 10809-10909"
|
||||
rm -f "$nbd_stderr_fifo"
|
||||
exit 1
|
||||
}
|
||||
|
|
|
@ -105,10 +105,8 @@ _qemu_io_wrapper()
|
|||
|
||||
_qemu_nbd_wrapper()
|
||||
{
|
||||
(
|
||||
echo $BASHPID > "${QEMU_TEST_DIR}/qemu-nbd.pid"
|
||||
exec "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS "$@"
|
||||
)
|
||||
"$QEMU_NBD_PROG" --pid-file="${QEMU_TEST_DIR}/qemu-nbd.pid" \
|
||||
$QEMU_NBD_OPTIONS "$@"
|
||||
}
|
||||
|
||||
_qemu_vxhs_wrapper()
|
||||
|
|
|
@ -209,9 +209,9 @@ def qemu_nbd(*args):
|
|||
'''Run qemu-nbd in daemon mode and return the parent's exit code'''
|
||||
return subprocess.call(qemu_nbd_args + ['--fork'] + list(args))
|
||||
|
||||
def qemu_nbd_pipe(*args):
|
||||
def qemu_nbd_early_pipe(*args):
|
||||
'''Run qemu-nbd in daemon mode and return both the parent's exit code
|
||||
and its output'''
|
||||
and its output in case of an error'''
|
||||
subp = subprocess.Popen(qemu_nbd_args + ['--fork'] + list(args),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
|
@ -221,7 +221,10 @@ def qemu_nbd_pipe(*args):
|
|||
sys.stderr.write('qemu-nbd received signal %i: %s\n' %
|
||||
(-exitcode,
|
||||
' '.join(qemu_nbd_args + ['--fork'] + list(args))))
|
||||
return exitcode, subp.communicate()[0]
|
||||
if exitcode == 0:
|
||||
return exitcode, ''
|
||||
else:
|
||||
return exitcode, subp.communicate()[0]
|
||||
|
||||
def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt):
|
||||
'''Return True if two image files are identical'''
|
||||
|
|
Loading…
Reference in a new issue