Index: sys/cam/cam.h =================================================================== --- sys/cam/cam.h +++ sys/cam/cam.h @@ -92,8 +92,9 @@ u_int32_t generation; int index; #define CAM_UNQUEUED_INDEX -1 -#define CAM_ACTIVE_INDEX -2 -#define CAM_DONEQ_INDEX -3 +#define CAM_TRANSIENT_INDEX -2 +#define CAM_ACTIVE_INDEX -3 +#define CAM_DONEQ_INDEX -4 #define CAM_EXTRAQ_INDEX INT_MAX } cam_pinfo; Index: sys/cam/cam_queue.h =================================================================== --- sys/cam/cam_queue.h +++ sys/cam/cam_queue.h @@ -136,7 +136,7 @@ * camq_remove: Remove and arbitrary entry from the queue maintaining * queue order. */ -cam_pinfo *camq_remove(struct camq *queue, int index); +cam_pinfo *camq_remove(struct camq *queue, int index, int new_index); #define CAMQ_HEAD 1 /* Head of queue index */ /* Index the first element in the heap */ @@ -203,7 +203,8 @@ */ if (queue->entries == queue->array_size && camq_resize(&ccbq->queue, queue->array_size * 2) != CAM_REQ_CMP) { - old_ccb = (struct ccb_hdr *)camq_remove(queue, queue->entries); + old_ccb = (struct ccb_hdr *)camq_remove(queue, queue->entries, + CAM_TRANSIENT_INDEX); TAILQ_INSERT_HEAD(&ccbq->queue_extra_head, old_ccb, xpt_links.tqe); old_ccb->pinfo.index = CAM_EXTRAQ_INDEX; @@ -223,12 +224,12 @@ if (ccb->ccb_h.pinfo.index == CAM_EXTRAQ_INDEX) { TAILQ_REMOVE(&ccbq->queue_extra_head, &ccb->ccb_h, xpt_links.tqe); - ccb->ccb_h.pinfo.index = CAM_UNQUEUED_INDEX; + ccb->ccb_h.pinfo.index = CAM_TRANSIENT_INDEX; ccbq->queue_extra_entries--; return; } - camq_remove(queue, ccb->ccb_h.pinfo.index); + camq_remove(queue, ccb->ccb_h.pinfo.index, CAM_TRANSIENT_INDEX); /* * If there are some CCBs on TAILQ, find the best one and move it Index: sys/cam/cam_queue.c =================================================================== --- sys/cam/cam_queue.c +++ sys/cam/cam_queue.c @@ -170,12 +170,19 @@ * Heap(1, num_elements) property and an index such that 1 <= index <= * num_elements, remove that entry and restore the Heap(1, num_elements-1) * property. + * + * Care should be taken to avoid glitches in the value of index because in some + * contexts it may be inspected by a thread that does not possess a contending + * lock. In particular, a temporary value of CAM_UNQUEUED_INDEX may be + * interpreted as "done" in some contexts. */ cam_pinfo * -camq_remove(struct camq *queue, int index) +camq_remove(struct camq *queue, int index, int new_index) { cam_pinfo *removed_entry; + KASSERT(new_index < 0, ("%s: bad new_index %d", __func__, new_index)); + if (index == 0 || index > queue->entries) return (NULL); removed_entry = queue->queue_array[index]; @@ -184,7 +191,7 @@ queue->queue_array[index]->index = index; heap_down(queue->queue_array, index, queue->entries - 1); } - removed_entry->index = CAM_UNQUEUED_INDEX; + removed_entry->index = new_index; queue->entries--; return (removed_entry); } Index: sys/cam/cam_xpt.c =================================================================== --- sys/cam/cam_xpt.c +++ sys/cam/cam_xpt.c @@ -3257,7 +3257,8 @@ struct xpt_proto *proto; device = (struct cam_ed *)camq_remove(&devq->send_queue, - CAMQ_HEAD); + CAMQ_HEAD, + CAM_UNQUEUED_INDEX); CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("running device %p\n", device)); @@ -4316,7 +4317,8 @@ 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); + camq_remove(&devq->send_queue, dev->devq_entry.index, + CAM_UNQUEUED_INDEX); return (freeze); }