Skip to content

Commit 08b9e0a

Browse files
committed
cxl/pmem: Fix reference counting for delayed work
There is a potential race between queue_work() returning and the queued-work running that could result in put_device() running before get_device(). Introduce the cxl_nvdimm_bridge_state_work() helper that takes the reference unconditionally, but drops it if no new work was queued, to keep the references balanced. Fixes: 8fdcb17 ("cxl/pmem: Add initial infrastructure for pmem support") Cc: <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Reviewed-by: Ben Widawsky <[email protected]> Link: https://lore.kernel.org/r/163553734757.2509761.3305231863616785470.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams <[email protected]>
1 parent fa55b7d commit 08b9e0a

File tree

1 file changed

+13
-4
lines changed

1 file changed

+13
-4
lines changed

drivers/cxl/pmem.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,14 +266,24 @@ static void cxl_nvb_update_state(struct work_struct *work)
266266
put_device(&cxl_nvb->dev);
267267
}
268268

269+
static void cxl_nvdimm_bridge_state_work(struct cxl_nvdimm_bridge *cxl_nvb)
270+
{
271+
/*
272+
* Take a reference that the workqueue will drop if new work
273+
* gets queued.
274+
*/
275+
get_device(&cxl_nvb->dev);
276+
if (!queue_work(cxl_pmem_wq, &cxl_nvb->state_work))
277+
put_device(&cxl_nvb->dev);
278+
}
279+
269280
static void cxl_nvdimm_bridge_remove(struct device *dev)
270281
{
271282
struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev);
272283

273284
if (cxl_nvb->state == CXL_NVB_ONLINE)
274285
cxl_nvb->state = CXL_NVB_OFFLINE;
275-
if (queue_work(cxl_pmem_wq, &cxl_nvb->state_work))
276-
get_device(&cxl_nvb->dev);
286+
cxl_nvdimm_bridge_state_work(cxl_nvb);
277287
}
278288

279289
static int cxl_nvdimm_bridge_probe(struct device *dev)
@@ -294,8 +304,7 @@ static int cxl_nvdimm_bridge_probe(struct device *dev)
294304
}
295305

296306
cxl_nvb->state = CXL_NVB_ONLINE;
297-
if (queue_work(cxl_pmem_wq, &cxl_nvb->state_work))
298-
get_device(&cxl_nvb->dev);
307+
cxl_nvdimm_bridge_state_work(cxl_nvb);
299308

300309
return 0;
301310
}

0 commit comments

Comments
 (0)