Skip to content

Commit 4018bcd

Browse files
committed
cdev_pager_allocate(): ensure that the cdev_pager_ops ctr is called only once
PR: 278826 (cherry picked from commit e934040)
1 parent a19d42b commit 4018bcd

File tree

1 file changed

+51
-19
lines changed

1 file changed

+51
-19
lines changed

sys/vm/device_pager.c

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,15 @@ cdev_pager_lookup(void *handle)
118118
{
119119
vm_object_t object;
120120

121+
again:
121122
mtx_lock(&dev_pager_mtx);
122123
object = vm_pager_object_lookup(&dev_pager_object_list, handle);
124+
if (object != NULL && object->un_pager.devp.dev == NULL) {
125+
msleep(&object->un_pager.devp.dev, &dev_pager_mtx,
126+
PVM | PDROP, "cdplkp", 0);
127+
vm_object_deallocate(object);
128+
goto again;
129+
}
123130
mtx_unlock(&dev_pager_mtx);
124131
return (object);
125132
}
@@ -129,9 +136,8 @@ cdev_pager_allocate(void *handle, enum obj_type tp,
129136
const struct cdev_pager_ops *ops, vm_ooffset_t size, vm_prot_t prot,
130137
vm_ooffset_t foff, struct ucred *cred)
131138
{
132-
vm_object_t object, object1;
139+
vm_object_t object;
133140
vm_pindex_t pindex;
134-
u_short color;
135141

136142
if (tp != OBJT_DEVICE && tp != OBJT_MGTDEVICE)
137143
return (NULL);
@@ -157,32 +163,36 @@ cdev_pager_allocate(void *handle, enum obj_type tp,
157163
pindex < OFF_TO_IDX(size))
158164
return (NULL);
159165

160-
if (ops->cdev_pg_ctor(handle, size, prot, foff, cred, &color) != 0)
161-
return (NULL);
166+
again:
162167
mtx_lock(&dev_pager_mtx);
163168

164169
/*
165170
* Look up pager, creating as necessary.
166171
*/
167-
object1 = NULL;
168172
object = vm_pager_object_lookup(&dev_pager_object_list, handle);
169173
if (object == NULL) {
174+
vm_object_t object1;
175+
170176
/*
171177
* Allocate object and associate it with the pager. Initialize
172178
* the object's pg_color based upon the physical address of the
173179
* device's memory.
174180
*/
175181
mtx_unlock(&dev_pager_mtx);
176182
object1 = vm_object_allocate(tp, pindex);
177-
object1->flags |= OBJ_COLORED;
178-
object1->pg_color = color;
179-
object1->handle = handle;
180-
object1->un_pager.devp.ops = ops;
181-
object1->un_pager.devp.dev = handle;
182-
TAILQ_INIT(&object1->un_pager.devp.devp_pglist);
183183
mtx_lock(&dev_pager_mtx);
184184
object = vm_pager_object_lookup(&dev_pager_object_list, handle);
185185
if (object != NULL) {
186+
object1->type = OBJT_DEAD;
187+
vm_object_deallocate(object1);
188+
object1 = NULL;
189+
if (object->un_pager.devp.dev == NULL) {
190+
msleep(&object->un_pager.devp.dev,
191+
&dev_pager_mtx, PVM | PDROP, "cdplkp", 0);
192+
vm_object_deallocate(object);
193+
goto again;
194+
}
195+
186196
/*
187197
* We raced with other thread while allocating object.
188198
*/
@@ -194,29 +204,51 @@ cdev_pager_allocate(void *handle, enum obj_type tp,
194204
KASSERT(object->un_pager.devp.ops == ops,
195205
("Inconsistent devops %p %p", object, ops));
196206
} else {
207+
u_short color;
208+
197209
object = object1;
198210
object1 = NULL;
199211
object->handle = handle;
212+
object->un_pager.devp.ops = ops;
213+
TAILQ_INIT(&object->un_pager.devp.devp_pglist);
200214
TAILQ_INSERT_TAIL(&dev_pager_object_list, object,
201215
pager_object_list);
216+
mtx_unlock(&dev_pager_mtx);
202217
if (ops->cdev_pg_populate != NULL)
203218
vm_object_set_flag(object, OBJ_POPULATE);
219+
if (ops->cdev_pg_ctor(handle, size, prot, foff,
220+
cred, &color) != 0) {
221+
mtx_lock(&dev_pager_mtx);
222+
TAILQ_REMOVE(&dev_pager_object_list, object,
223+
pager_object_list);
224+
wakeup(&object->un_pager.devp.dev);
225+
mtx_unlock(&dev_pager_mtx);
226+
object->type = OBJT_DEAD;
227+
vm_object_deallocate(object);
228+
object = NULL;
229+
mtx_lock(&dev_pager_mtx);
230+
} else {
231+
mtx_lock(&dev_pager_mtx);
232+
object->flags |= OBJ_COLORED;
233+
object->pg_color = color;
234+
object->un_pager.devp.dev = handle;
235+
wakeup(&object->un_pager.devp.dev);
236+
}
204237
}
238+
MPASS(object1 == NULL);
205239
} else {
240+
if (object->un_pager.devp.dev == NULL) {
241+
msleep(&object->un_pager.devp.dev,
242+
&dev_pager_mtx, PVM | PDROP, "cdplkp", 0);
243+
vm_object_deallocate(object);
244+
goto again;
245+
}
206246
if (pindex > object->size)
207247
object->size = pindex;
208248
KASSERT(object->type == tp,
209249
("Inconsistent device pager type %p %d", object, tp));
210250
}
211251
mtx_unlock(&dev_pager_mtx);
212-
if (object1 != NULL) {
213-
object1->handle = object1;
214-
mtx_lock(&dev_pager_mtx);
215-
TAILQ_INSERT_TAIL(&dev_pager_object_list, object1,
216-
pager_object_list);
217-
mtx_unlock(&dev_pager_mtx);
218-
vm_object_deallocate(object1);
219-
}
220252
return (object);
221253
}
222254

0 commit comments

Comments
 (0)