vmw_balloon.c (d7568c130d0d0ff1fc5b364fc879b91f108a3d54) | vmw_balloon.c (48e3d668b7902cca3c61e9e2098e7f76b5646c28) |
---|---|
1/* 2 * VMware Balloon driver. 3 * | 1/* 2 * VMware Balloon driver. 3 * |
4 * Copyright (C) 2000-2013, VMware, Inc. All Rights Reserved. | 4 * Copyright (C) 2000-2014, VMware, Inc. All Rights Reserved. |
5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; version 2 of the License and no later version. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or --- 25 unchanged lines hidden (view full) --- 38#include <linux/kernel.h> 39#include <linux/mm.h> 40#include <linux/vmalloc.h> 41#include <linux/sched.h> 42#include <linux/module.h> 43#include <linux/workqueue.h> 44#include <linux/debugfs.h> 45#include <linux/seq_file.h> | 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; version 2 of the License and no later version. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or --- 25 unchanged lines hidden (view full) --- 38#include <linux/kernel.h> 39#include <linux/mm.h> 40#include <linux/vmalloc.h> 41#include <linux/sched.h> 42#include <linux/module.h> 43#include <linux/workqueue.h> 44#include <linux/debugfs.h> 45#include <linux/seq_file.h> |
46#include <linux/vmw_vmci_defs.h> 47#include <linux/vmw_vmci_api.h> |
|
46#include <asm/hypervisor.h> 47 48MODULE_AUTHOR("VMware, Inc."); 49MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); | 48#include <asm/hypervisor.h> 49 50MODULE_AUTHOR("VMware, Inc."); 51MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); |
50MODULE_VERSION("1.4.1.0-k"); | 52MODULE_VERSION("1.5.0.0-k"); |
51MODULE_ALIAS("dmi:*:svnVMware*:*"); 52MODULE_ALIAS("vmware_vmmemctl"); 53MODULE_LICENSE("GPL"); 54 55/* 56 * Various constants controlling rate of inflaint/deflating balloon, 57 * measured in pages. 58 */ --- 37 unchanged lines hidden (view full) --- 96#define VMW_BALLOON_HV_PORT 0x5670 97#define VMW_BALLOON_HV_MAGIC 0x456c6d6f 98#define VMW_BALLOON_GUEST_ID 1 /* Linux */ 99 100enum vmwballoon_capabilities { 101 /* 102 * Bit 0 is reserved and not associated to any capability. 103 */ | 53MODULE_ALIAS("dmi:*:svnVMware*:*"); 54MODULE_ALIAS("vmware_vmmemctl"); 55MODULE_LICENSE("GPL"); 56 57/* 58 * Various constants controlling rate of inflaint/deflating balloon, 59 * measured in pages. 60 */ --- 37 unchanged lines hidden (view full) --- 98#define VMW_BALLOON_HV_PORT 0x5670 99#define VMW_BALLOON_HV_MAGIC 0x456c6d6f 100#define VMW_BALLOON_GUEST_ID 1 /* Linux */ 101 102enum vmwballoon_capabilities { 103 /* 104 * Bit 0 is reserved and not associated to any capability. 105 */ |
104 VMW_BALLOON_BASIC_CMDS = (1 << 1), 105 VMW_BALLOON_BATCHED_CMDS = (1 << 2), 106 VMW_BALLOON_BATCHED_2M_CMDS = (1 << 3), | 106 VMW_BALLOON_BASIC_CMDS = (1 << 1), 107 VMW_BALLOON_BATCHED_CMDS = (1 << 2), 108 VMW_BALLOON_BATCHED_2M_CMDS = (1 << 3), 109 VMW_BALLOON_SIGNALLED_WAKEUP_CMD = (1 << 4), |
107}; 108 109#define VMW_BALLOON_CAPABILITIES (VMW_BALLOON_BASIC_CMDS \ 110 | VMW_BALLOON_BATCHED_CMDS \ | 110}; 111 112#define VMW_BALLOON_CAPABILITIES (VMW_BALLOON_BASIC_CMDS \ 113 | VMW_BALLOON_BATCHED_CMDS \ |
111 | VMW_BALLOON_BATCHED_2M_CMDS) | 114 | VMW_BALLOON_BATCHED_2M_CMDS \ 115 | VMW_BALLOON_SIGNALLED_WAKEUP_CMD) |
112 113#define VMW_BALLOON_2M_SHIFT (9) 114#define VMW_BALLOON_NUM_PAGE_SIZES (2) 115 116/* 117 * Backdoor commands availability: 118 * 119 * START, GET_TARGET and GUEST_ID are always available, 120 * 121 * VMW_BALLOON_BASIC_CMDS: 122 * LOCK and UNLOCK commands, 123 * VMW_BALLOON_BATCHED_CMDS: 124 * BATCHED_LOCK and BATCHED_UNLOCK commands. 125 * VMW BALLOON_BATCHED_2M_CMDS: | 116 117#define VMW_BALLOON_2M_SHIFT (9) 118#define VMW_BALLOON_NUM_PAGE_SIZES (2) 119 120/* 121 * Backdoor commands availability: 122 * 123 * START, GET_TARGET and GUEST_ID are always available, 124 * 125 * VMW_BALLOON_BASIC_CMDS: 126 * LOCK and UNLOCK commands, 127 * VMW_BALLOON_BATCHED_CMDS: 128 * BATCHED_LOCK and BATCHED_UNLOCK commands. 129 * VMW BALLOON_BATCHED_2M_CMDS: |
126 * BATCHED_2M_LOCK and BATCHED_2M_UNLOCK commands. | 130 * BATCHED_2M_LOCK and BATCHED_2M_UNLOCK commands, 131 * VMW VMW_BALLOON_SIGNALLED_WAKEUP_CMD: 132 * VMW_BALLOON_CMD_VMCI_DOORBELL_SET command. |
127 */ 128#define VMW_BALLOON_CMD_START 0 129#define VMW_BALLOON_CMD_GET_TARGET 1 130#define VMW_BALLOON_CMD_LOCK 2 131#define VMW_BALLOON_CMD_UNLOCK 3 132#define VMW_BALLOON_CMD_GUEST_ID 4 133#define VMW_BALLOON_CMD_BATCHED_LOCK 6 134#define VMW_BALLOON_CMD_BATCHED_UNLOCK 7 135#define VMW_BALLOON_CMD_BATCHED_2M_LOCK 8 136#define VMW_BALLOON_CMD_BATCHED_2M_UNLOCK 9 | 133 */ 134#define VMW_BALLOON_CMD_START 0 135#define VMW_BALLOON_CMD_GET_TARGET 1 136#define VMW_BALLOON_CMD_LOCK 2 137#define VMW_BALLOON_CMD_UNLOCK 3 138#define VMW_BALLOON_CMD_GUEST_ID 4 139#define VMW_BALLOON_CMD_BATCHED_LOCK 6 140#define VMW_BALLOON_CMD_BATCHED_UNLOCK 7 141#define VMW_BALLOON_CMD_BATCHED_2M_LOCK 8 142#define VMW_BALLOON_CMD_BATCHED_2M_UNLOCK 9 |
143#define VMW_BALLOON_CMD_VMCI_DOORBELL_SET 10 |
|
137 138 139/* error codes */ 140#define VMW_BALLOON_SUCCESS 0 141#define VMW_BALLOON_FAILURE -1 142#define VMW_BALLOON_ERROR_CMD_INVALID 1 143#define VMW_BALLOON_ERROR_PPN_INVALID 2 144#define VMW_BALLOON_ERROR_PPN_LOCKED 3 --- 64 unchanged lines hidden (view full) --- 209 result = __dummy1; \ 210 result &= -1UL; \ 211 __status & -1UL; \ 212}) 213 214#ifdef CONFIG_DEBUG_FS 215struct vmballoon_stats { 216 unsigned int timer; | 144 145 146/* error codes */ 147#define VMW_BALLOON_SUCCESS 0 148#define VMW_BALLOON_FAILURE -1 149#define VMW_BALLOON_ERROR_CMD_INVALID 1 150#define VMW_BALLOON_ERROR_PPN_INVALID 2 151#define VMW_BALLOON_ERROR_PPN_LOCKED 3 --- 64 unchanged lines hidden (view full) --- 216 result = __dummy1; \ 217 result &= -1UL; \ 218 __status & -1UL; \ 219}) 220 221#ifdef CONFIG_DEBUG_FS 222struct vmballoon_stats { 223 unsigned int timer; |
224 unsigned int doorbell; |
|
217 218 /* allocation statistics */ 219 unsigned int alloc[VMW_BALLOON_NUM_PAGE_SIZES]; 220 unsigned int alloc_fail[VMW_BALLOON_NUM_PAGE_SIZES]; 221 unsigned int sleep_alloc; 222 unsigned int sleep_alloc_fail; 223 unsigned int refused_alloc[VMW_BALLOON_NUM_PAGE_SIZES]; 224 unsigned int refused_free[VMW_BALLOON_NUM_PAGE_SIZES]; --- 5 unchanged lines hidden (view full) --- 230 unsigned int unlock[VMW_BALLOON_NUM_PAGE_SIZES]; 231 unsigned int unlock_fail[VMW_BALLOON_NUM_PAGE_SIZES]; 232 unsigned int target; 233 unsigned int target_fail; 234 unsigned int start; 235 unsigned int start_fail; 236 unsigned int guest_type; 237 unsigned int guest_type_fail; | 225 226 /* allocation statistics */ 227 unsigned int alloc[VMW_BALLOON_NUM_PAGE_SIZES]; 228 unsigned int alloc_fail[VMW_BALLOON_NUM_PAGE_SIZES]; 229 unsigned int sleep_alloc; 230 unsigned int sleep_alloc_fail; 231 unsigned int refused_alloc[VMW_BALLOON_NUM_PAGE_SIZES]; 232 unsigned int refused_free[VMW_BALLOON_NUM_PAGE_SIZES]; --- 5 unchanged lines hidden (view full) --- 238 unsigned int unlock[VMW_BALLOON_NUM_PAGE_SIZES]; 239 unsigned int unlock_fail[VMW_BALLOON_NUM_PAGE_SIZES]; 240 unsigned int target; 241 unsigned int target_fail; 242 unsigned int start; 243 unsigned int start_fail; 244 unsigned int guest_type; 245 unsigned int guest_type_fail; |
246 unsigned int doorbell_set; 247 unsigned int doorbell_unset; |
|
238}; 239 240#define STATS_INC(stat) (stat)++ 241#else 242#define STATS_INC(stat) 243#endif 244 245struct vmballoon; --- 48 unchanged lines hidden (view full) --- 294 295 /* debugfs file exporting statistics */ 296 struct dentry *dbg_entry; 297#endif 298 299 struct sysinfo sysinfo; 300 301 struct delayed_work dwork; | 248}; 249 250#define STATS_INC(stat) (stat)++ 251#else 252#define STATS_INC(stat) 253#endif 254 255struct vmballoon; --- 48 unchanged lines hidden (view full) --- 304 305 /* debugfs file exporting statistics */ 306 struct dentry *dbg_entry; 307#endif 308 309 struct sysinfo sysinfo; 310 311 struct delayed_work dwork; |
312 313 struct vmci_handle vmci_doorbell; |
|
302}; 303 304static struct vmballoon balloon; 305 306/* 307 * Send "start" command to the host, communicating supported version 308 * of the protocol. 309 */ --- 678 unchanged lines hidden (view full) --- 988 __free_page(b->page); 989 return false; 990 } 991 992 return true; 993} 994 995/* | 314}; 315 316static struct vmballoon balloon; 317 318/* 319 * Send "start" command to the host, communicating supported version 320 * of the protocol. 321 */ --- 678 unchanged lines hidden (view full) --- 1000 __free_page(b->page); 1001 return false; 1002 } 1003 1004 return true; 1005} 1006 1007/* |
1008 * Receive notification and resize balloon 1009 */ 1010static void vmballoon_doorbell(void *client_data) 1011{ 1012 struct vmballoon *b = client_data; 1013 1014 STATS_INC(b->stats.doorbell); 1015 1016 mod_delayed_work(system_freezable_wq, &b->dwork, 0); 1017} 1018 1019/* 1020 * Clean up vmci doorbell 1021 */ 1022static void vmballoon_vmci_cleanup(struct vmballoon *b) 1023{ 1024 int error; 1025 1026 VMWARE_BALLOON_CMD(VMCI_DOORBELL_SET, VMCI_INVALID_ID, 1027 VMCI_INVALID_ID, error); 1028 STATS_INC(b->stats.doorbell_unset); 1029 1030 if (!vmci_handle_is_invalid(b->vmci_doorbell)) { 1031 vmci_doorbell_destroy(b->vmci_doorbell); 1032 b->vmci_doorbell = VMCI_INVALID_HANDLE; 1033 } 1034} 1035 1036/* 1037 * Initialize vmci doorbell, to get notified as soon as balloon changes 1038 */ 1039static int vmballoon_vmci_init(struct vmballoon *b) 1040{ 1041 int error = 0; 1042 1043 if ((b->capabilities & VMW_BALLOON_SIGNALLED_WAKEUP_CMD) != 0) { 1044 error = vmci_doorbell_create(&b->vmci_doorbell, 1045 VMCI_FLAG_DELAYED_CB, 1046 VMCI_PRIVILEGE_FLAG_RESTRICTED, 1047 vmballoon_doorbell, b); 1048 1049 if (error == VMCI_SUCCESS) { 1050 VMWARE_BALLOON_CMD(VMCI_DOORBELL_SET, 1051 b->vmci_doorbell.context, 1052 b->vmci_doorbell.resource, error); 1053 STATS_INC(b->stats.doorbell_set); 1054 } 1055 } 1056 1057 if (error != 0) { 1058 vmballoon_vmci_cleanup(b); 1059 1060 return -EIO; 1061 } 1062 1063 return 0; 1064} 1065 1066/* |
|
996 * Perform standard reset sequence by popping the balloon (in case it 997 * is not empty) and then restarting protocol. This operation normally 998 * happens when host responds with VMW_BALLOON_ERROR_RESET to a command. 999 */ 1000static void vmballoon_reset(struct vmballoon *b) 1001{ | 1067 * Perform standard reset sequence by popping the balloon (in case it 1068 * is not empty) and then restarting protocol. This operation normally 1069 * happens when host responds with VMW_BALLOON_ERROR_RESET to a command. 1070 */ 1071static void vmballoon_reset(struct vmballoon *b) 1072{ |
1073 int error; 1074 1075 vmballoon_vmci_cleanup(b); 1076 |
|
1002 /* free all pages, skipping monitor unlock */ 1003 vmballoon_pop(b); 1004 1005 if (!vmballoon_send_start(b, VMW_BALLOON_CAPABILITIES)) 1006 return; 1007 1008 if ((b->capabilities & VMW_BALLOON_BATCHED_CMDS) != 0) { 1009 b->ops = &vmballoon_batched_ops; --- 9 unchanged lines hidden (view full) --- 1019 return; 1020 } 1021 } else if ((b->capabilities & VMW_BALLOON_BASIC_CMDS) != 0) { 1022 b->ops = &vmballoon_basic_ops; 1023 b->batch_max_pages = 1; 1024 } 1025 1026 b->reset_required = false; | 1077 /* free all pages, skipping monitor unlock */ 1078 vmballoon_pop(b); 1079 1080 if (!vmballoon_send_start(b, VMW_BALLOON_CAPABILITIES)) 1081 return; 1082 1083 if ((b->capabilities & VMW_BALLOON_BATCHED_CMDS) != 0) { 1084 b->ops = &vmballoon_batched_ops; --- 9 unchanged lines hidden (view full) --- 1094 return; 1095 } 1096 } else if ((b->capabilities & VMW_BALLOON_BASIC_CMDS) != 0) { 1097 b->ops = &vmballoon_basic_ops; 1098 b->batch_max_pages = 1; 1099 } 1100 1101 b->reset_required = false; |
1102 1103 error = vmballoon_vmci_init(b); 1104 if (error) 1105 pr_err("failed to initialize vmci doorbell\n"); 1106 |
|
1027 if (!vmballoon_send_guest_id(b)) 1028 pr_err("failed to send guest ID to the host\n"); 1029} 1030 1031/* 1032 * Balloon work function: reset protocol, if needed, get the new size and 1033 * adjust balloon as needed. Repeat in 1 sec. 1034 */ --- 57 unchanged lines hidden (view full) --- 1092 /* format rate info */ 1093 seq_printf(f, 1094 "rateSleepAlloc: %8d pages/sec\n", 1095 b->rate_alloc); 1096 1097 seq_printf(f, 1098 "\n" 1099 "timer: %8u\n" | 1107 if (!vmballoon_send_guest_id(b)) 1108 pr_err("failed to send guest ID to the host\n"); 1109} 1110 1111/* 1112 * Balloon work function: reset protocol, if needed, get the new size and 1113 * adjust balloon as needed. Repeat in 1 sec. 1114 */ --- 57 unchanged lines hidden (view full) --- 1172 /* format rate info */ 1173 seq_printf(f, 1174 "rateSleepAlloc: %8d pages/sec\n", 1175 b->rate_alloc); 1176 1177 seq_printf(f, 1178 "\n" 1179 "timer: %8u\n" |
1180 "doorbell: %8u\n" |
|
1100 "start: %8u (%4u failed)\n" 1101 "guestType: %8u (%4u failed)\n" 1102 "2m-lock: %8u (%4u failed)\n" 1103 "lock: %8u (%4u failed)\n" 1104 "2m-unlock: %8u (%4u failed)\n" 1105 "unlock: %8u (%4u failed)\n" 1106 "target: %8u (%4u failed)\n" 1107 "prim2mAlloc: %8u (%4u failed)\n" 1108 "primNoSleepAlloc: %8u (%4u failed)\n" 1109 "primCanSleepAlloc: %8u (%4u failed)\n" 1110 "prim2mFree: %8u\n" 1111 "primFree: %8u\n" 1112 "err2mAlloc: %8u\n" 1113 "errAlloc: %8u\n" 1114 "err2mFree: %8u\n" | 1181 "start: %8u (%4u failed)\n" 1182 "guestType: %8u (%4u failed)\n" 1183 "2m-lock: %8u (%4u failed)\n" 1184 "lock: %8u (%4u failed)\n" 1185 "2m-unlock: %8u (%4u failed)\n" 1186 "unlock: %8u (%4u failed)\n" 1187 "target: %8u (%4u failed)\n" 1188 "prim2mAlloc: %8u (%4u failed)\n" 1189 "primNoSleepAlloc: %8u (%4u failed)\n" 1190 "primCanSleepAlloc: %8u (%4u failed)\n" 1191 "prim2mFree: %8u\n" 1192 "primFree: %8u\n" 1193 "err2mAlloc: %8u\n" 1194 "errAlloc: %8u\n" 1195 "err2mFree: %8u\n" |
1115 "errFree: %8u\n", | 1196 "errFree: %8u\n" 1197 "doorbellSet: %8u\n" 1198 "doorbellUnset: %8u\n", |
1116 stats->timer, | 1199 stats->timer, |
1200 stats->doorbell, |
|
1117 stats->start, stats->start_fail, 1118 stats->guest_type, stats->guest_type_fail, 1119 stats->lock[true], stats->lock_fail[true], 1120 stats->lock[false], stats->lock_fail[false], 1121 stats->unlock[true], stats->unlock_fail[true], 1122 stats->unlock[false], stats->unlock_fail[false], 1123 stats->target, stats->target_fail, 1124 stats->alloc[true], stats->alloc_fail[true], 1125 stats->alloc[false], stats->alloc_fail[false], 1126 stats->sleep_alloc, stats->sleep_alloc_fail, 1127 stats->free[true], 1128 stats->free[false], 1129 stats->refused_alloc[true], stats->refused_alloc[false], | 1201 stats->start, stats->start_fail, 1202 stats->guest_type, stats->guest_type_fail, 1203 stats->lock[true], stats->lock_fail[true], 1204 stats->lock[false], stats->lock_fail[false], 1205 stats->unlock[true], stats->unlock_fail[true], 1206 stats->unlock[false], stats->unlock_fail[false], 1207 stats->target, stats->target_fail, 1208 stats->alloc[true], stats->alloc_fail[true], 1209 stats->alloc[false], stats->alloc_fail[false], 1210 stats->sleep_alloc, stats->sleep_alloc_fail, 1211 stats->free[true], 1212 stats->free[false], 1213 stats->refused_alloc[true], stats->refused_alloc[false], |
1130 stats->refused_free[true], stats->refused_free[false]); | 1214 stats->refused_free[true], stats->refused_free[false], 1215 stats->doorbell_set, stats->doorbell_unset); |
1131 1132 return 0; 1133} 1134 1135static int vmballoon_debug_open(struct inode *inode, struct file *file) 1136{ 1137 return single_open(file, vmballoon_debug_show, inode->i_private); 1138} --- 60 unchanged lines hidden (view full) --- 1199 balloon.rate_alloc = VMW_BALLOON_RATE_ALLOC_MAX; 1200 1201 INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work); 1202 1203 error = vmballoon_debugfs_init(&balloon); 1204 if (error) 1205 return error; 1206 | 1216 1217 return 0; 1218} 1219 1220static int vmballoon_debug_open(struct inode *inode, struct file *file) 1221{ 1222 return single_open(file, vmballoon_debug_show, inode->i_private); 1223} --- 60 unchanged lines hidden (view full) --- 1284 balloon.rate_alloc = VMW_BALLOON_RATE_ALLOC_MAX; 1285 1286 INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work); 1287 1288 error = vmballoon_debugfs_init(&balloon); 1289 if (error) 1290 return error; 1291 |
1292 balloon.vmci_doorbell = VMCI_INVALID_HANDLE; |
|
1207 balloon.batch_page = NULL; 1208 balloon.page = NULL; 1209 balloon.reset_required = true; 1210 1211 queue_delayed_work(system_freezable_wq, &balloon.dwork, 0); 1212 1213 return 0; 1214} 1215module_init(vmballoon_init); 1216 1217static void __exit vmballoon_exit(void) 1218{ | 1293 balloon.batch_page = NULL; 1294 balloon.page = NULL; 1295 balloon.reset_required = true; 1296 1297 queue_delayed_work(system_freezable_wq, &balloon.dwork, 0); 1298 1299 return 0; 1300} 1301module_init(vmballoon_init); 1302 1303static void __exit vmballoon_exit(void) 1304{ |
1305 vmballoon_vmci_cleanup(&balloon); |
|
1219 cancel_delayed_work_sync(&balloon.dwork); 1220 1221 vmballoon_debugfs_exit(&balloon); 1222 1223 /* 1224 * Deallocate all reserved memory, and reset connection with monitor. 1225 * Reset connection before deallocating memory to avoid potential for 1226 * additional spurious resets from guest touching deallocated pages. 1227 */ 1228 vmballoon_send_start(&balloon, 0); 1229 vmballoon_pop(&balloon); 1230} 1231module_exit(vmballoon_exit); | 1306 cancel_delayed_work_sync(&balloon.dwork); 1307 1308 vmballoon_debugfs_exit(&balloon); 1309 1310 /* 1311 * Deallocate all reserved memory, and reset connection with monitor. 1312 * Reset connection before deallocating memory to avoid potential for 1313 * additional spurious resets from guest touching deallocated pages. 1314 */ 1315 vmballoon_send_start(&balloon, 0); 1316 vmballoon_pop(&balloon); 1317} 1318module_exit(vmballoon_exit); |