]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/ledger.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / osfmk / kern / ledger.c
index 983e51b9c522d9c82431ca05cffdeb4a4da6fc9f..001cad83b4e3ea2e95fc492a654b6d6ecaa9e564 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2010-2018 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -44,6 +44,9 @@
 
 #include <libkern/OSAtomic.h>
 #include <mach/mach_types.h>
+#include <os/overflow.h>
+
+#include <vm/pmap.h>
 
 /*
  * Ledger entry flags. Bits in second nibble (masked by 0xF0) are used for
@@ -56,7 +59,7 @@
 #define        LF_REFILL_INPROGRESS    0x0800  /* the ledger is being refilled */
 #define        LF_CALLED_BACK          0x1000  /* callback was called for balance in deficit */
 #define        LF_WARNED               0x2000  /* callback was called for balance warning */ 
-#define        LF_TRACKING_MAX         0x4000  /* track max balance over user-specfied time */
+#define        LF_TRACKING_MAX         0x4000  /* track max balance. Exclusive w.r.t refill */
 #define LF_PANIC_ON_NEGATIVE   0x8000  /* panic if it goes negative */
 #define LF_TRACK_CREDIT_ONLY   0x10000 /* only update "credit" */
 
@@ -111,6 +114,8 @@ struct ledger_template {
        int                     lt_table_size;
        volatile uint32_t       lt_inuse;
        lck_mtx_t               lt_lock;
+       zone_t                  lt_zone;
+       bool                    lt_initialized;
        struct entry_template   *lt_entries;
 };
 
@@ -128,44 +133,6 @@ struct ledger_template {
        splx(s);                                                \
 }
 
-/*
- * Use 2 "tocks" to track the rolling maximum balance of a ledger entry.
- */
-#define        NTOCKS 2
-/*
- * The explicit alignment is to ensure that atomic operations don't panic
- * on ARM.
- */
-struct ledger_entry {
-        volatile uint32_t               le_flags;
-        ledger_amount_t                 le_limit;
-        ledger_amount_t                 le_warn_level;
-        volatile ledger_amount_t        le_credit __attribute__((aligned(8)));
-        volatile ledger_amount_t        le_debit  __attribute__((aligned(8)));
-       union {
-               struct {
-                       /*
-                        * XXX - the following two fields can go away if we move all of
-                        * the refill logic into process policy
-                        */
-                       uint64_t        le_refill_period;
-                       uint64_t        le_last_refill;
-               } le_refill;
-               struct _le_peak {
-                       uint32_t        le_max;  /* Lower 32-bits of observed max balance */
-                       uint32_t        le_time; /* time when this peak was observed */
-               } le_peaks[NTOCKS];
-       } _le;
-} __attribute__((aligned(8)));
-
-struct ledger {
-       uint64_t                l_id;
-       int32_t                 l_refs;
-       int32_t                 l_size;
-       struct ledger_template  *l_template;
-       struct ledger_entry     l_entries[0] __attribute__((aligned(8)));
-};
-
 static int ledger_cnt = 0;
 /* ledger ast helper functions */
 static uint32_t ledger_check_needblock(ledger_t l, uint64_t now);
@@ -173,8 +140,8 @@ static kern_return_t ledger_perform_blocking(ledger_t l);
 static uint32_t flag_set(volatile uint32_t *flags, uint32_t bit);
 static uint32_t flag_clear(volatile uint32_t *flags, uint32_t bit);
 
-static void ledger_entry_check_new_balance(ledger_t ledger, int entry,
-                                          struct ledger_entry *le);
+static void ledger_entry_check_new_balance(thread_t thread, ledger_t ledger,
+                                           int entry, struct ledger_entry *le);
 
 #if 0
 static void
@@ -225,6 +192,7 @@ ledger_template_create(const char *name)
        template->lt_cnt = 0;
        template->lt_table_size = 1;
        template->lt_inuse = 0;
