/****************************************************************************** * xenbus_xs.c * * This is the kernel equivalent of the "xs" library. We don't need everything * and we use xenbus_comms for communication. * * Copyright (C) 2005 Rusty Russell, IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation; or, when distributed * separately from the Linux kernel or incorporated into other * software packages, subject to the following license: * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this source file (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #define pr_fmt(fmt) … #include <linux/unistd.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/uio.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/err.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/kthread.h> #include <linux/reboot.h> #include <linux/rwsem.h> #include <linux/mutex.h> #include <asm/xen/hypervisor.h> #include <xen/xenbus.h> #include <xen/xen.h> #include "xenbus.h" /* * Framework to protect suspend/resume handling against normal Xenstore * message handling: * During suspend/resume there must be no open transaction and no pending * Xenstore request. * New watch events happening in this time can be ignored by firing all watches * after resume. */ /* Lock protecting enter/exit critical region. */ static DEFINE_SPINLOCK(xs_state_lock); /* Number of users in critical region (protected by xs_state_lock). */ static unsigned int xs_state_users; /* Suspend handler waiting or already active (protected by xs_state_lock)? */ static int xs_suspend_active; /* Unique Xenstore request id (protected by xs_state_lock). */ static uint32_t xs_request_id; /* Wait queue for all callers waiting for critical region to become usable. */ static DECLARE_WAIT_QUEUE_HEAD(xs_state_enter_wq); /* Wait queue for suspend handling waiting for critical region being empty. */ static DECLARE_WAIT_QUEUE_HEAD(xs_state_exit_wq); /* List of registered watches, and a lock to protect it. */ static LIST_HEAD(watches); static DEFINE_SPINLOCK(watches_lock); /* List of pending watch callback events, and a lock to protect it. */ static LIST_HEAD(watch_events); static DEFINE_SPINLOCK(watch_events_lock); /* Protect watch (de)register against save/restore. */ static DECLARE_RWSEM(xs_watch_rwsem); /* * Details of the xenwatch callback kernel thread. The thread waits on the * watch_events_waitq for work to do (queued on watch_events list). When it * wakes up it acquires the xenwatch_mutex before reading the list and * carrying out work. */ static pid_t xenwatch_pid; static DEFINE_MUTEX(xenwatch_mutex); static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq); static void xs_suspend_enter(void) { … } static void xs_suspend_exit(void) { … } static uint32_t xs_request_enter(struct xb_req_data *req) { … } void xs_request_exit(struct xb_req_data *req) { … } static int get_error(const char *errorstring) { … } static bool xenbus_ok(void) { … } static bool test_reply(struct xb_req_data *req) { … } static void *read_reply(struct xb_req_data *req) { … } static void xs_send(struct xb_req_data *req, struct xsd_sockmsg *msg) { … } static void *xs_wait_for_reply(struct xb_req_data *req, struct xsd_sockmsg *msg) { … } static void xs_wake_up(struct xb_req_data *req) { … } int xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void *par) { … } EXPORT_SYMBOL(…); /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ static void *xs_talkv(struct xenbus_transaction t, enum xsd_sockmsg_type type, const struct kvec *iovec, unsigned int num_vecs, unsigned int *len) { … } /* Simplified version of xs_talkv: single message. */ static void *xs_single(struct xenbus_transaction t, enum xsd_sockmsg_type type, const char *string, unsigned int *len) { … } /* Many commands only need an ack, don't care what it says. */ static int xs_error(char *reply) { … } static unsigned int count_strings(const char *strings, unsigned int len) { … } /* Return the path to dir with /name appended. Buffer must be kfree()'ed. */ static char *join(const char *dir, const char *name) { … } static char **split(char *strings, unsigned int len, unsigned int *num) { … } char **xenbus_directory(struct xenbus_transaction t, const char *dir, const char *node, unsigned int *num) { … } EXPORT_SYMBOL_GPL(…); /* Check if a path exists. Return 1 if it does. */ int xenbus_exists(struct xenbus_transaction t, const char *dir, const char *node) { … } EXPORT_SYMBOL_GPL(…); /* Get the value of a single file. * Returns a kmalloced value: call free() on it after use. * len indicates length in bytes. */ void *xenbus_read(struct xenbus_transaction t, const char *dir, const char *node, unsigned int *len) { … } EXPORT_SYMBOL_GPL(…); /* Write the value of a single file. * Returns -err on failure. */ int xenbus_write(struct xenbus_transaction t, const char *dir, const char *node, const char *string) { … } EXPORT_SYMBOL_GPL(…); /* Create a new directory. */ int xenbus_mkdir(struct xenbus_transaction t, const char *dir, const char *node) { … } EXPORT_SYMBOL_GPL(…); /* Destroy a file or directory (directories must be empty). */ int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node) { … } EXPORT_SYMBOL_GPL(…); /* Start a transaction: changes by others will not be seen during this * transaction, and changes will not be visible to others until end. */ int xenbus_transaction_start(struct xenbus_transaction *t) { … } EXPORT_SYMBOL_GPL(…); /* End a transaction. * If abandon is true, transaction is discarded instead of committed. */ int xenbus_transaction_end(struct xenbus_transaction t, int abort) { … } EXPORT_SYMBOL_GPL(…); /* Single read and scanf: returns -errno or num scanned. */ int xenbus_scanf(struct xenbus_transaction t, const char *dir, const char *node, const char *fmt, ...) { … } EXPORT_SYMBOL_GPL(…); /* Read an (optional) unsigned value. */ unsigned int xenbus_read_unsigned(const char *dir, const char *node, unsigned int default_val) { … } EXPORT_SYMBOL_GPL(…); /* Single printf and write: returns -errno or 0. */ int xenbus_printf(struct xenbus_transaction t, const char *dir, const char *node, const char *fmt, ...) { … } EXPORT_SYMBOL_GPL(…); /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ int xenbus_gather(struct xenbus_transaction t, const char *dir, ...) { … } EXPORT_SYMBOL_GPL(…); static int xs_watch(const char *path, const char *token) { … } static int xs_unwatch(const char *path, const char *token) { … } static struct xenbus_watch *find_watch(const char *token) { … } int xs_watch_msg(struct xs_watch_event *event) { … } /* * Certain older XenBus toolstack cannot handle reading values that are * not populated. Some Xen 3.4 installation are incapable of doing this * so if we are running on anything older than 4 do not attempt to read * control/platform-feature-xs_reset_watches. */ static bool xen_strict_xenbus_quirk(void) { … } static void xs_reset_watches(void) { … } /* Register callback to watch this node. */ int register_xenbus_watch(struct xenbus_watch *watch) { … } EXPORT_SYMBOL_GPL(…); void unregister_xenbus_watch(struct xenbus_watch *watch) { … } EXPORT_SYMBOL_GPL(…); void xs_suspend(void) { … } void xs_resume(void) { … } void xs_suspend_cancel(void) { … } static int xenwatch_thread(void *unused) { … } /* * Wake up all threads waiting for a xenstore reply. In case of shutdown all * pending replies will be marked as "aborted" in order to let the waiters * return in spite of xenstore possibly no longer being able to reply. This * will avoid blocking shutdown by a thread waiting for xenstore but being * necessary for shutdown processing to proceed. */ static int xs_reboot_notify(struct notifier_block *nb, unsigned long code, void *unused) { … } static struct notifier_block xs_reboot_nb = …; int xs_init(void) { … }