FreeBSD Bugzilla – Attachment 162840 Details for
Bug 204298
xpt_release_device() panic: mutex CAM queue lock not owned
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
revised patch with a LOR fix and mav's cleanups
pr204298.patch (text/plain), 6.05 KB, created by
Scott M. Ferris
on 2015-11-06 07:59:14 UTC
(
hide
)
Description:
revised patch with a LOR fix and mav's cleanups
Filename:
MIME Type:
Creator:
Scott M. Ferris
Created:
2015-11-06 07:59:14 UTC
Size:
6.05 KB
patch
obsolete
>diff --git i/sys/cam/cam_xpt.c w/sys/cam/cam_xpt.c >index fb5d041..53ee166 100644 >--- i/sys/cam/cam_xpt.c >+++ w/sys/cam/cam_xpt.c >@@ -2867,6 +2867,7 @@ call_sim: > { > struct ccb_relsim *crs; > struct cam_ed *dev; >+ int release_device; > > crs = &start_ccb->crs; > dev = path->device; >@@ -2875,6 +2876,7 @@ call_sim: > crs->ccb_h.status = CAM_DEV_NOT_THERE; > break; > } >+ release_device = 0; > > if ((crs->release_flags & RELSIM_ADJUST_OPENINGS) != 0) { > >@@ -2889,6 +2891,17 @@ call_sim: > } > } > >+ if ((crs->release_flags & RELSIM_RELEASE_AFTER_TIMEOUT) != 0) { >+ /* >+ * Since the callout gets a pointer to the device, >+ * acquire a reference to make sure the device can't >+ * go away until the callout finishes or is stopped. >+ * Acquire the ref now since we can't acquire >+ * bus->eb_mtx while holding devq->send_mtx. >+ */ >+ xpt_acquire_device(dev); >+ } >+ > mtx_lock(&dev->sim->devq->send_mtx); > if ((crs->release_flags & RELSIM_RELEASE_AFTER_TIMEOUT) != 0) { > >@@ -2901,6 +2914,17 @@ call_sim: > */ > start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; > callout_stop(&dev->callout); >+ /* >+ * If CAM_DEV_REL_TIMEOUT_PENDING is still >+ * set, then the callout is still >+ * cancelable, since we hold the callout >+ * mutex and the callout function clears the >+ * flag before it ever unlocks/relocks the >+ * mutex. Since the callout we just stopped >+ * already had a ref, we don't need another, >+ * so make sure we release the extra one. >+ */ >+ release_device = 1; > } else { > > start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; >@@ -2944,6 +2968,9 @@ call_sim: > } > mtx_unlock(&dev->sim->devq->send_mtx); > >+ if (release_device) >+ xpt_release_device(dev); >+ > if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) > xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE); > start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt; >@@ -4308,8 +4335,11 @@ xpt_release_devq_timeout(void *arg) > CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE, ("xpt_release_devq_timeout\n")); > devq = dev->sim->devq; > mtx_assert(&devq->send_mtx, MA_OWNED); >+ dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; > if (xpt_release_devq_device(dev, /*count*/1, /*run_queue*/TRUE)) > xpt_run_devq(devq); >+ mtx_unlock(&devq->send_mtx); >+ xpt_release_device(dev); > } > > void >@@ -4345,19 +4375,10 @@ xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) > } > dev->ccbq.queue.qfrozen_cnt -= count; > if (dev->ccbq.queue.qfrozen_cnt == 0) { >- /* >- * No longer need to wait for a successful >- * command completion. >- */ >- dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; >- /* >- * Remove any timeouts that might be scheduled >- * to release this queue. >- */ >- if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { >- callout_stop(&dev->callout); >- dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; >- } >+ KASSERT((dev->flags & CAM_DEV_REL_ON_COMPLETE) == 0, >+ ("released the queue while still waiting for completion")); >+ KASSERT((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) == 0, >+ ("released the queue while still having timeout pending")); > /* > * Now that we are unfrozen schedule the > * device so any pending transactions are >@@ -4647,6 +4668,36 @@ xpt_destroy_device(void *context, int pending) > { > struct cam_ed *device = context; > >+ callout_drain(&device->callout); >+ >+ /* Release our slot in the devq */ >+ devq = bus->sim->devq; >+ mtx_lock(&devq->send_mtx); >+ cam_devq_resize(devq, devq->send_queue.array_size - 1); >+ KASSERT((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) == 0, >+ ("destroying device while still having timeout pending")); >+ mtx_unlock(&devq->send_mtx); >+ >+ KASSERT(SLIST_EMPTY(&device->periphs), >+ ("destroying device, but periphs list is not empty")); >+ KASSERT(device->devq_entry.index == CAM_UNQUEUED_INDEX, >+ ("destroying device while still queued for ccbs")); >+ >+ xpt_release_target(device->target); >+ >+ cam_ccbq_fini(&device->ccbq); >+ /* >+ * Free allocated memory. free(9) does nothing if the >+ * supplied pointer is NULL, so it is safe to call without >+ * checking. >+ */ >+ free(device->supported_vpds, M_CAMXPT); >+ free(device->device_id, M_CAMXPT); >+ free(device->ext_inq, M_CAMXPT); >+ free(device->physpath, M_CAMXPT); >+ free(device->rcap_buf, M_CAMXPT); >+ free(device->serial_num, M_CAMXPT); >+ > mtx_lock(&device->device_mtx); > mtx_destroy(&device->device_mtx); > free(device, M_CAMDEV); >@@ -4690,7 +4741,8 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) > device->tag_saved_openings = 0; > device->refcount = 1; > mtx_init(&device->device_mtx, "CAM device lock", NULL, MTX_DEF); >- callout_init_mtx(&device->callout, &devq->send_mtx, 0); >+ callout_init_mtx(&device->callout, &devq->send_mtx, >+ CALLOUT_RETURNUNLOCKED); > TASK_INIT(&device->device_destroy_task, 0, xpt_destroy_device, device); > /* > * Hold a reference to our parent bus so it >@@ -4735,34 +4787,13 @@ xpt_release_device(struct cam_ed *device) > device->target->generation++; > mtx_unlock(&bus->eb_mtx); > >- /* Release our slot in the devq */ >- devq = bus->sim->devq; >- mtx_lock(&devq->send_mtx); >- cam_devq_resize(devq, devq->send_queue.array_size - 1); >- mtx_unlock(&devq->send_mtx); >- > KASSERT(SLIST_EMPTY(&device->periphs), > ("destroying device, but periphs list is not empty")); > KASSERT(device->devq_entry.index == CAM_UNQUEUED_INDEX, > ("destroying device while still queued for ccbs")); >+ KASSERT((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) == 0, >+ ("destroying device while still having timeout pending")); > >- if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) >- callout_stop(&device->callout); >- >- xpt_release_target(device->target); >- >- cam_ccbq_fini(&device->ccbq); >- /* >- * Free allocated memory. free(9) does nothing if the >- * supplied pointer is NULL, so it is safe to call without >- * checking. >- */ >- free(device->supported_vpds, M_CAMXPT); >- free(device->device_id, M_CAMXPT); >- free(device->ext_inq, M_CAMXPT); >- free(device->physpath, M_CAMXPT); >- free(device->rcap_buf, M_CAMXPT); >- free(device->serial_num, M_CAMXPT); > taskqueue_enqueue(xsoftc.xpt_taskq, &device->device_destroy_task); > } >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 204298
:
162793
|
162814
| 162840