317 lines · c
1/******************************************************************************2 * Talks to Xen Store to figure out what devices we have (backend half).3 *4 * Copyright (C) 2005 Rusty Russell, IBM Corporation5 * Copyright (C) 2005 Mike Wray, Hewlett-Packard6 * Copyright (C) 2005, 2006 XenSource Ltd7 * Copyright (C) 2007 Solarflare Communications, Inc.8 *9 * This program is free software; you can redistribute it and/or10 * modify it under the terms of the GNU General Public License version 211 * as published by the Free Software Foundation; or, when distributed12 * separately from the Linux kernel or incorporated into other13 * software packages, subject to the following license:14 *15 * Permission is hereby granted, free of charge, to any person obtaining a copy16 * of this source file (the "Software"), to deal in the Software without17 * restriction, including without limitation the rights to use, copy, modify,18 * merge, publish, distribute, sublicense, and/or sell copies of the Software,19 * and to permit persons to whom the Software is furnished to do so, subject to20 * the following conditions:21 *22 * The above copyright notice and this permission notice shall be included in23 * all copies or substantial portions of the Software.24 *25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE28 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS31 * IN THE SOFTWARE.32 */33 34#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt35 36#define DPRINTK(fmt, ...) \37 pr_debug("(%s:%d) " fmt "\n", \38 __func__, __LINE__, ##__VA_ARGS__)39 40#include <linux/kernel.h>41#include <linux/err.h>42#include <linux/string.h>43#include <linux/ctype.h>44#include <linux/fcntl.h>45#include <linux/mm.h>46#include <linux/notifier.h>47#include <linux/export.h>48#include <linux/semaphore.h>49 50#include <asm/page.h>51#include <asm/xen/hypervisor.h>52#include <asm/hypervisor.h>53#include <xen/xenbus.h>54#include <xen/features.h>55 56#include "xenbus.h"57 58/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */59static int backend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename)60{61 int domid, err;62 const char *devid, *type, *frontend;63 unsigned int typelen;64 65 type = strchr(nodename, '/');66 if (!type)67 return -EINVAL;68 type++;69 typelen = strcspn(type, "/");70 if (!typelen || type[typelen] != '/')71 return -EINVAL;72 73 devid = strrchr(nodename, '/') + 1;74 75 err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,76 "frontend", NULL, &frontend,77 NULL);78 if (err)79 return err;80 if (strlen(frontend) == 0)81 err = -ERANGE;82 if (!err && !xenbus_exists(XBT_NIL, frontend, ""))83 err = -ENOENT;84 kfree(frontend);85 86 if (err)87 return err;88 89 if (snprintf(bus_id, XEN_BUS_ID_SIZE, "%.*s-%i-%s",90 typelen, type, domid, devid) >= XEN_BUS_ID_SIZE)91 return -ENOSPC;92 return 0;93}94 95static int xenbus_uevent_backend(const struct device *dev,96 struct kobj_uevent_env *env)97{98 const struct xenbus_device *xdev;99 const struct xenbus_driver *drv;100 const struct xen_bus_type *bus;101 102 DPRINTK("");103 104 if (dev == NULL)105 return -ENODEV;106 107 xdev = to_xenbus_device(dev);108 bus = container_of(xdev->dev.bus, struct xen_bus_type, bus);109 110 if (add_uevent_var(env, "MODALIAS=xen-backend:%s", xdev->devicetype))111 return -ENOMEM;112 113 /* stuff we want to pass to /sbin/hotplug */114 if (add_uevent_var(env, "XENBUS_TYPE=%s", xdev->devicetype))115 return -ENOMEM;116 117 if (add_uevent_var(env, "XENBUS_PATH=%s", xdev->nodename))118 return -ENOMEM;119 120 if (add_uevent_var(env, "XENBUS_BASE_PATH=%s", bus->root))121 return -ENOMEM;122 123 if (dev->driver) {124 drv = to_xenbus_driver(dev->driver);125 if (drv && drv->uevent)126 return drv->uevent(xdev, env);127 }128 129 return 0;130}131 132/* backend/<typename>/<frontend-uuid>/<name> */133static int xenbus_probe_backend_unit(struct xen_bus_type *bus,134 const char *dir,135 const char *type,136 const char *name)137{138 char *nodename;139 int err;140 141 nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name);142 if (!nodename)143 return -ENOMEM;144 145 DPRINTK("%s\n", nodename);146 147 err = xenbus_probe_node(bus, type, nodename);148 kfree(nodename);149 return err;150}151 152/* backend/<typename>/<frontend-domid> */153static int xenbus_probe_backend(struct xen_bus_type *bus, const char *type,154 const char *domid)155{156 char *nodename;157 int err = 0;158 char **dir;159 unsigned int i, dir_n = 0;160 161 DPRINTK("");162 163 nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", bus->root, type, domid);164 if (!nodename)165 return -ENOMEM;166 167 dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);168 if (IS_ERR(dir)) {169 kfree(nodename);170 return PTR_ERR(dir);171 }172 173 for (i = 0; i < dir_n; i++) {174 err = xenbus_probe_backend_unit(bus, nodename, type, dir[i]);175 if (err)176 break;177 }178 kfree(dir);179 kfree(nodename);180 return err;181}182 183static bool frontend_will_handle(struct xenbus_watch *watch,184 const char *path, const char *token)185{186 return watch->nr_pending == 0;187}188 189static void frontend_changed(struct xenbus_watch *watch,190 const char *path, const char *token)191{192 xenbus_otherend_changed(watch, path, token, 0);193}194 195static struct xen_bus_type xenbus_backend = {196 .root = "backend",197 .levels = 3, /* backend/type/<frontend>/<id> */198 .get_bus_id = backend_bus_id,199 .probe = xenbus_probe_backend,200 .otherend_will_handle = frontend_will_handle,201 .otherend_changed = frontend_changed,202 .bus = {203 .name = "xen-backend",204 .match = xenbus_match,205 .uevent = xenbus_uevent_backend,206 .probe = xenbus_dev_probe,207 .remove = xenbus_dev_remove,208 .dev_groups = xenbus_dev_groups,209 },210};211 212static void backend_changed(struct xenbus_watch *watch,213 const char *path, const char *token)214{215 DPRINTK("");216 217 xenbus_dev_changed(path, &xenbus_backend);218}219 220static struct xenbus_watch be_watch = {221 .node = "backend",222 .callback = backend_changed,223};224 225static int read_frontend_details(struct xenbus_device *xendev)226{227 return xenbus_read_otherend_details(xendev, "frontend-id", "frontend");228}229 230int xenbus_dev_is_online(struct xenbus_device *dev)231{232 return !!xenbus_read_unsigned(dev->nodename, "online", 0);233}234EXPORT_SYMBOL_GPL(xenbus_dev_is_online);235 236int __xenbus_register_backend(struct xenbus_driver *drv, struct module *owner,237 const char *mod_name)238{239 drv->read_otherend_details = read_frontend_details;240 241 return xenbus_register_driver_common(drv, &xenbus_backend,242 owner, mod_name);243}244EXPORT_SYMBOL_GPL(__xenbus_register_backend);245 246static int backend_probe_and_watch(struct notifier_block *notifier,247 unsigned long event,248 void *data)249{250 /* Enumerate devices in xenstore and watch for changes. */251 xenbus_probe_devices(&xenbus_backend);252 register_xenbus_watch(&be_watch);253 254 return NOTIFY_DONE;255}256 257static int backend_reclaim_memory(struct device *dev, void *data)258{259 const struct xenbus_driver *drv;260 struct xenbus_device *xdev;261 262 if (!dev->driver)263 return 0;264 drv = to_xenbus_driver(dev->driver);265 if (drv && drv->reclaim_memory) {266 xdev = to_xenbus_device(dev);267 if (down_trylock(&xdev->reclaim_sem))268 return 0;269 drv->reclaim_memory(xdev);270 up(&xdev->reclaim_sem);271 }272 return 0;273}274 275/*276 * Returns 0 always because we are using shrinker to only detect memory277 * pressure.278 */279static unsigned long backend_shrink_memory_count(struct shrinker *shrinker,280 struct shrink_control *sc)281{282 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL,283 backend_reclaim_memory);284 return 0;285}286 287static int __init xenbus_probe_backend_init(void)288{289 struct shrinker *backend_memory_shrinker;290 static struct notifier_block xenstore_notifier = {291 .notifier_call = backend_probe_and_watch292 };293 int err;294 295 DPRINTK("");296 297 /* Register ourselves with the kernel bus subsystem */298 err = bus_register(&xenbus_backend.bus);299 if (err)300 return err;301 302 register_xenstore_notifier(&xenstore_notifier);303 304 backend_memory_shrinker = shrinker_alloc(0, "xen-backend");305 if (!backend_memory_shrinker) {306 pr_warn("shrinker allocation failed\n");307 return 0;308 }309 310 backend_memory_shrinker->count_objects = backend_shrink_memory_count;311 312 shrinker_register(backend_memory_shrinker);313 314 return 0;315}316subsys_initcall(xenbus_probe_backend_init);317