~ubuntu-branches/ubuntu/precise/open-vm-tools/precise

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
440
440
/*
441
441
 *----------------------------------------------------------------------
442
442
 *
443
 
 * BalloonErrorPagesAlloc --
 
443
 * BalloonErrorPageStore --
444
444
 *
445
445
 *      Attempt to add "page" to list of non-balloonable pages
446
446
 *      associated with "b".
456
456
 */
457
457
 
458
458
static int
459
 
BalloonErrorPagesAlloc(Balloon *b,      // IN
460
 
                       PageHandle page) // IN
 
459
BalloonErrorPageStore(Balloon *b,      // IN
 
460
                      PageHandle page) // IN
461
461
{
462
462
   /* fail if list already full */
463
463
   if (b->errors.pageCount >= BALLOON_ERROR_PAGES) {
505
505
/*
506
506
 *----------------------------------------------------------------------
507
507
 *
 
508
 * BalloonGetChunk --
 
509
 *
 
510
 *      Attempt to find a "chunk" with a free slot to store locked page.
 
511
 *      Try to allocate new chunk if all existing chunks are full.
 
512
 *
 
513
 * Results:
 
514
 *      Returns NULL on failure.
 
515
 *
 
516
 * Side effects:
 
517
 *      None.
 
518
 *
 
519
 *----------------------------------------------------------------------
 
520
 */
 
521
 
 
522
static BalloonChunk *
 
523
BalloonGetChunk(Balloon *b)         // IN
 
524
{
 
525
   BalloonChunk *chunk;
 
526
 
 
527
   /* Get first chunk from the list */
 
528
   if (DblLnkLst_IsLinked(&b->chunks)) {
 
529
      chunk = DblLnkLst_Container(b->chunks.next, BalloonChunk, node);
 
530
      if (chunk->pageCount < BALLOON_CHUNK_PAGES) {
 
531
         /* This chunk has free slots, use it */
 
532
         return chunk;
 
533
      }
 
534
   }
 
535
 
 
536
   /* create new chunk */
 
537
   chunk = BalloonChunk_Create();
 
538
   if (chunk != NULL) {
 
539
      DblLnkLst_LinkFirst(&b->chunks, &chunk->node);
 
540
 
 
541
      /* update stats */
 
542
      b->nChunks++;
 
543
   }
 
544
 
 
545
   return chunk;
 
546
}
 
547
 
 
548
/*
 
549
 *----------------------------------------------------------------------
 
550
 *
 
551
 * BalloonPageStore --
 
552
 *
 
553
 *      Add "page" to the given "chunk".
 
554
 *
 
555
 * Results:
 
556
 *      None.
 
557
 *
 
558
 * Side effects:
 
559
 *      None.
 
560
 *
 
561
 *----------------------------------------------------------------------
 
562
 */
 
563
 
 
564
static void
 
565
BalloonPageStore(BalloonChunk *chunk, PageHandle page)
 
566
{
 
567
   chunk->page[chunk->pageCount++] = page;
 
568
}
 
569
 
 
570
 
 
571
/*
 
572
 *----------------------------------------------------------------------
 
573
 *
508
574
 * BalloonPageAlloc --
509
575
 *
510
576
 *      Attempts to allocate a physical page, inflating balloon "b".
523
589
BalloonPageAlloc(Balloon *b,                     // IN
524
590
                 BalloonPageAllocType allocType) // IN
525
591
{
 
592
   PageHandle page;
526
593
   BalloonChunk *chunk = NULL;
527
 
   PageHandle page;
 
594
   Bool locked;
528
595
   int status;
529
596
 
530
 
 retry:
531
 
 
532
597
   /* allocate page, fail if unable */
533
 
   STATS_INC(b->stats.primAlloc[allocType]);
534
 
 
535
 
   /*
536
 
    * Attempts to allocate and reserve a physical page.
537
 
    *
538
 
    * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
539
 
    *      The allocation can wait (sleep) for page writeout (swap) by the guest.
540
 
    * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
541
 
    *      If allocation of a page requires disk writeout, then just fail. DON'T sleep.
542
 
    *
543
 
    * Returns the physical address of the allocated page, or 0 if error.
544
 
    */
545
 
   page = OS_ReservedPageAlloc(allocType);
546
 
 
547
 
   if (page == PAGE_HANDLE_INVALID) {
548
 
      STATS_INC(b->stats.primAllocFail[allocType]);
549
 
      return BALLOON_PAGE_ALLOC_FAILURE;
550
 
   }
551
 
 
552
 
   /* Find chunk with free space, create it if necessary. */
553
 
   if (DblLnkLst_IsLinked(&b->chunks)) {
554
 
      /* Get first chunk from the list */
555
 
      chunk = DblLnkLst_Container(b->chunks.next, BalloonChunk, node);
556
 
      if (chunk->pageCount >= BALLOON_CHUNK_PAGES) {
557
 
         /* This chunk is full. */
558
 
         chunk = NULL;
559
 
      }
560
 
   }
561
 
 
562
 
   if (chunk == NULL) {
563
 
      /* create new chunk */
564
 
      chunk = BalloonChunk_Create();
565
 
      if (chunk == NULL) {
566
 
         /* reclaim storage, fail */
567
 
         OS_ReservedPageFree(page);
 
598
   do {
 
599
      STATS_INC(b->stats.primAlloc[allocType]);
 
600
 
 
601
      /*
 
602
       * Attempts to allocate and reserve a physical page.
 
603
       *
 
604
       * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
 
605
       *      The allocation can wait (sleep) for page writeout (swap) by the guest.
 
606
       * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
 
607
       *      If allocation of a page requires disk writeout, then just fail. DON'T sleep.
 
608
       *
 
609
       * Returns the physical address of the allocated page, or 0 if error.
 
610
       */
 
611
      page = OS_ReservedPageAlloc(allocType);
 
612
      if (page == PAGE_HANDLE_INVALID) {
 
613
         STATS_INC(b->stats.primAllocFail[allocType]);
568
614
         return BALLOON_PAGE_ALLOC_FAILURE;
569
615
      }
570
616
 
571
 
      DblLnkLst_LinkFirst(&b->chunks, &chunk->node);
572
 
 
573
 
      /* update stats */
574
 
      b->nChunks++;
575
 
   }
576
 
 
577
 
   /* inform monitor via backdoor */
578
 
   status = BalloonMonitorLockPage(b, page);
579
 
   if (status != BALLOON_SUCCESS) {
580
 
      /* place on list of non-balloonable pages, retry allocation */
581
 
      if ((status != BALLOON_ERROR_RESET) &&
582
 
          (BalloonErrorPagesAlloc(b, page) == BALLOON_SUCCESS)) {
583
 
         goto retry;
584
 
      }
585
 
 
586
 
      /* reclaim storage, fail */
587
 
      OS_ReservedPageFree(page);
588
 
      return status;
589
 
   }
 
617
      /* Get the chunk to store allocated page. */
 
618
      if (!chunk) {
 
619
         chunk = BalloonGetChunk(b);
 
620
         if (!chunk) {
 
621
            OS_ReservedPageFree(page);
 
622
            return BALLOON_PAGE_ALLOC_FAILURE;
 
623
         }
 
624
      }
 
625
 
 
626
      /* inform monitor via backdoor */
 
627
      status = BalloonMonitorLockPage(b, page);
 
628
      locked = status == BALLOON_SUCCESS;
 
629
      if (!locked) {
 
630
         if (status == BALLOON_ERROR_RESET ||
 
631
             status == BALLOON_ERROR_PPN_NOTNEEDED) {
 
632
            OS_ReservedPageFree(page);
 
633
            return status;
 
634
         }
 
635
 
 
636
         /* place on list of non-balloonable pages, retry allocation */
 
637
         status = BalloonErrorPageStore(b, page);
 
638
         if (status != BALLOON_SUCCESS) {
 
639
            OS_ReservedPageFree(page);
 
640
            return status;
 
641
         }
 
642
      }
 
643
   } while (!locked);
590
644
 
591
645
   /* track allocated page */
592
 
   chunk->page[chunk->pageCount++] = page;
 
646
   BalloonPageStore(chunk, page);
593
647
 
594
648
   /* update balloon size */
595
649
   b->nPages++;
596
650
 
597
 
   return BALLOON_SUCCESS;
 
651
   return status;
598
652
}
599
653
 
600
654
 
682
736
/*
683
737
 *----------------------------------------------------------------------
684
738
 *
685
 
 * BalloonDecreaseRateAlloc --
686
 
 *
687
 
 *      Wrapper to quickly reduce the page allocation rate. This function
688
 
 *      is called only when a CANSLEEP allocation fails. This implies severe
689
 
 *      memory pressure inside the guest, so quickly decrease the rateAlloc.
690
 
 *
691
 
 * Results:
692
 
 *      None.
693
 
 *
694
 
 * Side effects:
695
 
 *      None.
696
 
 *
697
 
 *----------------------------------------------------------------------
698
 
 */
699
 
 
700
 
static void
701
 
BalloonDecreaseRateAlloc(Balloon *b) // IN
702
 
{
703
 
   if (BALLOON_RATE_ADAPT) {
704
 
      b->rateAlloc = MAX(b->rateAlloc / 2, BALLOON_RATE_ALLOC_MIN);
705
 
   }
706
 
}
707
 
 
708
 
 
709
 
/*
710
 
 *----------------------------------------------------------------------
711
 
 *
712
 
 * BalloonIncreaseRateAlloc --
713
 
 *
714
 
 *      Wrapper to increase the page allocation rate.
715
 
 *
716
 
 *      This function is called when the balloon target is met or
717
 
 *      b->rateAlloc (or more) pages have been successfully allocated.
718
 
 *      This implies that the guest may not be under high memory
719
 
 *      pressure. So let us increase the rateAlloc.
720
 
 *
721
 
 *      If meeting balloon target requires less than b->rateAlloc
722
 
 *      pages, then we do not change the page allocation rate.
723
 
 *
724
 
 *      If the number of pages successfully allocated (nAlloc) is far
725
 
 *      higher than b->rateAlloc, then it implies that NOSLEEP
726
 
 *      allocations are highly successful. Therefore, we predict that
727
 
 *      the guest is under no memory pressure, and so increase
728
 
 *      b->rateAlloc quickly.
729
 
 *
730
 
 * Results:
731
 
 *      None.
732
 
 *
733
 
 * Side effects:
734
 
 *      None.
735
 
 *
736
 
 *----------------------------------------------------------------------
737
 
 */
738
 
 
739
 
static void
740
 
BalloonIncreaseRateAlloc(Balloon *b,    // IN
741
 
                         uint32 nAlloc) // IN
742
 
{
743
 
   if (BALLOON_RATE_ADAPT) {
744
 
      if (nAlloc >= b->rateAlloc) {
745
 
         uint32 mult = nAlloc / b->rateAlloc;
746
 
         b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC,
747
 
                            BALLOON_RATE_ALLOC_MAX);
748
 
      }
749
 
   }
750
 
}
751
 
 
752
 
 
753
 
/*
754
 
 *----------------------------------------------------------------------
755
 
 *
756
739
 * BalloonInflate--
757
740
 *
758
741
 *      Attempts to allocate physical pages to inflate balloon.
770
753
BalloonInflate(Balloon *b,    // IN
771
754
               uint32 target) // IN
772
755
{
773
 
   int status, allocations = 0;
774
 
   uint32 i, nAllocNoSleep, nAllocCanSleep;
 
756
   unsigned int goal;
 
757
   unsigned int rate;
 
758
   unsigned int i;
 
759
   unsigned int allocations = 0;
 
760
   int status = 0;
 
761
   BalloonPageAllocType allocType = BALLOON_PAGE_ALLOC_NOSLEEP;
775
762
 
776
763
   /*
777
764
    * First try NOSLEEP page allocations to inflate balloon.
787
774
    * predicted that the guest is under memory pressure, then we
788
775
    * slowdown page allocations considerably.
789
776
    */
790
 
   if (b->slowPageAllocationCycles > 0) {
791
 
      nAllocNoSleep = MIN(target - b->nPages, b->rateAlloc);
792
 
   } else {
793
 
      nAllocNoSleep = MIN(target - b->nPages, BALLOON_NOSLEEP_ALLOC_MAX);
794
 
   }
795
 
 
796
 
   for (i = 0; i < nAllocNoSleep; i++) {
797
 
      /* Try NOSLEEP allocation */
798
 
      status = BalloonPageAlloc(b, BALLOON_PAGE_ALLOC_NOSLEEP);
 
777
 
 
778
   goal = target - b->nPages;
 
779
   /*
 
780
    * Start with no sleep allocation rate which may be higher
 
781
    * than sleeping allocation rate.
 
782
    */
 
783
   rate = b->slowPageAllocationCycles ?
 
784
                b->rateAlloc : BALLOON_NOSLEEP_ALLOC_MAX;
 
785
 
 
786
   for (i = 0; i < goal; i++) {
 
787
 
 
788
      status = BalloonPageAlloc(b, allocType);
799
789
      if (status != BALLOON_SUCCESS) {
800
790
         if (status != BALLOON_PAGE_ALLOC_FAILURE) {
801
791
            /*
802
 
             * Not a page allocation failure, so release non-balloonable
803
 
             * pages, and fail.
804
 
             */
805
 
            BalloonErrorPagesFree(b);
806
 
            return status;
807
 
         }
 
792
             * Not a page allocation failure, stop this cycle.
 
793
             * Maybe we'll get new target from the host soon.
 
794
             */
 
795
            break;
 
796
         }
 
797
 
 
798
         if (allocType == BALLOON_PAGE_ALLOC_CANSLEEP) {
 
799
            /*
 
800
             * CANSLEEP page allocation failed, so guest is under severe
 
801
             * memory pressure. Quickly decrease allocation rate.
 
802
             */
 
803
            b->rateAlloc = MAX(b->rateAlloc / 2, BALLOON_RATE_ALLOC_MIN);
 
804
            break;
 
805
         }
 
806
 
808
807
         /*
809
808
          * NOSLEEP page allocation failed, so the guest is under memory
810
 
          * pressure. Let us slowdown page allocations for next few
811
 
          * cycles so that the guest gets out of memory pressure.
 
809
          * pressure. Let us slow down page allocations for next few cycles
 
810
          * so that the guest gets out of memory pressure. Also, if we
 
811
          * already allocated b->rateAlloc pages, let's pause, otherwise
 
812
          * switch to sleeping allocations.
812
813
          */
813
814
         b->slowPageAllocationCycles = SLOW_PAGE_ALLOCATION_CYCLES;
 
815
 
 
816
         if (i >= b->rateAlloc)
 
817
            break;
 
818
 
 
819
         allocType = BALLOON_PAGE_ALLOC_CANSLEEP;
 
820
         /* Lower rate for sleeping allocations. */
 
821
         rate = b->rateAlloc;
 
822
      }
 
823
 
 
824
      if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
 
825
         OS_Yield();
 
826
         allocations = 0;
 
827
      }
 
828
 
 
829
      if (i >= rate) {
 
830
         /* We allocated enough pages, let's take a break. */
814
831
         break;
815
832
      }
816
 
 
817
 
      if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
818
 
         OS_Yield();
819
 
         allocations = 0;
820
 
      }
