diff options
author | kib <kib@FreeBSD.org> | 2011-07-30 14:13:57 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2011-07-30 14:13:57 +0000 |
commit | 645f499b5d3641bac9a4abe3b0e295baac6d3de6 (patch) | |
tree | 11e7298569d761c6de538384fb3f0205e6faf5be /sys/vm | |
parent | 2c49d0ddddb36a82316ce90920948d8b660a8da4 (diff) | |
download | FreeBSD-src-645f499b5d3641bac9a4abe3b0e295baac6d3de6.zip FreeBSD-src-645f499b5d3641bac9a4abe3b0e295baac6d3de6.tar.gz |
Fix a race in the device pager allocation. If another thread won and
allocated the device pager for the given handle, then the object
fictitious pages list and the object membership in the global object
list still need to be initialized. Otherwise, dev_pager_dealloc() will
traverse uninitialized pointers.
Reported and tested by: pho
Reviewed by: jhb
Approved by: re (kensmith)
MFC after: 1 week
Diffstat (limited to 'sys/vm')
-rw-r--r-- | sys/vm/device_pager.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c index 411482a..d46d170 100644 --- a/sys/vm/device_pager.c +++ b/sys/vm/device_pager.c @@ -147,6 +147,7 @@ dev_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, object1 = vm_object_allocate(OBJT_DEVICE, pindex); object1->flags |= OBJ_COLORED; object1->pg_color = atop(paddr) - OFF_TO_IDX(off - PAGE_SIZE); + TAILQ_INIT(&object1->un_pager.devp.devp_pglist); mtx_lock(&dev_pager_mtx); object = vm_pager_object_lookup(&dev_pager_object_list, handle); if (object != NULL) { @@ -159,7 +160,6 @@ dev_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, object = object1; object1 = NULL; object->handle = handle; - TAILQ_INIT(&object->un_pager.devp.devp_pglist); TAILQ_INSERT_TAIL(&dev_pager_object_list, object, pager_object_list); } @@ -169,7 +169,14 @@ dev_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, } mtx_unlock(&dev_pager_mtx); dev_relthread(dev, ref); - vm_object_deallocate(object1); + if (object1 != NULL) { + object1->handle = object1; + mtx_lock(&dev_pager_mtx); + TAILQ_INSERT_TAIL(&dev_pager_object_list, object1, + pager_object_list); + mtx_unlock(&dev_pager_mtx); + vm_object_deallocate(object1); + } return (object); } |