~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201207201942

« back to all changes in this revision

Viewing changes to modules/solaris/vmmemctl/vmballoon.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2009-10-18 12:28:19 UTC
  • mfrom: (1.1.7 upstream) (2.4.9 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091018122819-00vqew6m0ztpqcqp
Tags: 2009.10.15-201664-1
MergingĀ upstreamĀ versionĀ 2009.10.15-201664.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*********************************************************
2
 
 * Copyright (C) 2000 VMware, Inc. All rights reserved.
3
 
 *
4
 
 * The contents of this file are subject to the terms of the Common
5
 
 * Development and Distribution License (the "License") version 1.0
6
 
 * and no later version.  You may not use this file except in
7
 
 * compliance with the License.
8
 
 *
9
 
 * You can obtain a copy of the License at
10
 
 *         http://www.opensource.org/licenses/cddl1.php
11
 
 *
12
 
 * See the License for the specific language governing permissions
13
 
 * and limitations under the License.
14
 
 *
15
 
 *********************************************************/
16
 
 
17
 
/* 
18
 
 * vmballoon.c --
19
 
 *
20
 
 *      VMware server physical memory management driver for Unix-ish
21
 
 *      (Linux, FreeBSD, Solaris) guests.  The driver acts like a
22
 
 *      "balloon" that can be inflated to reclaim physical pages by
23
 
 *      reserving them in the guest and invalidating them in the
24
 
 *      monitor, freeing up the underlying machine pages so they can
25
 
 *      be allocated to other guests.  The balloon can also be
26
 
 *      deflated to allow the guest to use more physical memory.
27
 
 *      Higher level policies can control the sizes of balloons in VMs
28
 
 *      in order to manage physical memory resources.
29
 
 */
30
 
 
31
 
#ifdef __cplusplus
32
 
extern "C" {
33
 
#endif
34
 
 
35
 
/*
36
 
 * Compile-Time Options
37
 
 */
38
 
 
39
 
#define BALLOON_RATE_ADAPT      (1)
40
 
 
41
 
#define BALLOON_DEBUG           (1)
42
 
#define BALLOON_DEBUG_VERBOSE   (0)
43
 
 
44
 
#define BALLOON_STATS
45
 
#define BALLOON_STATS_PROCFS
46
 
 
47
 
/*
48
 
 * Includes
49
 
 */
50
 
 
51
 
#include "balloon_def.h"
52
 
#include "os.h"
53
 
#include "backdoor.h"
54
 
#include "backdoor_balloon.h"
55
 
 
56
 
#include "vmballoon.h"
57
 
 
58
 
/*
59
 
 * Constants
60
 
 */
61
 
 
62
 
#ifndef NULL
63
 
#define NULL 0
64
 
#endif
65
 
 
66
 
#define BALLOON_NAME                    "vmmemctl"
67
 
#define BALLOON_NAME_VERBOSE            "VMware memory control driver"
68
 
 
69
 
#define BALLOON_PROTOCOL_VERSION        (2)
70
 
 
71
 
#define BALLOON_CHUNK_PAGES             (1000)
72
 
 
73
 
#define BALLOON_NOSLEEP_ALLOC_MAX       (16384)
74
 
 
75
 
#define BALLOON_RATE_ALLOC_MIN          (512)
76
 
#define BALLOON_RATE_ALLOC_MAX          (2048)
77
 
#define BALLOON_RATE_ALLOC_INC          (16)
78
 
 
79
 
#define BALLOON_RATE_FREE_MIN           (512)
80
 
#define BALLOON_RATE_FREE_MAX           (16384)
81
 
#define BALLOON_RATE_FREE_INC           (16)
82
 
 
83
 
#define BALLOON_ERROR_PAGES             (16)
84
 
 
85
 
/* 
86
 
 * When guest is under memory pressure, use a reduced page allocation
87
 
 * rate for next several cycles.
88
 
 */
89
 
#define SLOW_PAGE_ALLOCATION_CYCLES     (4)
90
 
 
91
 
/* 
92
 
 * Move it to bora/public/balloon_def.h later, if needed. Note that
93
 
 * BALLOON_PAGE_ALLOC_FAILURE is an internal error code used for
94
 
 * distinguishing page allocation failures from monitor-backdoor errors.
95
 
 * We use value 1000 because all monitor-backdoor error codes are < 1000.
96
 
 */
97
 
#define BALLOON_PAGE_ALLOC_FAILURE      (1000)
98
 
 
99
 
// Maximum number of page allocations without yielding processor
100
 
#define BALLOON_ALLOC_YIELD_THRESHOLD   (1024)
101
 
 
102
 
 
103
 
/*
104
 
 * Types
105
 
 */
106
 
 
107
 
typedef struct BalloonChunk {
108
 
   unsigned long page[BALLOON_CHUNK_PAGES];
109
 
   uint32 nextPage;
110
 
   struct BalloonChunk *prev, *next;
111
 
} BalloonChunk;
112
 
 
113
 
typedef struct {
114
 
   unsigned long page[BALLOON_ERROR_PAGES];
115
 
   uint32 nextPage;
116
 
} BalloonErrorPages;
117
 
 
118
 
typedef struct {
119
 
   /* sets of reserved physical pages */
120
 
   BalloonChunk *chunks;
121
 
   int nChunks;
122
 
 
123
 
   /* transient list of non-balloonable pages */
124
 
   BalloonErrorPages errors;
125
 
 
126
 
   /* balloon size */
127
 
   int nPages;
128
 
   int nPagesTarget;
129
 
 
130
 
   /* reset flag */
131
 
   int resetFlag;
132
 
 
133
 
   /* adjustment rates (pages per second) */
134
 
   int rateAlloc;
135
 
   int rateFree;
136
 
 
137
 
   /* slowdown page allocations for next few cycles */
138
 
   int slowPageAllocationCycles;
139
 
 
140
 
   /* statistics */
141
 
   BalloonStats stats;
142
 
} Balloon;
143
 
 
144
 
/*
145
 
 * Globals
146
 
 */
147
 
 
148
 
static Balloon globalBalloon;
149
 
 
150
 
/*
151
 
 * Forward Declarations
152
 
 */
153
 
 
154
 
static int BalloonGuestType(void);
155
 
 
156
 
static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep);
157
 
static void   BalloonPrimFreePage(unsigned long page);
158
 
 
159
 
static int  Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType);
160
 
static int  Balloon_FreePage(Balloon *b, int monitorUnlock);
161
 
static int  Balloon_AdjustSize(Balloon *b, uint32 target);
162
 
static void Balloon_Reset(Balloon *b);
163
 
 
164
 
static void Balloon_StartTimer(Balloon *b);
165
 
static void Balloon_StopTimer(Balloon *b);
166
 
static void CDECL Balloon_BH(void *data);
167
 
 
168
 
static int Balloon_MonitorStart(Balloon *b);
169
 
static int Balloon_MonitorGuestType(Balloon *b);
170
 
static int Balloon_MonitorGetTarget(Balloon *b, uint32 *nPages);
171
 
static int Balloon_MonitorLockPage(Balloon *b, unsigned long addr);
172
 
static int Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr);
173
 
 
174
 
/*
175
 
 * Macros
176
 
 */
177
 
 
178
 
#ifndef MIN
179
 
