From: Joan Lledó <jlle...@member.fsf.org> * New structure for the internal hash table: * 127 slots identified by the device address, each one containing a queue of pagers belonging to that device. * New auxiliary index [pager: device] to quick search of pagers.
* dev_pager.c: * struct dev_pager: add offset field * struct dev_pager_entry: add offset field * struct dev_pager_hashtable: * is now an index [pager: device] * new hash table dev_device_hashtable * index [device: queue of pagers] * dev_pager_setup(): record the offset * device_map_page(): add the recorded offset on the fly --- device/dev_pager.c | 102 +++++++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 32 deletions(-) diff --git a/device/dev_pager.c b/device/dev_pager.c index 37ec69fd..fe4a560c 100644 --- a/device/dev_pager.c +++ b/device/dev_pager.c @@ -113,6 +113,7 @@ struct dev_pager { ipc_port_t pager; /* pager port */ ipc_port_t pager_request; /* Known request port */ ipc_port_t pager_name; /* Known name port */ + vm_offset_t offset; /* offset within the pager, in bytes*/ mach_device_t device; /* Device handle */ int type; /* to distinguish */ #define DEV_PAGER_TYPE 0 @@ -150,24 +151,26 @@ void dev_pager_deallocate(dev_pager_t ds) * A hash table of ports for device_pager backed objects. */ -#define DEV_PAGER_HASH_COUNT 127 +#define DEV_HASH_COUNT 127 struct dev_pager_entry { queue_chain_t links; ipc_port_t name; + vm_offset_t offset; dev_pager_t pager_rec; }; typedef struct dev_pager_entry *dev_pager_entry_t; -queue_head_t dev_pager_hashtable[DEV_PAGER_HASH_COUNT]; +queue_head_t dev_device_hashtable[DEV_HASH_COUNT]; struct kmem_cache dev_pager_hash_cache; +mach_device_t dev_pager_hashtable[DEV_HASH_COUNT]; decl_simple_lock_data(, - dev_pager_hash_lock) + dev_hash_lock) -#define dev_pager_hash(name_port) \ - (((vm_offset_t)(name_port) & 0xffffff) % DEV_PAGER_HASH_COUNT) +#define dev_hash(key) \ + (((vm_offset_t)(key) & 0xffffff) % DEV_HASH_COUNT) -void dev_pager_hash_init(void) +void dev_hash_init(void) { int i; vm_size_t size; @@ -175,72 +178,106 @@ void dev_pager_hash_init(void) size = sizeof(struct dev_pager_entry); kmem_cache_init(&dev_pager_hash_cache, "dev_pager_entry", size, 0, NULL, 0); - for (i = 0; i < DEV_PAGER_HASH_COUNT; i++) - queue_init(&dev_pager_hashtable[i]); - simple_lock_init(&dev_pager_hash_lock); + for (i = 0; i < DEV_HASH_COUNT; i++) { + queue_init(&dev_device_hashtable[i]); + dev_pager_hashtable[i] = MACH_DEVICE_NULL; + } + simple_lock_init(&dev_hash_lock); } -void dev_pager_hash_insert( - const ipc_port_t name_port, +void dev_hash_insert( + const mach_device_t device, + const vm_offset_t offset, const dev_pager_t rec) { dev_pager_entry_t new_entry; new_entry = (dev_pager_entry_t) kmem_cache_alloc(&dev_pager_hash_cache); - new_entry->name = name_port; + new_entry->name = rec->pager; + new_entry->offset = offset; new_entry->pager_rec = rec; - simple_lock(&dev_pager_hash_lock); - queue_enter(&dev_pager_hashtable[dev_pager_hash(name_port)], + simple_lock(&dev_hash_lock); + queue_enter(&dev_device_hashtable[dev_hash(device)], new_entry, dev_pager_entry_t, links); - simple_unlock(&dev_pager_hash_lock); + dev_pager_hashtable[dev_hash(rec->pager)] = device; + simple_unlock(&dev_hash_lock); } -void dev_pager_hash_delete(const ipc_port_t name_port) +void dev_hash_delete( + const mach_device_t device, + const vm_offset_t offset) { queue_t bucket; dev_pager_entry_t entry; - bucket = &dev_pager_hashtable[dev_pager_hash(name_port)]; + bucket = &dev_device_hashtable[dev_hash(device)]; - simple_lock(&dev_pager_hash_lock); + simple_lock(&dev_hash_lock); for (entry = (dev_pager_entry_t)queue_first(bucket); !queue_end(bucket, &entry->links); entry = (dev_pager_entry_t)queue_next(&entry->links)) { - if (entry->name == name_port) { + if (entry->offset == offset) { queue_remove(bucket, entry, dev_pager_entry_t, links); + dev_pager_hashtable[dev_hash(entry->pager_rec->pager)] = MACH_DEVICE_NULL; break; } } - simple_unlock(&dev_pager_hash_lock); + simple_unlock(&dev_hash_lock); if (entry) kmem_cache_free(&dev_pager_hash_cache, (vm_offset_t)entry); } +dev_pager_t dev_device_hash_lookup( + const mach_device_t device, + vm_offset_t offset) +{ + queue_t bucket; + dev_pager_entry_t entry; + dev_pager_t pager; + + bucket = &dev_device_hashtable[dev_hash(device)]; + + simple_lock(&dev_hash_lock); + for (entry = (dev_pager_entry_t)queue_first(bucket); + !queue_end(bucket, &entry->links); + entry = (dev_pager_entry_t)queue_next(&entry->links)) { + if (entry->offset == offset) { + pager = entry->pager_rec; + dev_pager_reference(pager); + simple_unlock(&dev_hash_lock); + return (pager); + } + } + simple_unlock(&dev_hash_lock); + return (DEV_PAGER_NULL); +} + dev_pager_t dev_pager_hash_lookup(const ipc_port_t name_port) { + mach_device_t device; queue_t bucket; dev_pager_entry_t entry; dev_pager_t pager; - bucket = &dev_pager_hashtable[dev_pager_hash(name_port)]; + device = dev_pager_hashtable[dev_hash(name_port)]; + bucket = &dev_device_hashtable[dev_hash(device)]; - simple_lock(&dev_pager_hash_lock); + simple_lock(&dev_hash_lock); for (entry = (dev_pager_entry_t)queue_first(bucket); !queue_end(bucket, &entry->links); entry = (dev_pager_entry_t)queue_next(&entry->links)) { if (entry->name == name_port) { pager = entry->pager_rec; dev_pager_reference(pager); - simple_unlock(&dev_pager_hash_lock); + simple_unlock(&dev_hash_lock); return (pager); } } - simple_unlock(&dev_pager_hash_lock); + simple_unlock(&dev_hash_lock); return (DEV_PAGER_NULL); } -/* FIXME: This is not recording offset! */ kern_return_t device_pager_setup( const mach_device_t device, int prot, @@ -261,7 +298,7 @@ kern_return_t device_pager_setup( * and port to represent this object. */ - d = dev_pager_hash_lookup((ipc_port_t)device); /* HACK */ + d = dev_device_hash_lookup(device, offset); if (d != DEV_PAGER_NULL) { *pager = (mach_port_t) ipc_port_make_send(d->pager); dev_pager_deallocate(d); @@ -287,6 +324,7 @@ kern_return_t device_pager_setup( d->client_count = 0; d->pager_request = IP_NULL; d->pager_name = IP_NULL; + d->offset = offset; d->device = device; mach_device_reference(device); d->prot = prot; @@ -297,8 +335,7 @@ kern_return_t device_pager_setup( d->type = CHAR_PAGER_TYPE; } - dev_pager_hash_insert(d->pager, d); - dev_pager_hash_insert((ipc_port_t)device, d); /* HACK */ + dev_hash_insert(d->device, d->offset, d); *pager = (mach_port_t) ipc_port_make_send(d->pager); return (KERN_SUCCESS); @@ -424,7 +461,9 @@ vm_offset_t device_map_page( return pmap_phys_address( (*(ds->device->dev_ops->d_mmap)) - (ds->device->dev_number, offset, ds->prot)); + (ds->device->dev_number, + ds->offset + offset, + ds->prot)); } kern_return_t device_pager_init_pager( @@ -493,8 +532,7 @@ kern_return_t device_pager_terminate( assert(ds->pager_request == pager_request); assert(ds->pager_name == pager_name); - dev_pager_hash_delete(ds->pager); - dev_pager_hash_delete((ipc_port_t)ds->device); /* HACK */ + dev_hash_delete(ds->device, ds->offset); mach_device_deallocate(ds->device); /* release the send rights we have saved from the init call */ @@ -553,5 +591,5 @@ void device_pager_init(void) /* * Initialize the name port hashing stuff. */ - dev_pager_hash_init(); + dev_hash_init(); } -- 2.31.1