Print this page
OS-11 rcapd behaves poorly when under extreme load
OS-399 zone phys. mem. cap should be a rctl and have associated kstat
        
*** 19,99 ****
   * CDDL HEADER END
   */
  /*
   * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
   * Use is subject to license terms.
   */
  
- #pragma ident   "%Z%%M% %I%     %E% SMI"
- 
  #include <procfs.h>
  #include <project.h>
  #include <stdlib.h>
  #include <strings.h>
  #include <zone.h>
  #include <libzonecfg.h>
  #include "rcapd.h"
  #include "utils.h"
  
  extern boolean_t gz_capped;
  
                                  /* round up to next y = 2^n */
  #define ROUNDUP(x, y)           (((x) + ((y) - 1)) & ~((y) - 1))
  
! static void
! update_zone(zone_entry_t *zent, void *walk_data)
  {
!         void(*update_notification_cb)(char *, char *, int, uint64_t, int) =
!             (void(*)(char *, char *, int, uint64_t, int))walk_data;
!         int changes;
!         int64_t max_rss;
          uint64_t mcap;
!         lcollection_t *lcol;
!         rcid_t colid;
  
!         if (zone_getattr(zent->zid, ZONE_ATTR_PHYS_MCAP, &mcap,
!             sizeof (mcap)) != -1 && mcap != 0)
!                 max_rss = ROUNDUP(mcap, 1024) / 1024;
!         else
!                 max_rss = 0;
  
!         if (zent->zid == GLOBAL_ZONEID) {
!                 if (max_rss > 0)
!                         gz_capped = B_TRUE;
!                 else
!                         gz_capped = B_FALSE;
          }
  
  
!         colid.rcid_type = RCIDT_ZONE;
!         colid.rcid_val = zent->zid;
  
!         lcol = lcollection_insert_update(&colid, max_rss, zent->zname,
!             &changes);
!         if (update_notification_cb != NULL)
!                 update_notification_cb("zone", zent->zname, changes, max_rss,
!                     (lcol != NULL) ? lcol->lcol_mark : 0);
  }
  
! 
  /* ARGSUSED */
  void
  lcollection_update_zone(lcollection_update_type_t ut,
      void(*update_notification_cb)(char *, char *, int, uint64_t, int))
  {
!         int i;
!         uint_t nzents;
!         zone_entry_t *zents;
  
!         /*
!          * Enumerate running zones.
!          */
!         if (get_running_zones(&nzents, &zents) != 0)
!                 return;
! 
!         for (i = 0; i < nzents; i++) {
!                 update_zone(&zents[i], (void *)update_notification_cb);
! 
          }
  
!         free(zents);
  }
--- 19,156 ----
   * CDDL HEADER END
   */
  /*
   * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
   * Use is subject to license terms.
+  * Copyright 2011 Joyent, Inc.  All rights reserved.
   */
  
  #include <procfs.h>
  #include <project.h>
  #include <stdlib.h>
  #include <strings.h>
  #include <zone.h>
  #include <libzonecfg.h>
+ #include <dirent.h>
+ #include <libproc.h>
  #include "rcapd.h"
  #include "utils.h"
  
  extern boolean_t gz_capped;
  
                                  /* round up to next y = 2^n */
  #define ROUNDUP(x, y)           (((x) + ((y) - 1)) & ~((y) - 1))
  
! static struct ps_prochandle *
! grab_zone_proc(zoneid_t zid)
  {
!         DIR *dirp;
!         struct dirent *dentp;
!         int pid, pid_self, tmp;
!         psinfo_t psinfo;
!         struct ps_prochandle *pr = NULL;
! 
!         pid_self = getpid();
! 
!         if ((dirp = opendir("/proc")) == NULL)
!                 return (NULL);
! 
!         while (dentp = readdir(dirp)) {
!                 pid = atoi(dentp->d_name);
! 
!                 /* Skip self */
!                 if (pid == pid_self)
!                         continue;
! 
!                 if (proc_get_psinfo(pid, &psinfo) != 0)
!                         continue;
! 
!                 if (psinfo.pr_zoneid != zid)
!                         continue;
! 
!                 /* attempt to grab process */
!                 if ((pr = Pgrab(pid, 0, &tmp)) != NULL) {
!                         if (Psetflags(pr, PR_RLC) != 0) {
!                                 Prelease(pr, 0);
!                         }
!                         if (Pcreate_agent(pr) == 0) {
!                                 if (pr_getzoneid(pr) != zid) {
!                                         Prelease(pr, 0);
!                                         continue;
!                                 }
! 
!                                 (void) closedir(dirp);
!                                 return (pr);
!                         } else {
!                                 Prelease(pr, 0);
!                         }
!                 }
!         }
! 
!         (void) closedir(dirp);
!         return (NULL);
! }
! 
! static uint64_t
! get_zone_cap(zoneid_t zid)
! {
!         rctlblk_t *rblk;
          uint64_t mcap;
!         struct ps_prochandle *pr;
  
!         if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL)
!                 return (UINT64_MAX);
  
!         if ((pr = grab_zone_proc(zid)) == NULL) {
!                 free(rblk);
!                 return (UINT64_MAX);
          }
  
+         if (pr_getrctl(pr, "zone.max-physical-memory", NULL, rblk,
+             RCTL_FIRST)) {
+                 Pdestroy_agent(pr);
+                 Prelease(pr, 0);
+                 free(rblk);
+                 return (UINT64_MAX);
+         }
  
!         Pdestroy_agent(pr);
!         Prelease(pr, 0);
  
!         mcap = rctlblk_get_value(rblk);
!         free(rblk);
!         return (mcap);
  }
  
! /*
!  * For zones, rcapd only caps the global zone, since each non-global zone
!  * caps itself.
!  */
  /* ARGSUSED */
  void
  lcollection_update_zone(lcollection_update_type_t ut,
      void(*update_notification_cb)(char *, char *, int, uint64_t, int))
  {
!         int changes;
!         int64_t max_rss;
!         uint64_t mcap;
!         lcollection_t *lcol;
!         rcid_t colid;
  
!         mcap = get_zone_cap(GLOBAL_ZONEID);
!         if (mcap != 0 && mcap != UINT64_MAX) {
!                 max_rss = ROUNDUP(mcap, 1024) / 1024;
!                 gz_capped = B_TRUE;
!         } else {
!                 max_rss = UINT64_MAX / 1024;
!                 gz_capped = B_FALSE;
          }
  
!         colid.rcid_type = RCIDT_ZONE;
!         colid.rcid_val = GLOBAL_ZONEID;
! 
!         lcol = lcollection_insert_update(&colid, max_rss, GLOBAL_ZONENAME,
!             &changes);
!         if (update_notification_cb != NULL)
!                 update_notification_cb("zone", GLOBAL_ZONENAME, changes,
!                     max_rss, (lcol != NULL) ? lcol->lcol_mark : 0);
  }