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