|
|
1.1.1.2 root 1: /*
1.1 root 2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University
4: * All Rights Reserved.
1.1.1.2 root 5: *
1.1 root 6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
1.1.1.2 root 11: *
1.1 root 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1.1.1.2 root 15: *
1.1 root 16: * Carnegie Mellon requests users of this software to return to
1.1.1.2 root 17: *
1.1 root 18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
1.1.1.2 root 22: *
1.1 root 23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: */
28: /*
29: * File: ipc/ipc_right.c
30: * Author: Rich Draves
31: * Date: 1989
32: *
33: * Functions to manipulate IPC capabilities.
34: */
35:
36: #include <mach/boolean.h>
37: #include <mach/kern_return.h>
38: #include <mach/port.h>
39: #include <mach/message.h>
40: #include <kern/assert.h>
1.1.1.3 ! root 41: #include <kern/debug.h>
1.1 root 42: #include <ipc/port.h>
43: #include <ipc/ipc_entry.h>
44: #include <ipc/ipc_space.h>
45: #include <ipc/ipc_object.h>
46: #include <ipc/ipc_hash.h>
47: #include <ipc/ipc_port.h>
48: #include <ipc/ipc_pset.h>
49: #include <ipc/ipc_marequest.h>
50: #include <ipc/ipc_right.h>
51: #include <ipc/ipc_notify.h>
52:
53:
54:
55: /*
56: * Routine: ipc_right_lookup_write
57: * Purpose:
58: * Finds an entry in a space, given the name.
59: * Conditions:
60: * Nothing locked. If successful, the space is write-locked.
61: * Returns:
62: * KERN_SUCCESS Found an entry.
63: * KERN_INVALID_TASK The space is dead.
64: * KERN_INVALID_NAME Name doesn't exist in space.
65: */
66:
67: kern_return_t
68: ipc_right_lookup_write(
69: ipc_space_t space,
70: mach_port_t name,
71: ipc_entry_t *entryp)
72: {
73: ipc_entry_t entry;
74:
75: assert(space != IS_NULL);
76:
77: is_write_lock(space);
78:
79: if (!space->is_active) {
80: is_write_unlock(space);
81: return KERN_INVALID_TASK;
82: }
83:
84: if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) {
85: is_write_unlock(space);
86: return KERN_INVALID_NAME;
87: }
88:
89: *entryp = entry;
90: return KERN_SUCCESS;
91: }
92:
93: /*
94: * Routine: ipc_right_reverse
95: * Purpose:
96: * Translate (space, object) -> (name, entry).
97: * Only finds send/receive rights.
98: * Returns TRUE if an entry is found; if so,
99: * the object is locked and active.
100: * Conditions:
101: * The space must be locked (read or write) and active.
102: * Nothing else locked.
103: */
104:
105: boolean_t
106: ipc_right_reverse(
107: ipc_space_t space,
108: ipc_object_t object,
109: mach_port_t *namep,
110: ipc_entry_t *entryp)
111: {
112: ipc_port_t port;
113: mach_port_t name;
114: ipc_entry_t entry;
115:
116: /* would switch on io_otype to handle multiple types of object */
117:
118: assert(space->is_active);
119: assert(io_otype(object) == IOT_PORT);
120:
121: port = (ipc_port_t) object;
122:
123: ip_lock(port);
124: if (!ip_active(port)) {
125: ip_unlock(port);
126:
127: return FALSE;
128: }
129:
130: if (port->ip_receiver == space) {
131: name = port->ip_receiver_name;
132: assert(name != MACH_PORT_NULL);
133:
134: entry = ipc_entry_lookup(space, name);
135:
136: assert(entry != IE_NULL);
137: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
138: assert(port == (ipc_port_t) entry->ie_object);
139:
140: *namep = name;
141: *entryp = entry;
142: return TRUE;
143: }
144:
145: if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) {
146: assert((entry = *entryp) != IE_NULL);
147: assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
148: assert(port == (ipc_port_t) entry->ie_object);
149:
150: return TRUE;
151: }
152:
153: ip_unlock(port);
154: return FALSE;
155: }
156:
157: /*
158: * Routine: ipc_right_dnrequest
159: * Purpose:
160: * Make a dead-name request, returning the previously
161: * registered send-once right. If notify is IP_NULL,
162: * just cancels the previously registered request.
163: *
164: * This interacts with the IE_BITS_COMPAT, because they
165: * both use ie_request. If this is a compat entry, then
166: * previous always gets IP_NULL. If notify is IP_NULL,
167: * then the entry remains a compat entry. Otherwise
168: * the real dead-name request is registered and the entry
169: * is no longer a compat entry.
170: * Conditions:
171: * Nothing locked. May allocate memory.
172: * Only consumes/returns refs if successful.
173: * Returns:
174: * KERN_SUCCESS Made/canceled dead-name request.
175: * KERN_INVALID_TASK The space is dead.
176: * KERN_INVALID_NAME Name doesn't exist in space.
177: * KERN_INVALID_RIGHT Name doesn't denote port/dead rights.
178: * KERN_INVALID_ARGUMENT Name denotes dead name, but
179: * immediate is FALSE or notify is IP_NULL.
180: * KERN_UREFS_OVERFLOW Name denotes dead name, but
181: * generating immediate notif. would overflow urefs.
182: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
183: */
184:
185: kern_return_t
186: ipc_right_dnrequest(
187: ipc_space_t space,
188: mach_port_t name,
189: boolean_t immediate,
190: ipc_port_t notify,
191: ipc_port_t *previousp)
192: {
193: ipc_port_t previous;
194:
195: for (;;) {
196: ipc_entry_t entry;
197: ipc_entry_bits_t bits;
198: kern_return_t kr;
199:
200: kr = ipc_right_lookup_write(space, name, &entry);
201: if (kr != KERN_SUCCESS)
202: return kr;
203: /* space is write-locked and active */
204:
205: bits = entry->ie_bits;
206: if (bits & MACH_PORT_TYPE_PORT_RIGHTS) {
207: ipc_port_t port;
208: ipc_port_request_index_t request;
209:
210: port = (ipc_port_t) entry->ie_object;
211: assert(port != IP_NULL);
212:
213: if (!ipc_right_check(space, port, name, entry)) {
214: /* port is locked and active */
215:
216: if (notify == IP_NULL) {
217: previous = ipc_right_dncancel_macro(
218: space, port, name, entry);
219:
220: ip_unlock(port);
221: is_write_unlock(space);
222: break;
223: }
224:
225: /*
226: * If a registered soright exists,
227: * want to atomically switch with it.
228: * If ipc_port_dncancel finds us a
229: * soright, then the following
230: * ipc_port_dnrequest will reuse
231: * that slot, so we are guaranteed
232: * not to unlock and retry.
233: */
234:
235: previous = ipc_right_dncancel_macro(space,
236: port, name, entry);
237:
238: kr = ipc_port_dnrequest(port, name, notify,
239: &request);
240: if (kr != KERN_SUCCESS) {
241: assert(previous == IP_NULL);
242: is_write_unlock(space);
243:
244: kr = ipc_port_dngrow(port);
245: /* port is unlocked */
246: if (kr != KERN_SUCCESS)
247: return kr;
248:
249: continue;
250: }
251:
252: assert(request != 0);
253: ip_unlock(port);
254:
255: entry->ie_request = request;
256: is_write_unlock(space);
257: break;
258: }
259:
260: bits = entry->ie_bits;
261: assert(bits & MACH_PORT_TYPE_DEAD_NAME);
262: }
263:
264: if ((bits & MACH_PORT_TYPE_DEAD_NAME) &&
265: immediate && (notify != IP_NULL)) {
266: mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
267:
268: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
269: assert(urefs > 0);
270:
271: if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) {
272: is_write_unlock(space);
273: return KERN_UREFS_OVERFLOW;
274: }
275:
276: entry->ie_bits = bits + 1; /* increment urefs */
277: is_write_unlock(space);
278:
279: ipc_notify_dead_name(notify, name);
280: previous = IP_NULL;
281: break;
282: }
283:
284: is_write_unlock(space);
285: if (bits & MACH_PORT_TYPE_PORT_OR_DEAD)
286: return KERN_INVALID_ARGUMENT;
287: else
288: return KERN_INVALID_RIGHT;
289: }
290:
291: *previousp = previous;
292: return KERN_SUCCESS;
293: }
294:
295: /*
296: * Routine: ipc_right_dncancel
297: * Purpose:
298: * Cancel a dead-name request and return the send-once right.
299: * Afterwards, entry->ie_request == 0.
300: * Conditions:
301: * The space must be write-locked; the port must be locked.
302: * The port must be active; the space doesn't have to be.
303: */
304:
305: ipc_port_t
306: ipc_right_dncancel(
307: ipc_space_t space,
308: ipc_port_t port,
309: mach_port_t name,
310: ipc_entry_t entry)
311: {
312: ipc_port_t dnrequest;
313:
314: assert(ip_active(port));
315: assert(port == (ipc_port_t) entry->ie_object);
316:
317: dnrequest = ipc_port_dncancel(port, name, entry->ie_request);
318: entry->ie_request = 0;
319:
320: return dnrequest;
321: }
322:
323: /*
324: * Routine: ipc_right_inuse
325: * Purpose:
326: * Check if an entry is being used.
327: * Returns TRUE if it is.
328: * Conditions:
329: * The space is write-locked and active.
330: * It is unlocked if the entry is inuse.
331: */
332:
333: boolean_t
334: ipc_right_inuse(space, name, entry)
335: ipc_space_t space;
336: mach_port_t name;
337: ipc_entry_t entry;
338: {
339: ipc_entry_bits_t bits = entry->ie_bits;
340:
341: if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
342: is_write_unlock(space);
343: return TRUE;
344: }
345:
346: return FALSE;
347: }
348:
349: /*
350: * Routine: ipc_right_check
351: * Purpose:
352: * Check if the port has died. If it has,
353: * clean up the entry and return TRUE.
354: * Conditions:
355: * The space is write-locked; the port is not locked.
356: * If returns FALSE, the port is also locked and active.
357: * Otherwise, entry is converted to a dead name, freeing
358: * a reference to port.
359: */
360:
361: boolean_t
362: ipc_right_check(space, port, name, entry)
363: ipc_space_t space;
364: ipc_port_t port;
365: mach_port_t name;
366: ipc_entry_t entry;
367: {
368: ipc_entry_bits_t bits;
369:
370: assert(space->is_active);
371: assert(port == (ipc_port_t) entry->ie_object);
372:
373: ip_lock(port);
374: if (ip_active(port))
375: return FALSE;
376: ip_unlock(port);
377:
378: /* this was either a pure send right or a send-once right */
379:
380: bits = entry->ie_bits;
381: assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
382: assert(IE_BITS_UREFS(bits) > 0);
383:
384: if (bits & MACH_PORT_TYPE_SEND) {
385: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
386:
387: /* clean up msg-accepted request */
388:
389: if (bits & IE_BITS_MAREQUEST) {
390: bits &= ~IE_BITS_MAREQUEST;
391:
392: ipc_marequest_cancel(space, name);
393: }
394:
395: ipc_hash_delete(space, (ipc_object_t) port, name, entry);
396: } else {
397: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
398: assert(IE_BITS_UREFS(bits) == 1);
399: assert((bits & IE_BITS_MAREQUEST) == 0);
400: }
401:
402: ipc_port_release(port);
403:
404: /* convert entry to dead name */
405:
406: bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
407:
408: if (entry->ie_request != 0) {
409: assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
410:
411: entry->ie_request = 0;
412: bits++; /* increment urefs */
413: }
414:
415: entry->ie_bits = bits;
416: entry->ie_object = IO_NULL;
417:
418: return TRUE;
419: }
420:
421: /*
422: * Routine: ipc_right_clean
423: * Purpose:
424: * Cleans up an entry in a dead space.
425: * The entry isn't deallocated or removed
426: * from reverse hash tables.
427: * Conditions:
428: * The space is dead and unlocked.
429: */
430:
431: void
432: ipc_right_clean(
433: ipc_space_t space,
434: mach_port_t name,
435: ipc_entry_t entry)
436: {
437: ipc_entry_bits_t bits = entry->ie_bits;
438: mach_port_type_t type = IE_BITS_TYPE(bits);
439:
440: assert(!space->is_active);
441:
442: /*
443: * We can't clean up IE_BITS_MAREQUEST when the space is dead.
444: * This is because ipc_marequest_destroy can't turn off
445: * the bit if the space is dead. Hence, it might be on
446: * even though the marequest has been destroyed. It's OK
447: * not to cancel the marequest, because ipc_marequest_destroy
448: * cancels for us if the space is dead.
449: *
450: * IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
451: * problem, because we check that the port is active. If
452: * we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
453: * would still work, but dead space refs would accumulate
454: * in ip_dnrequests. They would use up slots in
455: * ip_dnrequests and keep the spaces from being freed.
456: */
457:
458: switch (type) {
459: case MACH_PORT_TYPE_DEAD_NAME:
460: assert(entry->ie_request == 0);
461: assert(entry->ie_object == IO_NULL);
462: assert((bits & IE_BITS_MAREQUEST) == 0);
463: break;
464:
465: case MACH_PORT_TYPE_PORT_SET: {
466: ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
467:
468: assert(entry->ie_request == 0);
469: assert((bits & IE_BITS_MAREQUEST) == 0);
470: assert(pset != IPS_NULL);
471:
472: ips_lock(pset);
473: assert(ips_active(pset));
474:
475: ipc_pset_destroy(pset); /* consumes ref, unlocks */
476: break;
477: }
478:
479: case MACH_PORT_TYPE_SEND:
480: case MACH_PORT_TYPE_RECEIVE:
481: case MACH_PORT_TYPE_SEND_RECEIVE:
482: case MACH_PORT_TYPE_SEND_ONCE: {
483: ipc_port_t port = (ipc_port_t) entry->ie_object;
484: ipc_port_t dnrequest;
485: ipc_port_t nsrequest = IP_NULL;
486: mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
487:
488: assert(port != IP_NULL);
489: ip_lock(port);
490:
491: if (!ip_active(port)) {
492: ip_release(port);
493: ip_check_unlock(port);
494: break;
495: }
496:
497: dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
498:
499: if (type & MACH_PORT_TYPE_SEND) {
500: assert(port->ip_srights > 0);
501: if (--port->ip_srights == 0) {
502: nsrequest = port->ip_nsrequest;
503: if (nsrequest != IP_NULL) {
504: port->ip_nsrequest = IP_NULL;
505: mscount = port->ip_mscount;
506: }
507: }
508: }
509:
510: if (type & MACH_PORT_TYPE_RECEIVE) {
511: assert(port->ip_receiver_name == name);
512: assert(port->ip_receiver == space);
513:
514: ipc_port_clear_receiver(port);
515: ipc_port_destroy(port); /* consumes our ref, unlocks */
516: } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
517: assert(port->ip_sorights > 0);
518: ip_unlock(port);
519:
520: ipc_notify_send_once(port); /* consumes our ref */
521: } else {
522: assert(port->ip_receiver != space);
523:
524: ip_release(port);
525: ip_unlock(port); /* port is active */
526: }
527:
528: if (nsrequest != IP_NULL)
529: ipc_notify_no_senders(nsrequest, mscount);
530:
531: if (dnrequest != IP_NULL)
532: ipc_notify_port_deleted(dnrequest, name);
533: break;
534: }
535:
536: default:
537: #if MACH_ASSERT
538: assert(!"ipc_right_clean: strange type");
539: #else
540: panic("ipc_right_clean: strange type");
541: #endif
542: }
543: }
544:
545: /*
546: * Routine: ipc_right_destroy
547: * Purpose:
548: * Destroys an entry in a space.
549: * Conditions:
550: * The space is write-locked, and is unlocked upon return.
551: * The space must be active.
552: * Returns:
553: * KERN_SUCCESS The entry was destroyed.
554: */
555:
556: kern_return_t
557: ipc_right_destroy(
558: ipc_space_t space,
559: mach_port_t name,
560: ipc_entry_t entry)
561: {
562: ipc_entry_bits_t bits = entry->ie_bits;
563: mach_port_type_t type = IE_BITS_TYPE(bits);
564:
565: assert(space->is_active);
566:
567: switch (type) {
568: case MACH_PORT_TYPE_DEAD_NAME:
569: assert(entry->ie_request == 0);
570: assert(entry->ie_object == IO_NULL);
571: assert((bits & IE_BITS_MAREQUEST) == 0);
572:
573: ipc_entry_dealloc(space, name, entry);
574: is_write_unlock(space);
575: break;
576:
577: case MACH_PORT_TYPE_PORT_SET: {
578: ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
579:
580: assert(entry->ie_request == 0);
581: assert(pset != IPS_NULL);
582:
583: entry->ie_object = IO_NULL;
584: ipc_entry_dealloc(space, name, entry);
585:
586: ips_lock(pset);
587: assert(ips_active(pset));
588: is_write_unlock(space);
589:
590: ipc_pset_destroy(pset); /* consumes ref, unlocks */
591: break;
592: }
593:
594: case MACH_PORT_TYPE_SEND:
595: case MACH_PORT_TYPE_RECEIVE:
596: case MACH_PORT_TYPE_SEND_RECEIVE:
597: case MACH_PORT_TYPE_SEND_ONCE: {
598: ipc_port_t port = (ipc_port_t) entry->ie_object;
599: ipc_port_t nsrequest = IP_NULL;
600: mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
601: ipc_port_t dnrequest;
602:
603: assert(port != IP_NULL);
604:
605: if (bits & IE_BITS_MAREQUEST) {
606: assert(type & MACH_PORT_TYPE_SEND_RECEIVE);
607:
608: ipc_marequest_cancel(space, name);
609: }
610:
611: if (type == MACH_PORT_TYPE_SEND)
612: ipc_hash_delete(space, (ipc_object_t) port,
613: name, entry);
614:
615: ip_lock(port);
616:
617: if (!ip_active(port)) {
618: assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
619:
620: ip_release(port);
621: ip_check_unlock(port);
622:
623: entry->ie_request = 0;
624: entry->ie_object = IO_NULL;
625: ipc_entry_dealloc(space, name, entry);
626: is_write_unlock(space);
627:
628: break;
629: }
630:
631: dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
632:
633: entry->ie_object = IO_NULL;
634: ipc_entry_dealloc(space, name, entry);
635: is_write_unlock(space);
636:
637: if (type & MACH_PORT_TYPE_SEND) {
638: assert(port->ip_srights > 0);
639: if (--port->ip_srights == 0) {
640: nsrequest = port->ip_nsrequest;
641: if (nsrequest != IP_NULL) {
642: port->ip_nsrequest = IP_NULL;
643: mscount = port->ip_mscount;
644: }
645: }
646: }
647:
648: if (type & MACH_PORT_TYPE_RECEIVE) {
649: assert(ip_active(port));
650: assert(port->ip_receiver == space);
651:
652: ipc_port_clear_receiver(port);
653: ipc_port_destroy(port); /* consumes our ref, unlocks */
654: } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
655: assert(port->ip_sorights > 0);
656: ip_unlock(port);
657:
658: ipc_notify_send_once(port); /* consumes our ref */
659: } else {
660: assert(port->ip_receiver != space);
661:
662: ip_release(port);
663: ip_unlock(port);
664: }
665:
666: if (nsrequest != IP_NULL)
667: ipc_notify_no_senders(nsrequest, mscount);
668:
669: if (dnrequest != IP_NULL)
670: ipc_notify_port_deleted(dnrequest, name);
671: break;
672: }
673:
674: default:
675: #if MACH_ASSERT
676: assert(!"ipc_right_destroy: strange type");
677: #else
678: panic("ipc_right_destroy: strange type");
679: #endif
680: }
681:
682: return KERN_SUCCESS;
683: }
684:
685: /*
686: * Routine: ipc_right_dealloc
687: * Purpose:
688: * Releases a send/send-once/dead-name user ref.
689: * Like ipc_right_delta with a delta of -1,
690: * but looks at the entry to determine the right.
691: * Conditions:
692: * The space is write-locked, and is unlocked upon return.
693: * The space must be active.
694: * Returns:
695: * KERN_SUCCESS A user ref was released.
696: * KERN_INVALID_RIGHT Entry has wrong type.
697: */
698:
699: kern_return_t
700: ipc_right_dealloc(space, name, entry)
701: ipc_space_t space;
702: mach_port_t name;
703: ipc_entry_t entry;
704: {
705: ipc_entry_bits_t bits = entry->ie_bits;
706: mach_port_type_t type = IE_BITS_TYPE(bits);
707:
708: assert(space->is_active);
709:
710: switch (type) {
711: case MACH_PORT_TYPE_DEAD_NAME: {
712: dead_name:
713:
714: assert(IE_BITS_UREFS(bits) > 0);
715: assert(entry->ie_request == 0);
716: assert(entry->ie_object == IO_NULL);
717: assert((bits & IE_BITS_MAREQUEST) == 0);
718:
719: if (IE_BITS_UREFS(bits) == 1)
720: ipc_entry_dealloc(space, name, entry);
721: else
722: entry->ie_bits = bits-1; /* decrement urefs */
723:
724: is_write_unlock(space);
725: break;
726: }
727:
728: case MACH_PORT_TYPE_SEND_ONCE: {
729: ipc_port_t port, dnrequest;
730:
731: assert(IE_BITS_UREFS(bits) == 1);
732: assert((bits & IE_BITS_MAREQUEST) == 0);
733:
734: port = (ipc_port_t) entry->ie_object;
735: assert(port != IP_NULL);
736:
737: if (ipc_right_check(space, port, name, entry)) {
738: bits = entry->ie_bits;
739: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
740: goto dead_name;
741: }
742: /* port is locked and active */
743:
744: assert(port->ip_sorights > 0);
745:
746: dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
747: ip_unlock(port);
748:
749: entry->ie_object = IO_NULL;
750: ipc_entry_dealloc(space, name, entry);
751: is_write_unlock(space);
752:
753: ipc_notify_send_once(port);
754:
755: if (dnrequest != IP_NULL)
756: ipc_notify_port_deleted(dnrequest, name);
757: break;
758: }
759:
760: case MACH_PORT_TYPE_SEND: {
761: ipc_port_t port;
762: ipc_port_t dnrequest = IP_NULL;
763: ipc_port_t nsrequest = IP_NULL;
764: mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
765:
766: assert(IE_BITS_UREFS(bits) > 0);
767:
768: port = (ipc_port_t) entry->ie_object;
769: assert(port != IP_NULL);
770:
771: if (ipc_right_check(space, port, name, entry)) {
772: bits = entry->ie_bits;
773: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
774: goto dead_name;
775: }
776: /* port is locked and active */
777:
778: assert(port->ip_srights > 0);
779:
780: if (IE_BITS_UREFS(bits) == 1) {
781: if (--port->ip_srights == 0) {
782: nsrequest = port->ip_nsrequest;
783: if (nsrequest != IP_NULL) {
784: port->ip_nsrequest = IP_NULL;
785: mscount = port->ip_mscount;
786: }
787: }
788:
789: dnrequest = ipc_right_dncancel_macro(space, port,
790: name, entry);
791:
792: ipc_hash_delete(space, (ipc_object_t) port,
793: name, entry);
794:
795: if (bits & IE_BITS_MAREQUEST)
796: ipc_marequest_cancel(space, name);
797:
798: ip_release(port);
799: entry->ie_object = IO_NULL;
800: ipc_entry_dealloc(space, name, entry);
801: } else
802: entry->ie_bits = bits-1; /* decrement urefs */
803:
804: ip_unlock(port); /* even if dropped a ref, port is active */
805: is_write_unlock(space);
806:
807: if (nsrequest != IP_NULL)
808: ipc_notify_no_senders(nsrequest, mscount);
809:
810: if (dnrequest != IP_NULL)
811: ipc_notify_port_deleted(dnrequest, name);
812: break;
813: }
814:
815: case MACH_PORT_TYPE_SEND_RECEIVE: {
816: ipc_port_t port;
817: ipc_port_t nsrequest = IP_NULL;
818: mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
819:
820: assert(IE_BITS_UREFS(bits) > 0);
821:
822: port = (ipc_port_t) entry->ie_object;
823: assert(port != IP_NULL);
824:
825: ip_lock(port);
826: assert(ip_active(port));
827: assert(port->ip_receiver_name == name);
828: assert(port->ip_receiver == space);
829: assert(port->ip_srights > 0);
830:
831: if (IE_BITS_UREFS(bits) == 1) {
832: if (--port->ip_srights == 0) {
833: nsrequest = port->ip_nsrequest;
834: if (nsrequest != IP_NULL) {
835: port->ip_nsrequest = IP_NULL;
836: mscount = port->ip_mscount;
837: }
838: }
839:
840: entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
841: MACH_PORT_TYPE_SEND);
842: } else
843: entry->ie_bits = bits-1; /* decrement urefs */
844:
845: ip_unlock(port);
846: is_write_unlock(space);
847:
848: if (nsrequest != IP_NULL)
849: ipc_notify_no_senders(nsrequest, mscount);
850: break;
851: }
852:
853: default:
854: is_write_unlock(space);
855: return KERN_INVALID_RIGHT;
856: }
857:
858: return KERN_SUCCESS;
859: }
860:
861: /*
862: * Routine: ipc_right_delta
863: * Purpose:
864: * Modifies the user-reference count for a right.
865: * May deallocate the right, if the count goes to zero.
866: * Conditions:
867: * The space is write-locked, and is unlocked upon return.
868: * The space must be active.
869: * Returns:
870: * KERN_SUCCESS Count was modified.
871: * KERN_INVALID_RIGHT Entry has wrong type.
872: * KERN_INVALID_VALUE Bad delta for the right.
873: * KERN_UREFS_OVERFLOW OK delta, except would overflow.
874: */
875:
876: kern_return_t
877: ipc_right_delta(space, name, entry, right, delta)
878: ipc_space_t space;
879: mach_port_t name;
880: ipc_entry_t entry;
881: mach_port_right_t right;
882: mach_port_delta_t delta;
883: {
884: ipc_entry_bits_t bits = entry->ie_bits;
885:
886: assert(space->is_active);
887: assert(right < MACH_PORT_RIGHT_NUMBER);
888:
889: /* Rights-specific restrictions and operations. */
890:
891: switch (right) {
892: case MACH_PORT_RIGHT_PORT_SET: {
893: ipc_pset_t pset;
894:
895: if ((bits & MACH_PORT_TYPE_PORT_SET) == 0)
896: goto invalid_right;
897:
898: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
899: assert(IE_BITS_UREFS(bits) == 0);
900: assert((bits & IE_BITS_MAREQUEST) == 0);
901: assert(entry->ie_request == 0);
902:
903: if (delta == 0)
904: goto success;
905:
906: if (delta != -1)
907: goto invalid_value;
908:
909: pset = (ipc_pset_t) entry->ie_object;
910: assert(pset != IPS_NULL);
911:
912: entry->ie_object = IO_NULL;
913: ipc_entry_dealloc(space, name, entry);
914:
915: ips_lock(pset);
916: assert(ips_active(pset));
917: is_write_unlock(space);
918:
919: ipc_pset_destroy(pset); /* consumes ref, unlocks */
920: break;
921: }
922:
923: case MACH_PORT_RIGHT_RECEIVE: {
924: ipc_port_t port;
925: ipc_port_t dnrequest = IP_NULL;
926:
927: if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
928: goto invalid_right;
929:
930: if (delta == 0)
931: goto success;
932:
933: if (delta != -1)
934: goto invalid_value;
935:
936: if (bits & IE_BITS_MAREQUEST) {
937: bits &= ~IE_BITS_MAREQUEST;
938:
939: ipc_marequest_cancel(space, name);
940: }
941:
942: port = (ipc_port_t) entry->ie_object;
943: assert(port != IP_NULL);
944:
945: /*
946: * The port lock is needed for ipc_right_dncancel;
947: * otherwise, we wouldn't have to take the lock
948: * until just before dropping the space lock.
949: */
950:
951: ip_lock(port);
952: assert(ip_active(port));
953: assert(port->ip_receiver_name == name);
954: assert(port->ip_receiver == space);
955:
956: if (bits & MACH_PORT_TYPE_SEND) {
957: assert(IE_BITS_TYPE(bits) ==
958: MACH_PORT_TYPE_SEND_RECEIVE);
959: assert(IE_BITS_UREFS(bits) > 0);
960: assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
961: assert(port->ip_srights > 0);
962:
963: /*
964: * The remaining send right turns into a
965: * dead name. Notice we don't decrement
966: * ip_srights, generate a no-senders notif,
967: * or use ipc_right_dncancel, because the
968: * port is destroyed "first".
969: */
970:
971: bits &= ~IE_BITS_TYPE_MASK;
972: bits |= MACH_PORT_TYPE_DEAD_NAME;
973:
974: if (entry->ie_request != 0) {
975: entry->ie_request = 0;
976: bits++; /* increment urefs */
977: }
978:
979: entry->ie_bits = bits;
980: entry->ie_object = IO_NULL;
981: } else {
982: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
983: assert(IE_BITS_UREFS(bits) == 0);
984:
985: dnrequest = ipc_right_dncancel_macro(space, port,
986: name, entry);
987:
988: entry->ie_object = IO_NULL;
989: ipc_entry_dealloc(space, name, entry);
990: }
991: is_write_unlock(space);
992:
993: ipc_port_clear_receiver(port);
994: ipc_port_destroy(port); /* consumes ref, unlocks */
995:
996: if (dnrequest != IP_NULL)
997: ipc_notify_port_deleted(dnrequest, name);
998: break;
999: }
1000:
1001: case MACH_PORT_RIGHT_SEND_ONCE: {
1002: ipc_port_t port, dnrequest;
1003:
1004: if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1005: goto invalid_right;
1006:
1007: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1008: assert(IE_BITS_UREFS(bits) == 1);
1009: assert((bits & IE_BITS_MAREQUEST) == 0);
1010:
1011: if ((delta > 0) || (delta < -1))
1012: goto invalid_value;
1013:
1014: port = (ipc_port_t) entry->ie_object;
1015: assert(port != IP_NULL);
1016:
1017: if (ipc_right_check(space, port, name, entry)) {
1018: assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
1019: goto invalid_right;
1020: }
1021: /* port is locked and active */
1022:
1023: assert(port->ip_sorights > 0);
1024:
1025: if (delta == 0) {
1026: ip_unlock(port);
1027: goto success;
1028: }
1029:
1030: dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1031: ip_unlock(port);
1032:
1033: entry->ie_object = IO_NULL;
1034: ipc_entry_dealloc(space, name, entry);
1035: is_write_unlock(space);
1036:
1037: ipc_notify_send_once(port);
1038:
1039: if (dnrequest != IP_NULL)
1040: ipc_notify_port_deleted(dnrequest, name);
1041: break;
1042: }
1043:
1044: case MACH_PORT_RIGHT_DEAD_NAME: {
1045: mach_port_urefs_t urefs;
1046:
1047: if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1048: ipc_port_t port;
1049:
1050: port = (ipc_port_t) entry->ie_object;
1051: assert(port != IP_NULL);
1052:
1053: if (!ipc_right_check(space, port, name, entry)) {
1054: /* port is locked and active */
1055: ip_unlock(port);
1056: goto invalid_right;
1057: }
1058:
1059: bits = entry->ie_bits;
1060: } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0)
1061: goto invalid_right;
1062:
1063: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1064: assert(IE_BITS_UREFS(bits) > 0);
1065: assert((bits & IE_BITS_MAREQUEST) == 0);
1066: assert(entry->ie_object == IO_NULL);
1067: assert(entry->ie_request == 0);
1068:
1069: urefs = IE_BITS_UREFS(bits);
1070: if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
1071: goto invalid_value;
1072: if (MACH_PORT_UREFS_OVERFLOW(urefs, delta))
1073: goto urefs_overflow;
1074:
1075: if ((urefs + delta) == 0)
1076: ipc_entry_dealloc(space, name, entry);
1077: else
1078: entry->ie_bits = bits + delta;
1079:
1080: is_write_unlock(space);
1081: break;
1082: }
1083:
1084: case MACH_PORT_RIGHT_SEND: {
1085: mach_port_urefs_t urefs;
1086: ipc_port_t port;
1087: ipc_port_t dnrequest = IP_NULL;
1088: ipc_port_t nsrequest = IP_NULL;
1089: mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
1090:
1091: if ((bits & MACH_PORT_TYPE_SEND) == 0)
1092: goto invalid_right;
1093:
1094: /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
1095:
1096: urefs = IE_BITS_UREFS(bits);
1097: if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
1098: goto invalid_value;
1099: if (MACH_PORT_UREFS_OVERFLOW(urefs+1, delta))
1100: goto urefs_overflow;
1101:
1102: port = (ipc_port_t) entry->ie_object;
1103: assert(port != IP_NULL);
1104:
1105: if (ipc_right_check(space, port, name, entry)) {
1106: assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1107: goto invalid_right;
1108: }
1109: /* port is locked and active */
1110:
1111: assert(port->ip_srights > 0);
1112:
1113: if ((urefs + delta) == 0) {
1114: if (--port->ip_srights == 0) {
1115: nsrequest = port->ip_nsrequest;
1116: if (nsrequest != IP_NULL) {
1117: port->ip_nsrequest = IP_NULL;
1118: mscount = port->ip_mscount;
1119: }
1120: }
1121:
1122: if (bits & MACH_PORT_TYPE_RECEIVE) {
1123: assert(port->ip_receiver_name == name);
1124: assert(port->ip_receiver == space);
1125: assert(IE_BITS_TYPE(bits) ==
1126: MACH_PORT_TYPE_SEND_RECEIVE);
1127:
1128: entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1129: MACH_PORT_TYPE_SEND);
1130: } else {
1131: assert(IE_BITS_TYPE(bits) ==
1132: MACH_PORT_TYPE_SEND);
1133:
1134: dnrequest = ipc_right_dncancel_macro(
1135: space, port, name, entry);
1136:
1137: ipc_hash_delete(space, (ipc_object_t) port,
1138: name, entry);
1139:
1140: if (bits & IE_BITS_MAREQUEST)
1141: ipc_marequest_cancel(space, name);
1142:
1143: ip_release(port);
1144: entry->ie_object = IO_NULL;
1145: ipc_entry_dealloc(space, name, entry);
1146: }
1147: } else
1148: entry->ie_bits = bits + delta;
1149:
1150: ip_unlock(port); /* even if dropped a ref, port is active */
1151: is_write_unlock(space);
1152:
1153: if (nsrequest != IP_NULL)
1154: ipc_notify_no_senders(nsrequest, mscount);
1155:
1156: if (dnrequest != IP_NULL)
1157: ipc_notify_port_deleted(dnrequest, name);
1158: break;
1159: }
1160:
1161: default:
1162: #if MACH_ASSERT
1163: assert(!"ipc_right_delta: strange right");
1164: #else
1165: panic("ipc_right_delta: strange right");
1166: #endif
1167: }
1168:
1169: return KERN_SUCCESS;
1170:
1171: success:
1172: is_write_unlock(space);
1173: return KERN_SUCCESS;
1174:
1175: invalid_right:
1176: is_write_unlock(space);
1177: return KERN_INVALID_RIGHT;
1178:
1179: invalid_value:
1180: is_write_unlock(space);
1181: return KERN_INVALID_VALUE;
1182:
1183: urefs_overflow:
1184: is_write_unlock(space);
1185: return KERN_UREFS_OVERFLOW;
1186: }
1187:
1188: /*
1189: * Routine: ipc_right_info
1190: * Purpose:
1191: * Retrieves information about the right.
1192: * Conditions:
1193: * The space is write-locked, and is unlocked upon return
1194: * if the call is unsuccessful. The space must be active.
1195: * Returns:
1196: * KERN_SUCCESS Retrieved info; space still locked.
1197: */
1198:
1199: kern_return_t
1200: ipc_right_info(
1201: ipc_space_t space,
1202: mach_port_t name,
1203: ipc_entry_t entry,
1204: mach_port_type_t *typep,
1205: mach_port_urefs_t *urefsp)
1206: {
1207: ipc_entry_bits_t bits = entry->ie_bits;
1208: ipc_port_request_index_t request;
1209: mach_port_type_t type;
1210:
1211: if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1212: ipc_port_t port = (ipc_port_t) entry->ie_object;
1213:
1214: if (ipc_right_check(space, port, name, entry)) {
1215: bits = entry->ie_bits;
1216: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1217: } else
1218: ip_unlock(port);
1219: }
1220:
1221: type = IE_BITS_TYPE(bits);
1222: request = entry->ie_request;
1223:
1224: if (request != 0)
1225: type |= MACH_PORT_TYPE_DNREQUEST;
1226: if (bits & IE_BITS_MAREQUEST)
1227: type |= MACH_PORT_TYPE_MAREQUEST;
1228:
1229: *typep = type;
1230: *urefsp = IE_BITS_UREFS(bits);
1231: return KERN_SUCCESS;
1232: }
1233:
1234: /*
1235: * Routine: ipc_right_copyin_check
1236: * Purpose:
1237: * Check if a subsequent ipc_right_copyin would succeed.
1238: * Conditions:
1239: * The space is locked (read or write) and active.
1240: */
1241:
1242: boolean_t
1243: ipc_right_copyin_check(
1244: ipc_space_t space,
1245: mach_port_t name,
1246: ipc_entry_t entry,
1247: mach_msg_type_name_t msgt_name)
1248: {
1249: ipc_entry_bits_t bits = entry->ie_bits;
1250:
1251: assert(space->is_active);
1252:
1253: switch (msgt_name) {
1254: case MACH_MSG_TYPE_MAKE_SEND:
1255: case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1256: case MACH_MSG_TYPE_MOVE_RECEIVE:
1257: if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1258: return FALSE;
1259:
1260: break;
1261:
1262: case MACH_MSG_TYPE_COPY_SEND:
1263: case MACH_MSG_TYPE_MOVE_SEND:
1264: case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1265: ipc_port_t port;
1266: boolean_t active;
1267:
1268: if (bits & MACH_PORT_TYPE_DEAD_NAME)
1269: break;
1270:
1271: if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1272: return FALSE;
1273:
1274: port = (ipc_port_t) entry->ie_object;
1275: assert(port != IP_NULL);
1276:
1277: ip_lock(port);
1278: active = ip_active(port);
1279: ip_unlock(port);
1280:
1281: if (!active) {
1282: break;
1283: }
1284:
1285: if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1286: if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1287: return FALSE;
1288: } else {
1289: if ((bits & MACH_PORT_TYPE_SEND) == 0)
1290: return FALSE;
1291: }
1292:
1293: break;
1294: }
1295:
1296: default:
1297: #if MACH_ASSERT
1298: assert(!"ipc_right_copyin_check: strange rights");
1299: #else
1300: panic("ipc_right_copyin_check: strange rights");
1301: #endif
1302: }
1303:
1304: return TRUE;
1305: }
1306:
1307: /*
1308: * Routine: ipc_right_copyin
1309: * Purpose:
1310: * Copyin a capability from a space.
1311: * If successful, the caller gets a ref
1312: * for the resulting object, unless it is IO_DEAD,
1313: * and possibly a send-once right which should
1314: * be used in a port-deleted notification.
1315: *
1316: * If deadok is not TRUE, the copyin operation
1317: * will fail instead of producing IO_DEAD.
1318: *
1319: * The entry is never deallocated (except
1320: * when KERN_INVALID_NAME), so the caller
1321: * should deallocate the entry if its type
1322: * is MACH_PORT_TYPE_NONE.
1323: * Conditions:
1324: * The space is write-locked and active.
1325: * Returns:
1326: * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1327: * KERN_INVALID_RIGHT Name doesn't denote correct right.
1328: */
1329:
1330: kern_return_t
1331: ipc_right_copyin(
1332: ipc_space_t space,
1333: mach_port_t name,
1334: ipc_entry_t entry,
1335: mach_msg_type_name_t msgt_name,
1336: boolean_t deadok,
1337: ipc_object_t *objectp,
1338: ipc_port_t *sorightp)
1339: {
1340: ipc_entry_bits_t bits = entry->ie_bits;
1341:
1342: assert(space->is_active);
1343:
1344: switch (msgt_name) {
1345: case MACH_MSG_TYPE_MAKE_SEND: {
1346: ipc_port_t port;
1347:
1348: if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1349: goto invalid_right;
1350:
1351: port = (ipc_port_t) entry->ie_object;
1352: assert(port != IP_NULL);
1353:
1354: ip_lock(port);
1355: assert(ip_active(port));
1356: assert(port->ip_receiver_name == name);
1357: assert(port->ip_receiver == space);
1358:
1359: port->ip_mscount++;
1360: port->ip_srights++;
1361: ip_reference(port);
1362: ip_unlock(port);
1363:
1364: *objectp = (ipc_object_t) port;
1365: *sorightp = IP_NULL;
1366: break;
1367: }
1368:
1369: case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1370: ipc_port_t port;
1371:
1372: if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1373: goto invalid_right;
1374:
1375: port = (ipc_port_t) entry->ie_object;
1376: assert(port != IP_NULL);
1377:
1378: ip_lock(port);
1379: assert(ip_active(port));
1380: assert(port->ip_receiver_name == name);
1381: assert(port->ip_receiver == space);
1382:
1383: port->ip_sorights++;
1384: ip_reference(port);
1385: ip_unlock(port);
1386:
1387: *objectp = (ipc_object_t) port;
1388: *sorightp = IP_NULL;
1389: break;
1390: }
1391:
1392: case MACH_MSG_TYPE_MOVE_RECEIVE: {
1393: ipc_port_t port;
1394: ipc_port_t dnrequest = IP_NULL;
1395:
1396: if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1397: goto invalid_right;
1398:
1399: port = (ipc_port_t) entry->ie_object;
1400: assert(port != IP_NULL);
1401:
1402: ip_lock(port);
1403: assert(ip_active(port));
1404: assert(port->ip_receiver_name == name);
1405: assert(port->ip_receiver == space);
1406:
1407: if (bits & MACH_PORT_TYPE_SEND) {
1408: assert(IE_BITS_TYPE(bits) ==
1409: MACH_PORT_TYPE_SEND_RECEIVE);
1410: assert(IE_BITS_UREFS(bits) > 0);
1411: assert(port->ip_srights > 0);
1412:
1413: ipc_hash_insert(space, (ipc_object_t) port,
1414: name, entry);
1415:
1416: ip_reference(port);
1417: } else {
1418: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1419: assert(IE_BITS_UREFS(bits) == 0);
1420:
1421: dnrequest = ipc_right_dncancel_macro(space, port,
1422: name, entry);
1423:
1424: if (bits & IE_BITS_MAREQUEST)
1425: ipc_marequest_cancel(space, name);
1426:
1427: entry->ie_object = IO_NULL;
1428: }
1429: entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
1430:
1431: ipc_port_clear_receiver(port);
1432:
1433: port->ip_receiver_name = MACH_PORT_NULL;
1434: port->ip_destination = IP_NULL;
1435: ip_unlock(port);
1436:
1437: *objectp = (ipc_object_t) port;
1438: *sorightp = dnrequest;
1439: break;
1440: }
1441:
1442: case MACH_MSG_TYPE_COPY_SEND: {
1443: ipc_port_t port;
1444:
1445: if (bits & MACH_PORT_TYPE_DEAD_NAME)
1446: goto copy_dead;
1447:
1448: /* allow for dead send-once rights */
1449:
1450: if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1451: goto invalid_right;
1452:
1453: assert(IE_BITS_UREFS(bits) > 0);
1454:
1455: port = (ipc_port_t) entry->ie_object;
1456: assert(port != IP_NULL);
1457:
1458: if (ipc_right_check(space, port, name, entry)) {
1459: bits = entry->ie_bits;
1460: goto copy_dead;
1461: }
1462: /* port is locked and active */
1463:
1464: if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1465: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1466: assert(port->ip_sorights > 0);
1467:
1468: ip_unlock(port);
1469: goto invalid_right;
1470: }
1471:
1472: assert(port->ip_srights > 0);
1473:
1474: port->ip_srights++;
1475: ip_reference(port);
1476: ip_unlock(port);
1477:
1478: *objectp = (ipc_object_t) port;
1479: *sorightp = IP_NULL;
1480: break;
1481: }
1482:
1483: case MACH_MSG_TYPE_MOVE_SEND: {
1484: ipc_port_t port;
1485: ipc_port_t dnrequest = IP_NULL;
1486:
1487: if (bits & MACH_PORT_TYPE_DEAD_NAME)
1488: goto move_dead;
1489:
1490: /* allow for dead send-once rights */
1491:
1492: if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1493: goto invalid_right;
1494:
1495: assert(IE_BITS_UREFS(bits) > 0);
1496:
1497: port = (ipc_port_t) entry->ie_object;
1498: assert(port != IP_NULL);
1499:
1500: if (ipc_right_check(space, port, name, entry)) {
1501: bits = entry->ie_bits;
1502: goto move_dead;
1503: }
1504: /* port is locked and active */
1505:
1506: if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1507: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1508: assert(port->ip_sorights > 0);
1509:
1510: ip_unlock(port);
1511: goto invalid_right;
1512: }
1513:
1514: assert(port->ip_srights > 0);
1515:
1516: if (IE_BITS_UREFS(bits) == 1) {
1517: if (bits & MACH_PORT_TYPE_RECEIVE) {
1518: assert(port->ip_receiver_name == name);
1519: assert(port->ip_receiver == space);
1520: assert(IE_BITS_TYPE(bits) ==
1521: MACH_PORT_TYPE_SEND_RECEIVE);
1522:
1523: ip_reference(port);
1524: } else {
1525: assert(IE_BITS_TYPE(bits) ==
1526: MACH_PORT_TYPE_SEND);
1527:
1528: dnrequest = ipc_right_dncancel_macro(
1529: space, port, name, entry);
1530:
1531: ipc_hash_delete(space, (ipc_object_t) port,
1532: name, entry);
1533:
1534: if (bits & IE_BITS_MAREQUEST)
1535: ipc_marequest_cancel(space, name);
1536:
1537: entry->ie_object = IO_NULL;
1538: }
1539: entry->ie_bits = bits &~
1540: (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
1541: } else {
1542: port->ip_srights++;
1543: ip_reference(port);
1544: entry->ie_bits = bits-1; /* decrement urefs */
1545: }
1546:
1547: ip_unlock(port);
1548:
1549: *objectp = (ipc_object_t) port;
1550: *sorightp = dnrequest;
1551: break;
1552: }
1553:
1554: case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1555: ipc_port_t port;
1556: ipc_port_t dnrequest;
1557:
1558: if (bits & MACH_PORT_TYPE_DEAD_NAME)
1559: goto move_dead;
1560:
1561: /* allow for dead send rights */
1562:
1563: if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1564: goto invalid_right;
1565:
1566: assert(IE_BITS_UREFS(bits) > 0);
1567:
1568: port = (ipc_port_t) entry->ie_object;
1569: assert(port != IP_NULL);
1570:
1571: if (ipc_right_check(space, port, name, entry)) {
1572: bits = entry->ie_bits;
1573: goto move_dead;
1574: }
1575: /* port is locked and active */
1576:
1577: if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1578: assert(bits & MACH_PORT_TYPE_SEND);
1579: assert(port->ip_srights > 0);
1580:
1581: ip_unlock(port);
1582: goto invalid_right;
1583: }
1584:
1585: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1586: assert(IE_BITS_UREFS(bits) == 1);
1587: assert((bits & IE_BITS_MAREQUEST) == 0);
1588: assert(port->ip_sorights > 0);
1589:
1590: dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1591: ip_unlock(port);
1592:
1593: entry->ie_object = IO_NULL;
1594: entry->ie_bits = bits &~ MACH_PORT_TYPE_SEND_ONCE;
1595:
1596: *objectp = (ipc_object_t) port;
1597: *sorightp = dnrequest;
1598: break;
1599: }
1600:
1601: default:
1602: #if MACH_ASSERT
1603: assert(!"ipc_right_copyin: strange rights");
1604: #else
1605: panic("ipc_right_copyin: strange rights");
1606: #endif
1607: }
1608:
1609: return KERN_SUCCESS;
1610:
1611: copy_dead:
1612: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1613: assert(IE_BITS_UREFS(bits) > 0);
1614: assert((bits & IE_BITS_MAREQUEST) == 0);
1615: assert(entry->ie_request == 0);
1616: assert(entry->ie_object == 0);
1617:
1618: if (!deadok)
1619: goto invalid_right;
1620:
1621: *objectp = IO_DEAD;
1622: *sorightp = IP_NULL;
1623: return KERN_SUCCESS;
1624:
1625: move_dead:
1626: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1627: assert(IE_BITS_UREFS(bits) > 0);
1628: assert((bits & IE_BITS_MAREQUEST) == 0);
1629: assert(entry->ie_request == 0);
1630: assert(entry->ie_object == 0);
1631:
1632: if (!deadok)
1633: goto invalid_right;
1634:
1635: if (IE_BITS_UREFS(bits) == 1)
1636: entry->ie_bits = bits &~ MACH_PORT_TYPE_DEAD_NAME;
1637: else
1638: entry->ie_bits = bits-1; /* decrement urefs */
1639:
1640: *objectp = IO_DEAD;
1641: *sorightp = IP_NULL;
1642: return KERN_SUCCESS;
1643:
1644: invalid_right:
1645: return KERN_INVALID_RIGHT;
1646: }
1647:
1648: /*
1649: * Routine: ipc_right_copyin_undo
1650: * Purpose:
1651: * Undoes the effects of an ipc_right_copyin
1652: * of a send/send-once right that is dead.
1653: * (Object is either IO_DEAD or a dead port.)
1654: * Conditions:
1655: * The space is write-locked and active.
1656: */
1657:
1658: void
1659: ipc_right_copyin_undo(
1660: ipc_space_t space,
1661: mach_port_t name,
1662: ipc_entry_t entry,
1663: mach_msg_type_name_t msgt_name,
1664: ipc_object_t object,
1665: ipc_port_t soright)
1666: {
1667: ipc_entry_bits_t bits = entry->ie_bits;
1668:
1669: assert(space->is_active);
1670:
1671: assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1672: (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
1673: (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1674:
1675: if (soright != IP_NULL) {
1676: assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1677: (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1678: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1679: assert(entry->ie_object == IO_NULL);
1680: assert(object != IO_DEAD);
1681:
1682: entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1683: MACH_PORT_TYPE_DEAD_NAME | 2);
1684: } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
1685: assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1686: (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1687: assert(entry->ie_object == IO_NULL);
1688:
1689: entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1690: MACH_PORT_TYPE_DEAD_NAME | 1);
1691: } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
1692: assert(entry->ie_object == IO_NULL);
1693: assert(object == IO_DEAD);
1694: assert(IE_BITS_UREFS(bits) > 0);
1695:
1696: if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
1697: assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
1698:
1699: entry->ie_bits = bits+1; /* increment urefs */
1700: }
1701: } else {
1702: assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1703: (msgt_name == MACH_MSG_TYPE_COPY_SEND));
1704: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
1705: assert(object != IO_DEAD);
1706: assert(entry->ie_object == object);
1707: assert(IE_BITS_UREFS(bits) > 0);
1708:
1709: if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
1710: assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX-1);
1711:
1712: entry->ie_bits = bits+1; /* increment urefs */
1713: }
1714:
1715: /*
1716: * May as well convert the entry to a dead name.
1717: * (Or if it is a compat entry, destroy it.)
1718: */
1719:
1720: (void) ipc_right_check(space, (ipc_port_t) object,
1721: name, entry);
1722: /* object is dead so it is not locked */
1723: }
1724:
1725: /* release the reference acquired by copyin */
1726:
1727: if (object != IO_DEAD)
1728: ipc_object_release(object);
1729: }
1730:
1731: /*
1732: * Routine: ipc_right_copyin_two
1733: * Purpose:
1734: * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
1735: * and deadok == FALSE, except that this moves two
1736: * send rights at once.
1737: * Conditions:
1738: * The space is write-locked and active.
1739: * The object is returned with two refs/send rights.
1740: * Returns:
1741: * KERN_SUCCESS Acquired an object.
1742: * KERN_INVALID_RIGHT Name doesn't denote correct right.
1743: */
1744:
1745: kern_return_t
1746: ipc_right_copyin_two(
1747: ipc_space_t space,
1748: mach_port_t name,
1749: ipc_entry_t entry,
1750: ipc_object_t *objectp,
1751: ipc_port_t *sorightp)
1752: {
1753: ipc_entry_bits_t bits = entry->ie_bits;
1754: mach_port_urefs_t urefs;
1755: ipc_port_t port;
1756: ipc_port_t dnrequest = IP_NULL;
1757:
1758: assert(space->is_active);
1759:
1760: if ((bits & MACH_PORT_TYPE_SEND) == 0)
1761: goto invalid_right;
1762:
1763: urefs = IE_BITS_UREFS(bits);
1764: if (urefs < 2)
1765: goto invalid_right;
1766:
1767: port = (ipc_port_t) entry->ie_object;
1768: assert(port != IP_NULL);
1769:
1770: if (ipc_right_check(space, port, name, entry)) {
1771: goto invalid_right;
1772: }
1773: /* port is locked and active */
1774:
1775: assert(port->ip_srights > 0);
1776:
1777: if (urefs == 2) {
1778: if (bits & MACH_PORT_TYPE_RECEIVE) {
1779: assert(port->ip_receiver_name == name);
1780: assert(port->ip_receiver == space);
1781: assert(IE_BITS_TYPE(bits) ==
1782: MACH_PORT_TYPE_SEND_RECEIVE);
1783:
1784: port->ip_srights++;
1785: ip_reference(port);
1786: ip_reference(port);
1787: } else {
1788: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
1789:
1790: dnrequest = ipc_right_dncancel_macro(space, port,
1791: name, entry);
1792:
1793: ipc_hash_delete(space, (ipc_object_t) port,
1794: name, entry);
1795:
1796: if (bits & IE_BITS_MAREQUEST)
1797: ipc_marequest_cancel(space, name);
1798:
1799: port->ip_srights++;
1800: ip_reference(port);
1801: entry->ie_object = IO_NULL;
1802: }
1803: entry->ie_bits = bits &~
1804: (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
1805: } else {
1806: port->ip_srights += 2;
1807: ip_reference(port);
1808: ip_reference(port);
1809: entry->ie_bits = bits-2; /* decrement urefs */
1810: }
1811: ip_unlock(port);
1812:
1813: *objectp = (ipc_object_t) port;
1814: *sorightp = dnrequest;
1815: return KERN_SUCCESS;
1816:
1817: invalid_right:
1818: return KERN_INVALID_RIGHT;
1819: }
1820:
1821: /*
1822: * Routine: ipc_right_copyout
1823: * Purpose:
1824: * Copyout a capability to a space.
1825: * If successful, consumes a ref for the object.
1826: *
1827: * Always succeeds when given a newly-allocated entry,
1828: * because user-reference overflow isn't a possibility.
1829: *
1830: * If copying out the object would cause the user-reference
1831: * count in the entry to overflow, and overflow is TRUE,
1832: * then instead the user-reference count is left pegged
1833: * to its maximum value and the copyout succeeds anyway.
1834: * Conditions:
1835: * The space is write-locked and active.
1836: * The object is locked and active.
1837: * The object is unlocked; the space isn't.
1838: * Returns:
1839: * KERN_SUCCESS Copied out capability.
1840: * KERN_UREFS_OVERFLOW User-refs would overflow;
1841: * guaranteed not to happen with a fresh entry
1842: * or if overflow=TRUE was specified.
1843: */
1844:
1845: kern_return_t
1846: ipc_right_copyout(
1847: ipc_space_t space,
1848: mach_port_t name,
1849: ipc_entry_t entry,
1850: mach_msg_type_name_t msgt_name,
1851: boolean_t overflow,
1852: ipc_object_t object)
1853: {
1854: ipc_entry_bits_t bits = entry->ie_bits;
1855: ipc_port_t port;
1856:
1857: assert(IO_VALID(object));
1858: assert(io_otype(object) == IOT_PORT);
1859: assert(io_active(object));
1860: assert(entry->ie_object == object);
1861:
1862: port = (ipc_port_t) object;
1863:
1864: switch (msgt_name) {
1865: case MACH_MSG_TYPE_PORT_SEND_ONCE:
1866: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1867: assert(port->ip_sorights > 0);
1868:
1869: /* transfer send-once right and ref to entry */
1870: ip_unlock(port);
1871:
1872: entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1);
1873: break;
1874:
1875: case MACH_MSG_TYPE_PORT_SEND:
1876: assert(port->ip_srights > 0);
1877:
1878: if (bits & MACH_PORT_TYPE_SEND) {
1879: mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
1880:
1881: assert(port->ip_srights > 1);
1882: assert(urefs > 0);
1883: assert(urefs < MACH_PORT_UREFS_MAX);
1884:
1885: if (urefs+1 == MACH_PORT_UREFS_MAX) {
1886: if (overflow) {
1887: /* leave urefs pegged to maximum */
1888:
1889: port->ip_srights--;
1890: ip_release(port);
1891: ip_unlock(port);
1892: return KERN_SUCCESS;
1893: }
1894:
1895: ip_unlock(port);
1896: return KERN_UREFS_OVERFLOW;
1897: }
1898:
1899: port->ip_srights--;
1900: ip_release(port);
1901: ip_unlock(port);
1902: } else if (bits & MACH_PORT_TYPE_RECEIVE) {
1903: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1904: assert(IE_BITS_UREFS(bits) == 0);
1905:
1906: /* transfer send right to entry */
1907: ip_release(port);
1908: ip_unlock(port);
1909: } else {
1910: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1911: assert(IE_BITS_UREFS(bits) == 0);
1912:
1913: /* transfer send right and ref to entry */
1914: ip_unlock(port);
1915:
1916: /* entry is locked holding ref, so can use port */
1917:
1918: ipc_hash_insert(space, (ipc_object_t) port,
1919: name, entry);
1920: }
1921:
1922: entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1;
1923: break;
1924:
1925: case MACH_MSG_TYPE_PORT_RECEIVE: {
1926: ipc_port_t dest;
1927:
1928: assert(port->ip_mscount == 0);
1929: assert(port->ip_receiver_name == MACH_PORT_NULL);
1930: dest = port->ip_destination;
1931:
1932: port->ip_receiver_name = name;
1933: port->ip_receiver = space;
1934:
1935: assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
1936:
1937: if (bits & MACH_PORT_TYPE_SEND) {
1938: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
1939: assert(IE_BITS_UREFS(bits) > 0);
1940: assert(port->ip_srights > 0);
1941:
1942: ip_release(port);
1943: ip_unlock(port);
1944:
1945: /* entry is locked holding ref, so can use port */
1946:
1947: ipc_hash_delete(space, (ipc_object_t) port,
1948: name, entry);
1949: } else {
1950: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1951: assert(IE_BITS_UREFS(bits) == 0);
1952:
1953: /* transfer ref to entry */
1954: ip_unlock(port);
1955: }
1956:
1957: entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
1958:
1959: if (dest != IP_NULL)
1960: ipc_port_release(dest);
1961: break;
1962: }
1963:
1964: default:
1965: #if MACH_ASSERT
1966: assert(!"ipc_right_copyout: strange rights");
1967: #else
1968: panic("ipc_right_copyout: strange rights");
1969: #endif
1970: }
1971:
1972: return KERN_SUCCESS;
1973: }
1974:
1975: #if 0
1976: /*XXX same, but allows multiple duplicate send rights */
1977: kern_return_t
1978: ipc_right_copyout_multiname(space, name, entry, object)
1979: ipc_space_t space;
1980: mach_port_t name;
1981: ipc_entry_t entry;
1982: ipc_object_t object;
1983: {
1984: ipc_entry_bits_t bits = entry->ie_bits;
1985: ipc_port_t port;
1986:
1987: assert(IO_VALID(object));
1988: assert(io_otype(object) == IOT_PORT);
1989: assert(io_active(object));
1990: assert(entry->ie_object == object);
1991:
1992: port = (ipc_port_t) object;
1993:
1994: assert(port->ip_srights > 0);
1995:
1996: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1997: assert(IE_BITS_UREFS(bits) == 0);
1998:
1999: /* transfer send right and ref to entry */
2000: ip_unlock(port);
2001:
2002: /* entry is locked holding ref, so can use port */
2003:
2004: entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1;
2005:
2006: return KERN_SUCCESS;
2007: }
2008: #endif
2009:
2010: /*
2011: * Routine: ipc_right_rename
2012: * Purpose:
2013: * Transfer an entry from one name to another.
2014: * The old entry is deallocated.
2015: * Conditions:
2016: * The space is write-locked and active.
2017: * The new entry is unused. Upon return,
2018: * the space is unlocked.
2019: * Returns:
2020: * KERN_SUCCESS Moved entry to new name.
2021: */
2022:
2023: kern_return_t
2024: ipc_right_rename(
2025: ipc_space_t space,
2026: mach_port_t oname,
2027: ipc_entry_t oentry,
2028: mach_port_t nname,
2029: ipc_entry_t nentry)
2030: {
2031: ipc_entry_bits_t bits = oentry->ie_bits;
2032: ipc_port_request_index_t request = oentry->ie_request;
2033: ipc_object_t object = oentry->ie_object;
2034:
2035: assert(space->is_active);
2036: assert(oname != nname);
2037:
2038: /*
2039: * If IE_BITS_COMPAT, we can't allow the entry to be renamed
2040: * if the port is dead. (This would foil ipc_port_destroy.)
2041: * Instead we should fail because oentry shouldn't exist.
2042: * Note IE_BITS_COMPAT implies ie_request != 0.
2043: */
2044:
2045: if (request != 0) {
2046: ipc_port_t port;
2047:
2048: assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
2049: port = (ipc_port_t) object;
2050: assert(port != IP_NULL);
2051:
2052: if (ipc_right_check(space, port, oname, oentry)) {
2053: bits = oentry->ie_bits;
2054: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2055: assert(oentry->ie_request == 0);
2056: request = 0;
2057: assert(oentry->ie_object == IO_NULL);
2058: object = IO_NULL;
2059: } else {
2060: /* port is locked and active */
2061:
2062: ipc_port_dnrename(port, request, oname, nname);
2063: ip_unlock(port);
2064: oentry->ie_request = 0;
2065: }
2066: }
2067:
2068: if (bits & IE_BITS_MAREQUEST) {
2069: assert(bits & MACH_PORT_TYPE_SEND_RECEIVE);
2070:
2071: ipc_marequest_rename(space, oname, nname);
2072: }
2073:
2074: /* initialize nentry before letting ipc_hash_insert see it */
2075:
2076: assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
2077: nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
2078: nentry->ie_request = request;
2079: nentry->ie_object = object;
2080:
2081: switch (IE_BITS_TYPE(bits)) {
2082: case MACH_PORT_TYPE_SEND: {
2083: ipc_port_t port;
2084:
2085: port = (ipc_port_t) object;
2086: assert(port != IP_NULL);
2087:
2088: ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
2089: ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
2090: break;
2091: }
2092:
2093: case MACH_PORT_TYPE_RECEIVE:
2094: case MACH_PORT_TYPE_SEND_RECEIVE: {
2095: ipc_port_t port;
2096:
2097: port = (ipc_port_t) object;
2098: assert(port != IP_NULL);
2099:
2100: ip_lock(port);
2101: assert(ip_active(port));
2102: assert(port->ip_receiver_name == oname);
2103: assert(port->ip_receiver == space);
2104:
2105: port->ip_receiver_name = nname;
2106: ip_unlock(port);
2107: break;
2108: }
2109:
2110: case MACH_PORT_TYPE_PORT_SET: {
2111: ipc_pset_t pset;
2112:
2113: pset = (ipc_pset_t) object;
2114: assert(pset != IPS_NULL);
2115:
2116: ips_lock(pset);
2117: assert(ips_active(pset));
2118: assert(pset->ips_local_name == oname);
2119:
2120: pset->ips_local_name = nname;
2121: ips_unlock(pset);
2122: break;
2123: }
2124:
2125: case MACH_PORT_TYPE_SEND_ONCE:
2126: case MACH_PORT_TYPE_DEAD_NAME:
2127: break;
2128:
2129: default:
2130: #if MACH_ASSERT
2131: assert(!"ipc_right_rename: strange rights");
2132: #else
2133: panic("ipc_right_rename: strange rights");
2134: #endif
2135: }
2136:
2137: assert(oentry->ie_request == 0);
2138: oentry->ie_object = IO_NULL;
2139: ipc_entry_dealloc(space, oname, oentry);
2140: is_write_unlock(space);
2141:
2142: return KERN_SUCCESS;
2143: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.