#define MIN(a, b)       (((a) < (b)) ? (a) : (b))
180
 
#endif
181
 
#ifndef MAX
182
 
#define MAX(a, b)       (((a) > (b)) ? (a) : (b))
183
 
#endif
184
 
 
185
 
#ifdef  BALLOON_STATS
186
 
#define STATS_INC(stat) (stat)++
187
 
#else
188
 
#define STATS_INC(stat)
189
 
#endif
190
 
 
191
 
/*
192
 
 * Macros to generate operations for simple lists of OBJ.
193
 
 * OBJ must contain next and prev fields.
194
 
 * 
195
 
 */
196
 
 
197
 
#define GENERATE_LIST_INSERT(OBJ)                       \
198
 
static void OBJ ## _Insert(OBJ **head, OBJ *obj)        \
199
 
{                                                       \
200
 
   OBJ *h = *head;                                      \
201
 
                                                        \
202
 
   /* add element to head of list */                    \
203
 
   obj->next = h;                                       \
204
 
   if (h != NULL) {                                     \
205
 
      h->prev = obj;                                    \
206
 
   }                                                    \
207
 
   *head = obj;                                         \
208
 
   obj->prev = NULL;                                    \
209
 
}
210
 
 
211
 
#define GENERATE_LIST_REMOVE(OBJ)                       \
212
 
static void OBJ ## _Remove(OBJ **head, OBJ *obj)        \
213
 
{                                                       \
214
 
    /* splice element out of list */                    \
215
 
    if (obj->prev != NULL) {                            \
216
 
      obj->prev->next = obj->next;                      \
217
 
    } else {                                            \
218
 
      *head = obj->next;                                \
219
 
    }                                                   \
220
 
    if (obj->next != NULL) {                            \
221
 
      obj->next->prev = obj->prev;                      \
222
 
    }                                                   \
223
 
}
224
 
 
225
 
/*
226
 
 * List Operations
227
 
 */
228
 
 
229
 
GENERATE_LIST_INSERT(BalloonChunk);
230
 
GENERATE_LIST_REMOVE(BalloonChunk);
231
 
 
232
 
/*
233
 
 * Procfs Operations
234
 
 */
235
 
 
236
 
/*
237
 
 *----------------------------------------------------------------------
238
 
 *
239
 
 * BalloonProcRead --
240
 
 *
241
 
 *      Ballon driver status reporting routine.  Note that this is only
242
 
 *      used for Linux.
243
 
 *
244
 
 * Results:
245
 
 *      Writes ASCII status information into "buf".
246
 
 *      Returns number of bytes written.
247
 
 *
248
 
 * Side effects:
249
 
 *      None.
250
 
 *
251
 
 *----------------------------------------------------------------------
252
 
 */
253
 
static int CDECL
254
 
BalloonProcRead(char *buf)
255
 
{
256
 
   int len = 0;
257
 
   BalloonStats stats;
258
 
 
259
 
   BalloonGetStats(&stats);
260
 
 
261
 
   /* format size info */
262
 
   len += os_sprintf(buf + len,
263
 
                     "target:             %8d pages\n"
264
 
                     "current:            %8d pages\n",
265
 
                     stats.nPagesTarget,
266
 
                     stats.nPages);
267
 
 
268
 
   /* format rate info */
269
 
   len += os_sprintf(buf + len,
270
 
                     "rateNoSleepAlloc:   %8d pages/sec\n"
271
 
                     "rateSleepAlloc:     %8d pages/sec\n"
272
 
                     "rateFree:           %8d pages/sec\n",
273
 
                     BALLOON_NOSLEEP_ALLOC_MAX,
274
 
                     stats.rateAlloc,
275
 
                     stats.rateFree);
276
 
 
277
 
#ifdef  BALLOON_STATS_PROCFS
278
 
   len += os_sprintf(buf + len,
279
 
                     "\n"
280
 
                     "timer:              %8u\n"
281
 
                     "start:              %8u (%4u failed)\n"
282
 
                     "guestType:          %8u (%4u failed)\n"
283
 
                     "lock:               %8u (%4u failed)\n"
284
 
                     "unlock:             %8u (%4u failed)\n"
285
 
                     "target:             %8u (%4u failed)\n"
286
 
                     "primNoSleepAlloc:   %8u (%4u failed)\n"
287
 
                     "primCanSleepAlloc:  %8u (%4u failed)\n"
288
 
                     "primFree:           %8u\n"
289
 
                     "errAlloc:           %8u\n"
290
 
                     "errFree:            %8u\n",
291
 
                     stats.timer,
292
 
                     stats.start, stats.startFail,
293
 
                     stats.guestType, stats.guestTypeFail,
294
 
                     stats.lock,  stats.lockFail,
295
 
                     stats.unlock, stats.unlockFail,
296
 
                     stats.target, stats.targetFail,
297
 
                     stats.primAlloc[BALLOON_PAGE_ALLOC_NOSLEEP],
298
 
                     stats.primAllocFail[BALLOON_PAGE_ALLOC_NOSLEEP],
299
 
                     stats.primAlloc[BALLOON_PAGE_ALLOC_CANSLEEP],
300
 
                     stats.primAllocFail[BALLOON_PAGE_ALLOC_CANSLEEP],
301
 
                     stats.primFree,
302
 
                     stats.primErrorPageAlloc,
303
 
                     stats.primErrorPageFree);
304
 
#endif
305
 
 
306
 
   return(len);
307
 
}
308
 
 
309
 
/*
310
 
 * Utility Operations
311
 
 */
312
 
 
313
 
/*
314
 
 *----------------------------------------------------------------------
315
 
 *
316
 
 * AddrToPPN --
317
 
 *
318
 
 *      Return the physical page number corresponding to the specified
319
 
 *      Linux kernel-mapped address.
320
 
 *
321
 
 * Results:
322
 
 *      Returns PPN for "addr".
323
 
 *
324
 
 * Side effects:
325
 
 *      None.
326
 
 *
327
 
 *----------------------------------------------------------------------
328
 
 */
329
 
static inline unsigned long
330
 
AddrToPPN(unsigned long addr)
331
 
{
332
 
   return(os_addr_to_ppn(addr));
333
 
}
334
 
 
335
 
/*
336
 
 *----------------------------------------------------------------------
337
 
 *
338
 
 * BalloonPrimAllocPage --
339
 
 *
340
 
 *      Attempts to allocate and reserve a physical page.
341
 
 *
342
 
 *      If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
343
 
 *         The allocation can wait (sleep) for page writeout (swap)
344
 
 *         by the guest.
345
 
 *      otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
346
 
 *         If allocation of a page requires disk writeout, then
347
 
 *         just fail. DON'T sleep.
348
 
 *
349
 
 * Results:
350
 
 *      Returns the physical address of the allocated page, or 0 if error.
351
 
 *
352
 
 * Side effects:
353
 
 *      None.
354
 
 *
355
 
 *----------------------------------------------------------------------
356
 
 */
357
 
static unsigned long
358
 
BalloonPrimAllocPage(BalloonPageAllocType canSleep)
359
 
{
360
 
   return(os_alloc_reserved_page(canSleep));
361
 
}
362
 
 
363
 
