nbd patches for 2020-02-06

- Allow setting NBD description from QMP for parity with qemu-nbd
 - Remove deprecated 'qemu-nbd --partition'
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEccLMIrHEYCkn0vOqp6FrSiUnQ2oFAl48C6YACgkQp6FrSiUn
 Q2qZQwf/Q6oUzYisDoMT58eRI1DPVzwBSUXPnKf6yikDyEcQr/KByB9OJGhm5ang
 YsT52OpgZTzMXSsGL9RqitvgZtp4vwuDcYjoNafUkNXYHgno6ZojGyVBbypgb4VA
 FiTxoSH0CAD/m/PwVg+k/q0vxca3sFL/l759O55RaNbM7RVuuC6FoNpNvds2q4ch
 l71r5WKEwWBBTy94L4KU/+9RR5CrKmVBF8CqPCP0xE5fm/gYo5j+LFsWgUxYU8Bn
 5hjYboZN1FQJHQve7ErErR7OAf7trHEVVtkuNKMQnu9uU9OgqwS3ReQ2S3c11dsL
 sa0mRL1dPTw55HzRYCV6m0f5TRezuQ==
 =29Vs
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2020-02-06' into staging

nbd patches for 2020-02-06

- Allow setting NBD description from QMP for parity with qemu-nbd
- Remove deprecated 'qemu-nbd --partition'

# gpg: Signature made Thu 06 Feb 2020 12:50:46 GMT
# gpg:                using RSA key 71C2CC22B1C4602927D2F3AAA7A16B4A2527436A
# 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-2020-02-06:
  qemu-nbd: Removed deprecated --partition option
  docs: Fix typo in qemu-nbd -P replacement
  nbd: Allow description when creating NBD blockdev

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-02-06 18:59:12 +00:00
commit 5b7686f3fa
8 changed files with 45 additions and 182 deletions

View File

