brintos

brintos / linux-shallow public Read only

0
0
Text · 8.1 KiB · 5ebb723 Raw
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