/*
364
 
 *----------------------------------------------------------------------
365
 
 *
366
 
 * BalloonPrimFreePage --
367
 
 *
368
 
 *      Unreserves and deallocates specified physical page.
369
 
 *
370
 
 * Results:
371
 
 *      None.
372
 
 *
373
 
 * Side effects:
374
 
 *      None.
375
 
 *
376
 
 *----------------------------------------------------------------------
377
 
 */
378
 
static void
379
 
BalloonPrimFreePage(unsigned long page)
380
 
{
381
 
   return(os_free_reserved_page(page));
382
 
}
383
 
 
384
 
/*
385
 
 *----------------------------------------------------------------------
386
 
 *
387
 
 * BalloonGuestType --
388
 
 *
389
 
 *      Return balloon guest OS identifier obtained by parsing
390
 
 *      system-dependent identity string.
391
 
 *
392
 
 * Results:
393
 
 *      Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}.
394
 
 *
395
 
 * Side effects:
396
 
 *      None.
397
 
 *
398
 
 *----------------------------------------------------------------------
399
 
 */
400
 
static int
401
 
BalloonGuestType(void)
402
 
{
403
 
   char *identity;
404
 
 
405
 
   /* obtain OS identify string */
406
 
   identity = os_identity();
407
 
   
408
 
   /* unknown if not specified */
409
 
   if (identity == NULL) {
410
 
      return(BALLOON_GUEST_UNKNOWN);
411
 
   }
412
 
 
413
 
   /* classify based on first letter (avoid defining strcmp) */
414
 
   switch (identity[0]) {
415
 
   case 'l':
416
 
   case 'L':
417
 
      return(BALLOON_GUEST_LINUX);
418
 
   case 'b':
419
 
   case 'B':
420
 
      return(BALLOON_GUEST_BSD);
421
 
   case 's':
422
 
   case 'S':
423
 
      return(BALLOON_GUEST_SOLARIS);
424
 
   default:
425
 
      break;
426
 
   }
427
 
 
428
 
   /* unknown */
429
 
   return(BALLOON_GUEST_UNKNOWN);
430
 
}
431
 
 
432
 
/*
433
 
 * Returns information about balloon state, including the current and
434
 
 * target size, rates for allocating and freeing pages, and statistics
435
 
 * about past activity.
436
 
 */
437
 
void BalloonGetStats(BalloonStats *stats)
438
 
{
439
 
   Balloon *b = &globalBalloon;
440
 
 
441
 
   /*
442
 
    * Copy statistics out of global structure.
443
 
    */
444
 
   os_memcpy(stats, &b->stats, sizeof (BalloonStats));
445
 
 
446
 
   /*
447
 
    * Fill in additional information about size and rates, which is
448
 
    * normally kept in the Balloon structure itself.
449
 
    */
450
 
   stats->nPages = b->nPages;
451
 
   stats->nPagesTarget = b->nPagesTarget;
452
 
   stats->rateAlloc = b->rateAlloc;
453
 
   stats->rateFree = b->rateFree;
454
 
}
455
 
 
456
 
/*
457
 
 * BalloonChunk Operations
458
 
 */
459
 
 
460
 
/*
461
 
 *----------------------------------------------------------------------
462
 
 *
463
 
 * BalloonChunk_Create --
464
 
 *
465
 
 *      Creates a new BalloonChunk object capable of tracking
466
 
 *      BALLOON_CHUNK_PAGES PPNs.
467
 
 *
468
 
 *      We do not bother to define two versions (NOSLEEP and CANSLEEP)
469
 
 *      of os_kmalloc because Chunk_Create does not require a new page
470
 
 *      often.
471
 
 *
472
 
 * Results:
473
 
 *      Returns initialized BalloonChunk, or NULL if error.
474
 
 *
475
 
 * Side effects:
476
 
 *      None.
477
 
 *
478
 
 *----------------------------------------------------------------------
479
 
 */
480
 
static BalloonChunk *
481
 
BalloonChunk_Create(void)
482
 
{
483
 
   BalloonChunk *chunk;
484
 
 
485
 
   /* allocate memory, fail if unable */
486
 
   if ((chunk = (BalloonChunk *) os_kmalloc_nosleep(sizeof(BalloonChunk))) == NULL) {
487
 
      return(NULL);
488
 
   }
489
 
 
490
 
   /* initialize */
491
 
   os_bzero(chunk, sizeof(BalloonChunk));
492
 
 
493
 
   /* everything OK */
494
 
   return(chunk);
495
 
}
496
 
 
497
 
/*
498
 
 *----------------------------------------------------------------------
499
 
 *
500
 
 * BalloonChunk_Destroy --
501
 
 *
502
 
 *      Reclaims all storage associated with specified BalloonChunk.
503
 
 *
504
 
 * Results:
505
 
 *      None.
506
 
 *
507
 
 * Side effects:
508
 
 *      None.
509
 
 *
510
 
 *----------------------------------------------------------------------
511
 
 */
512
 
static void
513
 
BalloonChunk_Destroy(BalloonChunk *chunk)
514
 
{
515
 
   /* reclaim storage */
516
 
   os_kfree(chunk, sizeof (BalloonChunk));
517
 
}
518
 
 
519
 
/*
520
 
 * Balloon operations
521
 
 */
522
 
 
523
 
 
524
 
/*
525
 
 *----------------------------------------------------------------------
526
 
 *
527
 
 * Balloon_Init --
528
 
 *
529
 
 *      Initializes device state for balloon "b".
530
 
 *
531
 
 * Results:
532
 
 *      Returns BALLOON_SUCCESS.
533
 
 *
534
 
 * Side effects:
535
 
 *      None.
536
 
 *
537
 
 *----------------------------------------------------------------------
538
 
 */
539
 
static int
540
 
Balloon_Init(Balloon *b)
541
 
{
542
 
   /* clear state */
543
 
   os_bzero(b, sizeof(Balloon));
544
 
 
545
 
   /* initialize rates */
546
 
   b->rateAlloc = BALLOON_RATE_ALLOC_MAX;
547
 
   b->rateFree  = BALLOON_RATE_FREE_MAX;
548
 
 
549
 
   /* initialize reset flag */
550
 
   b->resetFlag = 1;
551
 
 
552
 
   /* everything OK */
553
 
   return(BALLOON_SUCCESS);
554
 
}
555
 
 
556
 
/*
557
 
 *----------------------------------------------------------------------
558
 
 *
559
 
 * Balloon_Deallocate --
560
 
 *
561
 
 *      Frees all allocated pages.
562
 
 *
563
 
 * Results:
564
 
 *      None.
565
 
 *
566
 
 * Side effects:
567
 
 *      None.
568
 
 *
569
 
 *----------------------------------------------------------------------
570
 
 */
571
 
static void
572
 
Balloon_Deallocate(Balloon *b)
573
 
{
574
 
   unsigned int cnt = 0;
575
 
 
576
 
   /* free all pages, skipping monitor unlock */
577
 
   while (b->nChunks > 0) {
578
 
      (void) Balloon_FreePage(b, FALSE);
579
 
      if (++cnt >= b->rateFree) {
580
 
         cnt = 0;
581
 
         os_yield();
582
 
      }
583
 
   }
584
 
}
585
 
 
586
 
