nbdcopy(1)

๐Ÿ’– NAME ๐Ÿ’–

okay so welcome to the LIBNBD corner of the man pages bestie ๐Ÿ’… โ€” this one is nbdcopy, and it's literally the tool for copying stuff to and from an NBD server. yes. that's the whole vibe. โœจ


โœจ SYNOPSIS โœจ

nbdcopy [--allocated] [--blkhash=DIGEST] [--blkhash-file=FILE]
        [-C N|--connections=N]
        [--destination-is-zero|--target-is-zero]
        [--extents | --extents=MAP | --no-extents]
        [--flush] [-p|--progress|--progress=FD]
        [--queue-size=N] [--request-size=N] [-R N|--requests=N]
        [-S N|--sparse=N] [--synchronous] [-T N|--threads=N]
        [--no-truncate] [-v|--verbose]
        SOURCE DESTINATION

SOURCE, DESTINATION := - | FILE | DEVICE | NBD-URI | [ CMD ARGS ... ]
DESTINATION += null:

nbdcopy --help

nbdcopy -V|--version

so like. you give it a source and a destination and it does the thing. yes queen ๐Ÿ‘‘


๐ŸŒˆ EXAMPLES ๐ŸŒˆ

nbdcopy nbd://example.com local.img

This copies literally everything from the NBD server at "example.com" to a local file called local.img. classic. iconic. ๐ŸŽ€

nbdcopy nbd://example.com - | file -

This streams the first part of the disk on the NBD server at "example.com" into the file(1) command. and no, bestie, the - here means "stream to stdout" (and therefore into the pipe to the file command). iykyk ๐Ÿซถ

nbdinfo(1) is another way to detect the content on an NBD server, btw.

nbdcopy -p /dev/sdX "nbd+unix:///?socket=/tmp/unixsock"

Copy the full local hard disk "/dev/sdX" to the NBD server listening on the Unix domain socket /tmp/unixsock. and because of the -p option this will print a progress bar. slay ๐Ÿฆ‹

nbdcopy nbd://server1 nbd://server2

Copy a full disk from one NBD server to another. no cap, literally server to server.

nbdcopy nbd://server1 nbd://server2 --blkhash

Copy a full disk from one NBD server to another, computing the blkhash (similar to a checksum) of the disk and printing that. two things at once, main character energy ๐Ÿ’…

