summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2007-08-07 15:36:25 +0000
committerkib <kib@FreeBSD.org>2007-08-07 15:36:25 +0000
commit8423133063e839c0837eb79f07c154c061ecc756 (patch)
treebd215a18467b2f34de98aec0553cf0ac7408ddbc
parentd64aca7c18603742d855a5bceb85b01a51a71194 (diff)
downloadFreeBSD-src-8423133063e839c0837eb79f07c154c061ecc756.zip
FreeBSD-src-8423133063e839c0837eb79f07c154c061ecc756.tar.gz
Protect the creation of the device pager with the dev_pager_mtx. Lookup
of device pager in the pagers list by handle is now synchronized with its removal from the list, and dev_pager_mtx is put before vm object lock in lock order. Dispose the dev_pager_sx lock, since dev_pager_mtx now covers the same block. Noted by: kensmith Reviewed by: alc Approved by: re (kensmith)
-rw-r--r--sys/vm/device_pager.c36
1 files changed, 24 insertions, 12 deletions
diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c
index bbca5cc..e557082 100644
--- a/sys/vm/device_pager.c
+++ b/sys/vm/device_pager.c
@@ -64,8 +64,6 @@ static boolean_t dev_pager_haspage(vm_object_t, vm_pindex_t, int *,
/* list of device pager objects */
static struct pagerlst dev_pager_object_list;
-/* protect against object creation */
-static struct sx dev_pager_sx;
/* protect list manipulation */
static struct mtx dev_pager_mtx;
@@ -89,7 +87,6 @@ static void
dev_pager_init()
{
TAILQ_INIT(&dev_pager_object_list);
- sx_init(&dev_pager_sx, "dev_pager create");
mtx_init(&dev_pager_mtx, "dev_pager list", NULL, MTX_DEF);
fakepg_zone = uma_zcreate("DP fakepg", sizeof(struct vm_page),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR,
@@ -103,7 +100,7 @@ static vm_object_t
dev_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff)
{
struct cdev *dev;
- vm_object_t object;
+ vm_object_t object, object1;
vm_pindex_t pindex;
unsigned int npages;
vm_paddr_t paddr;
@@ -143,29 +140,42 @@ dev_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t fo
/*
* Lock to prevent object creation race condition.
*/
- sx_xlock(&dev_pager_sx);
+ mtx_lock(&dev_pager_mtx);
/*
* Look up pager, creating as necessary.
*/
+ object1 = NULL;
object = vm_pager_object_lookup(&dev_pager_object_list, handle);
if (object == NULL) {
/*
* Allocate object and associate it with the pager.
*/
- object = vm_object_allocate(OBJT_DEVICE, pindex);
- object->handle = handle;
- TAILQ_INIT(&object->un_pager.devp.devp_pglist);
- mtx_lock(&dev_pager_mtx);
- TAILQ_INSERT_TAIL(&dev_pager_object_list, object, pager_object_list);
mtx_unlock(&dev_pager_mtx);
+ object1 = vm_object_allocate(OBJT_DEVICE, pindex);
+ mtx_lock(&dev_pager_mtx);
+ object = vm_pager_object_lookup(&dev_pager_object_list, handle);
+ if (object != NULL) {
+ /*
+ * We raced with other thread while allocating object.
+ */
+ if (pindex > object->size)
+ object->size = pindex;
+ } else {
+ 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);
+ }
} else {
if (pindex > object->size)
object->size = pindex;
}
-
- sx_xunlock(&dev_pager_sx);
+ mtx_unlock(&dev_pager_mtx);
dev_relthread(dev);
+ vm_object_deallocate(object1);
return (object);
}
@@ -175,9 +185,11 @@ dev_pager_dealloc(object)
{
vm_page_t m;
+ VM_OBJECT_UNLOCK(object);
mtx_lock(&dev_pager_mtx);
TAILQ_REMOVE(&dev_pager_object_list, object, pager_object_list);
mtx_unlock(&dev_pager_mtx);
+ VM_OBJECT_LOCK(object);
/*
* Free up our fake pages.
*/
OpenPOWER on IntegriCloud