/*
587
 
 *----------------------------------------------------------------------
588
 
 *
589
 
 * Balloon_Reset --
590
 
 *
591
 
 *      Resets balloon "b" to empty state.  Frees all allocated pages
592
 
 *      and attempts to reset contact with the monitor. 
593
 
 *
594
 
 * Results:
595
 
 *      None.
596
 
 *
597
 
 * Side effects:
598
 
 *      Schedules next execution of balloon timer handler.
599
 
 *
600
 
 *----------------------------------------------------------------------
601
 
 */
602
 
static void
603
 
Balloon_Reset(Balloon *b)
604
 
{
605
 
   uint32 status;
606
 
 
607
 
   /* free all pages, skipping monitor unlock */
608
 
   Balloon_Deallocate(b);
609
 
 
610
 
   /* send start command */
611
 
   status = Balloon_MonitorStart(b);
612
 
   if (status == BALLOON_SUCCESS) {
613
 
      /* clear flag */
614
 
      b->resetFlag = 0;
615
 
 
616
 
      /* report guest type */
617
 
      (void) Balloon_MonitorGuestType(b);
618
 
   }
619
 
}
620
 
 
621
 
/*
622
 
 *----------------------------------------------------------------------
623
 
 *
624
 
 * Balloon_BH --
625
 
 *
626
 
 *      Balloon bottom half handler.  Contacts monitor via backdoor
627
 
 *      to obtain balloon size target, and starts adjusting balloon
628
 
 *      size to achieve target by allocating or deallocating pages.
629
 
 *      Resets balloon if requested by the monitor.
630
 
 *
631
 
 * Results:
632
 
 *      None.
633
 
 *
634
 
 * Side effects:
635
 
 *      Schedules next execution of balloon timer handler.
636
 
 *
637
 
 *----------------------------------------------------------------------
638
 
 */
639
 
static void CDECL
640
 
Balloon_BH(void *data)
641
 
{
642
 
   Balloon *b = (Balloon *) data;
643
 
   uint32 target;
644
 
   int status;
645
 
 
646
 
   /* update stats */
647
 
   STATS_INC(b->stats.timer);
648
 
 
649
 
   /* reset, if specified */
650
 
   if (b->resetFlag) {
651
 
      Balloon_Reset(b);
652
 
   }
653
 
 
654
 
   /* contact monitor via backdoor */
655
 
   status = Balloon_MonitorGetTarget(b, &target);
656
 
 
657
 
   /* decrement slowPageAllocationCycles counter */
658
 
   if (b->slowPageAllocationCycles > 0) {
659
 
      b->slowPageAllocationCycles--;
660
 
   }
661
 
 
662
 
   if (status == BALLOON_SUCCESS) {
663
 
      /* update target, adjust size */
664
 
      b->nPagesTarget = target;
665
 
      (void) Balloon_AdjustSize(b, target);
666
 
   }
667
 
}
668
 
 
669
 
/*
670
 
 *----------------------------------------------------------------------
671
 
 *
672
 
 * Balloon_StartTimer --
673
 
 *
674
 
 *      Schedules next execution of balloon timer handler.
675
 
 *
676
 
 * Results:
677
 
 *      None.
678
 
 *
679
 
 * Side effects:
680
 
 *      None.
681
 
 *
682
 
 *----------------------------------------------------------------------
683
 
 */
684
 
static void
685
 
Balloon_StartTimer(Balloon *b)
686
 
{
687
 
   os_timer_start();
688
 
}
689
 
 
690
 
/*
691
 
 *----------------------------------------------------------------------
692
 
 *
693
 
 * Balloon_StopTimer --
694
 
 *
695
 
 *      Deschedules balloon timer handler.
696
 
 *
697
 
 * Results:
698
 
 *      None.
699
 
 *
700
 
 * Side effects:
701
 
 *      None.
702
 
 *
703
 
 *----------------------------------------------------------------------
704
 
 */
705
 
static void
706
 
Balloon_StopTimer(Balloon *b)
707
 
{
708
 
   os_timer_stop();
709
 
}
710
 
 
711
 
 
712
 
/*
713
 
 *----------------------------------------------------------------------
714
 
 *
715
 
 * Balloon_ErrorPagesAlloc --
716
 
 *
717
 
 *      Attempt to add "page" to list of non-balloonable pages
718
 
 *      associated with "b".
719
 
 *
720
 
 * Results:
721
 
 *      Returns BALLOON_SUCCESS iff successful, or BALLOON_FAILURE
722
 
 *      if non-balloonable page list is already full.
723
 
 *
724
 
 * Side effects:
725
 
 *      None.
726
 
 *
727
 
 *----------------------------------------------------------------------
728
 
 */
729
 
static int
730
 
Balloon_ErrorPagesAlloc(Balloon *b, unsigned long page)
731
 
{
732
 
   /* fail if list already full */
733
 
   if (b->errors.nextPage >= BALLOON_ERROR_PAGES) {
734
 
      return(BALLOON_FAILURE);
735
 
   }
736
 
 
737
 
   /* add page to list */
738
 
   b->errors.page[b->errors.nextPage] = page;
739
 
   b->errors.nextPage++;
740
 
   STATS_INC(b->stats.primErrorPageAlloc);
741
 
   return(BALLOON_SUCCESS);
742
 
}
743
 
 
744
 
/*
745
 
 *----------------------------------------------------------------------
746
 
 *
747
 
 * Balloon_ErrorPagesFree --
748
 
 *
749
 
 *      Deallocates all pages on the list of non-balloonable pages
750
 
 *      associated with "b".
751
 
 *
752
 
 * Results:
753
 
 *      None.
754
 
 *
755
 
 * Side effects:
756
 
 *      None.
757
 
 *
758
 
 *----------------------------------------------------------------------
759
 
 */
760
 
static void
761
 
Balloon_ErrorPagesFree(Balloon *b)
762
 
{
763
 
   int i;
764
 
 
765
 
   /* free all non-balloonable "error" pages */
766
 
   for (i = 0; i < b->errors.nextPage; i++) {
767
 
      BalloonPrimFreePage(b->errors.page[i]);      
768
 
      b->errors.page[i] = 0;
769
 
      STATS_INC(b->stats.primErrorPageFree);
770
 
   }
771
 
   b->errors.nextPage = 0;
772
 
}
773
 
 
774
 
/*
775
 
 *----------------------------------------------------------------------
776
 
 *
777
 
 * Balloon_AllocPage --
778
 
 *
779
 
 *      Attempts to allocate a physical page, inflating balloon "b".
780
 
 *      Informs monitor of PPN for allocated page via backdoor.
781
 
 *
782
 
 * Results:
783
 
 *      Returns BALLOON_SUCCESS if successful, otherwise error code.
784
 
 *
785
 
 * Side effects:
786
 
 *      None.
787
 
 *
788
 
 *----------------------------------------------------------------------
789
 
 */
790
 
static int
791
 
Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType)
792
 