nbdcopy -- [ qemu-nbd -r -f qcow2 https://example.com/disk.qcow2 ] -

Run qemu-nbd(8) as a subprocess to open URL "https://example.com/disk.qcow2", which is then streamed to stdout ("-"), converted to blocks of raw format data. note the -- โ€” it's there to prevent qemu-nbd flags from being interpreted as nbdcopy flags. respect the divider ๐Ÿ™ˆ

cat disk1 disk2 | nbdcopy -- - [ qemu-nbd -f qcow2 output.qcow2 ]

Concatenate two raw-format disk images into the qcow2 file output.qcow2. and heads up: the output file has to be precreated. โญ

nbdcopy nbd://server null:

Read the contents of the NBD server as fast as possible and throw it away (write it to a virtual null device). this is useful for benchmarking NBD servers and/or nbdcopy itself. speed test vibes ๐Ÿ”ฅ


๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

okay so nbdcopy copies to and from an NBD server. it can upload a local file to an NBD server, or download the contents of an NBD server to a local file, device or stdin/stdout. it can also copy between NBD servers. versatile queen โœจ

The local file can be a file, a block device (eg. "/dev/cdrom"), or "-" which means stream in from stdin or stream out to stdout.

The NBD server can be specified using an NBD URI (like "nbd://localhost"). The NBD server can be local or remote, and encryption can be used if libnbd was built with encryption support. alternately you can use square brackets around a qemu-nbd(8) or nbdkit(1) command to run the NBD server as a subprocess of nbdcopy. ๐Ÿงš

The destination may be the special word "null:" to throw away the output.

fr fr, for more complex copying operations including converting between disk formats use "qemu-img convert", see qemu-img(1). that's a whole different girl.

๐Ÿ’… OPTIONS ๐Ÿ’…

  • --help โ€” Display brief command line help and exit. ๐Ÿ’–
  • --allocated โ€” Normally nbdcopy tries to create sparse output (with holes) if the destination supports that. It does this in two ways: either using extent information from the source to copy holes (see --extents and --no-extents), or by detecting runs of zeroes (see -S). If you use --allocated then nbdcopy creates a fully allocated, non-sparse output on the destination. no holes, all vibes.
  • --blkhash, --blkhash=md5, --blkhash=md5/SIZE, --blkhash=sha1, --blkhash=sha1/SIZE, --blkhash=sha256, --blkhash=sha256/SIZE, --blkhash=sha512, --blkhash=sha512/SIZE โ€” Compute the blkhash of the disk image during the copy and print it at the end. Blkhash (https://gitlab.com/nirs/blkhash) is an algorithm similar to a checksum except that it can be computed in parallel. note that it is not compatible with programs like cksum(1) or sha256sum(1). Using this option will make nbdcopy slower. ๐Ÿ˜ญ

You can choose the digest function from "md5", "sha1", "sha256" (recommended), or "sha512". You can also choose the block size, the default being "64k" (recommended).

The --blkhash option without parameters selects sha256/64k.

To compute the blkhash of a file without copying it, you can do:

nbdcopy --blkhash -- disk.raw null:

or if the format is qcow2:

nbdcopy --blkhash -- [ qemu-nbd -f qcow2 disk.qcow2 ] null:
  • --blkhash-file=FILE โ€” If --blkhash is selected, choose where to print the blkhash to. The default is stdout. ๐Ÿ“
  • -C N, --connections=N โ€” Set the maximum number of NBD connections ("multi-conn"). By default nbdcopy will try to use multi-conn with up to 4 connections if the NBD server supports it. If copying between NBD servers then nbdcopy cannot use multi-conn if either of the servers does not support it. ๐Ÿ˜ค
  • --destination-is-zero, --target-is-zero โ€” Assume the destination is already zeroed. This allows nbdcopy to skip copying blocks of zeroes from the source to the destination.
โš ๏ธ This is not safe unless the destination device is already zeroed. nbddiscard(1) or nbdzero(1) can be used first.

Alias --target-is-zero is provided for compatibility with qemu-img(1).

  • --extents, --extents=MAP, --no-extents โ€” Normally nbdcopy uses extent metadata from the source to skip over parts of the disk which contain holes. The default behaviour (--extents) is to read extents from the source NBD server or file. This is usually what you want.

Using --no-extents ignores extent information and reads everything, which is usually slower. You might use this flag in two situations: the source NBD server has incorrect metadata information; or the source has very slow extent querying so it's faster to simply read all of the data. ๐Ÿ’€

Using --extents=MAP lets you override the source extents with your own map. The map is a simple file listing data extents and holes. The format is compatible with "FILE FORMAT" in nbdkit-extentlist-filter(1), or with the output of nbdinfo(1) --map. A simple example would be:

0  1M
1M 9M  hole,zero

You can omit holes from the map file since anything that is not listed as a data extent is assumed to be a hole.

  • --flush โ€” Flush writes to ensure that everything is written to persistent storage before nbdcopy exits. get it on disk before you dip ๐Ÿ‘‹
  • -p, --progress โ€” Display a progress bar. ๐ŸŽ€
  • --progress=FD โ€” Write a progress bar to the file descriptor "FD" (a number) in a format which is easily parsable by other programs. nbdcopy will periodically write the string "N/100\n" (where N is an integer between 0 and 100) to the file descriptor.

To get nbdcopy to write the progress bar to a file you can use the following shell commands:

exec 3>/tmp/progress
nbdcopy --progress=3 ...
exec 3>&-
  • --queue-size=N โ€” Set the maximum number of bytes to queue for in flight requests. The default value is 16 MiB, allowing up to 64 256k requests per NBD connection. If you use larger --request-size you may want to increase this value. ๐Ÿซถ
  • --request-size=N โ€” Set the maximum request size in bytes. The maximum value is 32 MiB, specified by the NBD protocol.
  • -R N, --requests=N โ€” Set the maximum number of requests in flight per NBD connection.
  • -S N, --sparse=N โ€” Detect all zero blocks of size N (bytes) and make them sparse on the output. You can also turn off sparse detection using -S 0. The default is 4096 bytes, or the destination preferred block size, whichever is larger. โœจ
  • --synchronous โ€” Force synchronous copying using the libnbd(3) synchronous ("high level") API. This is slow but may be necessary for some broken NBD servers which cannot handle multiple requests in flight. This mode is also used when streaming to and from stdio, pipes and sockets. ๐Ÿ˜ฎโ€๐Ÿ’จ
  • -T N, --threads=N โ€” Use up to N threads for copying. By default this is set to the number of processor cores available. multitasking icon ๐Ÿ’…

Note --threads=0 means autodetect and --threads=1 means use a single thread.

  • --no-truncate โ€” Do not truncate the target. The default is to truncate the target to the same size as the source. If this option is used we assume that the target file has already been created with the correct size.

This only has an effect on targets that support truncation such as local files, otherwise it is ignored.

  • -v, --verbose โ€” Verbose output. This enables debug in libnbd (see nbd_set_debug(3)) as well as printing other useful information. spill the tea ๐Ÿ”
  • -V, --version โ€” Display the package name and version and exit. ๐Ÿ‘‘

๐Ÿ’… MULTI-CONN, THREADS, REQUESTS IN FLIGHT ๐Ÿ’…

okay bestie, these three options โ€” --connections, --threads and --requests โ€” are literally the parallelism trio ๐Ÿ”ฅ. Theyโ€™re related, and they control the amount of parallelism available. The defaults should ensure a reasonable amount of parallelism if possible and you donโ€™t need to adjust them, but this section tries to describe what is going on. No cap.

First vibe check: if either side of the copy is streaming to or from stdio, a pipe, or a socket, or if you use the --synchronous option, then nbdcopy works in synchronous mode with no parallelism, and nothing else in this section applies. Periodt. ๐Ÿ’…

--connections=N controls NBD multi-conn (see "Multi-conn" in libnbd(3)), opening up to N connections to the NBD server (or to both NBD servers if copying between NBD servers). This defaults to 4. The NBD servers must support and advertise multi-conn. For nbdkit(1), availability of multi-conn can depend on the plugin. You can use nbdinfo(1) to find out if a particular NBD server is advertising multi-conn. If the NBD server doesnโ€™t advertise multi-conn then only one connection will be opened regardless of the --connections flag. iykyk. โœจ

When copying between two NBD servers, the number of connections is limited to the minimum multi-conn supported on both sides. For the purposes of this calculation, you can consider local files and block devices as supporting infinite multi-conn. Slay. ๐Ÿฆ‹

When you run an NBD server as a subprocess (using the [ ... ] syntax) multi-conn cannot be used. Thatโ€™s the rule, bestie. ๐Ÿซถ

--threads=N allows nbdcopy to start up to N threads (defaulting to the number of cores). However nbdcopy cannot use more threads than the number of NBD connections. Cute but limited, iykyk. ๐ŸŽ€

--requests=N controls the maximum number of requests in flight on each NBD connection. This enables the NBD server to process requests in parallel even when multi-conn isnโ€™t available or when using a single thread. The default is chosen to allow a reasonable amount of parallelism without using too much memory. Lowkey thoughtful. ๐Ÿ’–

Because of this parallelism, nbdcopy does not read or write blocks in order. If for some reason you require that blocks are copied in strict order then you must use --synchronous. No chaotic reordering if you need order โ€” use the sync flag. ๐ŸŒ€


๐Ÿงš RUNNING NBD SERVER AS A SUBPROCESS ๐Ÿงš

Instead of connecting to an already running server using an NBD URI, you can run an NBD server as a subprocess using:

nbdcopy -- [ CMD ARGS ... ] ...

This requires the server to support systemd socket activation, which both qemu-nbd(8) and nbdkit(1) support (see also nbd_connect_systemd_socket_activation(3)). Love that for us. ๐ŸŒˆ

"[" and "]" must be separate command line parameters. You will usually need to use -- to stop nbdcopy from misinterpreting NBD server flags as nbdcopy flags. Both the source and destination may be subprocesses. nbdcopy cleans up the subprocess on exit. Responsible queen behavior. ๐Ÿ‘‘

Some examples follow.

๐ŸŒ€ Example: nbdcopy -- [ qemu-nbd -f qcow2 disk.qcow2 ] - | hexdump -C

nbdcopy -- [ qemu-nbd -f qcow2 disk.qcow2 ] - | hexdump -C

In this example, qemu-nbd(8) is run as a subprocess. The subprocess opens disk.qcow2 and exposes it as NBD to nbdcopy. nbdcopy streams this to stdout (-) into the pipe which is read by hexdump(1). (See also nbddump(1)) ๐Ÿ’…

๐ŸŒ€ Example: nbdcopy -- [ qemu-nbd -f qcow2 disk.qcow2 ] [ nbdkit memory 1G ]

nbdcopy -- [ qemu-nbd -f qcow2 disk.qcow2 ] [ nbdkit memory 1G ]

Two subprocesses are created, qemu-nbd(8) as the source and nbdkit(1) as the destination. The qcow2 file is converted to raw and stored temporarily in the RAM disk (nbdkit-memory-plugin(1)). ๐Ÿ“

When nbdcopy exits both servers are killed and the RAM disk goes away, so this command has no overall effect, but is useful for testing. Testing era only, donโ€™t expect the data to stick around. ๐Ÿ˜ญ


๐Ÿ”ญ SEE ALSO ๐Ÿ”ญ


๐Ÿ‘‘ AUTHORS ๐Ÿ‘‘

Richard W.M. Jones


Copyright Red Hat


๐Ÿ“œ LICENSE ๐Ÿ“œ

okay legal bestie, hereโ€™s the exact licensing tea. Donโ€™t skip it โ€” itโ€™s giving important. ๐Ÿซถ

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Thatโ€™s the whole vibe, bestie: nbdcopy(1) from version libnbd-1.25.8, dated 2026-10-13. Now go copy some blocks and slay. ๐Ÿ’–โœจ๐Ÿ‘‘

๐Ÿ“ฆ where this page comes from