2009-02-09 12:05:51 -08:00
/******************************************************************************
* Talks to Xen Store to figure out what devices we have ( backend half ) .
*
* Copyright ( C ) 2005 Rusty Russell , IBM Corporation
* Copyright ( C ) 2005 Mike Wray , Hewlett - Packard
* Copyright ( C ) 2005 , 2006 XenSource Ltd
* Copyright ( C ) 2007 Solarflare Communications , Inc .
*
* 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 .
*/
2013-06-28 03:21:41 -07:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# define DPRINTK(fmt, ...) \
pr_debug ( " (%s:%d) " fmt " \n " , \
__func__ , __LINE__ , # # __VA_ARGS__ )
2009-02-09 12:05:51 -08:00
# include <linux/kernel.h>
# include <linux/err.h>
# include <linux/string.h>
# include <linux/ctype.h>
# include <linux/fcntl.h>
# include <linux/mm.h>
# include <linux/notifier.h>
2011-07-10 13:22:07 -04:00
# include <linux/export.h>
2009-02-09 12:05:51 -08:00
# include <asm/page.h>
# include <asm/pgtable.h>
# include <asm/xen/hypervisor.h>
# include <asm/hypervisor.h>
# include <xen/xenbus.h>
# include <xen/features.h>
# include "xenbus_comms.h"
# include "xenbus_probe.h"
/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
static int backend_bus_id ( char bus_id [ XEN_BUS_ID_SIZE ] , const char * nodename )
{
int domid , err ;
const char * devid , * type , * frontend ;
unsigned int typelen ;
type = strchr ( nodename , ' / ' ) ;
if ( ! type )
return - EINVAL ;
type + + ;
typelen = strcspn ( type , " / " ) ;
if ( ! typelen | | type [ typelen ] ! = ' / ' )
return - EINVAL ;
devid = strrchr ( nodename , ' / ' ) + 1 ;
err = xenbus_gather ( XBT_NIL , nodename , " frontend-id " , " %i " , & domid ,
" frontend " , NULL , & frontend ,
NULL ) ;
if ( err )
return err ;
if ( strlen ( frontend ) = = 0 )
err = - ERANGE ;
if ( ! err & & ! xenbus_exists ( XBT_NIL , frontend , " " ) )
err = - ENOENT ;
kfree ( frontend ) ;
if ( err )
return err ;
2010-12-10 14:39:15 +00:00
if ( snprintf ( bus_id , XEN_BUS_ID_SIZE , " %.*s-%i-%s " ,
typelen , type , domid , devid ) > = XEN_BUS_ID_SIZE )
2009-02-09 12:05:51 -08:00
return - ENOSPC ;
return 0 ;
}
static int xenbus_uevent_backend ( struct device * dev ,
struct kobj_uevent_env * env )
{
struct xenbus_device * xdev ;
struct xenbus_driver * drv ;
struct xen_bus_type * bus ;
DPRINTK ( " " ) ;
if ( dev = = NULL )
return - ENODEV ;
xdev = to_xenbus_device ( dev ) ;
bus = container_of ( xdev - > dev . bus , struct xen_bus_type , bus ) ;
2011-06-29 14:40:08 +02:00
if ( add_uevent_var ( env , " MODALIAS=xen-backend:%s " , xdev - > devicetype ) )
return - ENOMEM ;
2009-02-09 12:05:51 -08:00
/* stuff we want to pass to /sbin/hotplug */
if ( add_uevent_var ( env , " XENBUS_TYPE=%s " , xdev - > devicetype ) )
return - ENOMEM ;
if ( add_uevent_var ( env , " XENBUS_PATH=%s " , xdev - > nodename ) )
return - ENOMEM ;
if ( add_uevent_var ( env , " XENBUS_BASE_PATH=%s " , bus - > root ) )
return - ENOMEM ;
if ( dev - > driver ) {
drv = to_xenbus_driver ( dev - > driver ) ;
if ( drv & & drv - > uevent )
return drv - > uevent ( xdev , env ) ;
}
return 0 ;
}
/* backend/<typename>/<frontend-uuid>/<name> */
static int xenbus_probe_backend_unit ( struct xen_bus_type * bus ,
const char * dir ,
const char * type ,
const char * name )
{
char * nodename ;
int err ;
nodename = kasprintf ( GFP_KERNEL , " %s/%s " , dir , name ) ;
if ( ! nodename )
return - ENOMEM ;
DPRINTK ( " %s \n " , nodename ) ;
err = xenbus_probe_node ( bus , type , nodename ) ;
kfree ( nodename ) ;
return err ;
}
/* backend/<typename>/<frontend-domid> */
2010-12-10 14:39:15 +00:00
static int xenbus_probe_backend ( struct xen_bus_type * bus , const char * type ,
const char * domid )
2009-02-09 12:05:51 -08:00
{
char * nodename ;
int err = 0 ;
char * * dir ;
unsigned int i , dir_n = 0 ;
DPRINTK ( " " ) ;
nodename = kasprintf ( GFP_KERNEL , " %s/%s/%s " , bus - > root , type , domid ) ;
if ( ! nodename )
return - ENOMEM ;
dir = xenbus_directory ( XBT_NIL , nodename , " " , & dir_n ) ;
if ( IS_ERR ( dir ) ) {
kfree ( nodename ) ;
return PTR_ERR ( dir ) ;
}
for ( i = 0 ; i < dir_n ; i + + ) {
err = xenbus_probe_backend_unit ( bus , nodename , type , dir [ i ] ) ;
if ( err )
break ;
}
kfree ( dir ) ;
kfree ( nodename ) ;
return err ;
}
static void frontend_changed ( struct xenbus_watch * watch ,
const char * * vec , unsigned int len )
{
xenbus_otherend_changed ( watch , vec , len , 0 ) ;
}
static struct xen_bus_type xenbus_backend = {
. root = " backend " ,
2010-12-10 14:39:15 +00:00
. levels = 3 , /* backend/type/<frontend>/<id> */
2009-02-09 12:05:51 -08:00
. get_bus_id = backend_bus_id ,
. probe = xenbus_probe_backend ,
. otherend_changed = frontend_changed ,
. bus = {
2010-12-10 14:39:15 +00:00
. name = " xen-backend " ,
. match = xenbus_match ,
. uevent = xenbus_uevent_backend ,
. probe = xenbus_dev_probe ,
. remove = xenbus_dev_remove ,
. shutdown = xenbus_dev_shutdown ,
2013-10-06 23:55:49 -07:00
. dev_groups = xenbus_dev_groups ,
2009-02-09 12:05:51 -08:00
} ,
} ;
static void backend_changed ( struct xenbus_watch * watch ,
const char * * vec , unsigned int len )
{
DPRINTK ( " " ) ;
xenbus_dev_changed ( vec [ XS_WATCH_PATH ] , & xenbus_backend ) ;
}
static struct xenbus_watch be_watch = {
. node = " backend " ,
. callback = backend_changed ,
} ;
static int read_frontend_details ( struct xenbus_device * xendev )
{
return xenbus_read_otherend_details ( xendev , " frontend-id " , " frontend " ) ;
}
int xenbus_dev_is_online ( struct xenbus_device * dev )
{
int rc , val ;
rc = xenbus_scanf ( XBT_NIL , dev - > nodename , " online " , " %d " , & val ) ;
if ( rc ! = 1 )
val = 0 ; /* no online node present */
return val ;
}
EXPORT_SYMBOL_GPL ( xenbus_dev_is_online ) ;
2014-09-08 17:30:41 +01:00
int __xenbus_register_backend ( struct xenbus_driver * drv , struct module * owner ,
const char * mod_name )
2009-02-09 12:05:51 -08:00
{
drv - > read_otherend_details = read_frontend_details ;
2014-09-08 17:30:41 +01:00
return xenbus_register_driver_common ( drv , & xenbus_backend ,
owner , mod_name ) ;
2009-02-09 12:05:51 -08:00
}
2014-09-08 17:30:41 +01:00
EXPORT_SYMBOL_GPL ( __xenbus_register_backend ) ;
2009-02-09 12:05:51 -08:00
static int backend_probe_and_watch ( struct notifier_block * notifier ,
unsigned long event ,
void * data )
{
/* Enumerate devices in xenstore and watch for changes. */
xenbus_probe_devices ( & xenbus_backend ) ;
register_xenbus_watch ( & be_watch ) ;
2010-03-29 14:38:35 -07:00
2009-02-09 12:05:51 -08:00
return NOTIFY_DONE ;
}
static int __init xenbus_probe_backend_init ( void )
{
static struct notifier_block xenstore_notifier = {
. notifier_call = backend_probe_and_watch
} ;
int err ;
DPRINTK ( " " ) ;
/* Register ourselves with the kernel bus subsystem */
err = bus_register ( & xenbus_backend . bus ) ;
2010-03-29 14:38:35 -07:00
if ( err )
2009-02-09 12:05:51 -08:00
return err ;
register_xenstore_notifier ( & xenstore_notifier ) ;
return 0 ;
}
2009-03-04 22:32:16 -08:00
subsys_initcall ( xenbus_probe_backend_init ) ;