{
793
 
   BalloonChunk *chunk;
794
 
   unsigned long page;
795
 
   int status;
796
 
 
797
 
 retry:
798
 
 
799
 
   /* allocate page, fail if unable */
800
 
   STATS_INC(b->stats.primAlloc[allocType]);
801
 
 
802
 
   page = BalloonPrimAllocPage(allocType);
803
 
 
804
 
   if (page == 0) {
805
 
      STATS_INC(b->stats.primAllocFail[allocType]);
806
 
      return(BALLOON_PAGE_ALLOC_FAILURE);
807
 
   }
808
 
 
809
 
   /* find chunk with space, create if necessary */
810
 
   chunk = b->chunks;
811
 
   if ((chunk == NULL) || (chunk->nextPage >= BALLOON_CHUNK_PAGES)) {
812
 
      /* create new chunk */
813
 
      if ((chunk = BalloonChunk_Create()) == NULL) {
814
 
         /* reclaim storage, fail */
815
 
         BalloonPrimFreePage(page);
816
 
         return(BALLOON_PAGE_ALLOC_FAILURE);
817
 
      }
818
 
      BalloonChunk_Insert(&b->chunks, chunk);
819
 
 
820
 
      /* update stats */
821
 
      b->nChunks++;
822
 
   }
823
 
 
824
 
   /* inform monitor via backdoor */
825
 
   status = Balloon_MonitorLockPage(b, page);
826
 
   if (status != BALLOON_SUCCESS) {
827
 
      /* place on list of non-balloonable pages, retry allocation */
828
 
      if ((status != BALLOON_ERROR_RESET) &&
829
 
          (Balloon_ErrorPagesAlloc(b, page) == BALLOON_SUCCESS)) {
830
 
         goto retry;
831
 
      }
832
 
 
833
 
      /* reclaim storage, fail */
834
 
      BalloonPrimFreePage(page);
835
 
      return(status);
836
 
   }
837
 
 
838
 
   /* track allocated page */
839
 
   chunk->page[chunk->nextPage] = page;
840
 
   chunk->nextPage++;
841
 
 
842
 
   /* update balloon size */
843
 
   b->nPages++;
844
 
 
845
 
   /* everything OK */
846
 
   return(BALLOON_SUCCESS);
847
 
}
848
 
 
849
 
/*
850
 
 *----------------------------------------------------------------------
851
 
 *
852
 
 * Balloon_FreePage --
853
 
 *
854
 
 *      Attempts to deallocate a physical page, deflating balloon "b".
855
 
 *      Informs monitor of PPN for deallocated page via backdoor if
856
 
 *      "monitorUnlock" is specified.
857
 
 *
858
 
 * Results:
859
 
 *      Returns BALLOON_SUCCESS if successful, otherwise error code.
860
 
 *
861
 
 * Side effects:
862
 
 *      None.
863
 
 *
864
 
 *----------------------------------------------------------------------
865
 
 */
866
 
static int
867
 
Balloon_FreePage(Balloon *b, int monitorUnlock)
868
 
{
869
 
   BalloonChunk *chunk;
870
 
   unsigned long page;
871
 
   int status;
872
 
 
873
 
   chunk = b->chunks;
874
 
 
875
 
   while ((chunk != NULL) && (chunk->nextPage == 0)) {
876
 
      /* destroy empty chunk */
877
 
      BalloonChunk_Remove(&b->chunks, chunk);
878
 
      BalloonChunk_Destroy(chunk);
879
 
 
880
 
      /* update stats */
881
 
      b->nChunks--;
882
 
 
883
 
      chunk = b->chunks;
884
 
   }
885
 
 
886
 
   if (chunk == NULL) {
887
 
      return(BALLOON_FAILURE);
888
 
   }
889
 
 
890
 
   /* select page to deallocate */
891
 
   chunk->nextPage--;
892
 
   page = chunk->page[chunk->nextPage];
893
 
 
894
 
   /* inform monitor via backdoor */
895
 
   if (monitorUnlock) {
896
 
      status = Balloon_MonitorUnlockPage(b, page);
897
 
      if (status != BALLOON_SUCCESS) {
898
 
         /* reset next pointer, fail */
899
 
         chunk->nextPage++;
900
 
         return(status);
901
 
      }
902
 
   }
903
 
 
904
 
   /* deallocate page */
905
 
   BalloonPrimFreePage(page);
906
 
   STATS_INC(b->stats.primFree);
907
 
 
908
 
   /* update balloon size */
909
 
   b->nPages--;
910
 
 
911
 
   /* reclaim chunk, if empty */
912
 
   if (chunk->nextPage == 0) {
913
 
      /* destroy empty chunk */
914
 
      BalloonChunk_Remove(&b->chunks, chunk);
915
 
      BalloonChunk_Destroy(chunk);
916
 
 
917
 
      /* update stats */
918
 
      b->nChunks--;
919
 
   }
920
 
 
921
 
   /* everything OK */
922
 
   return(BALLOON_SUCCESS);
923
 
}
924
 
 
925
 
/*
926
 
 *----------------------------------------------------------------------
927
 
 *
928
 
 * BalloonDecreaseRateAlloc --
929
 
 *
930
 
 *      Wrapper to quickly reduce the page allocation rate. This function
931
 
 *      is called only when a CANSLEEP allocation fails. This implies severe 
932
 
 *      memory pressure inside the guest, so quickly decrease the rateAlloc.
933
 
 *
934
 
 * Results:
935
 
 *      None.
936
 
 *
937
 
 * Side effects:
938
 
 *      None.
939
 
 *
940
 
 *----------------------------------------------------------------------
941
 
 */
942
 
static void
943
 
BalloonDecreaseRateAlloc(Balloon *b)
944
 
{
945
 
   if (BALLOON_RATE_ADAPT) {
946
 
      b->rateAlloc = MAX(b->rateAlloc / 2, BALLOON_RATE_ALLOC_MIN);
947
 
   }
948
 
}
949
 
 
950
 
/*
951
 
 *----------------------------------------------------------------------
952
 
 *
953
 
 * BalloonIncreaseRateAlloc --
954
 
 *
955
 
 *      Wrapper to increase the page allocation rate. 
956
 
 *
957
 
 *      This function is called when the balloon target is met or
958
 
 *      b->rateAlloc (or more) pages have been successfully allocated.
959
 
 *      This implies that the guest may not be under high memory 
960
 
 *      pressure. So let us increase the rateAlloc.
961
 
 *
962
 
 *      If meeting balloon target requires less than b->rateAlloc
963
 
 *      pages, then we do not change the page allocation rate.
964
 
 *
965
 
 *      If the number of pages successfully allocated (nAlloc) is far
966
 
 *      higher than b->rateAlloc, then it implies that NOSLEEP 
967
 
 *      allocations are highly successful. Therefore, we predict that
968
 
 *      the guest is under no memory pressure, and so increase
969
 
 *      b->rateAlloc quickly.
970
 
 *
971
 
 * Results:
972
 
 *      None.
973
 
 *
974
 
 * Side effects:
975
 
 *      None.
976
 
 *
977
 
 *----------------------------------------------------------------------
978
 
 */
979
 
static void
980
 
BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc)
981
 
{
982
 
   if (BALLOON_RATE_ADAPT) {
983
 
      if (nAlloc >= b->rateAlloc) {
984
 
         uint32 mult = nAlloc / b->rateAlloc; 
985
 
         b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC,
986
 
                            BALLOON_RATE_ALLOC_MAX);
987
 
      }
988
 
   }
989
 
}
990
 
 
991
 
