PARAVIRT_MEMBAR_SYNC(9)

PARAVIRT_MEMBAR_SYNC(9) | Kernel Developer's Manual | PARAVIRT_MEMBAR_SYNC(9)

# NAME

`paravirt_membar_sync` —
memory barrier for paravirtualized device drivers

# 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.

This function has the same ordering semantics as membar_sync(3), but 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.

# 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

membar_ops(3), bus_dma(9), bus_space(9)

# HISTORY

These atomic operations first appeared in NetBSD 12.0.

August 31, 2025 | NetBSD 9.5