#include <ipc/ipc_table.h>
#include <ipc/ipc_port.h>
#include <string.h>
+#include <sys/kdebug.h>
/*
* Routine: ipc_entry_lookup
assert(is_active(space));
-
index = MACH_PORT_INDEX(name);
if (index < space->is_table_size) {
entry = &space->is_table[index];
if (IE_BITS_GEN(entry->ie_bits) != MACH_PORT_GEN(name) ||
- IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
+ IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) {
entry = IE_NULL;
+ }
}
else {
entry = IE_NULL;
return entry;
}
+
/*
- * Routine: ipc_entry_get
+ * Routine: ipc_entries_hold
* Purpose:
- * Tries to allocate an entry out of the space.
+ * Verifies that there are at least 'entries_needed'
+ * free list members
* Conditions:
* The space is write-locked and active throughout.
* An object may be locked. Will not allocate memory.
* Returns:
- * KERN_SUCCESS A free entry was found.
+ * KERN_SUCCESS Free entries were found.
* KERN_NO_SPACE No entry allocated.
*/
kern_return_t
-ipc_entry_get(
+ipc_entries_hold(
+ ipc_space_t space,
+ uint32_t entries_needed)
+{
+
+ ipc_entry_t table;
+ mach_port_index_t next_free = 0;
+ uint32_t i;
+
+ assert(is_active(space));
+
+ table = &space->is_table[0];
+
+ for (i = 0; i < entries_needed; i++) {
+ next_free = table[next_free].ie_next;
+ if (next_free == 0) {
+ return KERN_NO_SPACE;
+ }
+ assert(next_free < space->is_table_size);
+ assert(table[next_free].ie_object == IO_NULL);
+ }
+ return KERN_SUCCESS;
+}
+
+/*
+ * Routine: ipc_entry_claim
+ * Purpose:
+ * Take formal ownership of a held entry.
+ * Conditions:
+ * The space is write-locked and active throughout.
+ * An object may be locked. Will not allocate memory.
+ *
+ * Note: The returned entry must be marked as modified before
+ * releasing the space lock
+ */
+
+kern_return_t
+ipc_entry_claim(
ipc_space_t space,
mach_port_name_t *namep,
ipc_entry_t *entryp)
{
+ ipc_entry_t entry;
ipc_entry_t table;
mach_port_index_t first_free;
- ipc_entry_t free_entry;
+ mach_port_gen_t gen;
+ mach_port_name_t new_name;
- assert(is_active(space));
+ table = &space->is_table[0];
- {
- table = space->is_table;
- first_free = table->ie_next;
+ first_free = table->ie_next;
+ assert(first_free != 0);
- if (first_free == 0)
- return KERN_NO_SPACE;
+ entry = &table[first_free];
+ table->ie_next = entry->ie_next;
+ space->is_table_free--;
+
+ assert(table->ie_next < space->is_table_size);
- assert(first_free < space->is_table_size);
- free_entry = &table[first_free];
- table->ie_next = free_entry->ie_next;
+ /*
+ * Initialize the new entry: increment gencount and reset
+ * rollover point if it rolled over, and clear ie_request.
+ */
+ gen = ipc_entry_new_gen(entry->ie_bits);
+ if (__improbable(ipc_entry_gen_rolled(entry->ie_bits, gen))) {
+ ipc_entry_bits_t roll = ipc_space_get_rollpoint(space);
+ gen = ipc_entry_new_rollpoint(roll);
}
+ entry->ie_bits = gen;
+ entry->ie_request = IE_REQ_NONE;
/*
- * Initialize the new entry. We need only
- * increment the generation number and clear ie_request.
+ * The new name can't be MACH_PORT_NULL because index
+ * is non-zero. It can't be MACH_PORT_DEAD because
+ * the table isn't allowed to grow big enough.
+ * (See comment in ipc/ipc_table.h.)
*/
- {
- mach_port_name_t new_name;
- mach_port_gen_t gen;
+ new_name = MACH_PORT_MAKE(first_free, gen);
+ assert(MACH_PORT_VALID(new_name));
+ *namep = new_name;
+ *entryp = entry;
+
+ return KERN_SUCCESS;
+}
- gen = IE_BITS_NEW_GEN(free_entry->ie_bits);
- free_entry->ie_bits = gen;
- free_entry->ie_request = IE_REQ_NONE;
+/*
+ * Routine: ipc_entry_get
+ * Purpose:
+ * Tries to allocate an entry out of the space.
+ * Conditions:
+ * The space is write-locked and active throughout.
+ * An object may be locked. Will not allocate memory.
+ * Returns:
+ * KERN_SUCCESS A free entry was found.
+ * KERN_NO_SPACE No entry allocated.
+ */
- /*
- * The new name can't be MACH_PORT_NULL because index
- * is non-zero. It can't be MACH_PORT_DEAD because
- * the table isn't allowed to grow big enough.
- * (See comment in ipc/ipc_table.h.)
- */
- new_name = MACH_PORT_MAKE(first_free, gen);
- assert(MACH_PORT_VALID(new_name));
- *namep = new_name;
- }
+kern_return_t
+ipc_entry_get(
+ ipc_space_t space,
+ mach_port_name_t *namep,
+ ipc_entry_t *entryp)
+{
+ kern_return_t kr;
- assert(free_entry->ie_object == IO_NULL);
+ kr = ipc_entries_hold(space, 1);
+ if (KERN_SUCCESS != kr)
+ return kr;
- *entryp = free_entry;
- return KERN_SUCCESS;
+ return ipc_entry_claim(space, namep, entryp);
}
/*
mach_port_index_t index = MACH_PORT_INDEX(name);
mach_port_gen_t gen = MACH_PORT_GEN(name);
+ if (index > ipc_table_max_entries())
+ return KERN_NO_SPACE;
+
assert(MACH_PORT_VALID(name));
table[free_index].ie_next =
table[next_index].ie_next;
-
+ space->is_table_free--;
+
/* mark the previous entry modified - reconstructing the name */
ipc_entry_modified(space,
MACH_PORT_MAKE(free_index,
if ((index < size) && (entry == &table[index])) {
assert(IE_BITS_GEN(entry->ie_bits) == MACH_PORT_GEN(name));
- entry->ie_bits &= IE_BITS_GEN_MASK;
+ entry->ie_bits &= (IE_BITS_GEN_MASK | IE_BITS_ROLL_MASK);
entry->ie_next = table->ie_next;
table->ie_next = index;
+ space->is_table_free++;
} else {
/*
* Nothing to do. The entry does not match
space->is_low_mod = index;
if (index > space->is_high_mod)
space->is_high_mod = index;
+
+ KERNEL_DEBUG_CONSTANT(
+ MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_PORT_ENTRY_MODIFY) | DBG_FUNC_NONE,
+ space->is_task ? task_pid(space->is_task) : 0,
+ name,
+ entry->ie_bits,
+ 0,
+ 0);
}
#define IPC_ENTRY_GROW_STATS 1
return KERN_RESOURCE_SHORTAGE;
}
- /* initialize new entries (free chain in backwards order) */
- for (i = osize; i < size; i++) {
- table[i].ie_object = IO_NULL;
- table[i].ie_bits = IE_BITS_GEN_MASK;
- table[i].ie_index = 0;
- table[i].ie_next = i + 1;
- }
- table[size-1].ie_next = 0;
+ ipc_space_rand_freelist(space, table, osize, size);
/* clear out old entries in new table */
memset((void *)table, 0, osize * sizeof(*table));
space->is_table = table;
space->is_table_size = size;
space->is_table_next = nits;
+ space->is_table_free += size - osize;
is_done_growing(space);
is_write_unlock(space);
return KERN_SUCCESS;
}
+
+
+/*
+ * Routine: ipc_entry_name_mask
+ * Purpose:
+ * Ensure a mach port name has the default ipc entry
+ * generation bits set. This can be used to ensure that
+ * a name passed in by user space matches names generated
+ * by the kernel.
+ * Conditions:
+ * None.
+ * Returns:
+ * 'name' input with default generation bits masked or added
+ * as appropriate.
+ */
+mach_port_name_t
+ipc_entry_name_mask(mach_port_name_t name)
+{
+#ifndef NO_PORT_GEN
+ static mach_port_name_t null_name = MACH_PORT_MAKE(0, IE_BITS_GEN_MASK + IE_BITS_GEN_ONE);
+ return name | null_name;
+#else
+ static mach_port_name_t null_name = MACH_PORT_MAKE(0, ~(IE_BITS_GEN_MASK + IE_BITS_GEN_ONE));
+ return name & ~null_name;
+#endif
+}