void xenbus_dev_verror(device_t dev, int err, const char *fmt, va_list ap) { int ret; unsigned int len; char *printf_buffer = NULL, *path_buffer = NULL; #define PRINTF_BUFFER_SIZE 4096 printf_buffer = malloc(PRINTF_BUFFER_SIZE,M_XENBUS, M_WAITOK); len = sprintf(printf_buffer, "%i ", err); ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap); KASSERT(len + ret <= PRINTF_BUFFER_SIZE-1, ("xenbus error message too big")); device_printf(dev, "Error %s\n", printf_buffer); path_buffer = error_path(dev); if (path_buffer == NULL) { printf("xenbus: failed to write error node for %s (%s)\n", xenbus_get_node(dev), printf_buffer); goto fail; } if (xs_write(XST_NIL, path_buffer, "error", printf_buffer) != 0) { printf("xenbus: failed to write error node for %s (%s)\n", xenbus_get_node(dev), printf_buffer); goto fail; } fail: if (printf_buffer) free(printf_buffer,M_XENBUS); if (path_buffer) free(path_buffer,M_XENBUS); }
/** * \brief Construct the error path corresponding to the given XenBus * device. * * \param dev The XenBus device for which we are constructing an error path. * * \return On success, the contructed error path. Otherwise NULL. * * It is the caller's responsibility to free any returned error path * node using the M_XENBUS malloc type. */ static char * error_path(device_t dev) { char *path_buffer = malloc(strlen("error/") + strlen(xenbus_get_node(dev)) + 1,M_XENBUS, M_WAITOK); strcpy(path_buffer, "error/"); strcpy(path_buffer + strlen("error/"), xenbus_get_node(dev)); return (path_buffer); }
/** * Handler for all generic XenBus device systcl nodes. */ static int xenbusb_device_sysctl_handler(SYSCTL_HANDLER_ARGS) { device_t dev; const char *value; dev = (device_t)arg1; switch (arg2) { case XENBUS_IVAR_NODE: value = xenbus_get_node(dev); break; case XENBUS_IVAR_TYPE: value = xenbus_get_type(dev); break; case XENBUS_IVAR_STATE: value = xenbus_strstate(xenbus_get_state(dev)); break; case XENBUS_IVAR_OTHEREND_ID: return (sysctl_handle_int(oidp, NULL, xenbus_get_otherend_id(dev), req)); /* NOTREACHED */ case XENBUS_IVAR_OTHEREND_PATH: value = xenbus_get_otherend_path(dev); break; default: return (EINVAL); } return (SYSCTL_OUT_STR(req, value)); }
/** * \brief Backend XenBus method implementing responses to local * XenStore changes. * * \param bus The XenBus bus parent of child. * \param child The XenBus child whose peer stat has changed. * \param_path The tree relative sub-path to the modified node. The empty * string indicates the root of the tree was destroyed. */ static void xenbusb_back_localend_changed(device_t bus, device_t child, const char *path) { xenbusb_localend_changed(bus, child, path); if (strcmp(path, "/state") != 0 && strcmp(path, "/online") != 0) return; if (xenbus_get_state(child) != XenbusStateClosed || xenbus_dev_is_online(child) != 0) return; /* * Cleanup the hotplug entry in the XenStore if * present. The control domain expects any userland * component associated with this device to destroy * this node in order to signify it is safe to * teardown the device. However, not all backends * rely on userland components, and those that * do should either use a communication channel * other than the XenStore, or ensure the hotplug * data is already cleaned up. * * This removal ensures that no matter what path * is taken to mark a back-end closed, the control * domain will understand that it is closed. */ xs_rm(XST_NIL, xenbus_get_node(child), "hotplug-status"); }
/** * \param dev The NewBus device representing this XenBus bus. * \param child The NewBus device representing a child of dev%'s XenBus bus. */ static void xenbusb_verify_device(device_t dev, device_t child) { if (xs_exists(XST_NIL, xenbus_get_node(child), "") == 0) { /* * Device tree has been removed from Xenbus. * Tear down the device. */ xenbusb_delete_child(dev, child); } }
int xenbus_dev_is_online(device_t dev) { const char *path; int error; int value; path = xenbus_get_node(dev); error = xs_gather(XST_NIL, path, "online", "%d", &value, NULL); if (error != 0) { /* Default to not online. */ value = 0; } return (value); }