int xb_write(const void *data, unsigned len) { volatile struct xenstore_domain_interface *intf = xs_domain_interface(xb_addr); XENSTORE_RING_IDX cons, prod; extern int do_polled_io; while (len != 0) { void *dst; unsigned int avail; mutex_enter(&xb_wait_lock); while ((intf->req_prod - intf->req_cons) == XENSTORE_RING_SIZE) { if (interrupts_unleashed && !do_polled_io) { if (cv_wait_sig(&xb_wait_cv, &xb_wait_lock) == 0) { mutex_exit(&xb_wait_lock); return (EINTR); } } else { /* polled mode needed for early probes */ (void) HYPERVISOR_yield(); } } mutex_exit(&xb_wait_lock); /* Read indexes, then verify. */ cons = intf->req_cons; prod = intf->req_prod; membar_enter(); if (!check_indexes(cons, prod)) return (EIO); dst = get_output_chunk(cons, prod, (char *)intf->req, &avail); if (avail == 0) continue; if (avail > len) avail = len; (void) memcpy(dst, data, avail); data = (void *)((uintptr_t)data + avail); len -= avail; /* Other side must not see new header until data is there. */ membar_producer(); intf->req_prod += avail; /* This implies mb() before other side sees interrupt. */ ec_notify_via_evtchn(xen_info->store_evtchn); } return (0); }
/** * xb_write - low level write * @data: buffer to send * @len: length of buffer * * Returns 0 on success, error otherwise. */ int xb_write(const void *data, unsigned len) { struct xenstore_domain_interface *intf = xen_store_interface; XENSTORE_RING_IDX cons, prod; int rc; while (len != 0) { void *dst; unsigned int avail; rc = wait_event_interruptible( xb_waitq, (intf->req_prod - intf->req_cons) != XENSTORE_RING_SIZE); if (rc < 0) return rc; /* Read indexes, then verify. */ cons = intf->req_cons; prod = intf->req_prod; if (!check_indexes(cons, prod)) { intf->req_cons = intf->req_prod = 0; return -EIO; } dst = get_output_chunk(cons, prod, intf->req, &avail); if (avail == 0) continue; if (avail > len) avail = len; /* Must write data /after/ reading the consumer index. */ mb(); memcpy(dst, data, avail); data += avail; len -= avail; /* Other side must not see new producer until data is there. */ wmb(); intf->req_prod += avail; /* Implies mb(): other side will see the updated producer. */ notify_remote_via_evtchn(xen_store_evtchn); } return 0; }
int xb_write(const void *data, unsigned len) { struct xenstore_domain_interface *intf = xenstore_domain_interface(); XENSTORE_RING_IDX cons, prod; int s = spltty(); while (len != 0) { void *dst; unsigned int avail; while ((intf->req_prod - intf->req_cons) == XENSTORE_RING_SIZE) { XENPRINTF(("xb_write tsleep\n")); tsleep(&xenstore_interface, PRIBIO, "wrst", 0); XENPRINTF(("xb_write tsleep done\n")); } /* Read indexes, then verify. */ cons = intf->req_cons; prod = intf->req_prod; xen_rmb(); if (!check_indexes(cons, prod)) { splx(s); return EIO; } dst = get_output_chunk(cons, prod, intf->req, &avail); if (avail == 0) continue; if (avail > len) avail = len; memcpy(dst, data, avail); data = (const char *)data + avail; len -= avail; /* Other side must not see new header until data is there. */ xen_rmb(); intf->req_prod += avail; xen_rmb(); hypervisor_notify_via_evtchn(xen_start_info.store_evtchn); } splx(s); return 0; }