@ -144,6 +144,7 @@ void qmp_nbd_server_start(SocketAddressLegacy *addr,
} }
void qmp_nbd_server_add(const char *device, bool has_name, const char *name, void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
bool has_description, const char *description,
bool has_writable, bool writable, bool has_writable, bool writable,
bool has_bitmap, const char *bitmap, Error **errp) bool has_bitmap, const char *bitmap, Error **errp)
{ {
@ -167,6 +168,11 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
return; return;
} }
if (has_description && strlen(description) > NBD_MAX_STRING_SIZE) {
error_setg(errp, "description '%s' too long", description);
return;
}
if (nbd_export_find(name)) { if (nbd_export_find(name)) {
error_setg(errp, "NBD server already has export named '%s'", name); error_setg(errp, "NBD server already has export named '%s'", name);
return; return;
@ -195,7 +201,8 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
writable = false; writable = false;
} }
exp = nbd_export_new(bs, 0, len, name, NULL, bitmap, !writable, !writable, exp = nbd_export_new(bs, 0, len, name, description, bitmap,
!writable, !writable,
NULL, false, on_eject_blk, errp); NULL, false, on_eject_blk, errp);
if (!exp) { if (!exp) {
goto out; goto out;

View File

@ -72,13 +72,6 @@ driver options if ``--image-opts`` is specified.
Export the disk as read-only. Export the disk as read-only.
.. option:: -P, --partition=NUM
Deprecated: Only expose MBR partition *NUM*. Understands physical
partitions 1-4 and logical partition 5. New code should instead use
:option:`--image-opts` with the raw driver wrapping a subset of the
original image.
.. option:: -B, --bitmap=NAME .. option:: -B, --bitmap=NAME
If *filename* has a qcow2 persistent bitmap *NAME*, expose If *filename* has a qcow2 persistent bitmap *NAME*, expose
@ -224,14 +217,14 @@ a 1 megabyte subset of a raw file, using the export name 'subset':
-t -x subset -p 10810 \ -t -x subset -p 10810 \
--image-opts driver=raw,offset=1M,size=1M,file.driver=file,file.filename=file.raw --image-opts driver=raw,offset=1M,size=1M,file.driver=file,file.filename=file.raw
Serve a read-only copy of just the first MBR partition of a guest Serve a read-only copy of a guest image over a Unix socket with as
image over a Unix socket with as many as 5 simultaneous readers, with many as 5 simultaneous readers, with a persistent process forked as a
a persistent process forked as a daemon: daemon:
:: ::
qemu-nbd --fork --persistent --shared=5 --socket=/path/to/sock \ qemu-nbd --fork --persistent --shared=5 --socket=/path/to/sock \
--partition=1 --read-only --format=qcow2 file.qcow2 --read-only --format=qcow2 file.qcow2
Expose the guest-visible contents of a qcow2 file via a block device Expose the guest-visible contents of a qcow2 file via a block device
/dev/nbd0 (and possibly creating /dev/nbd0p1 and friends for /dev/nbd0 (and possibly creating /dev/nbd0p1 and friends for

View File

@ -2351,7 +2351,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
continue; continue;
} }
qmp_nbd_server_add(info->value->device, false, NULL, qmp_nbd_server_add(info->value->device, false, NULL, false, NULL,
true, writable, false, NULL, &local_err); true, writable, false, NULL, &local_err);
if (local_err != NULL) { if (local_err != NULL) {
@ -2373,7 +2373,7 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
bool writable = qdict_get_try_bool(qdict, "writable", false); bool writable = qdict_get_try_bool(qdict, "writable", false);
Error *local_err = NULL; Error *local_err = NULL;
qmp_nbd_server_add(device, !!name, name, true, writable, qmp_nbd_server_add(device, !!name, name, false, NULL, true, writable,
false, NULL, &local_err); false, NULL, &local_err);
hmp_handle_error(mon, local_err); hmp_handle_error(mon, local_err);
} }

View File

@ -250,9 +250,12 @@
# @name: Export name. If unspecified, the @device parameter is used as the # @name: Export name. If unspecified, the @device parameter is used as the
# export name. (Since 2.12) # export name. (Since 2.12)
# #
# @description: Free-form description of the export, up to 4096 bytes.
# (Since 5.0)
#
# @writable: Whether clients should be able to write to the device via the # @writable: Whether clients should be able to write to the device via the
# NBD connection (default false). # NBD connection (default false).
#
# @bitmap: Also export the dirty bitmap reachable from @device, so the # @bitmap: Also export the dirty bitmap reachable from @device, so the
# NBD client can use NBD_OPT_SET_META_CONTEXT with # NBD client can use NBD_OPT_SET_META_CONTEXT with
# "qemu:dirty-bitmap:NAME" to inspect the bitmap. (since 4.0) # "qemu:dirty-bitmap:NAME" to inspect the bitmap. (since 4.0)
@ -263,8 +266,8 @@
# Since: 1.3.0 # Since: 1.3.0
## ##
{ 'command': 'nbd-server-add', { 'command': 'nbd-server-add',
'data': {'device': 'str', '*name': 'str', '*writable': 'bool', 'data': {'device': 'str', '*name': 'str', '*description': 'str',
'*bitmap': 'str' } } '*writable': 'bool', '*bitmap': 'str' } }
## ##
# @NbdServerRemoveMode: # @NbdServerRemoveMode:

View File

@ -313,37 +313,6 @@ The above, converted to the current supported format:
@section Related binaries @section Related binaries
@subsection qemu-nbd --partition (since 4.0.0)
The ``qemu-nbd --partition $digit'' code (also spelled @option{-P})
can only handle MBR partitions, and has never correctly handled
logical partitions beyond partition 5. If you know the offset and
length of the partition (perhaps by using @code{sfdisk} within the
guest), you can achieve the effect of exporting just that subset of
the disk by use of the @option{--image-opts} option with a raw
blockdev using the @code{offset} and @code{size} parameters layered on
top of any other existing blockdev. For example, if partition 1 is
100MiB long starting at 1MiB, the old command:
@code{qemu-nbd -t -P 1 -f qcow2 file.qcow2}
can be rewritten as:
@code{qemu-nbd -t --image-opts driver=raw,offset=1M,size=100M,file.driver=qcow2,file.backing.driver=file,file.backing.filename=file.qcow2}
Alternatively, the @code{nbdkit} project provides a more powerful
partition filter on top of its nbd plugin, which can be used to select
an arbitrary MBR or GPT partition on top of any other full-image NBD
export. Using this to rewrite the above example results in:
@code{qemu-nbd -t -k /tmp/sock -f qcow2 file.qcow2 &}
@code{nbdkit -f --filter=partition nbd socket=/tmp/sock partition=1}
Note that if you are exposing the export via /dev/nbd0, it is easier
to just export the entire image and then mount only /dev/nbd0p1 than
it is to reinvoke @command{qemu-nbd -c /dev/nbd0} limited to just a
subset of the image.
@subsection qemu-img convert -n -o (since 4.2.0) @subsection qemu-img convert -n -o (since 4.2.0)
All options specified in @option{-o} are image creation options, so All options specified in @option{-o} are image creation options, so
@ -400,3 +369,21 @@ trouble after a recent upgrade.
The "autoload" parameter has been ignored since 2.12.0. All bitmaps The "autoload" parameter has been ignored since 2.12.0. All bitmaps
are automatically loaded from qcow2 images. are automatically loaded from qcow2 images.
@section Related binaries
@subsection qemu-nbd --partition (removed in 5.0.0)
The ``qemu-nbd --partition $digit'' code (also spelled @option{-P})
could only handle MBR partitions, and never correctly handled logical
partitions beyond partition 5. Exporting a partition can still be
done by utilizing the @option{--image-opts} option with a raw blockdev
using the @code{offset} and @code{size} parameters layered on top of
any other existing blockdev. For example, if partition 1 is 100MiB
long starting at 1MiB, the old command:
@code{qemu-nbd -t -P 1 -f qcow2 file.qcow2}
can be rewritten as:
@code{qemu-nbd -t --image-opts driver=raw,offset=1M,size=100M,file.driver=qcow2,file.file.driver=file,file.file.filename=file.qcow2}

View File

@ -100,7 +100,6 @@ static void usage(const char *name)
"\n" "\n"
"Exposing part of the image:\n" "Exposing part of the image:\n"
" -o, --offset=OFFSET offset into the image\n" " -o, --offset=OFFSET offset into the image\n"
" -P, --partition=NUM only expose partition NUM\n"
" -B, --bitmap=NAME expose a persistent dirty bitmap\n" " -B, --bitmap=NAME expose a persistent dirty bitmap\n"
"\n" "\n"
"General purpose options:\n" "General purpose options:\n"
@ -156,96 +155,6 @@ QEMU_COPYRIGHT "\n"
, name); , name);
} }
struct partition_record
{
uint8_t bootable;
uint8_t start_head;
uint32_t start_cylinder;
uint8_t start_sector;
uint8_t system;
uint8_t end_head;
uint8_t end_cylinder;
uint8_t end_sector;
uint32_t start_sector_abs;
uint32_t nb_sectors_abs;
};
static void read_partition(uint8_t *p, struct partition_record *r)
{
r->bootable = p[0];
r->start_head = p[1];
r->start_cylinder = p[3] | ((p[2] << 2) & 0x0300);
r->start_sector = p[2] & 0x3f;
r->system = p[4];
r->end_head = p[5];
r->end_cylinder = p[7] | ((p[6] << 2) & 0x300);
r->end_sector = p[6] & 0x3f;
r->start_sector_abs = ldl_le_p(p + 8);
r->nb_sectors_abs = ldl_le_p(p + 12);
}
static int find_partition(BlockBackend *blk, int partition,
uint64_t *offset, uint64_t *size)
{
struct partition_record mbr[4];
uint8_t data[MBR_SIZE];
int i;
int ext_partnum = 4;
int ret;
ret = blk_pread(blk, 0, data, sizeof(data));
if (ret < 0) {
error_report("error while reading: %s", strerror(-ret));
exit(EXIT_FAILURE);
}
if (data[510] != 0x55 || data[511] != 0xaa) {
return -EINVAL;
}
for (i = 0; i < 4; i++) {
read_partition(&data[446 + 16 * i], &mbr[i]);
if (!mbr[i].system || !mbr[i].nb_sectors_abs) {
continue;
}
if (mbr[i].system == 0xF || mbr[i].system == 0x5) {
struct partition_record ext[4];
uint8_t data1[MBR_SIZE];
int j;
ret = blk_pread(blk, mbr[i].start_sector_abs * MBR_SIZE,
data1, sizeof(data1));
if (ret < 0) {
error_report("error while reading: %s", strerror(-ret));
exit(EXIT_FAILURE);
}
for (j = 0; j < 4; j++) {
read_partition(&data1[446 + 16 * j], &ext[j]);
if (!ext[j].system || !ext[j].nb_sectors_abs) {
continue;
}
if ((ext_partnum + j + 1) == partition) {
*offset = (uint64_t)ext[j].start_sector_abs << 9;
*size = (uint64_t)ext[j].nb_sectors_abs << 9;
return 0;
}
}
ext_partnum += 4;
} else if ((i + 1) == partition) {
*offset = (uint64_t)mbr[i].start_sector_abs << 9;
*size = (uint64_t)mbr[i].nb_sectors_abs << 9;
return 0;
}
}
return -ENOENT;
}
static void termsig_handler(int signum) static void termsig_handler(int signum)
{ {
atomic_cmpxchg(&state, RUNNING, TERMINATE); atomic_cmpxchg(&state, RUNNING, TERMINATE);
@ -617,7 +526,7 @@ int main(int argc, char **argv)
int64_t fd_size; int64_t fd_size;
QemuOpts *sn_opts = NULL; QemuOpts *sn_opts = NULL;
const char *sn_id_or_name = NULL; const char *sn_id_or_name = NULL;
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:B:L"; const char *sopt = "hVb:o:p:rsnc:dvk:e:f:tl:x:T:D:B:L";
struct option lopt[] = { struct option lopt[] = {
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
@ -626,7 +535,6 @@ int main(int argc, char **argv)
{ "socket", required_argument, NULL, 'k' }, { "socket", required_argument, NULL, 'k' },
{ "offset", required_argument, NULL, 'o' }, { "offset", required_argument, NULL, 'o' },
{ "read-only", no_argument, NULL, 'r' }, { "read-only", no_argument, NULL, 'r' },
{ "partition", required_argument, NULL, 'P' },
{ "bitmap", required_argument, NULL, 'B' }, { "bitmap", required_argument, NULL, 'B' },
{ "connect", required_argument, NULL, 'c' }, { "connect", required_argument, NULL, 'c' },
{ "disconnect", no_argument, NULL, 'd' }, { "disconnect", no_argument, NULL, 'd' },
@ -657,7 +565,6 @@ int main(int argc, char **argv)
int ch; int ch;
int opt_ind = 0; int opt_ind = 0;
int flags = BDRV_O_RDWR; int flags = BDRV_O_RDWR;
int partition = 0;
int ret = 0; int ret = 0;
bool seen_cache = false; bool seen_cache = false;
bool seen_discard = false; bool seen_discard = false;
@ -789,15 +696,6 @@ int main(int argc, char **argv)
readonly = true; readonly = true;
flags &= ~BDRV_O_RDWR; flags &= ~BDRV_O_RDWR;
break; break;
case 'P':
warn_report("The '-P' option is deprecated; use --image-opts with "
"a raw device wrapper for subset exports instead");
if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 ||
partition < 1 || partition > 8) {
error_report("Invalid partition '%s'", optarg);
exit(EXIT_FAILURE);
}
break;
case 'B': case 'B':
bitmap = optarg; bitmap = optarg;
break; break;
@ -894,7 +792,7 @@ int main(int argc, char **argv)
error_report("List mode is incompatible with a file name"); error_report("List mode is incompatible with a file name");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (export_name || export_description || dev_offset || partition || if (export_name || export_description || dev_offset ||
device || disconnect || fmt || sn_id_or_name || bitmap || device || disconnect || fmt || sn_id_or_name || bitmap ||
seen_aio || seen_discard || seen_cache) { seen_aio || seen_discard || seen_cache) {
error_report("List mode is incompatible with per-device settings"); error_report("List mode is incompatible with per-device settings");
@ -1158,33 +1056,6 @@ int main(int argc, char **argv)
} }
fd_size -= dev_offset; fd_size -= dev_offset;
if (partition) {
uint64_t limit;
if (dev_offset) {
error_report("Cannot request partition and offset together");
exit(EXIT_FAILURE);
}
ret = find_partition(blk, partition, &dev_offset, &limit);
if (ret < 0) {
error_report("Could not find partition %d: %s", partition,
strerror(-ret));
exit(EXIT_FAILURE);
}
/*
* MBR partition limits are (32-bit << 9); this assert lets
* the compiler know that we can't overflow 64 bits.
*/
assert(dev_offset + limit >= dev_offset);
if (dev_offset + limit > fd_size) {
error_report("Discovered partition %d at offset %" PRIu64
" size %" PRIu64 ", but size exceeds file length %"
PRId64, partition, dev_offset, limit, fd_size);
exit(EXIT_FAILURE);
}
fd_size = limit;
}
export = nbd_export_new(bs, dev_offset, fd_size, export_name, export = nbd_export_new(bs, dev_offset, fd_size, export_name,
export_description, bitmap, readonly, shared > 1, export_description, bitmap, readonly, shared > 1,
nbd_export_closed, writethrough, NULL, nbd_export_closed, writethrough, NULL,

View File

@ -153,7 +153,7 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
"bitmap":"b3"}}' "error" # Missing bitmap "bitmap":"b3"}}' "error" # Missing bitmap
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
"arguments":{"device":"n", "name":"n2", "writable":true, "arguments":{"device":"n", "name":"n2", "writable":true,
"bitmap":"b2"}}' "return" "description":"some text", "bitmap":"b2"}}' "return"
$QEMU_NBD_PROG -L -k "$SOCK_DIR/nbd" $QEMU_NBD_PROG -L -k "$SOCK_DIR/nbd"
echo echo

View File

@ -50,7 +50,7 @@ exports available: 0
{"error": {"class": "GenericError", "desc": "Enabled bitmap 'b2' incompatible with readonly export"}} {"error": {"class": "GenericError", "desc": "Enabled bitmap 'b2' incompatible with readonly export"}}
{"execute":"nbd-server-add", "arguments":{"device":"n", "name":"n2", "bitmap":"b3"}} {"execute":"nbd-server-add", "arguments":{"device":"n", "name":"n2", "bitmap":"b3"}}
{"error": {"class": "GenericError", "desc": "Bitmap 'b3' is not found"}} {"error": {"class": "GenericError", "desc": "Bitmap 'b3' is not found"}}
{"execute":"nbd-server-add", "arguments":{"device":"n", "name":"n2", "writable":true, "bitmap":"b2"}} {"execute":"nbd-server-add", "arguments":{"device":"n", "name":"n2", "writable":true, "description":"some text", "bitmap":"b2"}}
{"return": {}} {"return": {}}
exports available: 2 exports available: 2
export: 'n' export: 'n'
@ -63,6 +63,7 @@ exports available: 2
base:allocation base:allocation
qemu:dirty-bitmap:b qemu:dirty-bitmap:b
export: 'n2' export: 'n2'
description: some text
size: 4194304 size: 4194304
flags: 0xced ( flush fua trim zeroes df cache fast-zero ) flags: 0xced ( flush fua trim zeroes df cache fast-zero )
min block: 1 min block: 1
@ -130,7 +131,7 @@ exports available: 0
{"error": {"class": "GenericError", "desc": "Enabled bitmap 'b2' incompatible with readonly export"}} {"error": {"class": "GenericError", "desc": "Enabled bitmap 'b2' incompatible with readonly export"}}
{"execute":"nbd-server-add", "arguments":{"device":"n", "name":"n2", "bitmap":"b3"}} {"execute":"nbd-server-add", "arguments":{"device":"n", "name":"n2", "bitmap":"b3"}}
{"error": {"class": "GenericError", "desc": "Bitmap 'b3' is not found"}} {"error": {"class": "GenericError", "desc": "Bitmap 'b3' is not found"}}
{"execute":"nbd-server-add", "arguments":{"device":"n", "name":"n2", "writable":true, "bitmap":"b2"}} {"execute":"nbd-server-add", "arguments":{"device":"n", "name":"n2", "writable":true, "description":"some text", "bitmap":"b2"}}
{"return": {}} {"return": {}}
exports available: 2 exports available: 2
export: 'n' export: 'n'
@ -143,6 +144,7 @@ exports available: 2
base:allocation base:allocation
qemu:dirty-bitmap:b qemu:dirty-bitmap:b
export: 'n2' export: 'n2'
description: some text
size: 4194304 size: 4194304
flags: 0xced ( flush fua trim zeroes df cache fast-zero ) flags: 0xced ( flush fua trim zeroes df cache fast-zero )
min block: 1 min block: 1