Annotation of XNU/osfmk/kern/ledger.c, revision 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.