2011-03-14 18:29:37 +03:00
/******************************************************************************
* Xen balloon driver - enables returning / claiming memory to / from Xen .
*
* Copyright ( c ) 2003 , B Dragovic
* Copyright ( c ) 2003 - 2004 , M Williamson , K Fraser
* Copyright ( c ) 2005 Dan M . Smith , IBM Corporation
*
* 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 14:21:41 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2011-03-14 18:29:37 +03:00
# include <linux/kernel.h>
2016-02-22 03:06:05 +03:00
# include <linux/errno.h>
# include <linux/mm_types.h>
# include <linux/init.h>
2011-03-14 18:29:37 +03:00
# include <linux/capability.h>
# include <xen/xen.h>
# include <xen/interface/xen.h>
# include <xen/balloon.h>
# include <xen/xenbus.h>
# include <xen/features.h>
# include <xen/page.h>
# define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
# define BALLOON_CLASS_NAME "xen_memory"
2011-12-15 03:32:50 +04:00
static struct device balloon_dev ;
2011-03-14 18:29:37 +03:00
2011-12-15 03:32:50 +04:00
static int register_balloon ( struct device * dev ) ;
2011-03-14 18:29:37 +03:00
/* React to a change in the target key */
static void watch_target ( struct xenbus_watch * watch ,
2017-02-09 16:39:57 +03:00
const char * path , const char * token )
2011-03-14 18:29:37 +03:00
{
2017-10-26 12:50:56 +03:00
unsigned long long new_target , static_max ;
2011-03-14 18:29:37 +03:00
int err ;
2017-07-10 11:10:45 +03:00
static bool watch_fired ;
static long target_diff ;
2011-03-14 18:29:37 +03:00
err = xenbus_scanf ( XBT_NIL , " memory " , " target " , " %llu " , & new_target ) ;
if ( err ! = 1 ) {
/* This is ok (for domain0 at least) - so just return */
return ;
}
/* The given memory/target value is in KiB, so it needs converting to
* pages . PAGE_SHIFT converts bytes to pages , hence PAGE_SHIFT - 10.
*/
2017-07-10 11:10:45 +03:00
new_target > > = PAGE_SHIFT - 10 ;
2017-10-26 12:50:56 +03:00
if ( ! watch_fired ) {
watch_fired = true ;
err = xenbus_scanf ( XBT_NIL , " memory " , " static-max " , " %llu " ,
& static_max ) ;
if ( err ! = 1 )
static_max = new_target ;
else
static_max > > = PAGE_SHIFT - 10 ;
target_diff = xen_pv_domain ( ) ? 0
: static_max - balloon_stats . target_pages ;
2017-07-10 11:10:45 +03:00
}
2017-10-26 12:50:56 +03:00
balloon_set_new_target ( new_target - target_diff ) ;
2011-03-14 18:29:37 +03:00
}
2011-07-28 17:23:03 +04:00
static struct xenbus_watch target_watch = {
. node = " memory/target " ,
. callback = watch_target ,
} ;
2011-03-14 18:29:37 +03:00
static int balloon_init_watcher ( struct notifier_block * notifier ,
unsigned long event ,
void * data )
{
int err ;
err = register_xenbus_watch ( & target_watch ) ;
if ( err )
2013-06-28 14:21:41 +04:00
pr_err ( " Failed to set balloon watcher \n " ) ;
2011-03-14 18:29:37 +03:00
return NOTIFY_DONE ;
}
2011-07-28 17:23:03 +04:00
static struct notifier_block xenstore_notifier = {
. notifier_call = balloon_init_watcher ,
} ;
2011-03-14 18:29:37 +03:00
2017-07-10 11:10:45 +03:00
void xen_balloon_init ( void )
2011-03-14 18:29:37 +03:00
{
2011-12-15 03:32:50 +04:00
register_balloon ( & balloon_dev ) ;
2011-03-14 18:29:37 +03:00
2011-12-15 03:32:50 +04:00
register_xen_selfballooning ( & balloon_dev ) ;
2011-07-08 22:26:21 +04:00
2011-03-14 18:29:37 +03:00
register_xenstore_notifier ( & xenstore_notifier ) ;
}
2017-07-10 11:10:45 +03:00
EXPORT_SYMBOL_GPL ( xen_balloon_init ) ;
2011-03-14 18:29:37 +03:00
# define BALLOON_SHOW(name, format, args...) \
2011-12-15 03:32:50 +04:00
static ssize_t show_ # # name ( struct device * dev , \
struct device_attribute * attr , \
2011-03-14 18:29:37 +03:00
char * buf ) \
{ \
return sprintf ( buf , format , # # args ) ; \
} \
2011-12-15 03:32:50 +04:00
static DEVICE_ATTR ( name , S_IRUGO , show_ # # name , NULL )
2011-03-14 18:29:37 +03:00
BALLOON_SHOW ( current_kb , " %lu \n " , PAGES2KB ( balloon_stats . current_pages ) ) ;
BALLOON_SHOW ( low_kb , " %lu \n " , PAGES2KB ( balloon_stats . balloon_low ) ) ;
BALLOON_SHOW ( high_kb , " %lu \n " , PAGES2KB ( balloon_stats . balloon_high ) ) ;
2011-12-15 03:32:50 +04:00
static DEVICE_ULONG_ATTR ( schedule_delay , 0444 , balloon_stats . schedule_delay ) ;
static DEVICE_ULONG_ATTR ( max_schedule_delay , 0644 , balloon_stats . max_schedule_delay ) ;
static DEVICE_ULONG_ATTR ( retry_count , 0444 , balloon_stats . retry_count ) ;
static DEVICE_ULONG_ATTR ( max_retry_count , 0644 , balloon_stats . max_retry_count ) ;
2011-03-14 18:29:37 +03:00
2011-12-15 03:32:50 +04:00
static ssize_t show_target_kb ( struct device * dev , struct device_attribute * attr ,
2011-03-14 18:29:37 +03:00
char * buf )
{
return sprintf ( buf , " %lu \n " , PAGES2KB ( balloon_stats . target_pages ) ) ;
}
2011-12-15 03:32:50 +04:00
static ssize_t store_target_kb ( struct device * dev ,
struct device_attribute * attr ,
2011-03-14 18:29:37 +03:00
const char * buf ,
size_t count )
{
char * endchar ;
unsigned long long target_bytes ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
target_bytes = simple_strtoull ( buf , & endchar , 0 ) * 1024 ;
balloon_set_new_target ( target_bytes > > PAGE_SHIFT ) ;
return count ;
}
2011-12-15 03:32:50 +04:00
static DEVICE_ATTR ( target_kb , S_IRUGO | S_IWUSR ,
2011-03-14 18:29:37 +03:00
show_target_kb , store_target_kb ) ;
2011-12-15 03:32:50 +04:00
static ssize_t show_target ( struct device * dev , struct device_attribute * attr ,
2011-03-14 18:29:37 +03:00
char * buf )
{
return sprintf ( buf , " %llu \n " ,
( unsigned long long ) balloon_stats . target_pages
< < PAGE_SHIFT ) ;
}
2011-12-15 03:32:50 +04:00
static ssize_t store_target ( struct device * dev ,
struct device_attribute * attr ,
2011-03-14 18:29:37 +03:00
const char * buf ,
size_t count )
{
char * endchar ;
unsigned long long target_bytes ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
target_bytes = memparse ( buf , & endchar ) ;
balloon_set_new_target ( target_bytes > > PAGE_SHIFT ) ;
return count ;
}
2011-12-15 03:32:50 +04:00
static DEVICE_ATTR ( target , S_IRUGO | S_IWUSR ,
2011-03-14 18:29:37 +03:00
show_target , store_target ) ;
2015-02-05 23:38:59 +03:00
static struct attribute * balloon_attrs [ ] = {
& dev_attr_target_kb . attr ,
& dev_attr_target . attr ,
& dev_attr_schedule_delay . attr . attr ,
& dev_attr_max_schedule_delay . attr . attr ,
& dev_attr_retry_count . attr . attr ,
& dev_attr_max_retry_count . attr . attr ,
NULL
} ;
static const struct attribute_group balloon_group = {
. attrs = balloon_attrs
2011-03-14 18:29:37 +03:00
} ;
static struct attribute * balloon_info_attrs [ ] = {
2011-12-15 03:32:50 +04:00
& dev_attr_current_kb . attr ,
& dev_attr_low_kb . attr ,
& dev_attr_high_kb . attr ,
2011-03-14 18:29:37 +03:00
NULL
} ;
2012-03-14 20:34:19 +04:00
static const struct attribute_group balloon_info_group = {
2011-03-14 18:29:37 +03:00
. name = " info " ,
. attrs = balloon_info_attrs
} ;
2015-02-05 23:38:59 +03:00
static const struct attribute_group * balloon_groups [ ] = {
& balloon_group ,
& balloon_info_group ,
NULL
} ;
2011-12-15 03:32:50 +04:00
static struct bus_type balloon_subsys = {
. name = BALLOON_CLASS_NAME ,
. dev_name = BALLOON_CLASS_NAME ,
2011-03-14 18:29:37 +03:00
} ;
2011-12-15 03:32:50 +04:00
static int register_balloon ( struct device * dev )
2011-03-14 18:29:37 +03:00
{
2015-02-05 23:38:59 +03:00
int error ;
2011-03-14 18:29:37 +03:00
2012-01-12 20:35:50 +04:00
error = subsys_system_register ( & balloon_subsys , NULL ) ;
2011-03-14 18:29:37 +03:00
if ( error )
return error ;
2011-12-15 03:32:50 +04:00
dev - > id = 0 ;
dev - > bus = & balloon_subsys ;
2015-02-05 23:38:59 +03:00
dev - > groups = balloon_groups ;
2011-03-14 18:29:37 +03:00
2011-12-15 03:32:50 +04:00
error = device_register ( dev ) ;
2011-03-14 18:29:37 +03:00
if ( error ) {
2011-12-15 03:32:50 +04:00
bus_unregister ( & balloon_subsys ) ;
2011-03-14 18:29:37 +03:00
return error ;
}
return 0 ;
}