821
 
   }
822
 
 
823
 
   /*
824
 
    * Check whether nosleep allocation successfully zapped nAllocNoSleep
825
 
    * pages.
826
 
    */
827
 
   if (i == nAllocNoSleep) {
828
 
      BalloonIncreaseRateAlloc(b, nAllocNoSleep);
829
 
      /* release non-balloonable pages, succeed */
830
 
      BalloonErrorPagesFree(b);
831
 
      return BALLOON_SUCCESS;
832
 
   } else {
833
 
      /*
834
 
       * NOSLEEP allocation failed, so the guest is under memory pressure.
835
 
       * If already b->rateAlloc pages were zapped, then succeed. Otherwise,
836
 
       * try CANSLEEP allocation.
837
 
       */
838
 
      if (i > b->rateAlloc) {
839
 
         BalloonIncreaseRateAlloc(b, i);
840
 
         /* release non-balloonable pages, succeed */
841
 
         BalloonErrorPagesFree(b);
842
 
         return BALLOON_SUCCESS;
843
 
      } else {
844
 
         /* update successful NOSLEEP allocations, and proceed */
845
 
         nAllocNoSleep = i;
846
 
      }
847
 
   }
848
 
 
849
 
   /*
850
 
    * Use CANSLEEP page allocation to inflate balloon if below target.
851
 
    *
852
 
    * Sleep allocations are required only when nosleep allocation fails.
853
 
    * This implies that the guest is already under memory pressure, so
854
 
    * let us always throttle canSleep allocations. The total number pages
855
 
    * allocated using noSleep and canSleep methods is throttled at
856
 
    * b->rateAlloc per second when the guest is under memory pressure.
857
 
    */
