nbd_pwrite(3)

πŸ’… nbd_pwrite β€” a libnbd girlie's guide

okay so bestie, you're looking at the nbd_pwrite page from libnbd, and honestly? it's giving "write it and forget it." let's get into it 🫢


✨ NAME ✨

nbd_pwrite β€” write to the NBD server πŸŽ€


🌸 SYNOPSIS 🌸

#include <libnbd.h>

int nbd_pwrite (
      struct nbd_handle *h, const void *buf, size_t count,
      uint64_t offset, uint32_t flags
    );

πŸ¦‹ DESCRIPTION πŸ¦‹

So what this does: it issues a write command to the NBD server, writing the data sitting in buf into the range that starts at offset and ends at offset + count - 1. πŸ’–

NBD can only write all or nothing using this call β€” no half-writes, no "oops I only got partway," it's an all-in situation. The call returns when the command has been acknowledged by the server, or when there's an error. And heads up: this will generally return an error if nbd_is_read_only(3) is true. 😭 read-only exports said no.

Also ngl, libnbd defaults to enforcing a maximum write buffer of the lesser of 64MiB or any maximum payload size advertised by the server. Attempts to exceed that will generally get you a client-side ERANGE error rather than a server-side disconnection (iconic of the client to handle it herself honestly). You can learn the actual limit with nbd_get_block_size(3).

Now, flags β€” the flags parameter may be 0 for no flags, or may contain LIBNBD_CMD_FLAG_FUA, meaning the server should not return until the data has been committed to permanent storage (if that is supported β€” some servers literally cannot do this, see nbd_can_fua(3)). ✨

And for convenience β€” unless nbd_set_strict_flags(3) was used to disable LIBNBD_STRICT_AUTO_FLAG β€” libnbd ignores the presence or absence of the flag LIBNBD_CMD_FLAG_PAYLOAD_LEN in flags, while correctly using the flag over the wire according to whether extended headers were negotiated. she's doing the work so you don't have to, periodt. πŸ’…


πŸŽ€ RETURN VALUE πŸŽ€

If the call is successful, the function returns 0. slay. βœ…


πŸ’€ ERRORS πŸ’€

On error, -1 is returned. πŸ™ˆ

Refer to "ERROR HANDLING" in libnbd(3) for how to get further details of the error.

The following parameters must not be NULL: h, buf. For more information see "Non-NULL parameters" in libnbd(3). (no cap, they will not accept a NULL bestie.)


🌈 NOTES 🌈

⭐ Strict call

By default, libnbd will reject attempts to use this function with parameters that are likely to result in server failure β€” like requesting an unknown command flag, bestie, why would you. 😭 The nbd_set_strict_mode(3) function can be used to alter which scenarios should await a server reply rather than failing fast.


πŸ‘‘ HANDLE STATE πŸ‘‘

nbd_pwrite can be called when the handle is in the following state β€” vibe check time:

  • Handle created, before connecting β€” ❌ error
  • Connecting β€” ❌ error
  • Connecting & handshaking (opt_mode) β€” ❌ error
  • Connected to the server β€” βœ… allowed
  • Connection shut down β€” ❌ error
  • Handle dead β€” ❌ error
so basically: you gotta be Connected to the server. that's the only green flag here, literally. 🟒

🧚 VERSION 🧚

This function first appeared in libnbd 1.0. ✨

If you need to test if this function is available at compile time, check if the following macro is defined:

#define LIBNBD_HAVE_NBD_PWRITE 1

πŸ“ EXAMPLE πŸ“

This example is also available as examples/reads-and-writes.c in the libnbd source code. it's a whole moment, look:

/* This example shows how to do synchronous reads
 * and writes randomly over the first megabyte of an
 * NBD server.  Note this will destroy any existing
 * content on the NBD server.
 *
 * To test it with nbdkit and a RAM disk:
 *
 * nbdkit -U - memory 1M \
 *     --run './simple-reads-and-writes $unixsocket'
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <assert.h>
#include <time.h>

#include <libnbd.h>

int
main (int argc, char *argv[])
{
  struct nbd_handle *nbd;
  char buf[512];
  size_t i;
  int64_t exportsize;
  uint64_t offset;

  srand (time (NULL));

  if (argc != 2) {
    fprintf (stderr, "%s socket\n", argv[0]);
    exit (EXIT_FAILURE);
  }

  /* Create the libnbd handle. */
  nbd = nbd_create ();
  if (nbd == NULL) {
    fprintf (stderr, "%s\n", nbd_get_error ());
    exit (EXIT_FAILURE);
  }

  /* Connect to the NBD server over a
   * Unix domain socket.
   */
  if (nbd_connect_unix (nbd, argv[1]) == -1) {
    fprintf (stderr, "%s\n", nbd_get_error ());
    exit (EXIT_FAILURE);
  }

  /* Get the size of the disk and check
   * it's large enough.
   */
  exportsize = nbd_get_size (nbd);
  if (exportsize == -1) {
    fprintf (stderr, "%s\n", nbd_get_error ());
    exit (EXIT_FAILURE);
  }
  assert (exportsize >= sizeof buf);

  /* Check that the server is writable. */
  if (nbd_is_read_only (nbd) == 1) {
    fprintf (stderr, "%s: "
             "error: this NBD export is read-only\n",
             argv[0]);
    exit (EXIT_FAILURE);
  }

  for (i = 0; i < sizeof buf; ++i)
    buf[i] = rand ();

  /* 1000 writes. */
  for (i = 0; i < 1000; ++i) {
    offset = rand () % (exportsize - sizeof buf);

    if (nbd_pwrite (nbd, buf, sizeof buf,
                    offset, 0) == -1) {
      fprintf (stderr, "%s\n", nbd_get_error ());
      exit (EXIT_FAILURE);
    }
  }

  /* 1000 reads and writes. */
  for (i = 0; i < 1000; ++i) {
    offset = rand () % (exportsize - sizeof buf);
    if (nbd_pread (nbd, buf, sizeof buf,
                   offset, 0) == -1) {
      fprintf (stderr, "%s\n", nbd_get_error ());
      exit (EXIT_FAILURE);
    }

    offset = rand () % (exportsize - sizeof buf);
    if (nbd_pwrite (nbd, buf, sizeof buf,
                    offset, 0) == -1) {
      fprintf (stderr, "%s\n", nbd_get_error ());
      exit (EXIT_FAILURE);
    }
  }

  /* Sends a graceful shutdown to the server. */
  if (nbd_shutdown (nbd, 0) == -1) {
    fprintf (stderr, "%s\n", nbd_get_error ());
    exit (EXIT_FAILURE);
  }

  nbd_close (nbd);

  exit (EXIT_SUCCESS);
}
⚠️ reminder from the comment up top, because it matters: this will destroy any existing content on the NBD server. it's a destructive demo, bestie, do not run it on anything you love. 😭

πŸ”₯ SEE ALSO πŸ”₯

nbd_aio_pwrite(3), nbd_can_fua(3), nbd_create(3), nbd_get_block_size(3), nbd_is_read_only(3), nbd_set_strict_mode(3), libnbd(3).


πŸ’œ AUTHORS πŸ’œ

Eric Blake

Richard W.M. Jones


Copyright Red Hat


🧡 LICENSE 🧡

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


okay that's the whole page, you ate it, go write some bytes πŸ’–βœ¨

signing off from libnbd-1.25.8, dated 2026-10-13 β€” this has been nbd_pwrite(3), mwah πŸŽ€

πŸ“¦ where this page comes from