/*
992
 
 *----------------------------------------------------------------------
993
 
 *
994
 
 * BalloonInflate--
995
 
 *
996
 
 *      Attempts to allocate physical pages to inflate balloon.
997
 
 *
998
 
 * Results:
999
 
 *      Returns BALLOON_SUCCESS if successful, otherwise error code.
1000
 
 *
1001
 
 * Side effects:
1002
 
 *      None.
1003
 
 *
1004
 
 *----------------------------------------------------------------------
1005
 
 */
1006
 
static int
1007
 
BalloonInflate(Balloon *b, uint32 target)
1008
 
{
1009
 
   int status, allocations = 0;
1010
 
   uint32 i, nAllocNoSleep, nAllocCanSleep;
1011
 
 
1012
 
   /* 
1013
 
    * First try NOSLEEP page allocations to inflate balloon.
1014
 
    *
1015
 
    * If we do not throttle nosleep allocations, we can drain all
1016
 
    * free pages in the guest quickly (if the balloon target is high).
1017
 
    * As a side-effect, draining free pages helps to inform (force)
1018
 
    * the guest to start swapping if balloon target is not met yet,
1019
 
    * which is a desired behavior. However, balloon driver can consume
1020
 
    * all available CPU cycles if too many pages are allocated in a 
1021
 
    * second. Therefore, we throttle nosleep allocations even when 
1022
 
    * the guest is not under memory pressure. OTOH, if we have already 
1023
 
    * predicted that the guest is under memory pressure, then we 
1024
 
    * slowdown page allocations considerably.
1025
 
    */
1026
 
   if (b->slowPageAllocationCycles > 0) {
1027
 
      nAllocNoSleep = MIN(target - b->nPages, b->rateAlloc);
1028
 
   } else {
1029
 
      nAllocNoSleep = MIN(target - b->nPages, BALLOON_NOSLEEP_ALLOC_MAX);
1030
 
   }
1031
 
 
1032
 
   for (i = 0; i < nAllocNoSleep; i++) {
1033
 
      /* Try NOSLEEP allocation */
1034
 
      status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_NOSLEEP);
1035
 
      if (status != BALLOON_SUCCESS) {
1036
 
         if (status != BALLOON_PAGE_ALLOC_FAILURE) {
1037
 
            /* 
1038
 
             * Not a page allocation failure, so release non-balloonable
1039
 
             * pages, and fail.
1040
 
             */
1041
 
            Balloon_ErrorPagesFree(b);
1042
 
            return(status);
1043
 
         }
1044
 
         /* 
1045
 
          * NOSLEEP page allocation failed, so the guest is under memory 
1046
 
          * pressure. Let us slowdown page allocations for next few 
1047
 
          * cycles so that the guest gets out of memory pressure.
1048
 
          */
1049
 
         b->slowPageAllocationCycles = SLOW_PAGE_ALLOCATION_CYCLES;
1050
 
         break;
1051
 
      }
1052
 
 
1053
 
      if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
1054
 
         os_yield();
1055
 
         allocations = 0;
1056
 
      }
1057
 
   }
1058
 
 
1059
 
   /* 
1060
 
    * Check whether nosleep allocation successfully zapped nAllocNoSleep
1061
 
    * pages.
1062
 
    */
1063
 
   if (i == nAllocNoSleep) {
1064
 
      BalloonIncreaseRateAlloc(b, nAllocNoSleep);
1065
 
      /* release non-balloonable pages, succeed */
1066
 
      Balloon_ErrorPagesFree(b);
1067
 
      return(BALLOON_SUCCESS);
1068
 
   } else {
1069
 
      /* 
1070
 
       * NOSLEEP allocation failed, so the guest is under memory pressure.
1071
 
       * If already b->rateAlloc pages were zapped, then succeed. Otherwise,
1072
 
       * try CANSLEEP allocation.
1073
 
       */
1074
 
      if (i > b->rateAlloc) {
1075
 
         BalloonIncreaseRateAlloc(b, i);
1076
 
         /* release non-balloonable pages, succeed */
1077
 
         Balloon_ErrorPagesFree(b);
1078
 
         return(BALLOON_SUCCESS);
1079
 
      } else {
1080
 
         /* update successful NOSLEEP allocations, and proceed */
1081
 
         nAllocNoSleep = i;
1082
 
      }
1083
 
   }
1084
 
 
1085
 
   /* 
1086
 
    * Use CANSLEEP page allocation to inflate balloon if below target.
1087
 
    *
1088
 
    * Sleep allocations are required only when nosleep allocation fails.
1089
 
    * This implies that the guest is already under memory pressure, so
1090
 
    * let us always throttle canSleep allocations. The total number pages
1091
 
    * allocated using noSleep and canSleep methods is throttled at 
1092
 
    * b->rateAlloc per second when the guest is under memory pressure. 
1093
 
    */
1094
 
   nAllocCanSleep = target - b->nPages;
1095
 
   nAllocCanSleep = MIN(nAllocCanSleep, b->rateAlloc - nAllocNoSleep);
1096
 
 
1097
 
   for (i = 0; i < nAllocCanSleep; i++) {
1098
 
      /* Try CANSLEEP allocation */
1099
 
      status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_CANSLEEP);
1100
 
      if(status != BALLOON_SUCCESS) {
1101
 
         if (status == BALLOON_PAGE_ALLOC_FAILURE) {
1102
 
            /* 
1103
 
             * CANSLEEP page allocation failed, so guest is under severe
1104
 
             * memory pressure. Quickly decrease rateAlloc.
1105
 
             */
1106
 
            BalloonDecreaseRateAlloc(b);
1107
 
         }
1108
 
         /* release non-balloonable pages, fail */
1109
 
         Balloon_ErrorPagesFree(b);
1110
 
         return(status);
1111
 
      }
1112
 
 
1113
 
      if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
1114
 
         os_yield();
1115
 
         allocations = 0;
1116
 
      }
1117
 
   }
1118
 
 
1119
 
   /* 
1120
 
    * Either met the balloon target or b->rateAlloc pages have been
1121
 
    * successfully zapped.
1122
 
    */
1123
 
   BalloonIncreaseRateAlloc(b, nAllocNoSleep + nAllocCanSleep);
1124
 
                            
1125
 
   /* release non-balloonable pages, succeed */
1126
 
   Balloon_ErrorPagesFree(b);
1127
 
   return(BALLOON_SUCCESS);
1128
 
}
1129
 
 
1130
 
/*
1131
 
 *----------------------------------------------------------------------
1132
 
 *
1133
 
 * BalloonDeflate --
1134
 
 *
1135
 
 *      Frees physical pages to deflate balloon.
1136
 
 *
1137
 
 * Results:
1138
 
 *      Returns BALLOON_SUCCESS if successful, otherwise error code.
1139
 
 *
1140
 
 * Side effects:
1141
 
 *      None.
1142
 
 *
1143
 
 *----------------------------------------------------------------------
1144
 
 */
1145
 
static int
1146
 
BalloonDeflate(Balloon *b, uint32 target)
1147
 