858
 
   nAllocCanSleep = target - b->nPages;
859
 
   nAllocCanSleep = MIN(nAllocCanSleep, b->rateAlloc - nAllocNoSleep);
860
 
 
861
 
   for (i = 0; i < nAllocCanSleep; i++) {
862
 
      /* Try CANSLEEP allocation */
863
 
      status = BalloonPageAlloc(b, BALLOON_PAGE_ALLOC_CANSLEEP);
864
 
      if(status != BALLOON_SUCCESS) {
865
 
         if (status == BALLOON_PAGE_ALLOC_FAILURE) {
866
 
            /*
867
 
             * CANSLEEP page allocation failed, so guest is under severe
868
 
             * memory pressure. Quickly decrease rateAlloc.
869
 
             */
870
 
            BalloonDecreaseRateAlloc(b);
871
 
         }
872
 
         /* release non-balloonable pages, fail */
873
 
         BalloonErrorPagesFree(b);
874
 
         return status;
875
 
      }
876
 
 
877
 
      if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
878
 
         OS_Yield();
879
 
         allocations = 0;
880
 
      }
881
 
   }
882
 
 
883
 
   /*
884
 
    * Either met the balloon target or b->rateAlloc pages have been
885
 
    * successfully zapped.
886
 
    */
887
 
   BalloonIncreaseRateAlloc(b, nAllocNoSleep + nAllocCanSleep);
 
833
   }
 
834
 
 
835
   /*
 
836
    * We reached our goal without failures so try increasing
 
837
    * allocation rate.
 
838
    */
 
839
   if (status == BALLOON_SUCCESS && i >= b->rateAlloc) {
 
840
      unsigned int mult = i / b->rateAlloc;
 
841
 
 
842
      b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC,
 
843
                         BALLOON_RATE_ALLOC_MAX);
 
844
   }
888
845
 
889
846
   /* release non-balloonable pages, succeed */
890
847
   BalloonErrorPagesFree(b);
1037
994
   uint32 status, target;
1038
995
   Backdoor_proto bp;
1039
996
 
1040
 
   ASSERT(b->guestType == (uint32) b->guestType);
1041
 
 
1042
997
   /* prepare backdoor args */
1043
998
   bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_GUEST_ID;
1044
999
   bp.in.size = b->guestType;