Some CAM locks polishing:

- Fix LOR and possible lock recursion when handling high-power commands.
Introduce new lock to protect left power quota and list of frozen devices.
 - Correct locking around xpt periph creation.
 - Remove seems never used XPT_FLAG_OPEN xpt periph flag.
This commit is contained in:
Alexander Motin 2013-11-10 12:16:09 +00:00
parent c6b15dd50d
commit daa5487f36

View File

@ -92,14 +92,9 @@ struct xpt_task {
uintptr_t data2;
};
typedef enum {
XPT_FLAG_OPEN = 0x01
} xpt_flags;
struct xpt_softc {
xpt_flags flags;
/* number of high powered commands that can go through right now */
struct mtx xpt_highpower_lock;
STAILQ_HEAD(highpowerlist, cam_ed) highpowerq;
int num_highpower;
@ -240,6 +235,7 @@ static timeout_t xpt_release_devq_timeout;
static void xpt_release_simq_timeout(void *arg) __unused;
static void xpt_acquire_bus(struct cam_eb *bus);
static void xpt_release_bus(struct cam_eb *bus);
static uint32_t xpt_freeze_devq_device(struct cam_ed *dev, u_int count);
static int xpt_release_devq_device(struct cam_ed *dev, u_int count,
int run_queue);
static struct cam_et*
@ -367,11 +363,6 @@ xptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
return(ENODEV);
}
/* Mark ourselves open */
mtx_lock(&xsoftc.xpt_lock);
xsoftc.flags |= XPT_FLAG_OPEN;
mtx_unlock(&xsoftc.xpt_lock);
return(0);
}
@ -379,11 +370,6 @@ static int
xptclose(struct cdev *dev, int flag, int fmt, struct thread *td)
{
/* Mark ourselves closed */
mtx_lock(&xsoftc.xpt_lock);
xsoftc.flags &= ~XPT_FLAG_OPEN;
mtx_unlock(&xsoftc.xpt_lock);
return(0);
}
@ -863,6 +849,7 @@ xpt_init(void *dummy)
xsoftc.num_highpower = CAM_MAX_HIGHPOWER;
mtx_init(&xsoftc.xpt_lock, "XPT lock", NULL, MTX_DEF);
mtx_init(&xsoftc.xpt_highpower_lock, "XPT highpower lock", NULL, MTX_DEF);
mtx_init(&xsoftc.xpt_topo_lock, "XPT topology lock", NULL, MTX_DEF);
xsoftc.xpt_taskq = taskqueue_create("CAM XPT task", M_WAITOK,
taskqueue_thread_enqueue, /*context*/&xsoftc.xpt_taskq);
@ -900,6 +887,7 @@ xpt_init(void *dummy)
" failing attach\n", status);
return (EINVAL);
}
mtx_unlock(&xsoftc.xpt_lock);
/*
* Looking at the XPT from the SIM layer, the XPT is
@ -914,11 +902,12 @@ xpt_init(void *dummy)
" failing attach\n", status);
return (EINVAL);
}
xpt_path_lock(path);
cam_periph_alloc(xptregister, NULL, NULL, NULL, "xpt", CAM_PERIPH_BIO,
path, NULL, 0, xpt_sim);
xpt_path_unlock(path);
xpt_free_path(path);
mtx_unlock(&xsoftc.xpt_lock);
if (cam_num_doneqs < 1)
cam_num_doneqs = 1 + mp_ncpus / 6;
else if (cam_num_doneqs > MAXCPU)
@ -3223,7 +3212,7 @@ xpt_run_devq(struct cam_devq *devq)
if ((work_ccb->ccb_h.flags & CAM_HIGH_POWER) != 0) {
mtx_lock(&xsoftc.xpt_lock);
mtx_lock(&xsoftc.xpt_highpower_lock);
if (xsoftc.num_highpower <= 0) {
/*
* We got a high power command, but we
@ -3231,11 +3220,11 @@ xpt_run_devq(struct cam_devq *devq)
* the device queue until we have a slot
* available.
*/
xpt_freeze_devq(work_ccb->ccb_h.path, 1);
xpt_freeze_devq_device(device, 1);
STAILQ_INSERT_TAIL(&xsoftc.highpowerq, device,
highpowerq_entry);
mtx_unlock(&xsoftc.xpt_lock);
mtx_unlock(&xsoftc.xpt_highpower_lock);
continue;
} else {
/*
@ -3244,7 +3233,7 @@ xpt_run_devq(struct cam_devq *devq)
*/
xsoftc.num_highpower--;
}
mtx_unlock(&xsoftc.xpt_lock);
mtx_unlock(&xsoftc.xpt_highpower_lock);
}
cam_ccbq_remove_ccb(&device->ccbq, work_ccb);
cam_ccbq_send_ccb(&device->ccbq, work_ccb);
@ -4286,6 +4275,24 @@ xpt_dev_async_default(u_int32_t async_code, struct cam_eb *bus,
printf("%s called\n", __func__);
}
static uint32_t
xpt_freeze_devq_device(struct cam_ed *dev, u_int count)
{
struct cam_devq *devq;
uint32_t freeze;
devq = dev->sim->devq;
mtx_assert(&devq->send_mtx, MA_OWNED);
CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE,
("xpt_freeze_devq_device(%d) %u->%u\n", count,
dev->ccbq.queue.qfrozen_cnt, dev->ccbq.queue.qfrozen_cnt + count));
freeze = (dev->ccbq.queue.qfrozen_cnt += count);
/* Remove frozen device from sendq. */
if (device_is_queued(dev))
camq_remove(&devq->send_queue, dev->devq_entry.index);
return (freeze);
}
u_int32_t
xpt_freeze_devq(struct cam_path *path, u_int count)
{
@ -4295,12 +4302,8 @@ xpt_freeze_devq(struct cam_path *path, u_int count)
devq = dev->sim->devq;
mtx_lock(&devq->send_mtx);
CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_freeze_devq() %u->%u\n",
dev->ccbq.queue.qfrozen_cnt, dev->ccbq.queue.qfrozen_cnt + count));
freeze = (dev->ccbq.queue.qfrozen_cnt += count);
/* Remove frozen device from sendq. */
if (device_is_queued(dev))
camq_remove(&devq->send_queue, dev->devq_entry.index);
CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_freeze_devq(%d)\n", count));
freeze = xpt_freeze_devq_device(dev, count);
mtx_unlock(&devq->send_mtx);
return (freeze);
}
@ -5150,7 +5153,7 @@ xpt_done_process(struct ccb_hdr *ccb_h)
struct highpowerlist *hphead;
struct cam_ed *device;
mtx_lock(&xsoftc.xpt_lock);
mtx_lock(&xsoftc.xpt_highpower_lock);
hphead = &xsoftc.highpowerq;
device = STAILQ_FIRST(hphead);
@ -5166,14 +5169,14 @@ xpt_done_process(struct ccb_hdr *ccb_h)
if (device != NULL) {
STAILQ_REMOVE_HEAD(hphead, highpowerq_entry);
mtx_unlock(&xsoftc.xpt_lock);
mtx_unlock(&xsoftc.xpt_highpower_lock);
mtx_lock(&device->sim->devq->send_mtx);
xpt_release_devq_device(device,
/*count*/1, /*runqueue*/TRUE);
mtx_unlock(&device->sim->devq->send_mtx);
} else
mtx_unlock(&xsoftc.xpt_lock);
mtx_unlock(&xsoftc.xpt_highpower_lock);
}
sim = ccb_h->path->bus->sim;