+       template->lt_zone = NULL;
        lck_mtx_init(&template->lt_lock, &ledger_lck_grp, LCK_ATTR_NULL);
 
        template->lt_entries = (struct entry_template *)
@@ -261,7 +229,7 @@ ledger_entry_add(ledger_template_t template, const char *key,
        int idx;
        struct entry_template *et;
 
-       if ((key == NULL) || (strlen(key) >= LEDGER_NAME_MAX))
+       if ((key == NULL) || (strlen(key) >= LEDGER_NAME_MAX) || (template->lt_zone != NULL))
                return (-1);
 
        template_lock(template);
@@ -269,18 +237,24 @@ ledger_entry_add(ledger_template_t template, const char *key,
        /* If the table is full, attempt to double its size */
        if (template->lt_cnt == template->lt_table_size) {
                struct entry_template *new_entries, *old_entries;
-               int old_cnt, old_sz;
+               int old_cnt, old_sz, new_sz = 0;
                spl_t s;
 
                old_cnt = template->lt_table_size;
-               old_sz = (int)(old_cnt * sizeof (struct entry_template));
-               new_entries = kalloc(old_sz * 2);
+               old_sz = old_cnt * (int)(sizeof(struct entry_template));
+               /* double old_sz allocation, but check for overflow */
+               if (os_mul_overflow(old_sz, 2, &new_sz)) {
+                       template_unlock(template);
+                       return -1;
+               }
+               new_entries = kalloc(new_sz);
                if (new_entries == NULL) {
                        template_unlock(template);
-                       return (-1);
+                       return -1;
                }
                memcpy(new_entries, template->lt_entries, old_sz);
                memset(((char *)new_entries) + old_sz, 0, old_sz);
+               /* assume: if the sz didn't overflow, neither will the count */
                template->lt_table_size = old_cnt * 2;
 
                old_entries = template->lt_entries;
@@ -340,6 +314,38 @@ ledger_key_lookup(ledger_template_t template, const char *key)
        return (idx);
 }
 
+/*
+ * Complete the initialization of ledger template
+ * by initializing ledger zone. After initializing
+ * the ledger zone, adding an entry in the ledger
+ * template would fail.
+ */
+void
+ledger_template_complete(ledger_template_t template)
+{
+       size_t ledger_size;
+       ledger_size = sizeof(struct ledger) + (template->lt_cnt * sizeof(struct ledger_entry));
+       template->lt_zone = zinit(ledger_size, CONFIG_TASK_MAX * ledger_size,
+                              ledger_size,
+                              template->lt_name);
+       template->lt_initialized = true;
+}
+
+/*
+ * Like ledger_template_complete, except we'll ask
+ * the pmap layer to manage allocations for us.
+ * Meant for ledgers that should be owned by the
+ * pmap layer.
+ */
+void
+ledger_template_complete_secure_alloc(ledger_template_t template)
+{
+       size_t ledger_size;
+       ledger_size = sizeof(struct ledger) + (template->lt_cnt * sizeof(struct ledger_entry));
+       pmap_ledger_alloc_init(ledger_size);
+       template->lt_initialized = true;
+}
+
 /*
  * Create a new ledger based on the specified template.  As part of the
  * ledger creation we need to allocate space for a table of ledger entries.
@@ -351,7 +357,7 @@ ledger_t
 ledger_instantiate(ledger_template_t template, int entry_type)
 {
        ledger_t ledger;
-       size_t cnt, sz;
+       size_t cnt;
        int i;
 
        template_lock(template);
@@ -359,9 +365,12 @@ ledger_instantiate(ledger_template_t template, int entry_type)
        cnt = template->lt_cnt;
        template_unlock(template);
 
-       sz = sizeof(*ledger) + (cnt * sizeof(struct ledger_entry));
+       if (template->lt_zone) {
+               ledger = (ledger_t)zalloc(template->lt_zone);
+       } else {
+               ledger = pmap_ledger_alloc();
+       }
 
-       ledger = (ledger_t)kalloc(sz);
        if (ledger == NULL) {
                ledger_template_dereference(template);
                return LEDGER_NULL;
@@ -450,8 +459,11 @@ ledger_dereference(ledger_t ledger)
 
        /* Just released the last reference.  Free it. */
        if (v == 1) {
-               kfree(ledger,
-                     sizeof(*ledger) + ledger->l_size * sizeof(struct ledger_entry));
+               if (ledger->l_template->lt_zone) {
+                       zfree(ledger->l_template->lt_zone, ledger);
+               } else {
+                       pmap_ledger_free(ledger);
+               }
        }
 
        return (KERN_SUCCESS);
@@ -604,10 +616,11 @@ ledger_refill(uint64_t now, ledger_t ledger, int entry)
 
        balance = le->le_credit - le->le_debit;
        due = periods * le->le_limit;
+
        if (balance - due < 0)
                due = balance;
 
-       assert(due >= 0);
+       assertf(due >= 0,"now=%llu, ledger=%p, entry=%d, balance=%lld, due=%lld", now, ledger, entry, balance, due);
 
        OSAddAtomic64(due, &le->le_debit);
 
@@ -630,72 +643,28 @@ ledger_refill(uint64_t now, ledger_t ledger, int entry)
                ledger_limit_entry_wakeup(le);
 }
 
-/*
- * In tenths of a second, the length of one lookback period (a "tock") for
- * ledger rolling maximum calculations. The effective lookback window will be this times
- * NTOCKS.
- *
- * Use a tock length of 2.5 seconds to get a total lookback period of 5 seconds.
- *
- * XXX Could make this caller-definable, at the point that rolling max tracking
- * is enabled for the entry.
- */
-#define        TOCKLEN 25
-
-/*
- * How many sched_tick's are there in one tock (one of our lookback periods)?
- *
- *  X sched_ticks        2.5 sec      N sched_ticks
- * ---------------   =  ----------  * -------------
- *      tock               tock            sec
- *
- * where N sched_ticks/sec is calculated via 1 << SCHED_TICK_SHIFT (see sched_prim.h)
- *
- * This should give us 20 sched_tick's in one 2.5 second-long tock.
- */
-#define SCHED_TICKS_PER_TOCK ((TOCKLEN * (1 << SCHED_TICK_SHIFT)) / 10)
-
-/*
- * Rolling max timestamps use their own unit (let's call this a "tock"). One tock is the
- * length of one lookback period that we use for our rolling max calculation.
- *
- * Calculate the current time in tocks from sched_tick (which runs at a some
- * fixed rate).
- */
-#define        CURRENT_TOCKSTAMP() (sched_tick / SCHED_TICKS_PER_TOCK)
-
-/*
- * Does the given tockstamp fall in either the current or the previous tocks?
- */
-#define TOCKSTAMP_IS_STALE(now, tock) ((((now) - (tock)) < NTOCKS) ? FALSE : TRUE)
-
 void
-ledger_entry_check_new_balance(ledger_t ledger, int entry, struct ledger_entry *le)
+ledger_entry_check_new_balance(thread_t thread, ledger_t ledger,
+                               int entry, struct ledger_entry *le)
 {
-       ledger_amount_t credit, debit;
-
        if (le->le_flags & LF_TRACKING_MAX) {
                ledger_amount_t balance = le->le_credit - le->le_debit;
-               uint32_t now = CURRENT_TOCKSTAMP();
-               struct _le_peak *p = &le->_le.le_peaks[now % NTOCKS];
 
-               if (!TOCKSTAMP_IS_STALE(now, p->le_time) || (balance > p->le_max)) {
-                       /*
-                        * The current balance is greater than the previously
-                        * observed peak for the current time block, *or* we
-                        * haven't yet recorded a peak for the current time block --
-                        * so this is our new peak.
-                        *
-                        * (We only track the lower 32-bits of a balance for rolling
-                        * max purposes.)
-                        */
-                       p->le_max = (uint32_t)balance;
-                       p->le_time = now;
+               if (balance > le->_le._le_max.le_lifetime_max){
+                       le->_le._le_max.le_lifetime_max = balance;
                }
+
+#if CONFIG_LEDGER_INTERVAL_MAX
+               if (balance > le->_le._le_max.le_interval_max) {
+                       le->_le._le_max.le_interval_max = balance;
+               }
+#endif /* LEDGER_CONFIG_INTERVAL_MAX */
        }
 
        /* Check to see whether we're due a refill */
        if (le->le_flags & LF_REFILL_SCHEDULED) {
+               assert(!(le->le_flags & LF_TRACKING_MAX));
+
                uint64_t now = mach_absolute_time();
                if ((now - le->_le.le_refill.le_last_refill) > le->_le.le_refill.le_refill_period)
                        ledger_refill(now, ledger, entry);
@@ -715,7 +684,7 @@ ledger_entry_check_new_balance(ledger_t ledger, int entry, struct ledger_entry *
                if ((le->le_flags & LEDGER_ACTION_BLOCK) ||
                    (!(le->le_flags & LF_CALLED_BACK) &&
                    entry_get_callback(ledger, entry))) {
-                       set_astledger(current_thread());
+                       act_set_astledger_async(thread);
                }
        } else {
                /*
@@ -744,7 +713,7 @@ ledger_entry_check_new_balance(ledger_t ledger, int entry, struct ledger_entry *
                                         * set the AST so it can be done before returning
                                         * to userland.
                                         */
-                                       set_astledger(current_thread());
+                                       act_set_astledger_async(thread);
                                }
                        } else {
                                /*
@@ -758,40 +727,36 @@ ledger_entry_check_new_balance(ledger_t ledger, int entry, struct ledger_entry *
                                         * know the ledger balance is now back below
                                         * the warning level.
                                         */
-                                       set_astledger(current_thread());
+                                       act_set_astledger_async(thread);
                                }
                        }
                }
        }
 
