2011-03-14 11:29:37 -04: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 03:21:41 -07:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2011-03-14 11:29:37 -04:00
# include <linux/kernel.h>
2016-02-21 19:06:05 -05:00
# include <linux/errno.h>
# include <linux/mm_types.h>
# include <linux/init.h>
2011-03-14 11:29:37 -04:00
# include <linux/capability.h>
2019-02-14 11:42:40 +01:00
# include <linux/memory_hotplug.h>
2011-03-14 11:29:37 -04:00
# 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>
2018-09-07 18:49:08 +02:00
# include <xen/mem-reservation.h>
2011-03-14 11:29:37 -04:00
# define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
# define BALLOON_CLASS_NAME "xen_memory"
2019-02-14 11:42:40 +01:00
# ifdef CONFIG_MEMORY_HOTPLUG
u64 xen_saved_max_mem_size = 0 ;
# endif
2011-12-14 15:32:50 -08:00
static struct device balloon_dev ;
2011-03-14 11:29:37 -04:00
2011-12-14 15:32:50 -08:00
static int register_balloon ( struct device * dev ) ;
2011-03-14 11:29:37 -04:00
/* React to a change in the target key */
static void watch_target ( struct xenbus_watch * watch ,
2017-02-09 14:39:57 +01:00
const char * path , const char * token )
2011-03-14 11:29:37 -04:00
{
2017-10-26 11:50:56 +02:00
unsigned long long new_target , static_max ;
2011-03-14 11:29:37 -04:00
int err ;
2017-07-10 10:10:45 +02:00
static bool watch_fired ;
static long target_diff ;
2011-03-14 11:29:37 -04:00
2019-02-14 11:42:40 +01:00
# ifdef CONFIG_MEMORY_HOTPLUG
/* The balloon driver will take care of adding memory now. */
if ( xen_saved_max_mem_size )
max_mem_size = xen_saved_max_mem_size ;
# endif
2011-03-14 11:29:37 -04: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 10:10:45 +02:00
new_target > > = PAGE_SHIFT - 10 ;
2017-10-26 11:50:56 +02:00
if ( ! watch_fired ) {
watch_fired = true ;
2018-10-07 16:05:38 -04:00
if ( ( xenbus_scanf ( XBT_NIL , " memory " , " static-max " ,
" %llu " , & static_max ) = = 1 ) | |
( xenbus_scanf ( XBT_NIL , " memory " , " memory_static_max " ,
" %llu " , & static_max ) = = 1 ) )
2017-10-26 11:50:56 +02:00
static_max > > = PAGE_SHIFT - 10 ;
2018-10-07 16:05:38 -04:00
else
static_max = new_target ;
2018-08-08 13:46:41 +02:00
target_diff = ( xen_pv_domain ( ) | | xen_initial_domain ( ) ) ? 0
2017-10-26 11:50:56 +02:00
: static_max - balloon_stats . target_pages ;
2017-07-10 10:10:45 +02:00
}
2017-10-26 11:50:56 +02:00
balloon_set_new_target ( new_target - target_diff ) ;
2011-03-14 11:29:37 -04:00
}
2011-07-28 15:23:03 +02:00
static struct xenbus_watch target_watch = {
. node = " memory/target " ,
. callback = watch_target ,
} ;
2011-03-14 11:29:37 -04: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 03:21:41 -07:00
pr_err ( " Failed to set balloon watcher \n " ) ;
2011-03-14 11:29:37 -04:00
return NOTIFY_DONE ;
}
2011-07-28 15:23:03 +02:00
static struct notifier_block xenstore_notifier = {
. notifier_call = balloon_init_watcher ,
} ;
2011-03-14 11:29:37 -04:00
2017-07-10 10:10:45 +02:00
void xen_balloon_init ( void )
2011-03-14 11:29:37 -04:00
{
2011-12-14 15:32:50 -08:00
register_balloon ( & balloon_dev ) ;
2011-03-14 11:29:37 -04:00
register_xenstore_notifier ( & xenstore_notifier ) ;
}
2017-07-10 10:10:45 +02:00
EXPORT_SYMBOL_GPL ( xen_balloon_init ) ;
2011-03-14 11:29:37 -04:00
# define BALLOON_SHOW(name, format, args...) \
2011-12-14 15:32:50 -08:00
static ssize_t show_ # # name ( struct device * dev , \
struct device_attribute * attr , \
2011-03-14 11:29:37 -04:00
char * buf ) \
{ \
return sprintf ( buf , format , # # args ) ; \
} \
2011-12-14 15:32:50 -08:00
static DEVICE_ATTR ( name , S_IRUGO , show_ # # name , NULL )
2011-03-14 11:29:37 -04: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-14 15:32:50 -08: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 ) ;
2018-09-07 18:49:08 +02:00
static DEVICE_BOOL_ATTR ( scrub_pages , 0644 , xen_scrub_pages ) ;
2011-03-14 11:29:37 -04:00
2011-12-14 15:32:50 -08:00
static ssize_t show_target_kb ( struct device * dev , struct device_attribute * attr ,
2011-03-14 11:29:37 -04:00
char * buf )
{
return sprintf ( buf , " %lu \n " , PAGES2KB ( balloon_stats . target_pages ) ) ;
}
2011-12-14 15:32:50 -08:00
static ssize_t store_target_kb ( struct device * dev ,
struct device_attribute * attr ,
2011-03-14 11:29:37 -04: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-14 15:32:50 -08:00
static DEVICE_ATTR ( target_kb , S_IRUGO | S_IWUSR ,
2011-03-14 11:29:37 -04:00
show_target_kb , store_target_kb ) ;
2011-12-14 15:32:50 -08:00
static ssize_t show_target ( struct device * dev , struct device_attribute * attr ,
2011-03-14 11:29:37 -04:00
char * buf )
{
return sprintf ( buf , " %llu \n " ,
( unsigned long long ) balloon_stats . target_pages
< < PAGE_SHIFT ) ;
}
2011-12-14 15:32:50 -08:00
static ssize_t store_target ( struct device * dev ,
struct device_attribute * attr ,
2011-03-14 11:29:37 -04: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-14 15:32:50 -08:00
static DEVICE_ATTR ( target , S_IRUGO | S_IWUSR ,
2011-03-14 11:29:37 -04:00
show_target , store_target ) ;
2015-02-05 21:38:59 +01: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 ,
2018-09-07 18:49:08 +02:00
& dev_attr_scrub_pages . attr . attr ,
2015-02-05 21:38:59 +01:00
NULL
} ;
static const struct attribute_group balloon_group = {
. attrs = balloon_attrs
2011-03-14 11:29:37 -04:00
} ;
static struct attribute * balloon_info_attrs [ ] = {
2011-12-14 15:32:50 -08:00
& dev_attr_current_kb . attr ,
& dev_attr_low_kb . attr ,
& dev_attr_high_kb . attr ,
2011-03-14 11:29:37 -04:00
NULL
} ;
2012-03-14 12:34:19 -04:00
static const struct attribute_group balloon_info_group = {
2011-03-14 11:29:37 -04:00
. name = " info " ,
. attrs = balloon_info_attrs
} ;
2015-02-05 21:38:59 +01:00
static const struct attribute_group * balloon_groups [ ] = {
& balloon_group ,
& balloon_info_group ,
NULL
} ;
2011-12-14 15:32:50 -08:00
static struct bus_type balloon_subsys = {
. name = BALLOON_CLASS_NAME ,
. dev_name = BALLOON_CLASS_NAME ,
2011-03-14 11:29:37 -04:00
} ;
2011-12-14 15:32:50 -08:00
static int register_balloon ( struct device * dev )
2011-03-14 11:29:37 -04:00
{
2015-02-05 21:38:59 +01:00
int error ;
2011-03-14 11:29:37 -04:00
2012-01-12 11:35:50 -05:00
error = subsys_system_register ( & balloon_subsys , NULL ) ;
2011-03-14 11:29:37 -04:00
if ( error )
return error ;
2011-12-14 15:32:50 -08:00
dev - > id = 0 ;
dev - > bus = & balloon_subsys ;
2015-02-05 21:38:59 +01:00
dev - > groups = balloon_groups ;
2011-03-14 11:29:37 -04:00
2011-12-14 15:32:50 -08:00
error = device_register ( dev ) ;
2011-03-14 11:29:37 -04:00
if ( error ) {
2011-12-14 15:32:50 -08:00
bus_unregister ( & balloon_subsys ) ;
2011-03-14 11:29:37 -04:00
return error ;
}
return 0 ;
}