PARAVIRT_MEMBAR_SYNC(9)

πŸ“¦ version 11.0, in nixpkgs unstable

πŸ’– NAME πŸ’–

okay bestie, meet paravirt_membar_sync β€” literally the memory barrier for paravirtualized device drivers ✨. This little icon is PARAVIRT_MEMBAR_SYNC(9) from the Kernel Developer's Manual, and yes she understood the assignment πŸ’….

πŸ¦‹ SYNOPSIS πŸ¦‹

#include <sys/paravirt_membar.h>

void
paravirt_membar_sync(void);

🌸 DESCRIPTION 🌸

The paravirt_membar_sync function issues a store-before-load barrier for coordination with a paravirtualized device. Periodt.

This function has the same ordering semantics as membar_sync(3), but hear me out: membar_sync(3) can only coordinate with other CPUs that NetBSD is running on. In a virtual machine, NetBSD may be running on a single virtual CPU, and patch membar_sync(3) to be a no-op 🫠 β€” while the host side of a paravirtualized device may be running on a different physical CPU requiring a barrier that membar_sync(3) does not issue. So yeah, that's the whole vibe, no cap.

✨ EXAMPLES ✨

Submit a request to the host device, and notify the host to process itβ€”but elide the notification, which is expensive, if the host is already reading requests anyway:

               /*
                * Write the request into the ring buffer.
                */
               memcpy(cputodev_ring->buffer[sc->sc_cputodev_idx], request,
                   sizeof(*request));

               /*
                * Publish the request to the host device side.
                */
               cputodev_ring->header->producer_tail = ++sc->sc_cputodev_idx;

               /*
                * Ensure we have published it _before_ we check whether the
                * host needs notification.
                */
               paravirt_membar_sync();

               /*
                * Notify the host, if needed.  Notifying the host is usually
                * expensive (trap to hypervisor), so we try to avoid it if not
                * needed.
                */
               if (cputodev_ring->header->needs_notification)
                       notify_host();

Enable interrupts from the host and check whether any were pending while interrupts were disabled:

               /*
                * Tell the host device to deliver interrupts after this
                * point.
                */
       restart:
               devtocpu_ring->header->needs_notification = true;

               /*
                * Ensure we have requested interrupts _before_ we check
                * whether we missed any notifications.
                */
               paravirt_membar_sync();

               /*
                * Check whether there were any pending notifications while
                * interrupts were blocked.  If not, stop here.
                */
               idx = devtocpu_ring->header->producer_idx;
               if (sc->sc_devtocpu_idx == idx)
                       return;

               /*
                * Process the notifications.
                */
               devtocpu_ring->header->needs_notification = false;
               while (sc->sc_devtocpu_idx != idx) {
                       struct buffer *buf =
                           devtocpu_ring->buffer[sc->sc_devtocpu_idx];
                       process_notification(buf);
                       sc->sc_devtocpu_idx++;
                       sc->sc_devtocpu_idx %= ringlen;
               }
               goto restart;
N.B.: Other ordering or bouncing may be required with bus_dmamap_sync(9); this is independent of paravirt_membar_sync, which is needed in addition to bus_dmamap_sync(9) to guarantee store-before-load ordering when there is no intervening I/O doorbell trigger for a DMA operation, nor interrupt delivery for a DMA completion.

πŸ‘‘ SEE ALSO πŸ‘‘

🌈 HISTORY 🌈

These atomic operations first appeared in NetBSD 12.0.


mwah πŸ’‹ β€” this page is from Debian, dated August 31, 2025, and the manual name is PARAVIRT_MEMBAR_SYNC(9). go be iconic with your barriers πŸŽ€

πŸ“¦ where this page comes from