-       credit = le->le_credit;
-       debit = le->le_debit;
        if ((le->le_flags & LF_PANIC_ON_NEGATIVE) &&
-           ((credit < debit) ||
-            (le->le_credit < le->le_debit))) {
-               panic("ledger_entry_check_new_balance(%p,%d): negative ledger %p credit:%lld/%lld debit:%lld/%lld balance:%lld/%lld\n",
+           (le->le_credit < le->le_debit)) {
+               panic("ledger_entry_check_new_balance(%p,%d): negative ledger %p credit:%lld debit:%lld balance:%lld\n",
                      ledger, entry, le,
-                     credit, le->le_credit,
-                     debit, le->le_debit,
-                     credit - debit, le->le_credit - le->le_debit);
+                     le->le_credit,
+                     le->le_debit,
+                     le->le_credit - le->le_debit);
        }
 }
 
 void
-ledger_check_new_balance(ledger_t ledger, int entry)
+ledger_check_new_balance(thread_t thread, ledger_t ledger, int entry)
 {
        struct ledger_entry *le;
        assert(entry > 0 && entry <= ledger->l_size);
        le = &ledger->l_entries[entry];
-       ledger_entry_check_new_balance(ledger, entry, le);
+       ledger_entry_check_new_balance(thread, ledger, entry, le);
 }
 
