Annotation of XNU/osfmk/kern/ledger.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @OSF_COPYRIGHT@
                     24:  */
                     25: /*
                     26:  * HISTORY
                     27:  * 
                     28:  * Revision 1.1.1.1  1998/09/22 21:05:34  wsanchez
                     29:  * Import of Mac OS X kernel (~semeria)
                     30:  *
                     31:  * Revision 1.1.1.1  1998/03/07 02:25:55  wsanchez
                     32:  * Import of OSF Mach kernel (~mburg)
                     33:  *
                     34:  * Revision 1.1.6.1  1995/01/06  19:47:19  devrcs
                     35:  *     mk6 CR668 - 1.3b26 merge
                     36:  *     new file for mk6
                     37:  *     [1994/10/12  22:19:28  dwm]
                     38:  *
                     39:  * Revision 1.1.3.4  1994/05/13  20:10:01  tmt
                     40:  *     Changed three unsigned casts to natural_t.
                     41:  *     [1994/05/12  22:12:28  tmt]
                     42:  * 
                     43:  * Revision 1.1.3.2  1993/11/30  18:26:24  jph
                     44:  *     CR10228 -- Typo in unlock(), ledger_ledger should be child_ledger.
                     45:  *     [1993/11/30  16:10:43  jph]
                     46:  * 
                     47:  * Revision 1.1.3.1  1993/11/24  21:22:14  jph
                     48:  *     CR9801 brezak merge, ledgers, security and NMK15_COMPAT
                     49:  *     [1993/11/23  22:41:07  jph]
                     50:  * 
                     51:  * Revision 1.1.1.4  1993/09/08  14:17:36  brezak
                     52:  *     Include <mach/ledger_server.h> for protos.
                     53:  * 
                     54:  * Revision 1.1.1.3  1993/08/20  14:16:55  brezak
                     55:  *     Created.
                     56:  * 
                     57:  * $EndLog$
                     58:  */
                     59: 
                     60: /*
                     61:  * 8/13/93
                     62:  * 
                     63:  * This is a half-hearted attempt at providing the parts of the
                     64:  * ledger facility to satisfy the ledger interfaces.
                     65:  *
                     66:  * This implementation basically leaves the (dysfunctional) ledgers
                     67:  * unfunctional and are mearly here to satisfy the Mach spec interface
                     68:  * reqirements.
                     69:  */
                     70: 
                     71: #include <mach/mach_types.h>
                     72: #include <mach/message.h>
                     73: #include <kern/mach_param.h>
                     74: #include <kern/misc_protos.h>
                     75: #include <mach/port.h>
                     76: #include <kern/lock.h>
                     77: #include <kern/ipc_kobject.h>
                     78: #include <ipc/ipc_space.h>
                     79: #include <ipc/ipc_port.h>
                     80: #include <kern/host.h>
                     81: #include <kern/ledger.h>
                     82: #include <mach/ledger_server.h>
                     83: 
                     84: ledger_t       root_wired_ledger;
                     85: ledger_t       root_paged_ledger;
                     86: 
                     87: 
                     88: /* Utility routine to handle entries to a ledger */
                     89: kern_return_t
                     90: ledger_enter(
                     91:             ledger_t           ledger,
                     92:             ledger_item_t      amount)
                     93: {
                     94:        /* Need to lock the ledger */
                     95:        ledger_lock(ledger);
                     96:        
                     97:        if (amount > 0) {
                     98:                if (ledger->ledger_limit != LEDGER_ITEM_INFINITY &&
                     99:                    ledger->ledger_balance + amount > ledger->ledger_limit) {
                    100:                        /* XXX this is where you do BAD things */
                    101:                        printf("Ledger limit exceeded ! ledger=%x lim=%d balance=%d\n",
                    102:                               ledger, ledger->ledger_limit,
                    103:                               ledger->ledger_balance);
                    104:                        ledger_unlock(ledger);
                    105:                        return(KERN_RESOURCE_SHORTAGE);
                    106:                }
                    107:                if ((natural_t)(ledger->ledger_balance + amount) 
                    108:                        < LEDGER_ITEM_INFINITY)
                    109:                        ledger->ledger_balance += amount;
                    110:                else
                    111:                        ledger->ledger_balance = LEDGER_ITEM_INFINITY;
                    112:        }
                    113:        else if (amount) {
                    114:                if (ledger->ledger_balance + amount > 0)
                    115:                        ledger->ledger_balance += amount;
                    116:                else
                    117:                        ledger->ledger_balance = 0;
                    118:        }
                    119:        ledger_unlock(ledger);
                    120:        return(KERN_SUCCESS);
                    121: }
                    122: 
                    123: /* Utility routine to create a new ledger */
                    124: static ledger_t
                    125: ledger_allocate(
                    126:                ledger_item_t   limit,
                    127:                ledger_t        ledger_ledger,
                    128:                ledger_t        ledger_parent)
                    129: {
                    130:        ledger_t        ledger;
                    131: 
                    132:        ledger = (ledger_t)kalloc(sizeof(ledger_data_t));
                    133:        if (ledger == LEDGER_NULL)
                    134:                return(LEDGER_NULL);
                    135: 
                    136:        ledger->ledger_self = ipc_port_alloc_kernel();
                    137:        if (ledger->ledger_self == IP_NULL)
                    138:                return(LEDGER_NULL);
                    139: 
                    140:        ledger_lock_init(ledger);
                    141:        ledger->ledger_limit = limit;
                    142:        ledger->ledger_balance = 0;
                    143:        ledger->ledger_service_port = MACH_PORT_NULL;
                    144:        ledger->ledger_ledger = ledger_ledger;
                    145:        ledger->ledger_parent = ledger_parent;
                    146:        ipc_kobject_set(ledger->ledger_self, (ipc_kobject_t)ledger,
                    147:                        IKOT_LEDGER);
                    148: 
                    149:        return(ledger);
                    150: }
                    151: 
                    152: /* Utility routine to destroy a ledger */
                    153: static void
                    154: ledger_deallocate(
                    155:                  ledger_t      ledger)
                    156: {
                    157:        /* XXX can be many send rights (copies) of this */
                    158:        ipc_port_dealloc_kernel(ledger->ledger_self);
                    159: 
                    160:        /* XXX release send right on service port */
                    161:        kfree((vm_offset_t)ledger, sizeof(*ledger));
                    162: }
                    163: 
                    164: 
                    165: /*
                    166:  * Inititalize the ledger facility
                    167:  */
                    168: void ledger_init(void)
                    169: {
                    170:        /*
                    171:         * Allocate the root ledgers; wired and paged.
                    172:         */
                    173:        root_wired_ledger = ledger_allocate(LEDGER_ITEM_INFINITY,
                    174:                                            LEDGER_NULL, LEDGER_NULL);
                    175:        if (root_wired_ledger == LEDGER_NULL)
                    176:                panic("can't allocate root (wired) ledger");
                    177:        ipc_port_make_send(root_wired_ledger->ledger_self);
                    178: 
                    179:        root_paged_ledger = ledger_allocate(LEDGER_ITEM_INFINITY,
                    180:                                            LEDGER_NULL, LEDGER_NULL);
                    181:        if (root_paged_ledger == LEDGER_NULL)
                    182:                panic("can't allocate root (paged) ledger");
                    183:        ipc_port_make_send(root_paged_ledger->ledger_self);
                    184: }
                    185: 
                    186: /*
                    187:  *     Create a subordinate ledger
                    188:  */
                    189: kern_return_t ledger_create(
                    190:                            ledger_t parent_ledger,
                    191:                            ledger_t ledger_ledger,
                    192:                            ledger_t *new_ledger,
                    193:                            ledger_item_t transfer)
                    194: {
                    195:        if (parent_ledger == LEDGER_NULL)
                    196:                return(KERN_INVALID_ARGUMENT);
                    197: 
                    198:        if (ledger_ledger == LEDGER_NULL)
                    199:                return(KERN_INVALID_LEDGER);
                    200: 
                    201:        /*
                    202:         * Allocate a new ledger and change the ledger_ledger for
                    203:         * its space.
                    204:         */
                    205:        ledger_lock(ledger_ledger);
                    206:        if ((ledger_ledger->ledger_limit != LEDGER_ITEM_INFINITY) &&
                    207:            (ledger_ledger->ledger_balance + sizeof(ledger_data_t) >
                    208:             ledger_ledger->ledger_limit)) {
                    209:                ledger_unlock(ledger_ledger);
                    210:                return(KERN_RESOURCE_SHORTAGE);
                    211:        }
                    212: 
                    213:        *new_ledger = ledger_allocate(LEDGER_ITEM_INFINITY, ledger_ledger, parent_ledger);
                    214:        if (*new_ledger == LEDGER_NULL) {
                    215:                ledger_unlock(ledger_ledger);
                    216:                return(KERN_RESOURCE_SHORTAGE);
                    217:        }
                    218:        
                    219:        /*
                    220:         * Now transfer the limit for the new ledger from the parent
                    221:         */
                    222:        ledger_lock(parent_ledger);
                    223:        if (parent_ledger->ledger_limit != LEDGER_ITEM_INFINITY) {
                    224:                /* Would the existing balance exceed the new limit ? */
                    225:                if (parent_ledger->ledger_limit - transfer < parent_ledger->ledger_balance) {
                    226:                        ledger_unlock(parent_ledger);
                    227:                        ledger_unlock(ledger_ledger);
                    228:                        return(KERN_RESOURCE_SHORTAGE);
                    229:                }
                    230:                if (parent_ledger->ledger_limit - transfer > 0)
                    231:                        parent_ledger->ledger_limit -= transfer;
                    232:                else
                    233:                        parent_ledger->ledger_limit = 0;
                    234:        }
                    235:        (*new_ledger)->ledger_limit = transfer;
                    236: 
                    237:        /* Charge the ledger against the ledger_ledger */
                    238:        ledger_ledger->ledger_balance += sizeof(ledger_data_t);
                    239:        ledger_unlock(parent_ledger);
                    240: 
                    241:        ledger_unlock(ledger_ledger);
                    242:        
                    243:        return(KERN_SUCCESS);
                    244: }
                    245: 
                    246: /*
                    247:  *     Get the remote ledger service port
                    248:  */
                    249: kern_return_t ledger_get_remote(
                    250:                                ledger_t ledger,
                    251:                                host_t host,
                    252:                                ledger_t *service)
                    253: {
                    254:        if (ledger == LEDGER_NULL)
                    255:                return(KERN_INVALID_ARGUMENT);
                    256: 
                    257:        if (host == HOST_NULL)
                    258:                return(KERN_INVALID_ARGUMENT);
                    259: 
                    260:        /* XXX if host != this host, call remote host */
                    261:        ledger_lock(ledger);
                    262:        *service = convert_port_to_ledger(ledger->ledger_service_port);
                    263:        ledger_unlock(ledger);
                    264:        
                    265:        return(KERN_SUCCESS);
                    266: }
                    267: 
                    268: /*
                    269:  *     Return the ledger limit and balance
                    270:  */
                    271: kern_return_t ledger_read(
                    272:                          ledger_t ledger,
                    273:                          ledger_item_t *balance,
                    274:                          ledger_item_t *limit)
                    275: {
                    276:        if (ledger == LEDGER_NULL)
                    277:                return(KERN_INVALID_ARGUMENT);
                    278:        
                    279:        ledger_lock(ledger);
                    280:        *balance = ledger->ledger_balance;
                    281:        *limit = ledger->ledger_limit;
                    282:        ledger_unlock(ledger);
                    283: 
                    284:        return(KERN_SUCCESS);
                    285: }
                    286: 
                    287: /*
                    288:  *     Sets the remote ledger service port
                    289:  */
                    290: kern_return_t ledger_set_remote(
                    291:                                ledger_t ledger,
                    292:                                ledger_t  service)
                    293: {
                    294:        if (ledger == LEDGER_NULL)
                    295:                return(KERN_INVALID_ARGUMENT);
                    296: 
                    297:        /* XXX Check that service port is a port */
                    298:        
                    299:        ledger_lock(ledger);
                    300:        ledger->ledger_service_port = service->ledger_self;
                    301:        ledger_unlock(ledger);
                    302:        
                    303:        return(KERN_SUCCESS);
                    304: }
                    305: 
                    306: /*
                    307:  *     Destroy a ledger
                    308:  */
                    309: kern_return_t ledger_terminate(
                    310:                               ledger_t ledger)
                    311: {
                    312:        if (ledger == LEDGER_NULL)
                    313:                return(KERN_INVALID_ARGUMENT);
                    314:        
                    315:        /* You can't deallocate kernel ledgers */
                    316:        if (ledger == root_wired_ledger ||
                    317:            ledger == root_paged_ledger)
                    318:                return(KERN_INVALID_LEDGER);
                    319: 
                    320:        /* Lock the ledger */
                    321:        ledger_lock(ledger);
                    322:        
                    323:        /* the parent ledger gets back the limit */
                    324:        ledger_lock(ledger->ledger_parent);
                    325:        if (ledger->ledger_parent->ledger_limit != LEDGER_ITEM_INFINITY) {
                    326:                assert((natural_t)(ledger->ledger_parent->ledger_limit +
                    327:                                  ledger->ledger_limit) <
                    328:                       LEDGER_ITEM_INFINITY);
                    329:                ledger->ledger_parent->ledger_limit += ledger->ledger_limit;
                    330:        }
                    331:        ledger_unlock(ledger->ledger_parent);
                    332: 
                    333:        /*
                    334:         * XXX The spec says that you have to destroy all objects that
                    335:         * have been created with this ledger. Nice work eh? For now
                    336:         * Transfer the balance to the parent and let it worry about
                    337:         * it.
                    338:         */
                    339:        /* XXX the parent ledger inherits the debt ?? */
                    340:        (void) ledger_enter(ledger->ledger_parent, ledger->ledger_balance);
                    341:        
                    342:        /* adjust the balance of the creation ledger */
                    343:        (void) ledger_enter(ledger->ledger_ledger, -sizeof(*ledger));
                    344: 
                    345:        /* delete the ledger */
                    346:        ledger_deallocate(ledger);
                    347: 
                    348:        return(KERN_SUCCESS);
                    349: }
                    350: 
                    351: /*
                    352:  *     Transfer resources from a parent ledger to a child
                    353:  */
                    354: kern_return_t ledger_transfer(
                    355:                              ledger_t parent_ledger,
                    356:                              ledger_t child_ledger,
                    357:                              ledger_item_t transfer)
                    358: {
                    359: #define abs(v) ((v) > 0)?(v):-(v)
                    360:        
                    361:        ledger_t src, dest;
                    362:        ledger_item_t amount = abs(transfer);
                    363:        
                    364:        if (parent_ledger == LEDGER_NULL)
                    365:                return(KERN_INVALID_ARGUMENT);
                    366: 
                    367:        if (child_ledger == LEDGER_NULL)
                    368:                return(KERN_INVALID_ARGUMENT);
                    369: 
                    370:        /* Must be different ledgers */
                    371:        if (parent_ledger == child_ledger)
                    372:                return(KERN_INVALID_ARGUMENT);
                    373: 
                    374:        if (transfer == 0)
                    375:                return(KERN_SUCCESS);
                    376:        
                    377:        ledger_lock(child_ledger);
                    378:        ledger_lock(parent_ledger);
                    379: 
                    380:        /* XXX Should be the parent you created it from ?? */
                    381:        if (parent_ledger != child_ledger->ledger_parent) {
                    382:                ledger_unlock(parent_ledger);
                    383:                ledger_unlock(child_ledger);
                    384:                return(KERN_INVALID_LEDGER);
                    385:        }
                    386: 
                    387:        if (transfer > 0) {
                    388:                dest = child_ledger;
                    389:                src = parent_ledger;
                    390:        }
                    391:        else {
                    392:                src = child_ledger;
                    393:                dest = parent_ledger;
                    394:        }
                    395: 
                    396:        if (src->ledger_limit != LEDGER_ITEM_INFINITY) {
                    397:                /* Would the existing balance exceed the new limit ? */
                    398:                if (src->ledger_limit - amount < src->ledger_balance) {
                    399:                        ledger_unlock(parent_ledger);
                    400:                        ledger_unlock(child_ledger);
                    401:                        return(KERN_RESOURCE_SHORTAGE);
                    402:                }
                    403:                if (src->ledger_limit - amount > 0)
                    404:                        src->ledger_limit -= amount;
                    405:                else
                    406:                        src->ledger_limit = 0;
                    407:        }
                    408: 
                    409:        if (dest->ledger_limit != LEDGER_ITEM_INFINITY) {
                    410:                if ((natural_t)(dest->ledger_limit + amount) 
                    411:                        < LEDGER_ITEM_INFINITY)
                    412:                        dest->ledger_limit += amount;
                    413:                else
                    414:                        dest->ledger_limit = (LEDGER_ITEM_INFINITY - 1);
                    415:        }
                    416: 
                    417:        ledger_unlock(parent_ledger);
                    418:        ledger_unlock(child_ledger);
                    419:        
                    420:        return(KERN_SUCCESS);
                    421: #undef abs
                    422: }
                    423: 
                    424: /*
                    425:  *     Routine:        convert_port_to_ledger
                    426:  *     Purpose:
                    427:  *             Convert from a port to a ledger.
                    428:  *             Doesn't consume the port ref; the ledger produced may be null.
                    429:  *     Conditions:
                    430:  *             Nothing locked.
                    431:  */
                    432: 
                    433: ledger_t
                    434: convert_port_to_ledger(
                    435:                       ipc_port_t port)
                    436: {
                    437:        ledger_t ledger = LEDGER_NULL;
                    438: 
                    439:        if (IP_VALID(port)) {
                    440:                ip_lock(port);
                    441:                if (ip_active(port) &&
                    442:                    (ip_kotype(port) == IKOT_LEDGER))
                    443:                        ledger = (ledger_t) port->ip_kobject;
                    444:                ip_unlock(port);
                    445:        }
                    446: 
                    447:        return ledger;
                    448: }
                    449: 
                    450: /*
                    451:  *     Routine:        convert_ledger_to_port
                    452:  *     Purpose:
                    453:  *             Convert from a ledger to a port.
                    454:  *             Produces a naked send right which may be invalid.
                    455:  *     Conditions:
                    456:  *             Nothing locked.
                    457:  */
                    458: 
                    459: ipc_port_t
                    460: convert_ledger_to_port(
                    461:                       ledger_t ledger)
                    462: {
                    463:        ipc_port_t port;
                    464: 
                    465:        port = ipc_port_make_send(ledger->ledger_self);
                    466: 
                    467:        return port;
                    468: }
                    469: 
                    470: /*
                    471:  * Copy a ledger
                    472:  */
                    473: ipc_port_t
                    474: ledger_copy(
                    475:            ledger_t ledger)
                    476: {
                    477:        /* XXX reference counting */
                    478:        assert(ledger);
                    479:        return(ipc_port_copy_send(ledger->ledger_self));
                    480: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.