{
1148
 
   int status, i;
1149
 
   uint32 nFree = b->nPages - target;
1150
 
      
1151
 
   /* limit deallocation rate */
1152
 
   nFree = MIN(nFree, b->rateFree);
1153
 
 
1154
 
   /* free pages to reach target */
1155
 
   for (i = 0; i < nFree; i++) {
1156
 
      if ((status = Balloon_FreePage(b, TRUE)) != BALLOON_SUCCESS) {
1157
 
         if (BALLOON_RATE_ADAPT) {
1158
 
            /* quickly decrease rate if error */
1159
 
            b->rateFree = MAX(b->rateFree / 2, BALLOON_RATE_FREE_MIN);
1160
 
         }
1161
 
         return(status);
1162
 
      }
1163
 
   }
1164
 
 
1165
 
   if (BALLOON_RATE_ADAPT) {
1166
 
      /* slowly increase rate if no errors */
1167
 
      b->rateFree = MIN(b->rateFree + BALLOON_RATE_FREE_INC,
1168
 
                        BALLOON_RATE_FREE_MAX);
1169
 
   }
1170
 
 
1171
 
   /* everything OK */
1172
 
   return(BALLOON_SUCCESS);
1173
 
}
1174
 
 
1175
 
/*
1176
 
 *----------------------------------------------------------------------
1177
 
 *
1178
 
 * Balloon_AdjustSize --
1179
 
 *
1180
 
 *      Attempts to allocate or deallocate physical pages in order
1181
 
 *      to reach desired "target" size for balloon "b".
1182
 
 *
1183
 
 * Results:
1184
 
 *      Returns BALLOON_SUCCESS if successful, otherwise error code.
1185
 
 *
1186
 
 * Side effects:
1187
 
 *      None.
1188
 
 *
1189
 
 *----------------------------------------------------------------------
1190
 
 */
1191
 
static int
1192
 
Balloon_AdjustSize(Balloon *b, uint32 target)
1193
 
{
1194
 
   /* done if already at target */
1195
 
   if (b->nPages == target) {
1196
 
      return(BALLOON_SUCCESS);
1197
 
   }
1198
 
 
1199
 
   /* inflate balloon if below target */
1200
 
   if (b->nPages < target) {
1201
 
      return BalloonInflate(b, target);
1202
 
   }
1203
 
 
1204
 
   /* deflate balloon if above target */
1205
 
   if (b->nPages > target) {
1206
 
      return BalloonDeflate(b, target);
1207
 
   }
1208
 
 
1209
 
   /* not reached */
1210
 
   return(BALLOON_FAILURE);
1211
 
}
1212
 
 
1213
 
/*
1214
 
 * Backdoor Operations
1215
 
 */
1216
 
 
1217
 
/*
1218
 
 *----------------------------------------------------------------------
1219
 
 *
1220
 
 * Balloon_MonitorStart --
1221
 
 *
1222
 
 *      Attempts to contact monitor via backdoor to begin operation.
1223
 
 *
1224
 
 * Results:
1225
 
 *      Returns BALLOON_SUCCESS if successful, otherwise error code.
1226
 
 *
1227
 
 * Side effects:
1228
 
 *      None.
1229
 
 *
1230
 
 *----------------------------------------------------------------------
1231
 
 */
1232
 
static int
1233
 
Balloon_MonitorStart(Balloon *b)
1234
 
{
1235
 
   uint32 status, target;
1236
 
   Backdoor_proto bp;
1237
 
 
1238
 
   /* prepare backdoor args */
1239
 
   bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_START;
1240
 
   bp.in.size = BALLOON_PROTOCOL_VERSION;
1241
 
 
1242
 
   /* invoke backdoor */
1243
 
   Backdoor_Balloon(&bp);
1244
 
 
1245
 
   /* parse return values */
1246
 
   status = bp.out.ax.word;
1247
 
   target = bp.out.bx.word;
1248
 
 
1249
 
   /* update stats */
1250
 
   STATS_INC(b->stats.start);
1251
 
   if (status != BALLOON_SUCCESS) {
1252
 
      STATS_INC(b->stats.startFail);
1253
 
   }
1254
 
 
1255
 
   /* everything OK */
1256
 
   return(status);
1257
 
}
1258
 
 
1259
 
/*
1260
 
 *----------------------------------------------------------------------
1261
 
 *
1262
 
 * Balloon_MonitorGuestType --
1263
 
 *
1264
 
 *      Attempts to contact monitor and report guest OS identity.
1265
 
 *
1266
 
 * Results:
1267
 
 *      Returns BALLOON_SUCCESS if successful, otherwise error code.
1268
 
 *
1269
 
 * Side effects:
1270
 
 *      None.
1271
 
 *
1272
 
 *----------------------------------------------------------------------
1273
 
 */
1274
 
static int
1275
 
Balloon_MonitorGuestType(Balloon *b)
1276
 
{
1277
 
   uint32 status, target;
1278
 
   Backdoor_proto bp;
1279
 
 
1280
 
   /* prepare backdoor args */
1281
 
   bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_GUEST_ID;
1282
 
   bp.in.size = BalloonGuestType();
1283
 
 
1284
 
   /* invoke backdoor */
1285
 
   Backdoor_Balloon(&bp);
1286
 
 
1287
 
   /* parse return values */
1288
 
   status = bp.out.ax.word;
1289
 
   target = bp.out.bx.word;
1290
 
 
1291
 
   /* set flag if reset requested */
1292
 
   if (status == BALLOON_ERROR_RESET) {
1293
 
      b->resetFlag = 1;
1294
 
   }
1295
 
 
1296
 
   /* update stats */
1297
 
   STATS_INC(b->stats.guestType);
1298
 
   if (status != BALLOON_SUCCESS) {
1299
 
      STATS_INC(b->stats.guestTypeFail);
1300
 
   }
1301
 
 
1302
 
   /* everything OK */
1303
 
   return(status);
1304
 
}
1305
 
 
1306
 
/*
1307
 
 *----------------------------------------------------------------------
1308
 
 *
1309
 
 * Balloon_MonitorGetTarget --
1310
 
 *
1311
 
 *      Attempts to contact monitor via backdoor to obtain desired
1312
 
 *      balloon size.
1313
 
 *
1314
 
 *      Predicts the maximum achievable balloon size and sends it 
1315
 
 *      to vmm => vmkernel via vEbx register.
1316
 
 *
1317
 
 *      os_predict_max_balloon_pages() returns either predicted max balloon
1318
 
 *      pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
1319
 
 *      vmkernel uses global config options for determining a guest's max
1320
 
 *      balloon size. Note that older vmballoon drivers set vEbx to 
1321
 
 *      BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
1322
 
 *      will fallback to config-based max balloon size estimation.
1323
 
 *
1324
 
 * Results:
1325
 
 *      If successful, sets "target" to value obtained from monitor,
1326
 
 *      and returns BALLOON_SUCCESS. Otherwise returns error code.
1327
 
 *
1328
 
 * Side effects:
1329
 
 *      None.
1330
 
 *
1331
 
 *----------------------------------------------------------------------
1332
 
 */
1333
 
static int
1334
 
Balloon_MonitorGetTarget(Balloon *b, uint32 *target)
1335
 