-
 /*
- * Add value to an entry in a ledger.
+ * Add value to an entry in a ledger for a specific thread.
  */
 kern_return_t
-ledger_credit(ledger_t ledger, int entry, ledger_amount_t amount)
+ledger_credit_thread(thread_t thread, ledger_t ledger, int entry, ledger_amount_t amount)
 {
        ledger_amount_t old, new;
        struct ledger_entry *le;
@@ -806,12 +771,33 @@ ledger_credit(ledger_t ledger, int entry, ledger_amount_t amount)
 
        old = OSAddAtomic64(amount, &le->le_credit);
        new = old + amount;
-       lprintf(("%p Credit %lld->%lld\n", current_thread(), old, new));
-       ledger_entry_check_new_balance(ledger, entry, le);
+       lprintf(("%p Credit %lld->%lld\n", thread, old, new));
+
+       if (thread) {
+               ledger_entry_check_new_balance(thread, ledger, entry, le);
+       }
 
        return (KERN_SUCCESS);
 }
 
+/*
+ * Add value to an entry in a ledger.
+ */
+kern_return_t
+ledger_credit(ledger_t ledger, int entry, ledger_amount_t amount)
+{
+       return ledger_credit_thread(current_thread(), ledger, entry, amount);
+}
+
+/*
+ * Add value to an entry in a ledger; do not check balance after update.
+ */
+kern_return_t
+ledger_credit_nocheck(ledger_t ledger, int entry, ledger_amount_t amount)
+{
+       return ledger_credit_thread(NULL, ledger, entry, amount);
+}
+
 /* Add all of one ledger's values into another.
  * They must have been created from the same template.
  * This is not done atomically. Another thread (if not otherwise synchronized)
@@ -824,17 +810,32 @@ kern_return_t
 ledger_rollup(ledger_t to_ledger, ledger_t from_ledger)
 {
        int i;
-       struct ledger_entry *from_le, *to_le;
 
        assert(to_ledger->l_template == from_ledger->l_template);
 
        for (i = 0; i < to_ledger->l_size; i++) {
-               if (ENTRY_VALID(from_ledger, i) && ENTRY_VALID(to_ledger, i)) {
-                       from_le = &from_ledger->l_entries[i];
-                       to_le   =   &to_ledger->l_entries[i];
-                       OSAddAtomic64(from_le->le_credit, &to_le->le_credit);
-                       OSAddAtomic64(from_le->le_debit,  &to_le->le_debit);
-               }
+               ledger_rollup_entry(to_ledger, from_ledger, i);
+       }
+
+       return (KERN_SUCCESS);
+}
+
+/* Add one ledger entry value to another.
+ * They must have been created from the same template.
+ * Since the credit and debit values are added one
+ * at a time, other thread might read the a bogus value.
+ */
+kern_return_t
+ledger_rollup_entry(ledger_t to_ledger, ledger_t from_ledger, int entry)
+{
+       struct ledger_entry *from_le, *to_le;
+
+       assert(to_ledger->l_template == from_ledger->l_template);
+       if (ENTRY_VALID(from_ledger, entry) && ENTRY_VALID(to_ledger, entry)) {
+               from_le = &from_ledger->l_entries[entry];
+               to_le   =   &to_ledger->l_entries[entry];
+               OSAddAtomic64(from_le->le_credit, &to_le->le_credit);
+               OSAddAtomic64(from_le->le_debit,  &to_le->le_debit);
        }
 
        return (KERN_SUCCESS);
@@ -849,6 +850,7 @@ kern_return_t
 ledger_zero_balance(ledger_t ledger, int entry)
 {
        struct ledger_entry *le;
+       ledger_amount_t debit, credit;
 
        if (!ENTRY_VALID(ledger, entry))
                return (KERN_INVALID_VALUE);
@@ -856,18 +858,21 @@ ledger_zero_balance(ledger_t ledger, int entry)
        le = &ledger->l_entries[entry];
 
 top:
+       debit = le->le_debit;
+       credit = le->le_credit;
+
        if (le->le_flags & LF_TRACK_CREDIT_ONLY) {
                assert(le->le_debit == 0);
-               if (!OSCompareAndSwap64(le->le_credit, 0, &le->le_credit)) {
+               if (!OSCompareAndSwap64(credit, 0, &le->le_credit)) {
                        goto top;
                }
                lprintf(("%p zeroed %lld->%lld\n", current_thread(), le->le_credit, 0));
-       } else if (le->le_credit > le->le_debit) {
-               if (!OSCompareAndSwap64(le->le_debit, le->le_credit, &le->le_debit))
+       } else if (credit > debit) {
+               if (!OSCompareAndSwap64(debit, credit, &le->le_debit))
                        goto top;
                lprintf(("%p zeroed %lld->%lld\n", current_thread(), le->le_debit, le->le_credit));
-       } else if (le->le_credit < le->le_debit) {
-               if (!OSCompareAndSwap64(le->le_credit, le->le_debit, &le->le_credit))
+       } else if (credit < debit) {
+               if (!OSCompareAndSwap64(credit, debit, &le->le_credit))
                        goto top;
                lprintf(("%p zeroed %lld->%lld\n", current_thread(), le->le_credit, le->le_debit));
        }
@@ -921,7 +926,10 @@ ledger_set_limit(ledger_t ledger, int entry, ledger_amount_t limit,
        }
 
        le->le_limit = limit;
-       le->_le.le_refill.le_last_refill = 0;
+       if (le->le_flags & LF_REFILL_SCHEDULED) {
+               assert(!(le->le_flags & LF_TRACKING_MAX));
+               le->_le.le_refill.le_last_refill = 0;
+       }
        flag_clear(&le->le_flags, LF_CALLED_BACK);
        flag_clear(&le->le_flags, LF_WARNED);        
        ledger_limit_entry_wakeup(le);
@@ -938,38 +946,43 @@ ledger_set_limit(ledger_t ledger, int entry, ledger_amount_t limit,
        return (KERN_SUCCESS);
 }
 
+#if CONFIG_LEDGER_INTERVAL_MAX
 kern_return_t
-ledger_get_maximum(ledger_t ledger, int entry,
-       ledger_amount_t *max_observed_balance)
+ledger_get_interval_max(ledger_t ledger, int entry,
+        ledger_amount_t *max_interval_balance, int reset)
 {
-       struct ledger_entry     *le;
-       uint32_t                now = CURRENT_TOCKSTAMP();
-       int                     i;
-
+       struct ledger_entry *le;
        le = &ledger->l_entries[entry];
 
        if (!ENTRY_VALID(ledger, entry) || !(le->le_flags & LF_TRACKING_MAX)) {
                return (KERN_INVALID_VALUE);
        }
 
-       /*
-        * Start with the current balance; if neither of the recorded peaks are
-        * within recent history, we use this.
-        */
-       *max_observed_balance = le->le_credit - le->le_debit;
-
-       for (i = 0; i < NTOCKS; i++) {
-               if (!TOCKSTAMP_IS_STALE(now, le->_le.le_peaks[i].le_time) &&
-                   (le->_le.le_peaks[i].le_max > *max_observed_balance)) {
-                       /*
-                        * The peak for this time block isn't stale, and it
-                        * is greater than the current balance -- so use it.
-                        */
-                       *max_observed_balance = le->_le.le_peaks[i].le_max;
-               }
+       *max_interval_balance = le->_le._le_max.le_interval_max;
+       lprintf(("ledger_get_interval_max: %lld%s\n", *max_interval_balance,
+               (reset) ? " --> 0" : ""));
+
+       if (reset) {
+               le->_le._le_max.le_interval_max = 0;
+       }
+
+       return (KERN_SUCCESS);
+}
+#endif /* CONFIG_LEDGER_INTERVAL_MAX */
+
+kern_return_t
+ledger_get_lifetime_max(ledger_t ledger, int entry,
+        ledger_amount_t *max_lifetime_balance)
+{
+       struct ledger_entry *le;
+       le = &ledger->l_entries[entry];
+
+       if (!ENTRY_VALID(ledger, entry) || !(le->le_flags & LF_TRACKING_MAX)) {
+               return (KERN_INVALID_VALUE);
        }
-       
-       lprintf(("ledger_get_maximum: %lld\n", *max_observed_balance));
+
+       *max_lifetime_balance = le->_le._le_max.le_lifetime_max;
+       lprintf(("ledger_get_lifetime_max: %lld\n", *max_lifetime_balance));
 
        return (KERN_SUCCESS);
 }
@@ -988,8 +1001,13 @@ ledger_track_maximum(ledger_template_t template, int entry,
                return (KERN_INVALID_VALUE);
        }
 
+       /* Refill is incompatible with max tracking. */
+       if (template->lt_entries[entry].et_flags & LF_REFILL_SCHEDULED) {
+               return (KERN_INVALID_VALUE);
+       }
+
        template->lt_entries[entry].et_flags |= LF_TRACKING_MAX;
-       template_unlock(template);      
+       template_unlock(template);
 
        return (KERN_SUCCESS);
 }
@@ -1207,7 +1225,7 @@ ledger_set_action(ledger_t ledger, int entry, int action)
 }
 
 kern_return_t
-ledger_debit(ledger_t ledger, int entry, ledger_amount_t amount)
+ledger_debit_thread(thread_t thread, ledger_t ledger, int entry, ledger_amount_t amount)
 {
        struct ledger_entry *le;
        ledger_amount_t old, new;
@@ -1230,9 +1248,23 @@ ledger_debit(ledger_t ledger, int entry, ledger_amount_t amount)
        }
        lprintf(("%p Debit %lld->%lld\n", thread, old, new));
 
-       ledger_entry_check_new_balance(ledger, entry, le);
+       if (thread) {
+               ledger_entry_check_new_balance(thread, ledger, entry, le);
+       }
+
        return (KERN_SUCCESS);
+}
 
+kern_return_t
+ledger_debit(ledger_t ledger, int entry, ledger_amount_t amount)
+{
+       return ledger_debit_thread(current_thread(), ledger, entry, amount);
+}
+
+kern_return_t
+ledger_debit_nocheck(ledger_t ledger, int entry, ledger_amount_t amount)
+{
+       return ledger_debit_thread(NULL, ledger, entry, amount);
 }
 
 void
@@ -1383,6 +1415,8 @@ ledger_check_needblock(ledger_t l, uint64_t now)
 
                /* We're over the limit, so refill if we are eligible and past due. */
                if (le->le_flags & LF_REFILL_SCHEDULED) {
+                       assert(!(le->le_flags & LF_TRACKING_MAX));
+
                        if ((le->_le.le_refill.le_last_refill + le->_le.le_refill.le_refill_period) > now) {
                                ledger_refill(now, l, i);
                                if (limit_exceeded(le) == FALSE)
@@ -1424,8 +1458,10 @@ ledger_perform_blocking(ledger_t l)
                    ((le->le_flags & LEDGER_ACTION_BLOCK) == 0))
                        continue;
 
+               assert(!(le->le_flags & LF_TRACKING_MAX));
+
                /* Prepare to sleep until the resource is refilled */
-               ret = assert_wait_deadline(le, TRUE,
+               ret = assert_wait_deadline(le, THREAD_INTERRUPTIBLE,
                    le->_le.le_refill.le_last_refill + le->_le.le_refill.le_refill_period);
                if (ret != THREAD_WAITING)
                        return(KERN_SUCCESS);
@@ -1497,6 +1533,25 @@ ledger_disable_panic_on_negative(ledger_t ledger, int entry)
        return (KERN_SUCCESS);
 }
 
+kern_return_t
+ledger_get_panic_on_negative(ledger_t ledger, int entry, int *panic_on_negative)
+{
+       struct ledger_entry *le;
+
+       if (!ENTRY_VALID(ledger, entry))
+               return (KERN_INVALID_ARGUMENT);
+
+       le = &ledger->l_entries[entry];
+
+       if (le->le_flags & LF_PANIC_ON_NEGATIVE) {
+               *panic_on_negative = TRUE;
+       } else {
+               *panic_on_negative = FALSE;
+       }
+
+       return (KERN_SUCCESS);
+}
+
 kern_return_t
 ledger_get_balance(ledger_t ledger, int entry, ledger_amount_t *balance)
 {