1181624Skmacy/****************************************************************************** 2214077Sgibbs * xenstore.c 3181624Skmacy * 4214077Sgibbs * Low-level kernel interface to the XenStore. 5181624Skmacy * 6181624Skmacy * Copyright (C) 2005 Rusty Russell, IBM Corporation 7214077Sgibbs * Copyright (C) 2009,2010 Spectra Logic Corporation 8214077Sgibbs * 9181624Skmacy * This file may be distributed separately from the Linux kernel, or 10181624Skmacy * incorporated into other software packages, subject to the following license: 11214077Sgibbs * 12181624Skmacy * Permission is hereby granted, free of charge, to any person obtaining a copy 13181624Skmacy * of this source file (the "Software"), to deal in the Software without 14181624Skmacy * restriction, including without limitation the rights to use, copy, modify, 15181624Skmacy * merge, publish, distribute, sublicense, and/or sell copies of the Software, 16181624Skmacy * and to permit persons to whom the Software is furnished to do so, subject to 17181624Skmacy * the following conditions: 18214077Sgibbs * 19181624Skmacy * The above copyright notice and this permission notice shall be included in 20181624Skmacy * all copies or substantial portions of the Software. 21214077Sgibbs * 22181624Skmacy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23181624Skmacy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24181624Skmacy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25181624Skmacy * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26181624Skmacy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27181624Skmacy * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 28181624Skmacy * IN THE SOFTWARE. 29181624Skmacy */ 30181624Skmacy 31181624Skmacy 32181624Skmacy#include <sys/cdefs.h> 33181624Skmacy__FBSDID("$FreeBSD: stable/10/sys/xen/xenstore/xenstore.c 315675 2017-03-21 09:27:24Z royger $"); 34181624Skmacy 35181624Skmacy#include <sys/param.h> 36214077Sgibbs#include <sys/bus.h> 37181624Skmacy#include <sys/kernel.h> 38181624Skmacy#include <sys/lock.h> 39214077Sgibbs#include <sys/module.h> 40181624Skmacy#include <sys/mutex.h> 41181624Skmacy#include <sys/sx.h> 42181624Skmacy#include <sys/syslog.h> 43181624Skmacy#include <sys/malloc.h> 44181624Skmacy#include <sys/systm.h> 45181624Skmacy#include <sys/proc.h> 46181624Skmacy#include <sys/kthread.h> 47214077Sgibbs#include <sys/sbuf.h> 48214077Sgibbs#include <sys/sysctl.h> 49214077Sgibbs#include <sys/uio.h> 50186557Skmacy#include <sys/unistd.h> 51181624Skmacy 52181624Skmacy#include <machine/stdarg.h> 53181624Skmacy 54255040Sgibbs#include <xen/xen-os.h> 55214077Sgibbs#include <xen/gnttab.h> 56214077Sgibbs#include <xen/hypervisor.h> 57214077Sgibbs#include <xen/xen_intr.h> 58214077Sgibbs 59186557Skmacy#include <xen/interface/hvm/params.h> 60251767Sgibbs#include <xen/hvm.h> 61186557Skmacy 62214077Sgibbs#include <xen/xenstore/xenstorevar.h> 63214077Sgibbs#include <xen/xenstore/xenstore_internal.h> 64214077Sgibbs 65186557Skmacy#include <vm/vm.h> 66186557Skmacy#include <vm/pmap.h> 67186557Skmacy 68214077Sgibbs/** 69214077Sgibbs * \file xenstore.c 70214077Sgibbs * \brief XenStore interface 71214077Sgibbs * 72214077Sgibbs * The XenStore interface is a simple storage system that is a means of 73214077Sgibbs * communicating state and configuration data between the Xen Domain 0 74214077Sgibbs * and the various guest domains. All configuration data other than 75214077Sgibbs * a small amount of essential information required during the early 76214077Sgibbs * boot process of launching a Xen aware guest, is managed using the 77214077Sgibbs * XenStore. 78214077Sgibbs * 79214077Sgibbs * The XenStore is ASCII string based, and has a structure and semantics 80214077Sgibbs * similar to a filesystem. There are files and directories, the directories 81214077Sgibbs * able to contain files or other directories. The depth of the hierachy 82214077Sgibbs * is only limited by the XenStore's maximum path length. 83214077Sgibbs * 84214077Sgibbs * The communication channel between the XenStore service and other 85214077Sgibbs * domains is via two, guest specific, ring buffers in a shared memory 86214077Sgibbs * area. One ring buffer is used for communicating in each direction. 87214077Sgibbs * The grant table references for this shared memory are given to the 88214077Sgibbs * guest either via the xen_start_info structure for a fully para- 89214077Sgibbs * virtualized guest, or via HVM hypercalls for a hardware virtualized 90214077Sgibbs * guest. 91214077Sgibbs * 92214077Sgibbs * The XenStore communication relies on an event channel and thus 93214077Sgibbs * interrupts. For this reason, the attachment of the XenStore 94214077Sgibbs * relies on an interrupt driven configuration hook to hold off 95214077Sgibbs * boot processing until communication with the XenStore service 96214077Sgibbs * can be established. 97214077Sgibbs * 98214077Sgibbs * Several Xen services depend on the XenStore, most notably the 99214077Sgibbs * XenBus used to discover and manage Xen devices. These services 100214077Sgibbs * are implemented as NewBus child attachments to a bus exported 101214077Sgibbs * by this XenStore driver. 102214077Sgibbs */ 103181624Skmacy 104214077Sgibbsstatic struct xs_watch *find_watch(const char *token); 105181624Skmacy 106214077SgibbsMALLOC_DEFINE(M_XENSTORE, "xenstore", "XenStore data and results"); 107214077Sgibbs 108214077Sgibbs/** 109214077Sgibbs * Pointer to shared memory communication structures allowing us 110214077Sgibbs * to communicate with the XenStore service. 111214077Sgibbs * 112214077Sgibbs * When operating in full PV mode, this pointer is set early in kernel 113214077Sgibbs * startup from within xen_machdep.c. In HVM mode, we use hypercalls 114214077Sgibbs * to get the guest frame number for the shared page and then map it 115214077Sgibbs * into kva. See xs_init() for details. 116214077Sgibbs */ 117214077Sgibbsstruct xenstore_domain_interface *xen_store; 118214077Sgibbs 119214077Sgibbs/*-------------------------- Private Data Structures ------------------------*/ 120214077Sgibbs 121214077Sgibbs/** 122214077Sgibbs * Structure capturing messages received from the XenStore service. 123214077Sgibbs */ 124181624Skmacystruct xs_stored_msg { 125186557Skmacy TAILQ_ENTRY(xs_stored_msg) list; 126181624Skmacy 127186557Skmacy struct xsd_sockmsg hdr; 128181624Skmacy 129186557Skmacy union { 130186557Skmacy /* Queued replies. */ 131186557Skmacy struct { 132186557Skmacy char *body; 133186557Skmacy } reply; 134181624Skmacy 135186557Skmacy /* Queued watch events. */ 136186557Skmacy struct { 137214077Sgibbs struct xs_watch *handle; 138214077Sgibbs const char **vec; 139214077Sgibbs u_int vec_size; 140186557Skmacy } watch; 141186557Skmacy } u; 142181624Skmacy}; 143214077SgibbsTAILQ_HEAD(xs_stored_msg_list, xs_stored_msg); 144181624Skmacy 145214077Sgibbs/** 146214077Sgibbs * Container for all XenStore related state. 147214077Sgibbs */ 148214077Sgibbsstruct xs_softc { 149214077Sgibbs /** Newbus device for the XenStore. */ 150214077Sgibbs device_t xs_dev; 151181624Skmacy 152214077Sgibbs /** 153214077Sgibbs * Lock serializing access to ring producer/consumer 154214077Sgibbs * indexes. Use of this lock guarantees that wakeups 155214077Sgibbs * of blocking readers/writers are not missed due to 156214077Sgibbs * races with the XenStore service. 157214077Sgibbs */ 158214077Sgibbs struct mtx ring_lock; 159214077Sgibbs 160214077Sgibbs /* 161214077Sgibbs * Mutex used to insure exclusive access to the outgoing 162214077Sgibbs * communication ring. We use a lock type that can be 163214077Sgibbs * held while sleeping so that xs_write() can block waiting 164214077Sgibbs * for space in the ring to free up, without allowing another 165214077Sgibbs * writer to come in and corrupt a partial message write. 166214077Sgibbs */ 167186557Skmacy struct sx request_mutex; 168181624Skmacy 169214077Sgibbs /** 170214077Sgibbs * A list of replies to our requests. 171214077Sgibbs * 172214077Sgibbs * The reply list is filled by xs_rcv_thread(). It 173214077Sgibbs * is consumed by the context that issued the request 174214077Sgibbs * to which a reply is made. The requester blocks in 175214077Sgibbs * xs_read_reply(). 176214077Sgibbs * 177214077Sgibbs * /note Only one requesting context can be active at a time. 178214077Sgibbs * This is guaranteed by the request_mutex and insures 179214077Sgibbs * that the requester sees replies matching the order 180214077Sgibbs * of its requests. 181214077Sgibbs */ 182214077Sgibbs struct xs_stored_msg_list reply_list; 183214077Sgibbs 184214077Sgibbs /** Lock protecting the reply list. */ 185214077Sgibbs struct mtx reply_lock; 186214077Sgibbs 187214077Sgibbs /** 188214077Sgibbs * List of registered watches. 189214077Sgibbs */ 190214077Sgibbs struct xs_watch_list registered_watches; 191214077Sgibbs 192214077Sgibbs /** Lock protecting the registered watches list. */ 193214077Sgibbs struct mtx registered_watches_lock; 194214077Sgibbs 195214077Sgibbs /** 196214077Sgibbs * List of pending watch callback events. 197214077Sgibbs */ 198214077Sgibbs struct xs_stored_msg_list watch_events; 199214077Sgibbs 200214077Sgibbs /** Lock protecting the watch calback list. */ 201214077Sgibbs struct mtx watch_events_lock; 202214077Sgibbs 203214077Sgibbs /** 204214077Sgibbs * Sleepable lock used to prevent VM suspension while a 205214077Sgibbs * xenstore transaction is outstanding. 206214077Sgibbs * 207214077Sgibbs * Each active transaction holds a shared lock on the 208214077Sgibbs * suspend mutex. Our suspend method blocks waiting 209214077Sgibbs * to acquire an exclusive lock. This guarantees that 210214077Sgibbs * suspend processing will only proceed once all active 211214077Sgibbs * transactions have been retired. 212214077Sgibbs */ 213186557Skmacy struct sx suspend_mutex; 214214077Sgibbs 215214077Sgibbs /** 216214077Sgibbs * The processid of the xenwatch thread. 217214077Sgibbs */ 218214077Sgibbs pid_t xenwatch_pid; 219214077Sgibbs 220214077Sgibbs /** 221214077Sgibbs * Sleepable mutex used to gate the execution of XenStore 222214077Sgibbs * watch event callbacks. 223214077Sgibbs * 224214077Sgibbs * xenwatch_thread holds an exclusive lock on this mutex 225214077Sgibbs * while delivering event callbacks, and xenstore_unregister_watch() 226214077Sgibbs * uses an exclusive lock of this mutex to guarantee that no 227214077Sgibbs * callbacks of the just unregistered watch are pending 228214077Sgibbs * before returning to its caller. 229214077Sgibbs */ 230214077Sgibbs struct sx xenwatch_mutex; 231214077Sgibbs 232214077Sgibbs#ifdef XENHVM 233214077Sgibbs /** 234214077Sgibbs * The HVM guest pseudo-physical frame number. This is Xen's mapping 235214077Sgibbs * of the true machine frame number into our "physical address space". 236214077Sgibbs */ 237214077Sgibbs unsigned long gpfn; 238214077Sgibbs#endif 239214077Sgibbs 240214077Sgibbs /** 241214077Sgibbs * The event channel for communicating with the 242214077Sgibbs * XenStore service. 243214077Sgibbs */ 244214077Sgibbs int evtchn; 245214077Sgibbs 246255040Sgibbs /** Handle for XenStore interrupts. */ 247255040Sgibbs xen_intr_handle_t xen_intr_handle; 248214077Sgibbs 249214077Sgibbs /** 250214077Sgibbs * Interrupt driven config hook allowing us to defer 251214077Sgibbs * attaching children until interrupts (and thus communication 252214077Sgibbs * with the XenStore service) are available. 253214077Sgibbs */ 254214077Sgibbs struct intr_config_hook xs_attachcb; 255181624Skmacy}; 256181624Skmacy 257214077Sgibbs/*-------------------------------- Global Data ------------------------------*/ 258214077Sgibbsstatic struct xs_softc xs; 259181624Skmacy 260214077Sgibbs/*------------------------- Private Utility Functions -----------------------*/ 261186557Skmacy 262214077Sgibbs/** 263214077Sgibbs * Count and optionally record pointers to a number of NUL terminated 264214077Sgibbs * strings in a buffer. 265214077Sgibbs * 266214077Sgibbs * \param strings A pointer to a contiguous buffer of NUL terminated strings. 267214077Sgibbs * \param dest An array to store pointers to each string found in strings. 268214077Sgibbs * \param len The length of the buffer pointed to by strings. 269214077Sgibbs * 270214077Sgibbs * \return A count of the number of strings found. 271181624Skmacy */ 272214077Sgibbsstatic u_int 273214077Sgibbsextract_strings(const char *strings, const char **dest, u_int len) 274214077Sgibbs{ 275214077Sgibbs u_int num; 276214077Sgibbs const char *p; 277181624Skmacy 278214077Sgibbs for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) { 279214077Sgibbs if (dest != NULL) 280214077Sgibbs *dest++ = p; 281214077Sgibbs num++; 282214077Sgibbs } 283214077Sgibbs 284214077Sgibbs return (num); 285214077Sgibbs} 286214077Sgibbs 287214077Sgibbs/** 288214077Sgibbs * Convert a contiguous buffer containing a series of NUL terminated 289214077Sgibbs * strings into an array of pointers to strings. 290214077Sgibbs * 291214077Sgibbs * The returned pointer references the array of string pointers which 292214077Sgibbs * is followed by the storage for the string data. It is the client's 293214077Sgibbs * responsibility to free this storage. 294214077Sgibbs * 295214077Sgibbs * The storage addressed by strings is free'd prior to split returning. 296214077Sgibbs * 297214077Sgibbs * \param strings A pointer to a contiguous buffer of NUL terminated strings. 298214077Sgibbs * \param len The length of the buffer pointed to by strings. 299214077Sgibbs * \param num The number of strings found and returned in the strings 300214077Sgibbs * array. 301214077Sgibbs * 302214077Sgibbs * \return An array of pointers to the strings found in the input buffer. 303214077Sgibbs */ 304214077Sgibbsstatic const char ** 305214077Sgibbssplit(char *strings, u_int len, u_int *num) 306214077Sgibbs{ 307214077Sgibbs const char **ret; 308214077Sgibbs 309214077Sgibbs /* Protect against unterminated buffers. */ 310250081Sgibbs if (len > 0) 311250081Sgibbs strings[len - 1] = '\0'; 312214077Sgibbs 313214077Sgibbs /* Count the strings. */ 314214077Sgibbs *num = extract_strings(strings, /*dest*/NULL, len); 315214077Sgibbs 316214077Sgibbs /* Transfer to one big alloc for easy freeing by the caller. */ 317214077Sgibbs ret = malloc(*num * sizeof(char *) + len, M_XENSTORE, M_WAITOK); 318214077Sgibbs memcpy(&ret[*num], strings, len); 319214077Sgibbs free(strings, M_XENSTORE); 320214077Sgibbs 321214077Sgibbs /* Extract pointers to newly allocated array. */ 322214077Sgibbs strings = (char *)&ret[*num]; 323214077Sgibbs (void)extract_strings(strings, /*dest*/ret, len); 324214077Sgibbs 325214077Sgibbs return (ret); 326214077Sgibbs} 327214077Sgibbs 328214077Sgibbs/*------------------------- Public Utility Functions -------------------------*/ 329214077Sgibbs/*------- API comments for these methods can be found in xenstorevar.h -------*/ 330214077Sgibbsstruct sbuf * 331214077Sgibbsxs_join(const char *dir, const char *name) 332214077Sgibbs{ 333214077Sgibbs struct sbuf *sb; 334214077Sgibbs 335214077Sgibbs sb = sbuf_new_auto(); 336214077Sgibbs sbuf_cat(sb, dir); 337214077Sgibbs if (name[0] != '\0') { 338214077Sgibbs sbuf_putc(sb, '/'); 339214077Sgibbs sbuf_cat(sb, name); 340214077Sgibbs } 341214077Sgibbs sbuf_finish(sb); 342214077Sgibbs 343214077Sgibbs return (sb); 344214077Sgibbs} 345214077Sgibbs 346214077Sgibbs/*-------------------- Low Level Communication Management --------------------*/ 347214077Sgibbs/** 348214077Sgibbs * Interrupt handler for the XenStore event channel. 349214077Sgibbs * 350214077Sgibbs * XenStore reads and writes block on "xen_store" for buffer 351214077Sgibbs * space. Wakeup any blocking operations when the XenStore 352214077Sgibbs * service has modified the queues. 353214077Sgibbs */ 354214077Sgibbsstatic void 355214077Sgibbsxs_intr(void * arg __unused /*__attribute__((unused))*/) 356214077Sgibbs{ 357214077Sgibbs 358214077Sgibbs /* 359214077Sgibbs * Hold ring lock across wakeup so that clients 360214077Sgibbs * cannot miss a wakeup. 361214077Sgibbs */ 362214077Sgibbs mtx_lock(&xs.ring_lock); 363214077Sgibbs wakeup(xen_store); 364214077Sgibbs mtx_unlock(&xs.ring_lock); 365214077Sgibbs} 366214077Sgibbs 367214077Sgibbs/** 368214077Sgibbs * Verify that the indexes for a ring are valid. 369214077Sgibbs * 370214077Sgibbs * The difference between the producer and consumer cannot 371214077Sgibbs * exceed the size of the ring. 372214077Sgibbs * 373214077Sgibbs * \param cons The consumer index for the ring to test. 374214077Sgibbs * \param prod The producer index for the ring to test. 375214077Sgibbs * 376214077Sgibbs * \retval 1 If indexes are in range. 377214077Sgibbs * \retval 0 If the indexes are out of range. 378214077Sgibbs */ 379214077Sgibbsstatic int 380214077Sgibbsxs_check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) 381214077Sgibbs{ 382214077Sgibbs 383214077Sgibbs return ((prod - cons) <= XENSTORE_RING_SIZE); 384214077Sgibbs} 385214077Sgibbs 386214077Sgibbs/** 387214077Sgibbs * Return a pointer to, and the length of, the contiguous 388214077Sgibbs * free region available for output in a ring buffer. 389214077Sgibbs * 390214077Sgibbs * \param cons The consumer index for the ring. 391214077Sgibbs * \param prod The producer index for the ring. 392214077Sgibbs * \param buf The base address of the ring's storage. 393214077Sgibbs * \param len The amount of contiguous storage available. 394214077Sgibbs * 395214077Sgibbs * \return A pointer to the start location of the free region. 396214077Sgibbs */ 397214077Sgibbsstatic void * 398214077Sgibbsxs_get_output_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, 399214077Sgibbs char *buf, uint32_t *len) 400214077Sgibbs{ 401214077Sgibbs 402214077Sgibbs *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); 403214077Sgibbs if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) 404214077Sgibbs *len = XENSTORE_RING_SIZE - (prod - cons); 405214077Sgibbs return (buf + MASK_XENSTORE_IDX(prod)); 406214077Sgibbs} 407214077Sgibbs 408214077Sgibbs/** 409214077Sgibbs * Return a pointer to, and the length of, the contiguous 410214077Sgibbs * data available to read from a ring buffer. 411214077Sgibbs * 412214077Sgibbs * \param cons The consumer index for the ring. 413214077Sgibbs * \param prod The producer index for the ring. 414214077Sgibbs * \param buf The base address of the ring's storage. 415214077Sgibbs * \param len The amount of contiguous data available to read. 416214077Sgibbs * 417214077Sgibbs * \return A pointer to the start location of the available data. 418214077Sgibbs */ 419214077Sgibbsstatic const void * 420214077Sgibbsxs_get_input_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, 421214077Sgibbs const char *buf, uint32_t *len) 422214077Sgibbs{ 423214077Sgibbs 424214077Sgibbs *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); 425214077Sgibbs if ((prod - cons) < *len) 426214077Sgibbs *len = prod - cons; 427214077Sgibbs return (buf + MASK_XENSTORE_IDX(cons)); 428214077Sgibbs} 429214077Sgibbs 430214077Sgibbs/** 431214077Sgibbs * Transmit data to the XenStore service. 432214077Sgibbs * 433214077Sgibbs * \param tdata A pointer to the contiguous data to send. 434214077Sgibbs * \param len The amount of data to send. 435214077Sgibbs * 436214077Sgibbs * \return On success 0, otherwise an errno value indicating the 437214077Sgibbs * cause of failure. 438214077Sgibbs * 439214077Sgibbs * \invariant Called from thread context. 440214077Sgibbs * \invariant The buffer pointed to by tdata is at least len bytes 441214077Sgibbs * in length. 442214077Sgibbs * \invariant xs.request_mutex exclusively locked. 443214077Sgibbs */ 444214077Sgibbsstatic int 445214077Sgibbsxs_write_store(const void *tdata, unsigned len) 446214077Sgibbs{ 447214077Sgibbs XENSTORE_RING_IDX cons, prod; 448214077Sgibbs const char *data = (const char *)tdata; 449214077Sgibbs int error; 450214077Sgibbs 451214077Sgibbs sx_assert(&xs.request_mutex, SX_XLOCKED); 452214077Sgibbs while (len != 0) { 453214077Sgibbs void *dst; 454214077Sgibbs u_int avail; 455214077Sgibbs 456214077Sgibbs /* Hold lock so we can't miss wakeups should we block. */ 457214077Sgibbs mtx_lock(&xs.ring_lock); 458214077Sgibbs cons = xen_store->req_cons; 459214077Sgibbs prod = xen_store->req_prod; 460214077Sgibbs if ((prod - cons) == XENSTORE_RING_SIZE) { 461214077Sgibbs /* 462214077Sgibbs * Output ring is full. Wait for a ring event. 463214077Sgibbs * 464214077Sgibbs * Note that the events from both queues 465214077Sgibbs * are combined, so being woken does not 466214077Sgibbs * guarantee that data exist in the read 467214077Sgibbs * ring. 468214077Sgibbs * 469214077Sgibbs * To simplify error recovery and the retry, 470214077Sgibbs * we specify PDROP so our lock is *not* held 471214077Sgibbs * when msleep returns. 472214077Sgibbs */ 473214077Sgibbs error = msleep(xen_store, &xs.ring_lock, PCATCH|PDROP, 474214077Sgibbs "xbwrite", /*timeout*/0); 475214077Sgibbs if (error && error != EWOULDBLOCK) 476214077Sgibbs return (error); 477214077Sgibbs 478214077Sgibbs /* Try again. */ 479214077Sgibbs continue; 480214077Sgibbs } 481214077Sgibbs mtx_unlock(&xs.ring_lock); 482214077Sgibbs 483214077Sgibbs /* Verify queue sanity. */ 484214077Sgibbs if (!xs_check_indexes(cons, prod)) { 485214077Sgibbs xen_store->req_cons = xen_store->req_prod = 0; 486214077Sgibbs return (EIO); 487214077Sgibbs } 488214077Sgibbs 489214077Sgibbs dst = xs_get_output_chunk(cons, prod, xen_store->req, &avail); 490214077Sgibbs if (avail > len) 491214077Sgibbs avail = len; 492214077Sgibbs 493214077Sgibbs memcpy(dst, data, avail); 494214077Sgibbs data += avail; 495214077Sgibbs len -= avail; 496214077Sgibbs 497214077Sgibbs /* 498214077Sgibbs * The store to the producer index, which indicates 499214077Sgibbs * to the other side that new data has arrived, must 500214077Sgibbs * be visible only after our copy of the data into the 501214077Sgibbs * ring has completed. 502214077Sgibbs */ 503214077Sgibbs wmb(); 504214077Sgibbs xen_store->req_prod += avail; 505214077Sgibbs 506214077Sgibbs /* 507255040Sgibbs * xen_intr_signal() implies mb(). The other side will see 508255040Sgibbs * the change to req_prod at the time of the interrupt. 509214077Sgibbs */ 510255040Sgibbs xen_intr_signal(xs.xen_intr_handle); 511214077Sgibbs } 512214077Sgibbs 513214077Sgibbs return (0); 514214077Sgibbs} 515214077Sgibbs 516214077Sgibbs/** 517214077Sgibbs * Receive data from the XenStore service. 518214077Sgibbs * 519214077Sgibbs * \param tdata A pointer to the contiguous buffer to receive the data. 520214077Sgibbs * \param len The amount of data to receive. 521214077Sgibbs * 522214077Sgibbs * \return On success 0, otherwise an errno value indicating the 523214077Sgibbs * cause of failure. 524214077Sgibbs * 525214077Sgibbs * \invariant Called from thread context. 526214077Sgibbs * \invariant The buffer pointed to by tdata is at least len bytes 527214077Sgibbs * in length. 528214077Sgibbs * 529214077Sgibbs * \note xs_read does not perform any internal locking to guarantee 530214077Sgibbs * serial access to the incoming ring buffer. However, there 531214077Sgibbs * is only one context processing reads: xs_rcv_thread(). 532214077Sgibbs */ 533214077Sgibbsstatic int 534214077Sgibbsxs_read_store(void *tdata, unsigned len) 535214077Sgibbs{ 536214077Sgibbs XENSTORE_RING_IDX cons, prod; 537214077Sgibbs char *data = (char *)tdata; 538214077Sgibbs int error; 539214077Sgibbs 540214077Sgibbs while (len != 0) { 541214077Sgibbs u_int avail; 542214077Sgibbs const char *src; 543214077Sgibbs 544214077Sgibbs /* Hold lock so we can't miss wakeups should we block. */ 545214077Sgibbs mtx_lock(&xs.ring_lock); 546214077Sgibbs cons = xen_store->rsp_cons; 547214077Sgibbs prod = xen_store->rsp_prod; 548214077Sgibbs if (cons == prod) { 549214077Sgibbs /* 550214077Sgibbs * Nothing to read. Wait for a ring event. 551214077Sgibbs * 552214077Sgibbs * Note that the events from both queues 553214077Sgibbs * are combined, so being woken does not 554214077Sgibbs * guarantee that data exist in the read 555214077Sgibbs * ring. 556214077Sgibbs * 557214077Sgibbs * To simplify error recovery and the retry, 558214077Sgibbs * we specify PDROP so our lock is *not* held 559214077Sgibbs * when msleep returns. 560214077Sgibbs */ 561214077Sgibbs error = msleep(xen_store, &xs.ring_lock, PCATCH|PDROP, 562228526Skevlo "xbread", /*timeout*/0); 563214077Sgibbs if (error && error != EWOULDBLOCK) 564214077Sgibbs return (error); 565214077Sgibbs continue; 566214077Sgibbs } 567214077Sgibbs mtx_unlock(&xs.ring_lock); 568214077Sgibbs 569214077Sgibbs /* Verify queue sanity. */ 570214077Sgibbs if (!xs_check_indexes(cons, prod)) { 571214077Sgibbs xen_store->rsp_cons = xen_store->rsp_prod = 0; 572214077Sgibbs return (EIO); 573214077Sgibbs } 574214077Sgibbs 575214077Sgibbs src = xs_get_input_chunk(cons, prod, xen_store->rsp, &avail); 576214077Sgibbs if (avail > len) 577214077Sgibbs avail = len; 578214077Sgibbs 579214077Sgibbs /* 580214077Sgibbs * Insure the data we read is related to the indexes 581214077Sgibbs * we read above. 582214077Sgibbs */ 583214077Sgibbs rmb(); 584214077Sgibbs 585214077Sgibbs memcpy(data, src, avail); 586214077Sgibbs data += avail; 587214077Sgibbs len -= avail; 588214077Sgibbs 589214077Sgibbs /* 590214077Sgibbs * Insure that the producer of this ring does not see 591214077Sgibbs * the ring space as free until after we have copied it 592214077Sgibbs * out. 593214077Sgibbs */ 594214077Sgibbs mb(); 595214077Sgibbs xen_store->rsp_cons += avail; 596214077Sgibbs 597214077Sgibbs /* 598255040Sgibbs * xen_intr_signal() implies mb(). The producer will see 599255040Sgibbs * the updated consumer index when the event is delivered. 600214077Sgibbs */ 601255040Sgibbs xen_intr_signal(xs.xen_intr_handle); 602214077Sgibbs } 603214077Sgibbs 604214077Sgibbs return (0); 605214077Sgibbs} 606214077Sgibbs 607214077Sgibbs/*----------------------- Received Message Processing ------------------------*/ 608214077Sgibbs/** 609214077Sgibbs * Block reading the next message from the XenStore service and 610214077Sgibbs * process the result. 611214077Sgibbs * 612214077Sgibbs * \param type The returned type of the XenStore message received. 613214077Sgibbs * 614214077Sgibbs * \return 0 on success. Otherwise an errno value indicating the 615214077Sgibbs * type of failure encountered. 616214077Sgibbs */ 617214077Sgibbsstatic int 618214077Sgibbsxs_process_msg(enum xsd_sockmsg_type *type) 619214077Sgibbs{ 620214077Sgibbs struct xs_stored_msg *msg; 621214077Sgibbs char *body; 622214077Sgibbs int error; 623214077Sgibbs 624214077Sgibbs msg = malloc(sizeof(*msg), M_XENSTORE, M_WAITOK); 625214077Sgibbs error = xs_read_store(&msg->hdr, sizeof(msg->hdr)); 626214077Sgibbs if (error) { 627214077Sgibbs free(msg, M_XENSTORE); 628214077Sgibbs return (error); 629214077Sgibbs } 630214077Sgibbs 631214077Sgibbs body = malloc(msg->hdr.len + 1, M_XENSTORE, M_WAITOK); 632214077Sgibbs error = xs_read_store(body, msg->hdr.len); 633214077Sgibbs if (error) { 634214077Sgibbs free(body, M_XENSTORE); 635214077Sgibbs free(msg, M_XENSTORE); 636214077Sgibbs return (error); 637214077Sgibbs } 638214077Sgibbs body[msg->hdr.len] = '\0'; 639214077Sgibbs 640214077Sgibbs *type = msg->hdr.type; 641214077Sgibbs if (msg->hdr.type == XS_WATCH_EVENT) { 642214077Sgibbs msg->u.watch.vec = split(body, msg->hdr.len, 643214077Sgibbs &msg->u.watch.vec_size); 644214077Sgibbs 645214077Sgibbs mtx_lock(&xs.registered_watches_lock); 646214077Sgibbs msg->u.watch.handle = find_watch( 647214077Sgibbs msg->u.watch.vec[XS_WATCH_TOKEN]); 648214077Sgibbs if (msg->u.watch.handle != NULL) { 649214077Sgibbs mtx_lock(&xs.watch_events_lock); 650214077Sgibbs TAILQ_INSERT_TAIL(&xs.watch_events, msg, list); 651214077Sgibbs wakeup(&xs.watch_events); 652214077Sgibbs mtx_unlock(&xs.watch_events_lock); 653214077Sgibbs } else { 654214077Sgibbs free(msg->u.watch.vec, M_XENSTORE); 655214077Sgibbs free(msg, M_XENSTORE); 656214077Sgibbs } 657214077Sgibbs mtx_unlock(&xs.registered_watches_lock); 658214077Sgibbs } else { 659214077Sgibbs msg->u.reply.body = body; 660214077Sgibbs mtx_lock(&xs.reply_lock); 661214077Sgibbs TAILQ_INSERT_TAIL(&xs.reply_list, msg, list); 662214077Sgibbs wakeup(&xs.reply_list); 663214077Sgibbs mtx_unlock(&xs.reply_lock); 664214077Sgibbs } 665214077Sgibbs 666214077Sgibbs return (0); 667214077Sgibbs} 668214077Sgibbs 669214077Sgibbs/** 670214077Sgibbs * Thread body of the XenStore receive thread. 671214077Sgibbs * 672214077Sgibbs * This thread blocks waiting for data from the XenStore service 673214077Sgibbs * and processes and received messages. 674214077Sgibbs */ 675214077Sgibbsstatic void 676214077Sgibbsxs_rcv_thread(void *arg __unused) 677214077Sgibbs{ 678214077Sgibbs int error; 679214077Sgibbs enum xsd_sockmsg_type type; 680214077Sgibbs 681214077Sgibbs for (;;) { 682214077Sgibbs error = xs_process_msg(&type); 683214077Sgibbs if (error) 684214077Sgibbs printf("XENSTORE error %d while reading message\n", 685214077Sgibbs error); 686214077Sgibbs } 687214077Sgibbs} 688214077Sgibbs 689214077Sgibbs/*---------------- XenStore Message Request/Reply Processing -----------------*/ 690214077Sgibbs/** 691214077Sgibbs * Filter invoked before transmitting any message to the XenStore service. 692214077Sgibbs * 693214077Sgibbs * The role of the filter may expand, but currently serves to manage 694214077Sgibbs * the interactions of messages with transaction state. 695214077Sgibbs * 696214077Sgibbs * \param request_msg_type The message type for the request. 697214077Sgibbs */ 698214077Sgibbsstatic inline void 699214077Sgibbsxs_request_filter(uint32_t request_msg_type) 700214077Sgibbs{ 701214077Sgibbs if (request_msg_type == XS_TRANSACTION_START) 702214077Sgibbs sx_slock(&xs.suspend_mutex); 703214077Sgibbs} 704214077Sgibbs 705214077Sgibbs/** 706214077Sgibbs * Filter invoked after transmitting any message to the XenStore service. 707214077Sgibbs * 708214077Sgibbs * The role of the filter may expand, but currently serves to manage 709214077Sgibbs * the interactions of messages with transaction state. 710214077Sgibbs * 711214077Sgibbs * \param request_msg_type The message type for the original request. 712214077Sgibbs * \param reply_msg_type The message type for any received reply. 713214077Sgibbs * \param request_reply_error The error status from the attempt to send 714214077Sgibbs * the request or retrieve the reply. 715214077Sgibbs */ 716214077Sgibbsstatic inline void 717214077Sgibbsxs_reply_filter(uint32_t request_msg_type, 718214077Sgibbs uint32_t reply_msg_type, int request_reply_error) 719214077Sgibbs{ 720214077Sgibbs /* 721214077Sgibbs * The count of transactions drops if we attempted 722214077Sgibbs * to end a transaction (even if that attempt fails 723225704Sgibbs * in error), we receive a transaction end acknowledgement, 724225704Sgibbs * or if our attempt to begin a transaction fails. 725214077Sgibbs */ 726214077Sgibbs if (request_msg_type == XS_TRANSACTION_END 727214077Sgibbs || (request_reply_error == 0 && reply_msg_type == XS_TRANSACTION_END) 728214077Sgibbs || (request_msg_type == XS_TRANSACTION_START 729214077Sgibbs && (request_reply_error != 0 || reply_msg_type == XS_ERROR))) 730214077Sgibbs sx_sunlock(&xs.suspend_mutex); 731214077Sgibbs 732214077Sgibbs} 733214077Sgibbs 734186557Skmacy#define xsd_error_count (sizeof(xsd_errors) / sizeof(xsd_errors[0])) 735186557Skmacy 736214077Sgibbs/** 737214077Sgibbs * Convert a XenStore error string into an errno number. 738214077Sgibbs * 739214077Sgibbs * \param errorstring The error string to convert. 740214077Sgibbs * 741214077Sgibbs * \return The errno best matching the input string. 742214077Sgibbs * 743214077Sgibbs * \note Unknown error strings are converted to EINVAL. 744214077Sgibbs */ 745186557Skmacystatic int 746186557Skmacyxs_get_error(const char *errorstring) 747181624Skmacy{ 748214077Sgibbs u_int i; 749181624Skmacy 750186557Skmacy for (i = 0; i < xsd_error_count; i++) { 751186557Skmacy if (!strcmp(errorstring, xsd_errors[i].errstring)) 752186557Skmacy return (xsd_errors[i].errnum); 753186557Skmacy } 754214077Sgibbs log(LOG_WARNING, "XENSTORE xen store gave: unknown error %s", 755186557Skmacy errorstring); 756186557Skmacy return (EINVAL); 757181624Skmacy} 758181624Skmacy 759214077Sgibbs/** 760214077Sgibbs * Block waiting for a reply to a message request. 761214077Sgibbs * 762214077Sgibbs * \param type The returned type of the reply. 763214077Sgibbs * \param len The returned body length of the reply. 764214077Sgibbs * \param result The returned body of the reply. 765214077Sgibbs * 766214077Sgibbs * \return 0 on success. Otherwise an errno indicating the 767214077Sgibbs * cause of failure. 768214077Sgibbs */ 769186557Skmacystatic int 770214077Sgibbsxs_read_reply(enum xsd_sockmsg_type *type, u_int *len, void **result) 771181624Skmacy{ 772186557Skmacy struct xs_stored_msg *msg; 773186557Skmacy char *body; 774186557Skmacy int error; 775181893Skmacy 776214077Sgibbs mtx_lock(&xs.reply_lock); 777214077Sgibbs while (TAILQ_EMPTY(&xs.reply_list)) { 778214077Sgibbs error = mtx_sleep(&xs.reply_list, &xs.reply_lock, 779214077Sgibbs PCATCH, "xswait", hz/10); 780214077Sgibbs if (error && error != EWOULDBLOCK) { 781214077Sgibbs mtx_unlock(&xs.reply_lock); 782214077Sgibbs return (error); 783181624Skmacy } 784189699Sdfr } 785214077Sgibbs msg = TAILQ_FIRST(&xs.reply_list); 786214077Sgibbs TAILQ_REMOVE(&xs.reply_list, msg, list); 787214077Sgibbs mtx_unlock(&xs.reply_lock); 788181624Skmacy 789186557Skmacy *type = msg->hdr.type; 790186557Skmacy if (len) 791186557Skmacy *len = msg->hdr.len; 792186557Skmacy body = msg->u.reply.body; 793181624Skmacy 794214077Sgibbs free(msg, M_XENSTORE); 795186557Skmacy *result = body; 796186557Skmacy return (0); 797181624Skmacy} 798181624Skmacy 799214077Sgibbs/** 800214077Sgibbs * Pass-thru interface for XenStore access by userland processes 801214077Sgibbs * via the XenStore device. 802214077Sgibbs * 803214077Sgibbs * Reply type and length data are returned by overwriting these 804214077Sgibbs * fields in the passed in request message. 805214077Sgibbs * 806214077Sgibbs * \param msg A properly formatted message to transmit to 807214077Sgibbs * the XenStore service. 808214077Sgibbs * \param result The returned body of the reply. 809214077Sgibbs * 810214077Sgibbs * \return 0 on success. Otherwise an errno indicating the cause 811214077Sgibbs * of failure. 812214077Sgibbs * 813214077Sgibbs * \note The returned result is provided in malloced storage and thus 814214077Sgibbs * must be free'd by the caller with 'free(result, M_XENSTORE); 815214077Sgibbs */ 816186557Skmacyint 817214077Sgibbsxs_dev_request_and_reply(struct xsd_sockmsg *msg, void **result) 818181624Skmacy{ 819214077Sgibbs uint32_t request_type; 820186557Skmacy int error; 821181624Skmacy 822214077Sgibbs request_type = msg->type; 823214077Sgibbs xs_request_filter(request_type); 824181624Skmacy 825214077Sgibbs sx_xlock(&xs.request_mutex); 826214077Sgibbs if ((error = xs_write_store(msg, sizeof(*msg) + msg->len)) == 0) 827186557Skmacy error = xs_read_reply(&msg->type, &msg->len, result); 828214077Sgibbs sx_xunlock(&xs.request_mutex); 829181624Skmacy 830214077Sgibbs xs_reply_filter(request_type, msg->type, error); 831181624Skmacy 832186557Skmacy return (error); 833181624Skmacy} 834181624Skmacy 835214077Sgibbs/** 836214077Sgibbs * Send a message with an optionally muti-part body to the XenStore service. 837214077Sgibbs * 838214077Sgibbs * \param t The transaction to use for this request. 839214077Sgibbs * \param request_type The type of message to send. 840214077Sgibbs * \param iovec Pointers to the body sections of the request. 841214077Sgibbs * \param num_vecs The number of body sections in the request. 842214077Sgibbs * \param len The returned length of the reply. 843214077Sgibbs * \param result The returned body of the reply. 844214077Sgibbs * 845214077Sgibbs * \return 0 on success. Otherwise an errno indicating 846214077Sgibbs * the cause of failure. 847214077Sgibbs * 848214077Sgibbs * \note The returned result is provided in malloced storage and thus 849214077Sgibbs * must be free'd by the caller with 'free(*result, M_XENSTORE); 850186557Skmacy */ 851186557Skmacystatic int 852214077Sgibbsxs_talkv(struct xs_transaction t, enum xsd_sockmsg_type request_type, 853214077Sgibbs const struct iovec *iovec, u_int num_vecs, u_int *len, void **result) 854181624Skmacy{ 855186557Skmacy struct xsd_sockmsg msg; 856186557Skmacy void *ret = NULL; 857214077Sgibbs u_int i; 858186557Skmacy int error; 859181624Skmacy 860186557Skmacy msg.tx_id = t.id; 861186557Skmacy msg.req_id = 0; 862214077Sgibbs msg.type = request_type; 863186557Skmacy msg.len = 0; 864186557Skmacy for (i = 0; i < num_vecs; i++) 865186557Skmacy msg.len += iovec[i].iov_len; 866181624Skmacy 867214077Sgibbs xs_request_filter(request_type); 868181624Skmacy 869214077Sgibbs sx_xlock(&xs.request_mutex); 870214077Sgibbs error = xs_write_store(&msg, sizeof(msg)); 871186557Skmacy if (error) { 872186557Skmacy printf("xs_talkv failed %d\n", error); 873214077Sgibbs goto error_lock_held; 874186557Skmacy } 875181624Skmacy 876186557Skmacy for (i = 0; i < num_vecs; i++) { 877214077Sgibbs error = xs_write_store(iovec[i].iov_base, iovec[i].iov_len); 878214077Sgibbs if (error) { 879186557Skmacy printf("xs_talkv failed %d\n", error); 880214077Sgibbs goto error_lock_held; 881181624Skmacy } 882186557Skmacy } 883181624Skmacy 884186557Skmacy error = xs_read_reply(&msg.type, len, &ret); 885181624Skmacy 886214077Sgibbserror_lock_held: 887214077Sgibbs sx_xunlock(&xs.request_mutex); 888214077Sgibbs xs_reply_filter(request_type, msg.type, error); 889186557Skmacy if (error) 890186557Skmacy return (error); 891181624Skmacy 892186557Skmacy if (msg.type == XS_ERROR) { 893186557Skmacy error = xs_get_error(ret); 894214077Sgibbs free(ret, M_XENSTORE); 895186557Skmacy return (error); 896186557Skmacy } 897181889Skmacy 898214077Sgibbs /* Reply is either error or an echo of our request message type. */ 899214077Sgibbs KASSERT(msg.type == request_type, ("bad xenstore message type")); 900181889Skmacy 901186557Skmacy if (result) 902186557Skmacy *result = ret; 903186557Skmacy else 904214077Sgibbs free(ret, M_XENSTORE); 905186557Skmacy 906186557Skmacy return (0); 907181624Skmacy} 908181624Skmacy 909214077Sgibbs/** 910214077Sgibbs * Wrapper for xs_talkv allowing easy transmission of a message with 911214077Sgibbs * a single, contiguous, message body. 912214077Sgibbs * 913214077Sgibbs * \param t The transaction to use for this request. 914214077Sgibbs * \param request_type The type of message to send. 915214077Sgibbs * \param body The body of the request. 916214077Sgibbs * \param len The returned length of the reply. 917214077Sgibbs * \param result The returned body of the reply. 918214077Sgibbs * 919214077Sgibbs * \return 0 on success. Otherwise an errno indicating 920214077Sgibbs * the cause of failure. 921214077Sgibbs * 922214077Sgibbs * \note The returned result is provided in malloced storage and thus 923214077Sgibbs * must be free'd by the caller with 'free(*result, M_XENSTORE); 924214077Sgibbs */ 925186557Skmacystatic int 926214077Sgibbsxs_single(struct xs_transaction t, enum xsd_sockmsg_type request_type, 927214077Sgibbs const char *body, u_int *len, void **result) 928181624Skmacy{ 929186557Skmacy struct iovec iovec; 930181624Skmacy 931214077Sgibbs iovec.iov_base = (void *)(uintptr_t)body; 932214077Sgibbs iovec.iov_len = strlen(body) + 1; 933181624Skmacy 934214077Sgibbs return (xs_talkv(t, request_type, &iovec, 1, len, result)); 935181624Skmacy} 936181624Skmacy 937214077Sgibbs/*------------------------- XenStore Watch Support ---------------------------*/ 938214077Sgibbs/** 939214077Sgibbs * Transmit a watch request to the XenStore service. 940214077Sgibbs * 941214077Sgibbs * \param path The path in the XenStore to watch. 942214077Sgibbs * \param tocken A unique identifier for this watch. 943214077Sgibbs * 944214077Sgibbs * \return 0 on success. Otherwise an errno indicating the 945214077Sgibbs * cause of failure. 946214077Sgibbs */ 947214077Sgibbsstatic int 948214077Sgibbsxs_watch(const char *path, const char *token) 949181624Skmacy{ 950214077Sgibbs struct iovec iov[2]; 951181624Skmacy 952214077Sgibbs iov[0].iov_base = (void *)(uintptr_t) path; 953214077Sgibbs iov[0].iov_len = strlen(path) + 1; 954214077Sgibbs iov[1].iov_base = (void *)(uintptr_t) token; 955214077Sgibbs iov[1].iov_len = strlen(token) + 1; 956181624Skmacy 957214077Sgibbs return (xs_talkv(XST_NIL, XS_WATCH, iov, 2, NULL, NULL)); 958181624Skmacy} 959181624Skmacy 960214077Sgibbs/** 961214077Sgibbs * Transmit an uwatch request to the XenStore service. 962214077Sgibbs * 963214077Sgibbs * \param path The path in the XenStore to watch. 964214077Sgibbs * \param tocken A unique identifier for this watch. 965214077Sgibbs * 966214077Sgibbs * \return 0 on success. Otherwise an errno indicating the 967214077Sgibbs * cause of failure. 968214077Sgibbs */ 969214077Sgibbsstatic int 970214077Sgibbsxs_unwatch(const char *path, const char *token) 971181624Skmacy{ 972214077Sgibbs struct iovec iov[2]; 973181624Skmacy 974214077Sgibbs iov[0].iov_base = (void *)(uintptr_t) path; 975214077Sgibbs iov[0].iov_len = strlen(path) + 1; 976214077Sgibbs iov[1].iov_base = (void *)(uintptr_t) token; 977214077Sgibbs iov[1].iov_len = strlen(token) + 1; 978181624Skmacy 979214077Sgibbs return (xs_talkv(XST_NIL, XS_UNWATCH, iov, 2, NULL, NULL)); 980214077Sgibbs} 981214077Sgibbs 982214077Sgibbs/** 983214077Sgibbs * Convert from watch token (unique identifier) to the associated 984214077Sgibbs * internal tracking structure for this watch. 985214077Sgibbs * 986214077Sgibbs * \param tocken The unique identifier for the watch to find. 987214077Sgibbs * 988214077Sgibbs * \return A pointer to the found watch structure or NULL. 989214077Sgibbs */ 990214077Sgibbsstatic struct xs_watch * 991214077Sgibbsfind_watch(const char *token) 992214077Sgibbs{ 993214077Sgibbs struct xs_watch *i, *cmp; 994214077Sgibbs 995214077Sgibbs cmp = (void *)strtoul(token, NULL, 16); 996214077Sgibbs 997214077Sgibbs LIST_FOREACH(i, &xs.registered_watches, list) 998214077Sgibbs if (i == cmp) 999214077Sgibbs return (i); 1000214077Sgibbs 1001214077Sgibbs return (NULL); 1002214077Sgibbs} 1003214077Sgibbs 1004214077Sgibbs/** 1005214077Sgibbs * Thread body of the XenStore watch event dispatch thread. 1006214077Sgibbs */ 1007214077Sgibbsstatic void 1008214077Sgibbsxenwatch_thread(void *unused) 1009214077Sgibbs{ 1010214077Sgibbs struct xs_stored_msg *msg; 1011214077Sgibbs 1012214077Sgibbs for (;;) { 1013214077Sgibbs 1014214077Sgibbs mtx_lock(&xs.watch_events_lock); 1015214077Sgibbs while (TAILQ_EMPTY(&xs.watch_events)) 1016214077Sgibbs mtx_sleep(&xs.watch_events, 1017214077Sgibbs &xs.watch_events_lock, 1018214077Sgibbs PWAIT | PCATCH, "waitev", hz/10); 1019214077Sgibbs 1020214077Sgibbs mtx_unlock(&xs.watch_events_lock); 1021214077Sgibbs sx_xlock(&xs.xenwatch_mutex); 1022214077Sgibbs 1023214077Sgibbs mtx_lock(&xs.watch_events_lock); 1024214077Sgibbs msg = TAILQ_FIRST(&xs.watch_events); 1025214077Sgibbs if (msg) 1026214077Sgibbs TAILQ_REMOVE(&xs.watch_events, msg, list); 1027214077Sgibbs mtx_unlock(&xs.watch_events_lock); 1028214077Sgibbs 1029214077Sgibbs if (msg != NULL) { 1030214077Sgibbs /* 1031214077Sgibbs * XXX There are messages coming in with a NULL 1032214077Sgibbs * XXX callback. This deserves further investigation; 1033214077Sgibbs * XXX the workaround here simply prevents the kernel 1034214077Sgibbs * XXX from panic'ing on startup. 1035214077Sgibbs */ 1036214077Sgibbs if (msg->u.watch.handle->callback != NULL) 1037214077Sgibbs msg->u.watch.handle->callback( 1038214077Sgibbs msg->u.watch.handle, 1039214077Sgibbs (const char **)msg->u.watch.vec, 1040214077Sgibbs msg->u.watch.vec_size); 1041214077Sgibbs free(msg->u.watch.vec, M_XENSTORE); 1042214077Sgibbs free(msg, M_XENSTORE); 1043214077Sgibbs } 1044214077Sgibbs 1045214077Sgibbs sx_xunlock(&xs.xenwatch_mutex); 1046186557Skmacy } 1047214077Sgibbs} 1048181624Skmacy 1049214077Sgibbs/*----------- XenStore Configuration, Initialization, and Control ------------*/ 1050214077Sgibbs/** 1051214077Sgibbs * Setup communication channels with the XenStore service. 1052214077Sgibbs * 1053214077Sgibbs * \return On success, 0. Otherwise an errno value indicating the 1054214077Sgibbs * type of failure. 1055214077Sgibbs */ 1056214077Sgibbsstatic int 1057214077Sgibbsxs_init_comms(void) 1058214077Sgibbs{ 1059214077Sgibbs int error; 1060214077Sgibbs 1061214077Sgibbs if (xen_store->rsp_prod != xen_store->rsp_cons) { 1062214077Sgibbs log(LOG_WARNING, "XENSTORE response ring is not quiescent " 1063214077Sgibbs "(%08x:%08x): fixing up\n", 1064214077Sgibbs xen_store->rsp_cons, xen_store->rsp_prod); 1065214077Sgibbs xen_store->rsp_cons = xen_store->rsp_prod; 1066214077Sgibbs } 1067214077Sgibbs 1068255040Sgibbs xen_intr_unbind(&xs.xen_intr_handle); 1069214077Sgibbs 1070255040Sgibbs error = xen_intr_bind_local_port(xs.xs_dev, xs.evtchn, 1071255040Sgibbs /*filter*/NULL, xs_intr, /*arg*/NULL, INTR_TYPE_NET|INTR_MPSAFE, 1072255040Sgibbs &xs.xen_intr_handle); 1073214077Sgibbs if (error) { 1074214077Sgibbs log(LOG_WARNING, "XENSTORE request irq failed %i\n", error); 1075214077Sgibbs return (error); 1076214077Sgibbs } 1077214077Sgibbs 1078214077Sgibbs return (0); 1079181624Skmacy} 1080181624Skmacy 1081214077Sgibbs/*------------------ Private Device Attachment Functions --------------------*/ 1082214077Sgibbsstatic void 1083214077Sgibbsxs_identify(driver_t *driver, device_t parent) 1084181624Skmacy{ 1085181624Skmacy 1086214077Sgibbs BUS_ADD_CHILD(parent, 0, "xenstore", 0); 1087214077Sgibbs} 1088181624Skmacy 1089214077Sgibbs/** 1090214077Sgibbs * Probe for the existance of the XenStore. 1091214077Sgibbs * 1092214077Sgibbs * \param dev 1093214077Sgibbs */ 1094214077Sgibbsstatic int 1095214077Sgibbsxs_probe(device_t dev) 1096214077Sgibbs{ 1097214077Sgibbs /* 1098214077Sgibbs * We are either operating within a PV kernel or being probed 1099214077Sgibbs * as the child of the successfully attached xenpci device. 1100214077Sgibbs * Thus we are in a Xen environment and there will be a XenStore. 1101216448Sgibbs * Unconditionally return success. 1102214077Sgibbs */ 1103214077Sgibbs device_set_desc(dev, "XenStore"); 1104214077Sgibbs return (0); 1105214077Sgibbs} 1106181624Skmacy 1107214077Sgibbsstatic void 1108214077Sgibbsxs_attach_deferred(void *arg) 1109214077Sgibbs{ 1110214077Sgibbs xs_dev_init(); 1111181624Skmacy 1112214077Sgibbs bus_generic_probe(xs.xs_dev); 1113214077Sgibbs bus_generic_attach(xs.xs_dev); 1114214077Sgibbs 1115214077Sgibbs config_intrhook_disestablish(&xs.xs_attachcb); 1116181624Skmacy} 1117181624Skmacy 1118214077Sgibbs/** 1119214077Sgibbs * Attach to the XenStore. 1120214077Sgibbs * 1121214077Sgibbs * This routine also prepares for the probe/attach of drivers that rely 1122214077Sgibbs * on the XenStore. 1123186557Skmacy */ 1124214077Sgibbsstatic int 1125214077Sgibbsxs_attach(device_t dev) 1126214077Sgibbs{ 1127214077Sgibbs int error; 1128214077Sgibbs 1129214077Sgibbs /* Allow us to get device_t from softc and vice-versa. */ 1130214077Sgibbs xs.xs_dev = dev; 1131214077Sgibbs device_set_softc(dev, &xs); 1132214077Sgibbs 1133214077Sgibbs /* 1134214077Sgibbs * This seems to be a layering violation. The XenStore is just 1135214077Sgibbs * one of many clients of the Grant Table facility. It happens 1136214077Sgibbs * to be the first and a gating consumer to all other devices, 1137214077Sgibbs * so this does work. A better place would be in the PV support 1138214077Sgibbs * code for fully PV kernels and the xenpci driver for HVM kernels. 1139214077Sgibbs */ 1140214077Sgibbs error = gnttab_init(); 1141214077Sgibbs if (error != 0) { 1142214077Sgibbs log(LOG_WARNING, 1143214077Sgibbs "XENSTORE: Error initializing grant tables: %d\n", error); 1144214077Sgibbs return (ENXIO); 1145214077Sgibbs } 1146214077Sgibbs 1147214077Sgibbs /* Initialize the interface to xenstore. */ 1148214077Sgibbs struct proc *p; 1149214077Sgibbs 1150214077Sgibbs#ifdef XENHVM 1151214077Sgibbs xs.evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN); 1152214077Sgibbs xs.gpfn = hvm_get_parameter(HVM_PARAM_STORE_PFN); 1153214077Sgibbs xen_store = pmap_mapdev(xs.gpfn * PAGE_SIZE, PAGE_SIZE); 1154214077Sgibbs#else 1155214077Sgibbs xs.evtchn = xen_start_info->store_evtchn; 1156214077Sgibbs#endif 1157214077Sgibbs 1158214077Sgibbs TAILQ_INIT(&xs.reply_list); 1159214077Sgibbs TAILQ_INIT(&xs.watch_events); 1160214077Sgibbs 1161214077Sgibbs mtx_init(&xs.ring_lock, "ring lock", NULL, MTX_DEF); 1162214077Sgibbs mtx_init(&xs.reply_lock, "reply lock", NULL, MTX_DEF); 1163214077Sgibbs sx_init(&xs.xenwatch_mutex, "xenwatch"); 1164214077Sgibbs sx_init(&xs.request_mutex, "xenstore request"); 1165214077Sgibbs sx_init(&xs.suspend_mutex, "xenstore suspend"); 1166214077Sgibbs mtx_init(&xs.registered_watches_lock, "watches", NULL, MTX_DEF); 1167214077Sgibbs mtx_init(&xs.watch_events_lock, "watch events", NULL, MTX_DEF); 1168214077Sgibbs 1169214077Sgibbs /* Initialize the shared memory rings to talk to xenstored */ 1170214077Sgibbs error = xs_init_comms(); 1171214077Sgibbs if (error) 1172214077Sgibbs return (error); 1173214077Sgibbs 1174214077Sgibbs error = kproc_create(xenwatch_thread, NULL, &p, RFHIGHPID, 1175214077Sgibbs 0, "xenwatch"); 1176214077Sgibbs if (error) 1177214077Sgibbs return (error); 1178214077Sgibbs xs.xenwatch_pid = p->p_pid; 1179214077Sgibbs 1180214077Sgibbs error = kproc_create(xs_rcv_thread, NULL, NULL, 1181214077Sgibbs RFHIGHPID, 0, "xenstore_rcv"); 1182214077Sgibbs 1183214077Sgibbs xs.xs_attachcb.ich_func = xs_attach_deferred; 1184214077Sgibbs xs.xs_attachcb.ich_arg = NULL; 1185214077Sgibbs config_intrhook_establish(&xs.xs_attachcb); 1186214077Sgibbs 1187214077Sgibbs return (error); 1188214077Sgibbs} 1189214077Sgibbs 1190214077Sgibbs/** 1191214077Sgibbs * Prepare for suspension of this VM by halting XenStore access after 1192214077Sgibbs * all transactions and individual requests have completed. 1193214077Sgibbs */ 1194214077Sgibbsstatic int 1195225704Sgibbsxs_suspend(device_t dev) 1196214077Sgibbs{ 1197225704Sgibbs int error; 1198214077Sgibbs 1199225704Sgibbs /* Suspend child Xen devices. */ 1200225704Sgibbs error = bus_generic_suspend(dev); 1201225704Sgibbs if (error != 0) 1202225704Sgibbs return (error); 1203225704Sgibbs 1204214077Sgibbs sx_xlock(&xs.suspend_mutex); 1205214077Sgibbs sx_xlock(&xs.request_mutex); 1206214077Sgibbs 1207214077Sgibbs return (0); 1208214077Sgibbs} 1209214077Sgibbs 1210214077Sgibbs/** 1211214077Sgibbs * Resume XenStore operations after this VM is resumed. 1212214077Sgibbs */ 1213214077Sgibbsstatic int 1214214077Sgibbsxs_resume(device_t dev __unused) 1215214077Sgibbs{ 1216214077Sgibbs struct xs_watch *watch; 1217214077Sgibbs char token[sizeof(watch) * 2 + 1]; 1218214077Sgibbs 1219214077Sgibbs xs_init_comms(); 1220214077Sgibbs 1221214077Sgibbs sx_xunlock(&xs.request_mutex); 1222214077Sgibbs 1223214077Sgibbs /* 1224214077Sgibbs * No need for registered_watches_lock: the suspend_mutex 1225214077Sgibbs * is sufficient. 1226214077Sgibbs */ 1227214077Sgibbs LIST_FOREACH(watch, &xs.registered_watches, list) { 1228214077Sgibbs sprintf(token, "%lX", (long)watch); 1229214077Sgibbs xs_watch(watch->node, token); 1230214077Sgibbs } 1231214077Sgibbs 1232214077Sgibbs sx_xunlock(&xs.suspend_mutex); 1233214077Sgibbs 1234225704Sgibbs /* Resume child Xen devices. */ 1235225704Sgibbs bus_generic_resume(dev); 1236225704Sgibbs 1237214077Sgibbs return (0); 1238214077Sgibbs} 1239214077Sgibbs 1240214077Sgibbs/*-------------------- Private Device Attachment Data -----------------------*/ 1241214077Sgibbsstatic device_method_t xenstore_methods[] = { 1242214077Sgibbs /* Device interface */ 1243214077Sgibbs DEVMETHOD(device_identify, xs_identify), 1244214077Sgibbs DEVMETHOD(device_probe, xs_probe), 1245214077Sgibbs DEVMETHOD(device_attach, xs_attach), 1246214077Sgibbs DEVMETHOD(device_detach, bus_generic_detach), 1247214077Sgibbs DEVMETHOD(device_shutdown, bus_generic_shutdown), 1248214077Sgibbs DEVMETHOD(device_suspend, xs_suspend), 1249214077Sgibbs DEVMETHOD(device_resume, xs_resume), 1250214077Sgibbs 1251214077Sgibbs /* Bus interface */ 1252214077Sgibbs DEVMETHOD(bus_add_child, bus_generic_add_child), 1253214077Sgibbs DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 1254214077Sgibbs DEVMETHOD(bus_release_resource, bus_generic_release_resource), 1255214077Sgibbs DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 1256214077Sgibbs DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 1257227843Smarius 1258227843Smarius DEVMETHOD_END 1259214077Sgibbs}; 1260214077Sgibbs 1261214077SgibbsDEFINE_CLASS_0(xenstore, xenstore_driver, xenstore_methods, 0); 1262214077Sgibbsstatic devclass_t xenstore_devclass; 1263214077Sgibbs 1264214077Sgibbs#ifdef XENHVM 1265214077SgibbsDRIVER_MODULE(xenstore, xenpci, xenstore_driver, xenstore_devclass, 0, 0); 1266214077Sgibbs#else 1267214077SgibbsDRIVER_MODULE(xenstore, nexus, xenstore_driver, xenstore_devclass, 0, 0); 1268214077Sgibbs#endif 1269214077Sgibbs 1270214077Sgibbs/*------------------------------- Sysctl Data --------------------------------*/ 1271214077Sgibbs/* XXX Shouldn't the node be somewhere else? */ 1272214077SgibbsSYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen"); 1273214077SgibbsSYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xs.evtchn, 0, ""); 1274214077SgibbsSYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, ""); 1275214077Sgibbs 1276214077Sgibbs/*-------------------------------- Public API --------------------------------*/ 1277214077Sgibbs/*------- API comments for these methods can be found in xenstorevar.h -------*/ 1278186557Skmacyint 1279214077Sgibbsxs_directory(struct xs_transaction t, const char *dir, const char *node, 1280214077Sgibbs u_int *num, const char ***result) 1281181624Skmacy{ 1282214077Sgibbs struct sbuf *path; 1283214077Sgibbs char *strings; 1284214077Sgibbs u_int len = 0; 1285186557Skmacy int error; 1286181624Skmacy 1287214077Sgibbs path = xs_join(dir, node); 1288214077Sgibbs error = xs_single(t, XS_DIRECTORY, sbuf_data(path), &len, 1289214077Sgibbs (void **)&strings); 1290214077Sgibbs sbuf_delete(path); 1291186557Skmacy if (error) 1292186557Skmacy return (error); 1293181624Skmacy 1294186557Skmacy *result = split(strings, len, num); 1295214077Sgibbs 1296186557Skmacy return (0); 1297181624Skmacy} 1298181624Skmacy 1299186557Skmacyint 1300214077Sgibbsxs_exists(struct xs_transaction t, const char *dir, const char *node) 1301181624Skmacy{ 1302214077Sgibbs const char **d; 1303186557Skmacy int error, dir_n; 1304181624Skmacy 1305214077Sgibbs error = xs_directory(t, dir, node, &dir_n, &d); 1306186557Skmacy if (error) 1307186557Skmacy return (0); 1308214077Sgibbs free(d, M_XENSTORE); 1309186557Skmacy return (1); 1310181624Skmacy} 1311181624Skmacy 1312186557Skmacyint 1313214077Sgibbsxs_read(struct xs_transaction t, const char *dir, const char *node, 1314214077Sgibbs u_int *len, void **result) 1315181624Skmacy{ 1316214077Sgibbs struct sbuf *path; 1317186557Skmacy void *ret; 1318186557Skmacy int error; 1319181624Skmacy 1320214077Sgibbs path = xs_join(dir, node); 1321214077Sgibbs error = xs_single(t, XS_READ, sbuf_data(path), len, &ret); 1322214077Sgibbs sbuf_delete(path); 1323186557Skmacy if (error) 1324186557Skmacy return (error); 1325186557Skmacy *result = ret; 1326186557Skmacy return (0); 1327181624Skmacy} 1328181624Skmacy 1329186557Skmacyint 1330214077Sgibbsxs_write(struct xs_transaction t, const char *dir, const char *node, 1331186557Skmacy const char *string) 1332181624Skmacy{ 1333214077Sgibbs struct sbuf *path; 1334186557Skmacy struct iovec iovec[2]; 1335186557Skmacy int error; 1336181624Skmacy 1337214077Sgibbs path = xs_join(dir, node); 1338181624Skmacy 1339214077Sgibbs iovec[0].iov_base = (void *)(uintptr_t) sbuf_data(path); 1340214077Sgibbs iovec[0].iov_len = sbuf_len(path) + 1; 1341186557Skmacy iovec[1].iov_base = (void *)(uintptr_t) string; 1342186557Skmacy iovec[1].iov_len = strlen(string); 1343181624Skmacy 1344186557Skmacy error = xs_talkv(t, XS_WRITE, iovec, 2, NULL, NULL); 1345214077Sgibbs sbuf_delete(path); 1346186557Skmacy 1347186557Skmacy return (error); 1348181624Skmacy} 1349181624Skmacy 1350186557Skmacyint 1351214077Sgibbsxs_mkdir(struct xs_transaction t, const char *dir, const char *node) 1352181624Skmacy{ 1353214077Sgibbs struct sbuf *path; 1354186557Skmacy int ret; 1355181624Skmacy 1356214077Sgibbs path = xs_join(dir, node); 1357214077Sgibbs ret = xs_single(t, XS_MKDIR, sbuf_data(path), NULL, NULL); 1358214077Sgibbs sbuf_delete(path); 1359181624Skmacy 1360186557Skmacy return (ret); 1361181624Skmacy} 1362181624Skmacy 1363186557Skmacyint 1364214077Sgibbsxs_rm(struct xs_transaction t, const char *dir, const char *node) 1365181624Skmacy{ 1366214077Sgibbs struct sbuf *path; 1367186557Skmacy int ret; 1368181624Skmacy 1369214077Sgibbs path = xs_join(dir, node); 1370214077Sgibbs ret = xs_single(t, XS_RM, sbuf_data(path), NULL, NULL); 1371214077Sgibbs sbuf_delete(path); 1372181624Skmacy 1373186557Skmacy return (ret); 1374181624Skmacy} 1375181624Skmacy 1376186557Skmacyint 1377214077Sgibbsxs_rm_tree(struct xs_transaction xbt, const char *base, const char *node) 1378181624Skmacy{ 1379214077Sgibbs struct xs_transaction local_xbt; 1380214077Sgibbs struct sbuf *root_path_sbuf; 1381214077Sgibbs struct sbuf *cur_path_sbuf; 1382214077Sgibbs char *root_path; 1383214077Sgibbs char *cur_path; 1384214077Sgibbs const char **dir; 1385186557Skmacy int error; 1386214077Sgibbs int empty; 1387181624Skmacy 1388214077Sgibbsretry: 1389214077Sgibbs root_path_sbuf = xs_join(base, node); 1390214077Sgibbs cur_path_sbuf = xs_join(base, node); 1391214077Sgibbs root_path = sbuf_data(root_path_sbuf); 1392214077Sgibbs cur_path = sbuf_data(cur_path_sbuf); 1393214077Sgibbs dir = NULL; 1394214077Sgibbs local_xbt.id = 0; 1395214077Sgibbs 1396214077Sgibbs if (xbt.id == 0) { 1397214077Sgibbs error = xs_transaction_start(&local_xbt); 1398214077Sgibbs if (error != 0) 1399214077Sgibbs goto out; 1400214077Sgibbs xbt = local_xbt; 1401186557Skmacy } 1402181624Skmacy 1403214077Sgibbs empty = 0; 1404214077Sgibbs while (1) { 1405214077Sgibbs u_int count; 1406214077Sgibbs u_int i; 1407181624Skmacy 1408214077Sgibbs error = xs_directory(xbt, cur_path, "", &count, &dir); 1409214077Sgibbs if (error) 1410214077Sgibbs goto out; 1411214077Sgibbs 1412214077Sgibbs for (i = 0; i < count; i++) { 1413214077Sgibbs error = xs_rm(xbt, cur_path, dir[i]); 1414214077Sgibbs if (error == ENOTEMPTY) { 1415214077Sgibbs struct sbuf *push_dir; 1416214077Sgibbs 1417214077Sgibbs /* 1418214077Sgibbs * Descend to clear out this sub directory. 1419214077Sgibbs * We'll return to cur_dir once push_dir 1420214077Sgibbs * is empty. 1421214077Sgibbs */ 1422214077Sgibbs push_dir = xs_join(cur_path, dir[i]); 1423214077Sgibbs sbuf_delete(cur_path_sbuf); 1424214077Sgibbs cur_path_sbuf = push_dir; 1425214077Sgibbs cur_path = sbuf_data(cur_path_sbuf); 1426214077Sgibbs break; 1427214077Sgibbs } else if (error != 0) { 1428214077Sgibbs goto out; 1429214077Sgibbs } 1430214077Sgibbs } 1431214077Sgibbs 1432214077Sgibbs free(dir, M_XENSTORE); 1433214077Sgibbs dir = NULL; 1434214077Sgibbs 1435214077Sgibbs if (i == count) { 1436214077Sgibbs char *last_slash; 1437214077Sgibbs 1438214077Sgibbs /* Directory is empty. It is now safe to remove. */ 1439214077Sgibbs error = xs_rm(xbt, cur_path, ""); 1440214077Sgibbs if (error != 0) 1441214077Sgibbs goto out; 1442214077Sgibbs 1443214077Sgibbs if (!strcmp(cur_path, root_path)) 1444214077Sgibbs break; 1445214077Sgibbs 1446214077Sgibbs /* Return to processing the parent directory. */ 1447214077Sgibbs last_slash = strrchr(cur_path, '/'); 1448214077Sgibbs KASSERT(last_slash != NULL, 1449214077Sgibbs ("xs_rm_tree: mangled path %s", cur_path)); 1450214077Sgibbs *last_slash = '\0'; 1451214077Sgibbs } 1452214077Sgibbs } 1453214077Sgibbs 1454214077Sgibbsout: 1455214077Sgibbs sbuf_delete(cur_path_sbuf); 1456214077Sgibbs sbuf_delete(root_path_sbuf); 1457214077Sgibbs if (dir != NULL) 1458214077Sgibbs free(dir, M_XENSTORE); 1459214077Sgibbs 1460214077Sgibbs if (local_xbt.id != 0) { 1461214077Sgibbs int terror; 1462214077Sgibbs 1463214077Sgibbs terror = xs_transaction_end(local_xbt, /*abort*/error != 0); 1464214077Sgibbs xbt.id = 0; 1465214077Sgibbs if (terror == EAGAIN && error == 0) 1466214077Sgibbs goto retry; 1467214077Sgibbs } 1468214077Sgibbs return (error); 1469181624Skmacy} 1470181624Skmacy 1471214077Sgibbsint 1472214077Sgibbsxs_transaction_start(struct xs_transaction *t) 1473181624Skmacy{ 1474214077Sgibbs char *id_str; 1475186557Skmacy int error; 1476181624Skmacy 1477214077Sgibbs error = xs_single(XST_NIL, XS_TRANSACTION_START, "", NULL, 1478214077Sgibbs (void **)&id_str); 1479214077Sgibbs if (error == 0) { 1480214077Sgibbs t->id = strtoul(id_str, NULL, 0); 1481214077Sgibbs free(id_str, M_XENSTORE); 1482214077Sgibbs } 1483214077Sgibbs return (error); 1484214077Sgibbs} 1485214077Sgibbs 1486214077Sgibbsint 1487214077Sgibbsxs_transaction_end(struct xs_transaction t, int abort) 1488214077Sgibbs{ 1489214077Sgibbs char abortstr[2]; 1490214077Sgibbs 1491186557Skmacy if (abort) 1492186557Skmacy strcpy(abortstr, "F"); 1493186557Skmacy else 1494186557Skmacy strcpy(abortstr, "T"); 1495181624Skmacy 1496214077Sgibbs return (xs_single(t, XS_TRANSACTION_END, abortstr, NULL, NULL)); 1497181624Skmacy} 1498181624Skmacy 1499186557Skmacyint 1500214077Sgibbsxs_scanf(struct xs_transaction t, const char *dir, const char *node, 1501214077Sgibbs int *scancountp, const char *fmt, ...) 1502181624Skmacy{ 1503186557Skmacy va_list ap; 1504186557Skmacy int error, ns; 1505186557Skmacy char *val; 1506181624Skmacy 1507214077Sgibbs error = xs_read(t, dir, node, NULL, (void **) &val); 1508186557Skmacy if (error) 1509186557Skmacy return (error); 1510181624Skmacy 1511186557Skmacy va_start(ap, fmt); 1512186557Skmacy ns = vsscanf(val, fmt, ap); 1513186557Skmacy va_end(ap); 1514214077Sgibbs free(val, M_XENSTORE); 1515186557Skmacy /* Distinctive errno. */ 1516186557Skmacy if (ns == 0) 1517186557Skmacy return (ERANGE); 1518186557Skmacy if (scancountp) 1519186557Skmacy *scancountp = ns; 1520186557Skmacy return (0); 1521181624Skmacy} 1522181624Skmacy 1523186557Skmacyint 1524214077Sgibbsxs_vprintf(struct xs_transaction t, 1525214077Sgibbs const char *dir, const char *node, const char *fmt, va_list ap) 1526181624Skmacy{ 1527214077Sgibbs struct sbuf *sb; 1528214077Sgibbs int error; 1529214077Sgibbs 1530214077Sgibbs sb = sbuf_new_auto(); 1531214077Sgibbs sbuf_vprintf(sb, fmt, ap); 1532214077Sgibbs sbuf_finish(sb); 1533214077Sgibbs error = xs_write(t, dir, node, sbuf_data(sb)); 1534214077Sgibbs sbuf_delete(sb); 1535214077Sgibbs 1536214077Sgibbs return (error); 1537214077Sgibbs} 1538214077Sgibbs 1539214077Sgibbsint 1540214077Sgibbsxs_printf(struct xs_transaction t, const char *dir, const char *node, 1541214077Sgibbs const char *fmt, ...) 1542214077Sgibbs{ 1543186557Skmacy va_list ap; 1544214077Sgibbs int error; 1545181624Skmacy 1546186557Skmacy va_start(ap, fmt); 1547214077Sgibbs error = xs_vprintf(t, dir, node, fmt, ap); 1548186557Skmacy va_end(ap); 1549181624Skmacy 1550186557Skmacy return (error); 1551181624Skmacy} 1552181624Skmacy 1553186557Skmacyint 1554214077Sgibbsxs_gather(struct xs_transaction t, const char *dir, ...) 1555181624Skmacy{ 1556186557Skmacy va_list ap; 1557186557Skmacy const char *name; 1558214077Sgibbs int error; 1559181624Skmacy 1560186557Skmacy va_start(ap, dir); 1561186557Skmacy error = 0; 1562186557Skmacy while (error == 0 && (name = va_arg(ap, char *)) != NULL) { 1563186557Skmacy const char *fmt = va_arg(ap, char *); 1564186557Skmacy void *result = va_arg(ap, void *); 1565186557Skmacy char *p; 1566181624Skmacy 1567214077Sgibbs error = xs_read(t, dir, name, NULL, (void **) &p); 1568186557Skmacy if (error) 1569186557Skmacy break; 1570186557Skmacy 1571186557Skmacy if (fmt) { 1572186557Skmacy if (sscanf(p, fmt, result) == 0) 1573186557Skmacy error = EINVAL; 1574214077Sgibbs free(p, M_XENSTORE); 1575186557Skmacy } else 1576186557Skmacy *(char **)result = p; 1577186557Skmacy } 1578186557Skmacy va_end(ap); 1579186557Skmacy 1580186557Skmacy return (error); 1581181624Skmacy} 1582181624Skmacy 1583186557Skmacyint 1584214077Sgibbsxs_register_watch(struct xs_watch *watch) 1585181624Skmacy{ 1586186557Skmacy /* Pointer in ascii is the token. */ 1587186557Skmacy char token[sizeof(watch) * 2 + 1]; 1588186557Skmacy int error; 1589181624Skmacy 1590186557Skmacy sprintf(token, "%lX", (long)watch); 1591181624Skmacy 1592214077Sgibbs sx_slock(&xs.suspend_mutex); 1593181624Skmacy 1594214077Sgibbs mtx_lock(&xs.registered_watches_lock); 1595186557Skmacy KASSERT(find_watch(token) == NULL, ("watch already registered")); 1596214077Sgibbs LIST_INSERT_HEAD(&xs.registered_watches, watch, list); 1597214077Sgibbs mtx_unlock(&xs.registered_watches_lock); 1598186557Skmacy 1599186557Skmacy error = xs_watch(watch->node, token); 1600214077Sgibbs 1601186557Skmacy /* Ignore errors due to multiple registration. */ 1602214077Sgibbs if (error == EEXIST) 1603214077Sgibbs error = 0; 1604214077Sgibbs 1605214077Sgibbs if (error != 0) { 1606214077Sgibbs mtx_lock(&xs.registered_watches_lock); 1607186557Skmacy LIST_REMOVE(watch, list); 1608214077Sgibbs mtx_unlock(&xs.registered_watches_lock); 1609186557Skmacy } 1610181624Skmacy 1611214077Sgibbs sx_sunlock(&xs.suspend_mutex); 1612181624Skmacy 1613186557Skmacy return (error); 1614181624Skmacy} 1615181624Skmacy 1616186557Skmacyvoid 1617214077Sgibbsxs_unregister_watch(struct xs_watch *watch) 1618181624Skmacy{ 1619186557Skmacy struct xs_stored_msg *msg, *tmp; 1620186557Skmacy char token[sizeof(watch) * 2 + 1]; 1621186557Skmacy int error; 1622181624Skmacy 1623186557Skmacy sprintf(token, "%lX", (long)watch); 1624181624Skmacy 1625214077Sgibbs sx_slock(&xs.suspend_mutex); 1626214077Sgibbs 1627214077Sgibbs mtx_lock(&xs.registered_watches_lock); 1628214077Sgibbs if (find_watch(token) == NULL) { 1629214077Sgibbs mtx_unlock(&xs.registered_watches_lock); 1630214077Sgibbs sx_sunlock(&xs.suspend_mutex); 1631214077Sgibbs return; 1632214077Sgibbs } 1633186557Skmacy LIST_REMOVE(watch, list); 1634214077Sgibbs mtx_unlock(&xs.registered_watches_lock); 1635181624Skmacy 1636186557Skmacy error = xs_unwatch(watch->node, token); 1637186557Skmacy if (error) 1638214077Sgibbs log(LOG_WARNING, "XENSTORE Failed to release watch %s: %i\n", 1639186557Skmacy watch->node, error); 1640181624Skmacy 1641214077Sgibbs sx_sunlock(&xs.suspend_mutex); 1642181624Skmacy 1643186557Skmacy /* Cancel pending watch events. */ 1644214077Sgibbs mtx_lock(&xs.watch_events_lock); 1645214077Sgibbs TAILQ_FOREACH_SAFE(msg, &xs.watch_events, list, tmp) { 1646186557Skmacy if (msg->u.watch.handle != watch) 1647186557Skmacy continue; 1648214077Sgibbs TAILQ_REMOVE(&xs.watch_events, msg, list); 1649214077Sgibbs free(msg->u.watch.vec, M_XENSTORE); 1650214077Sgibbs free(msg, M_XENSTORE); 1651186557Skmacy } 1652214077Sgibbs mtx_unlock(&xs.watch_events_lock); 1653181624Skmacy 1654186557Skmacy /* Flush any currently-executing callback, unless we are it. :-) */ 1655214077Sgibbs if (curproc->p_pid != xs.xenwatch_pid) { 1656214077Sgibbs sx_xlock(&xs.xenwatch_mutex); 1657214077Sgibbs sx_xunlock(&xs.xenwatch_mutex); 1658186557Skmacy } 1659181624Skmacy} 1660315675Sroyger 1661315675Sroygervoid 1662315675Sroygerxs_lock(void) 1663315675Sroyger{ 1664315675Sroyger 1665315675Sroyger sx_xlock(&xs.request_mutex); 1666315675Sroyger return; 1667315675Sroyger} 1668315675Sroyger 1669315675Sroygervoid 1670315675Sroygerxs_unlock(void) 1671315675Sroyger{ 1672315675Sroyger 1673315675Sroyger sx_xunlock(&xs.request_mutex); 1674315675Sroyger return; 1675315675Sroyger} 1676315675Sroyger 1677