git: 4018bcdea8e1 - stable/14 - cdev_pager_allocate(): ensure that the cdev_pager_ops ctr is called only once
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 19 May 2024 00:58:25 UTC
The branch stable/14 has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=4018bcdea8e1934eedba4b800e6feb2099b1091d
commit 4018bcdea8e1934eedba4b800e6feb2099b1091d
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-05-07 13:23:28 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-05-19 00:57:54 +0000
cdev_pager_allocate(): ensure that the cdev_pager_ops ctr is called only once
PR: 278826
(cherry picked from commit e93404065177d6c909cd64bf7d74fe0d8df35edf)
---
sys/vm/device_pager.c | 70 +++++++++++++++++++++++++++++++++++++--------------
1 file changed, 51 insertions(+), 19 deletions(-)
diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c
index 2d8f003c6f92..cb3b0e522d9a 100644
--- a/sys/vm/device_pager.c
+++ b/sys/vm/device_pager.c
@@ -118,8 +118,15 @@ cdev_pager_lookup(void *handle)
{
vm_object_t object;
+again:
mtx_lock(&dev_pager_mtx);
object = vm_pager_object_lookup(&dev_pager_object_list, handle);
+ if (object != NULL && object->un_pager.devp.dev == NULL) {
+ msleep(&object->un_pager.devp.dev, &dev_pager_mtx,
+ PVM | PDROP, "cdplkp", 0);
+ vm_object_deallocate(object);
+ goto again;
+ }
mtx_unlock(&dev_pager_mtx);
return (object);
}
@@ -129,9 +136,8 @@ cdev_pager_allocate(void *handle, enum obj_type tp,
const struct cdev_pager_ops *ops, vm_ooffset_t size, vm_prot_t prot,
vm_ooffset_t foff, struct ucred *cred)
{
- vm_object_t object, object1;
+ vm_object_t object;
vm_pindex_t pindex;
- u_short color;
if (tp != OBJT_DEVICE && tp != OBJT_MGTDEVICE)
return (NULL);
@@ -157,16 +163,16 @@ cdev_pager_allocate(void *handle, enum obj_type tp,
pindex < OFF_TO_IDX(size))
return (NULL);
- if (ops->cdev_pg_ctor(handle, size, prot, foff, cred, &color) != 0)
- return (NULL);
+again:
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) {
+ vm_object_t object1;
+
/*
* Allocate object and associate it with the pager. Initialize
* the object's pg_color based upon the physical address of the
@@ -174,15 +180,19 @@ cdev_pager_allocate(void *handle, enum obj_type tp,
*/
mtx_unlock(&dev_pager_mtx);
object1 = vm_object_allocate(tp, pindex);
- object1->flags |= OBJ_COLORED;
- object1->pg_color = color;
- object1->handle = handle;
- object1->un_pager.devp.ops = ops;
- object1->un_pager.devp.dev = handle;
- 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) {
+ object1->type = OBJT_DEAD;
+ vm_object_deallocate(object1);
+ object1 = NULL;
+ if (object->un_pager.devp.dev == NULL) {
+ msleep(&object->un_pager.devp.dev,
+ &dev_pager_mtx, PVM | PDROP, "cdplkp", 0);
+ vm_object_deallocate(object);
+ goto again;
+ }
+
/*
* We raced with other thread while allocating object.
*/
@@ -194,29 +204,51 @@ cdev_pager_allocate(void *handle, enum obj_type tp,
KASSERT(object->un_pager.devp.ops == ops,
("Inconsistent devops %p %p", object, ops));
} else {
+ u_short color;
+
object = object1;
object1 = NULL;
object->handle = handle;
+ object->un_pager.devp.ops = ops;
+ TAILQ_INIT(&object->un_pager.devp.devp_pglist);
TAILQ_INSERT_TAIL(&dev_pager_object_list, object,
pager_object_list);
+ mtx_unlock(&dev_pager_mtx);
if (ops->cdev_pg_populate != NULL)
vm_object_set_flag(object, OBJ_POPULATE);
+ if (ops->cdev_pg_ctor(handle, size, prot, foff,
+ cred, &color) != 0) {
+ mtx_lock(&dev_pager_mtx);
+ TAILQ_REMOVE(&dev_pager_object_list, object,
+ pager_object_list);
+ wakeup(&object->un_pager.devp.dev);
+ mtx_unlock(&dev_pager_mtx);
+ object->type = OBJT_DEAD;
+ vm_object_deallocate(object);
+ object = NULL;
+ mtx_lock(&dev_pager_mtx);
+ } else {
+ mtx_lock(&dev_pager_mtx);
+ object->flags |= OBJ_COLORED;
+ object->pg_color = color;
+ object->un_pager.devp.dev = handle;
+ wakeup(&object->un_pager.devp.dev);
+ }
}
+ MPASS(object1 == NULL);
} else {
+ if (object->un_pager.devp.dev == NULL) {
+ msleep(&object->un_pager.devp.dev,
+ &dev_pager_mtx, PVM | PDROP, "cdplkp", 0);
+ vm_object_deallocate(object);
+ goto again;
+ }
if (pindex > object->size)
object->size = pindex;
KASSERT(object->type == tp,
("Inconsistent device pager type %p %d", object, tp));
}
mtx_unlock(&dev_pager_mtx);
- 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);
}