{
1336
 
   Backdoor_proto bp;
1337
 
   uint32 status;
1338
 
 
1339
 
   /* prepare backdoor args */
1340
 
   bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET;
1341
 
   bp.in.size = os_predict_max_balloon_pages();
1342
 
 
1343
 
   /* invoke backdoor */
1344
 
   Backdoor_Balloon(&bp);
1345
 
 
1346
 
   /* parse return values */
1347
 
   status  = bp.out.ax.word;
1348
 
   *target = bp.out.bx.word;
1349
 
 
1350
 
   /* set flag if reset requested */
1351
 
   if (status == BALLOON_ERROR_RESET) {
1352
 
      b->resetFlag = 1;
1353
 
   }
1354
 
 
1355
 
   /* update stats */
1356
 
   STATS_INC(b->stats.target);
1357
 
   if (status != BALLOON_SUCCESS) {
1358
 
      STATS_INC(b->stats.targetFail);
1359
 
   }
1360
 
 
1361
 
   /* everything OK */
1362
 
   return(status);
1363
 
}
1364
 
 
1365
 
/*
1366
 
 *----------------------------------------------------------------------
1367
 
 *
1368
 
 * Balloon_MonitorLockPage --
1369
 
 *
1370
 
 *      Attempts to contact monitor and add PPN containing "addr" 
1371
 
 *      to set of "balloon locked" pages.
1372
 
 *
1373
 
 * Results:
1374
 
 *      Returns BALLOON_SUCCESS if successful, otherwise error code.
1375
 
 *
1376
 
 * Side effects:
1377
 
 *      None.
1378
 
 *
1379
 
 *----------------------------------------------------------------------
1380
 
 */
1381
 
static int
1382
 
Balloon_MonitorLockPage(Balloon *b, unsigned long addr)
1383
 
{
1384
 
   unsigned long ppn;
1385
 
   uint32 ppn32;
1386
 
   uint32 status, target;
1387
 
   Backdoor_proto bp;
1388
 
 
1389
 
   /* convert kernel-mapped "physical addr" to ppn */
1390
 
   ppn = AddrToPPN(addr);
1391
 
 
1392
 
   /* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */
1393
 
   ppn32 = (uint32)ppn;
1394
 
   if (ppn32 != ppn) {
1395
 
      return BALLOON_ERROR_PPN_INVALID;
1396
 
   }
1397
 
 
1398
 
   /* prepare backdoor args */
1399
 
   bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_LOCK;
1400
 
   bp.in.size = ppn32;
1401
 
 
1402
 
   /* invoke backdoor */
1403
 
   Backdoor_Balloon(&bp);
1404
 
 
1405
 
   /* parse return values */
1406
 
   status = bp.out.ax.word;
1407
 
   target = bp.out.bx.word;
1408
 
 
1409
 
   /* set flag if reset requested */
1410
 
   if (status == BALLOON_ERROR_RESET) {
1411
 
      b->resetFlag = 1;
1412
 
   }
1413
 
 
1414
 
   /* update stats */
1415
 
   STATS_INC(b->stats.lock);
1416
 
   if (status != BALLOON_SUCCESS) {
1417
 
      STATS_INC(b->stats.lockFail);
1418
 
   }
1419
 
 
1420
 
   /* everything OK */
1421
 
   return(status);
1422
 
}
1423
 
 
1424
 
/*
1425
 
 *----------------------------------------------------------------------
1426
 
 *
1427
 
 * Balloon_MonitorUnlockPage --
1428
 
 *
1429
 
 *      Attempts to contact monitor and remove PPN containing "addr" 
1430
 
 *      from set of "balloon locked" pages.
1431
 
 *
1432
 
 * Results:
1433
 
 *      Returns BALLOON_SUCCESS if successful, otherwise error code.
1434
 
 *
1435
 
 * Side effects:
1436
 
 *      None.
1437
 
 *
1438
 
 *----------------------------------------------------------------------
1439
 
 */
1440
 
static int
1441
 
Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr)
1442
 
{
1443
 
   unsigned long ppn;
1444
 
   uint32 ppn32;
1445
 
   uint32 status, target;
1446
 
   Backdoor_proto bp;
1447
 
 
1448
 
   /* convert kernel-mapped "physical addr" to ppn */
1449
 
   ppn = AddrToPPN(addr);
1450
 
 
1451
 
   /* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */
1452
 
   ppn32 = (uint32)ppn;
1453
 
   if (ppn32 != ppn) {
1454
 
      return BALLOON_ERROR_PPN_INVALID;
1455
 
   }
1456
 
 
1457
 
   /* prepare backdoor args */
1458
 
   bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_UNLOCK;
1459
 
   bp.in.size = ppn32;
1460
 
 
1461
 
   /* invoke backdoor */
1462
 
   Backdoor_Balloon(&bp);
1463
 
 
1464
 
   /* parse return values */
1465
 
   status = bp.out.ax.word;
1466
 
   target = bp.out.bx.word;
1467
 
 
1468
 
   /* set flag if reset requested */
1469
 
   if (status == BALLOON_ERROR_RESET) {
1470
 
      b->resetFlag = 1;
1471
 
   }
1472
 
 
1473
 
   /* update stats */
1474
 
   STATS_INC(b->stats.unlock);
1475
 
   if (status != BALLOON_SUCCESS) {
1476
 
      STATS_INC(b->stats.unlockFail);
1477
 
   }
1478
 
 
1479
 
   /* everything OK */
1480
 
   return(status);
1481
 
}
1482
 
 
1483
 
/*
1484
 
 * Module Operations
1485
 
 */
1486
 
 
1487
 
static int
1488
 
BalloonModuleInit(void)
1489
 
{
1490
 
   static int initialized = 0;
1491
 
   Balloon *b = &globalBalloon;
1492
 
 
1493
 
   /* initialize only once */
1494
 
   if (initialized++) {
1495
 
      return(BALLOON_FAILURE);
1496
 
   }
1497
 
 
1498
 
   /* initialize global state */
1499
 
   Balloon_Init(b);
1500
 
 
1501
 
   /* os-specific initialization */
1502
 
   os_init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
1503
 
   os_timer_init(Balloon_BH, (void *) b, os_timer_hz());
1504
 
 
1505
 
   /* start timer */
1506
 
   Balloon_StartTimer(b);
1507
 
 
1508
 
   /* everything OK */
1509
 
   return(BALLOON_SUCCESS);
1510
 
}
1511
 
 
1512
 
static void
1513
 
BalloonModuleCleanup(void)
1514
 
{
1515
 
   Balloon *b = &globalBalloon;
1516
 
 
1517
 
   /* stop timer */
1518
 
   Balloon_StopTimer(b);
1519
 
 
1520
 
   /*
1521
 
    * Deallocate all reserved memory, and reset connection with monitor.
1522
 
    * Reset connection before deallocating memory to avoid potential for
1523
 
    * additional spurious resets from guest touching deallocated pages.
1524
 
    */
1525
 
   (void) Balloon_MonitorStart(b);
1526
 
   Balloon_Deallocate(b);
1527
 
 
1528
 
   /* os-specific cleanup */
1529
 
   os_cleanup();
1530
 
}   
1531
 
 
1532
 
int init_module(void)
1533
 
{
1534
 
   return(BalloonModuleInit());
1535
 
}
1536
 
 
1537
 
void cleanup_module(void)
1538
 
{
1539
 
   BalloonModuleCleanup();
1540
 
}
1541
 
 
1542
 
#ifdef __cplusplus
1543
 
}
1544
 
#endif