162306a36Sopenharmony_ci/****************************************************************************** 262306a36Sopenharmony_ci * Talks to Xen Store to figure out what devices we have (backend half). 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2005 Rusty Russell, IBM Corporation 562306a36Sopenharmony_ci * Copyright (C) 2005 Mike Wray, Hewlett-Packard 662306a36Sopenharmony_ci * Copyright (C) 2005, 2006 XenSource Ltd 762306a36Sopenharmony_ci * Copyright (C) 2007 Solarflare Communications, Inc. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or 1062306a36Sopenharmony_ci * modify it under the terms of the GNU General Public License version 2 1162306a36Sopenharmony_ci * as published by the Free Software Foundation; or, when distributed 1262306a36Sopenharmony_ci * separately from the Linux kernel or incorporated into other 1362306a36Sopenharmony_ci * software packages, subject to the following license: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 1662306a36Sopenharmony_ci * of this source file (the "Software"), to deal in the Software without 1762306a36Sopenharmony_ci * restriction, including without limitation the rights to use, copy, modify, 1862306a36Sopenharmony_ci * merge, publish, distribute, sublicense, and/or sell copies of the Software, 1962306a36Sopenharmony_ci * and to permit persons to whom the Software is furnished to do so, subject to 2062306a36Sopenharmony_ci * the following conditions: 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 2362306a36Sopenharmony_ci * all copies or substantial portions of the Software. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2862306a36Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2962306a36Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 3062306a36Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 3162306a36Sopenharmony_ci * IN THE SOFTWARE. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define DPRINTK(fmt, ...) \ 3762306a36Sopenharmony_ci pr_debug("(%s:%d) " fmt "\n", \ 3862306a36Sopenharmony_ci __func__, __LINE__, ##__VA_ARGS__) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#include <linux/kernel.h> 4162306a36Sopenharmony_ci#include <linux/err.h> 4262306a36Sopenharmony_ci#include <linux/string.h> 4362306a36Sopenharmony_ci#include <linux/ctype.h> 4462306a36Sopenharmony_ci#include <linux/fcntl.h> 4562306a36Sopenharmony_ci#include <linux/mm.h> 4662306a36Sopenharmony_ci#include <linux/notifier.h> 4762306a36Sopenharmony_ci#include <linux/export.h> 4862306a36Sopenharmony_ci#include <linux/semaphore.h> 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#include <asm/page.h> 5162306a36Sopenharmony_ci#include <asm/xen/hypervisor.h> 5262306a36Sopenharmony_ci#include <asm/hypervisor.h> 5362306a36Sopenharmony_ci#include <xen/xenbus.h> 5462306a36Sopenharmony_ci#include <xen/features.h> 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#include "xenbus.h" 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */ 5962306a36Sopenharmony_cistatic int backend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci int domid, err; 6262306a36Sopenharmony_ci const char *devid, *type, *frontend; 6362306a36Sopenharmony_ci unsigned int typelen; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci type = strchr(nodename, '/'); 6662306a36Sopenharmony_ci if (!type) 6762306a36Sopenharmony_ci return -EINVAL; 6862306a36Sopenharmony_ci type++; 6962306a36Sopenharmony_ci typelen = strcspn(type, "/"); 7062306a36Sopenharmony_ci if (!typelen || type[typelen] != '/') 7162306a36Sopenharmony_ci return -EINVAL; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci devid = strrchr(nodename, '/') + 1; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid, 7662306a36Sopenharmony_ci "frontend", NULL, &frontend, 7762306a36Sopenharmony_ci NULL); 7862306a36Sopenharmony_ci if (err) 7962306a36Sopenharmony_ci return err; 8062306a36Sopenharmony_ci if (strlen(frontend) == 0) 8162306a36Sopenharmony_ci err = -ERANGE; 8262306a36Sopenharmony_ci if (!err && !xenbus_exists(XBT_NIL, frontend, "")) 8362306a36Sopenharmony_ci err = -ENOENT; 8462306a36Sopenharmony_ci kfree(frontend); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (err) 8762306a36Sopenharmony_ci return err; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (snprintf(bus_id, XEN_BUS_ID_SIZE, "%.*s-%i-%s", 9062306a36Sopenharmony_ci typelen, type, domid, devid) >= XEN_BUS_ID_SIZE) 9162306a36Sopenharmony_ci return -ENOSPC; 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int xenbus_uevent_backend(const struct device *dev, 9662306a36Sopenharmony_ci struct kobj_uevent_env *env) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci const struct xenbus_device *xdev; 9962306a36Sopenharmony_ci const struct xenbus_driver *drv; 10062306a36Sopenharmony_ci const struct xen_bus_type *bus; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci DPRINTK(""); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (dev == NULL) 10562306a36Sopenharmony_ci return -ENODEV; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci xdev = to_xenbus_device(dev); 10862306a36Sopenharmony_ci bus = container_of(xdev->dev.bus, struct xen_bus_type, bus); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (add_uevent_var(env, "MODALIAS=xen-backend:%s", xdev->devicetype)) 11162306a36Sopenharmony_ci return -ENOMEM; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* stuff we want to pass to /sbin/hotplug */ 11462306a36Sopenharmony_ci if (add_uevent_var(env, "XENBUS_TYPE=%s", xdev->devicetype)) 11562306a36Sopenharmony_ci return -ENOMEM; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (add_uevent_var(env, "XENBUS_PATH=%s", xdev->nodename)) 11862306a36Sopenharmony_ci return -ENOMEM; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (add_uevent_var(env, "XENBUS_BASE_PATH=%s", bus->root)) 12162306a36Sopenharmony_ci return -ENOMEM; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (dev->driver) { 12462306a36Sopenharmony_ci drv = to_xenbus_driver(dev->driver); 12562306a36Sopenharmony_ci if (drv && drv->uevent) 12662306a36Sopenharmony_ci return drv->uevent(xdev, env); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* backend/<typename>/<frontend-uuid>/<name> */ 13362306a36Sopenharmony_cistatic int xenbus_probe_backend_unit(struct xen_bus_type *bus, 13462306a36Sopenharmony_ci const char *dir, 13562306a36Sopenharmony_ci const char *type, 13662306a36Sopenharmony_ci const char *name) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci char *nodename; 13962306a36Sopenharmony_ci int err; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name); 14262306a36Sopenharmony_ci if (!nodename) 14362306a36Sopenharmony_ci return -ENOMEM; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci DPRINTK("%s\n", nodename); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci err = xenbus_probe_node(bus, type, nodename); 14862306a36Sopenharmony_ci kfree(nodename); 14962306a36Sopenharmony_ci return err; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* backend/<typename>/<frontend-domid> */ 15362306a36Sopenharmony_cistatic int xenbus_probe_backend(struct xen_bus_type *bus, const char *type, 15462306a36Sopenharmony_ci const char *domid) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci char *nodename; 15762306a36Sopenharmony_ci int err = 0; 15862306a36Sopenharmony_ci char **dir; 15962306a36Sopenharmony_ci unsigned int i, dir_n = 0; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci DPRINTK(""); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", bus->root, type, domid); 16462306a36Sopenharmony_ci if (!nodename) 16562306a36Sopenharmony_ci return -ENOMEM; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n); 16862306a36Sopenharmony_ci if (IS_ERR(dir)) { 16962306a36Sopenharmony_ci kfree(nodename); 17062306a36Sopenharmony_ci return PTR_ERR(dir); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci for (i = 0; i < dir_n; i++) { 17462306a36Sopenharmony_ci err = xenbus_probe_backend_unit(bus, nodename, type, dir[i]); 17562306a36Sopenharmony_ci if (err) 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci kfree(dir); 17962306a36Sopenharmony_ci kfree(nodename); 18062306a36Sopenharmony_ci return err; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic bool frontend_will_handle(struct xenbus_watch *watch, 18462306a36Sopenharmony_ci const char *path, const char *token) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci return watch->nr_pending == 0; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void frontend_changed(struct xenbus_watch *watch, 19062306a36Sopenharmony_ci const char *path, const char *token) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci xenbus_otherend_changed(watch, path, token, 0); 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic struct xen_bus_type xenbus_backend = { 19662306a36Sopenharmony_ci .root = "backend", 19762306a36Sopenharmony_ci .levels = 3, /* backend/type/<frontend>/<id> */ 19862306a36Sopenharmony_ci .get_bus_id = backend_bus_id, 19962306a36Sopenharmony_ci .probe = xenbus_probe_backend, 20062306a36Sopenharmony_ci .otherend_will_handle = frontend_will_handle, 20162306a36Sopenharmony_ci .otherend_changed = frontend_changed, 20262306a36Sopenharmony_ci .bus = { 20362306a36Sopenharmony_ci .name = "xen-backend", 20462306a36Sopenharmony_ci .match = xenbus_match, 20562306a36Sopenharmony_ci .uevent = xenbus_uevent_backend, 20662306a36Sopenharmony_ci .probe = xenbus_dev_probe, 20762306a36Sopenharmony_ci .remove = xenbus_dev_remove, 20862306a36Sopenharmony_ci .dev_groups = xenbus_dev_groups, 20962306a36Sopenharmony_ci }, 21062306a36Sopenharmony_ci}; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void backend_changed(struct xenbus_watch *watch, 21362306a36Sopenharmony_ci const char *path, const char *token) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci DPRINTK(""); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci xenbus_dev_changed(path, &xenbus_backend); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic struct xenbus_watch be_watch = { 22162306a36Sopenharmony_ci .node = "backend", 22262306a36Sopenharmony_ci .callback = backend_changed, 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic int read_frontend_details(struct xenbus_device *xendev) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci return xenbus_read_otherend_details(xendev, "frontend-id", "frontend"); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ciint xenbus_dev_is_online(struct xenbus_device *dev) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci return !!xenbus_read_unsigned(dev->nodename, "online", 0); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_dev_is_online); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ciint __xenbus_register_backend(struct xenbus_driver *drv, struct module *owner, 23762306a36Sopenharmony_ci const char *mod_name) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci drv->read_otherend_details = read_frontend_details; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return xenbus_register_driver_common(drv, &xenbus_backend, 24262306a36Sopenharmony_ci owner, mod_name); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__xenbus_register_backend); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int backend_probe_and_watch(struct notifier_block *notifier, 24762306a36Sopenharmony_ci unsigned long event, 24862306a36Sopenharmony_ci void *data) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci /* Enumerate devices in xenstore and watch for changes. */ 25162306a36Sopenharmony_ci xenbus_probe_devices(&xenbus_backend); 25262306a36Sopenharmony_ci register_xenbus_watch(&be_watch); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return NOTIFY_DONE; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int backend_reclaim_memory(struct device *dev, void *data) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci const struct xenbus_driver *drv; 26062306a36Sopenharmony_ci struct xenbus_device *xdev; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (!dev->driver) 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci drv = to_xenbus_driver(dev->driver); 26562306a36Sopenharmony_ci if (drv && drv->reclaim_memory) { 26662306a36Sopenharmony_ci xdev = to_xenbus_device(dev); 26762306a36Sopenharmony_ci if (down_trylock(&xdev->reclaim_sem)) 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci drv->reclaim_memory(xdev); 27062306a36Sopenharmony_ci up(&xdev->reclaim_sem); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci return 0; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/* 27662306a36Sopenharmony_ci * Returns 0 always because we are using shrinker to only detect memory 27762306a36Sopenharmony_ci * pressure. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_cistatic unsigned long backend_shrink_memory_count(struct shrinker *shrinker, 28062306a36Sopenharmony_ci struct shrink_control *sc) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, 28362306a36Sopenharmony_ci backend_reclaim_memory); 28462306a36Sopenharmony_ci return 0; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic struct shrinker backend_memory_shrinker = { 28862306a36Sopenharmony_ci .count_objects = backend_shrink_memory_count, 28962306a36Sopenharmony_ci .seeks = DEFAULT_SEEKS, 29062306a36Sopenharmony_ci}; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic int __init xenbus_probe_backend_init(void) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci static struct notifier_block xenstore_notifier = { 29562306a36Sopenharmony_ci .notifier_call = backend_probe_and_watch 29662306a36Sopenharmony_ci }; 29762306a36Sopenharmony_ci int err; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci DPRINTK(""); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Register ourselves with the kernel bus subsystem */ 30262306a36Sopenharmony_ci err = bus_register(&xenbus_backend.bus); 30362306a36Sopenharmony_ci if (err) 30462306a36Sopenharmony_ci return err; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci register_xenstore_notifier(&xenstore_notifier); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (register_shrinker(&backend_memory_shrinker, "xen-backend")) 30962306a36Sopenharmony_ci pr_warn("shrinker registration failed\n"); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_cisubsys_initcall(xenbus_probe_backend_init); 314