| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2011-07-20 13:35:30 +05:30
										 |  |  |  * Generic Balloon handlers and management | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2003-2008 Fabrice Bellard | 
					
						
							| 
									
										
										
										
											2011-07-20 13:35:30 +05:30
										 |  |  |  * Copyright (C) 2011 Red Hat, Inc. | 
					
						
							|  |  |  |  * Copyright (C) 2011 Amit Shah <amit.shah@redhat.com> | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
					
						
							|  |  |  |  * of this software and associated documentation files (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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 17:50:05 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2015-03-17 18:16:21 +01:00
										 |  |  | #include "qemu-common.h"
 | 
					
						
							| 
									
										
										
										
											2012-12-17 18:19:49 +01:00
										 |  |  | #include "exec/cpu-common.h"
 | 
					
						
							| 
									
										
										
										
											2012-12-17 18:20:04 +01:00
										 |  |  | #include "sysemu/kvm.h"
 | 
					
						
							|  |  |  | #include "sysemu/balloon.h"
 | 
					
						
							| 
									
										
										
										
											2010-08-11 17:16:03 +05:30
										 |  |  | #include "trace.h"
 | 
					
						
							| 
									
										
										
										
											2011-10-21 11:41:37 -02:00
										 |  |  | #include "qmp-commands.h"
 | 
					
						
							| 
									
										
										
										
											2015-03-17 17:22:46 +01:00
										 |  |  | #include "qapi/qmp/qerror.h"
 | 
					
						
							| 
									
										
										
										
											2012-12-17 18:19:43 +01:00
										 |  |  | #include "qapi/qmp/qjson.h"
 | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-20 13:08:46 +05:30
										 |  |  | static QEMUBalloonEvent *balloon_event_fn; | 
					
						
							| 
									
										
											  
											
												balloon: Separate out stat and balloon handling
Passing on '0' as ballooning target to indicate retrieval of stats is
bad API.  It also makes 'balloon 0' in the monitor cause a segfault.
Have two different functions handle the different functionality instead.
Detailed explanation from Markus's review:
1. do_info_balloon() is an info_async() method.  It receives a callback
   with argument, to be called exactly once (callback frees the
   argument).  It passes the callback via qemu_balloon_status() and
   indirectly through qemu_balloon_event to virtio_balloon_to_target().
   virtio_balloon_to_target() executes its balloon stats half.  It
   stores the callback in the device state.
   If it can't send a stats request, it resets stats and calls the
   callback right away.
   Else, it sends a stats request.  The device model runs the callback
   when it receives the answer.
   Works.
2. do_balloon() is a cmd_async() method.  It receives a callback with
   argument, to be called when the command completes.  do_balloon()
   calls it right before it succeeds.  Odd, but should work.
   Nevertheless, it passes the callback on via qemu_ballon() and
   indirectly through qemu_balloon_event to virtio_balloon_to_target().
   a. If the argument is non-zero, virtio_balloon_to_target() executes
      its balloon half, which doesn't use the callback in any way.
      Odd, but works.
   b. If the argument is zero, virtio_balloon_to_target() executes its
      balloon stats half, just like in 1.  It either calls the callback
      right away, or arranges for it to be called later.
      Thus, the callback runs twice: use after free and double free.
Test case: start with -S -device virtio-balloon, execute "balloon 0" in
human monitor.  Runs the callback first from virtio_balloon_to_target(),
then again from do_balloon().
Reported-by: Mike Cao <bcao@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
											
										 
											2011-07-20 13:30:56 +05:30
										 |  |  | static QEMUBalloonStatus *balloon_stat_fn; | 
					
						
							| 
									
										
										
										
											2011-07-20 13:08:46 +05:30
										 |  |  | static void *balloon_opaque; | 
					
						
							| 
									
										
										
										
											2015-11-05 18:11:23 +00:00
										 |  |  | static bool balloon_inhibited; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool qemu_balloon_is_inhibited(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return balloon_inhibited; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void qemu_balloon_inhibit(bool state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     balloon_inhibited = state; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-10 15:40:30 -07:00
										 |  |  | static bool have_balloon(Error **errp) | 
					
						
							| 
									
										
										
										
											2015-01-13 17:44:14 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     if (kvm_enabled() && !kvm_has_sync_mmu()) { | 
					
						
							| 
									
										
										
										
											2015-01-13 17:50:23 +01:00
										 |  |  |         error_set(errp, ERROR_CLASS_KVM_MISSING_CAP, | 
					
						
							|  |  |  |                   "Using KVM without synchronous MMU, balloon unavailable"); | 
					
						
							| 
									
										
										
										
											2015-01-13 17:44:14 +01:00
										 |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!balloon_event_fn) { | 
					
						
							| 
									
										
										
										
											2015-01-13 17:50:23 +01:00
										 |  |  |         error_set(errp, ERROR_CLASS_DEVICE_NOT_ACTIVE, | 
					
						
							|  |  |  |                   "No balloon device has been activated"); | 
					
						
							| 
									
										
										
										
											2015-01-13 17:44:14 +01:00
										 |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-27 12:28:19 +05:30
										 |  |  | int qemu_add_balloon_handler(QEMUBalloonEvent *event_func, | 
					
						
							|  |  |  |                              QEMUBalloonStatus *stat_func, void *opaque) | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-07-27 12:28:19 +05:30
										 |  |  |     if (balloon_event_fn || balloon_stat_fn || balloon_opaque) { | 
					
						
							|  |  |  |         /* We're already registered one balloon handler.  How many can
 | 
					
						
							|  |  |  |          * a guest really have? | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
											  
											
												balloon: Separate out stat and balloon handling
Passing on '0' as ballooning target to indicate retrieval of stats is
bad API.  It also makes 'balloon 0' in the monitor cause a segfault.
Have two different functions handle the different functionality instead.
Detailed explanation from Markus's review:
1. do_info_balloon() is an info_async() method.  It receives a callback
   with argument, to be called exactly once (callback frees the
   argument).  It passes the callback via qemu_balloon_status() and
   indirectly through qemu_balloon_event to virtio_balloon_to_target().
   virtio_balloon_to_target() executes its balloon stats half.  It
   stores the callback in the device state.
   If it can't send a stats request, it resets stats and calls the
   callback right away.
   Else, it sends a stats request.  The device model runs the callback
   when it receives the answer.
   Works.
2. do_balloon() is a cmd_async() method.  It receives a callback with
   argument, to be called when the command completes.  do_balloon()
   calls it right before it succeeds.  Odd, but should work.
   Nevertheless, it passes the callback on via qemu_ballon() and
   indirectly through qemu_balloon_event to virtio_balloon_to_target().
   a. If the argument is non-zero, virtio_balloon_to_target() executes
      its balloon half, which doesn't use the callback in any way.
      Odd, but works.
   b. If the argument is zero, virtio_balloon_to_target() executes its
      balloon stats half, just like in 1.  It either calls the callback
      right away, or arranges for it to be called later.
      Thus, the callback runs twice: use after free and double free.
Test case: start with -S -device virtio-balloon, execute "balloon 0" in
human monitor.  Runs the callback first from virtio_balloon_to_target(),
then again from do_balloon().
Reported-by: Mike Cao <bcao@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
											
										 
											2011-07-20 13:30:56 +05:30
										 |  |  |     balloon_event_fn = event_func; | 
					
						
							|  |  |  |     balloon_stat_fn = stat_func; | 
					
						
							| 
									
										
										
										
											2011-07-20 13:08:46 +05:30
										 |  |  |     balloon_opaque = opaque; | 
					
						
							| 
									
										
										
										
											2011-07-27 12:28:19 +05:30
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-09 14:30:39 +05:30
										 |  |  | void qemu_remove_balloon_handler(void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (balloon_opaque != opaque) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     balloon_event_fn = NULL; | 
					
						
							|  |  |  |     balloon_stat_fn = NULL; | 
					
						
							|  |  |  |     balloon_opaque = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-21 11:41:37 -02:00
										 |  |  | BalloonInfo *qmp_query_balloon(Error **errp) | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-21 11:41:37 -02:00
										 |  |  |     BalloonInfo *info; | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-10 15:40:30 -07:00
										 |  |  |     if (!have_balloon(errp)) { | 
					
						
							| 
									
										
										
										
											2011-10-21 11:41:37 -02:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-13 17:43:25 +01:00
										 |  |  |     info = g_malloc0(sizeof(*info)); | 
					
						
							|  |  |  |     balloon_stat_fn(balloon_opaque, info); | 
					
						
							| 
									
										
										
										
											2011-10-21 11:41:37 -02:00
										 |  |  |     return info; | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-13 17:43:25 +01:00
										 |  |  | void qmp_balloon(int64_t target, Error **errp) | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-02-10 15:40:30 -07:00
										 |  |  |     if (!have_balloon(errp)) { | 
					
						
							| 
									
										
										
										
											2011-11-25 14:38:09 -02:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-13 17:43:25 +01:00
										 |  |  |     if (target <= 0) { | 
					
						
							| 
									
										
										
										
											2015-03-17 11:54:50 +01:00
										 |  |  |         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "target", "a size"); | 
					
						
							| 
									
										
										
										
											2011-11-25 14:38:09 -02:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-07-27 16:50:54 +05:30
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-01-13 17:43:25 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     trace_balloon_event(balloon_opaque, target); | 
					
						
							|  |  |  |     balloon_event_fn(balloon_opaque, target); | 
					
						
							| 
									
										
										
										
											2010-04-01 19:57:12 +02:00
										 |  |  | } |