From ea541bfdaa5b2e2a893c8d76c67a43948947c7c5 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Mon, 5 Aug 2013 11:48:40 +0000 Subject: MFprojects/camlock r249505: Change CCB queue resize logic to be able safely handle overallocations: - (re)allocate queue space in power of 2 chunks with 64 elements minimum and never shrink it; with only 4/8 bytes per element size is insignificant. - automatically reallocate the queue to double size if it is overflowed. - if queue reallocation failed, store extra CCBs in unsorted TAILQ, fetching them back as soon as some queue element is freed. To free space in CCB for TAILQ linking, change highpowerq from keeping high-power CCBs to keeping devices frozen due to high-power CCBs. This encloses all pieces of queue resize logic inside of cam_queue.[ch], removing some not obvious duties from xpt_release_ccb(). --- sys/cam/cam_queue.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) (limited to 'sys/cam/cam_queue.h') diff --git a/sys/cam/cam_queue.h b/sys/cam/cam_queue.h index 9b27bae9c5c8..0bb449117662 100644 --- a/sys/cam/cam_queue.h +++ b/sys/cam/cam_queue.h @@ -57,6 +57,8 @@ SLIST_HEAD(ccb_hdr_slist, ccb_hdr); struct cam_ccbq { struct camq queue; + struct ccb_hdr_tailq queue_extra_head; + int queue_extra_entries; int devq_openings; int devq_allocating; int dev_openings; @@ -177,7 +179,7 @@ cam_ccbq_release_opening(struct cam_ccbq *ccbq); static __inline int cam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq) { - return (ccbq->queue.entries); + return (ccbq->queue.entries + ccbq->queue_extra_entries); } static __inline void @@ -190,14 +192,61 @@ cam_ccbq_take_opening(struct cam_ccbq *ccbq) static __inline void cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb) { + struct ccb_hdr *old_ccb; + struct camq *queue = &ccbq->queue; + ccbq->held--; - camq_insert(&ccbq->queue, &new_ccb->ccb_h.pinfo); + + /* + * If queue is already full, try to resize. + * If resize fail, push CCB with lowest priority out to the TAILQ. + */ + 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); + TAILQ_INSERT_HEAD(&ccbq->queue_extra_head, old_ccb, + xpt_links.tqe); + old_ccb->pinfo.index = CAM_EXTRAQ_INDEX; + ccbq->queue_extra_entries++; + } + + camq_insert(queue, &new_ccb->ccb_h.pinfo); } static __inline void cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb) { - camq_remove(&ccbq->queue, ccb->ccb_h.pinfo.index); + struct ccb_hdr *cccb, *bccb; + struct camq *queue = &ccbq->queue; + + /* If the CCB is on the TAILQ, remove it from there. */ + 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; + ccbq->queue_extra_entries--; + return; + } + + camq_remove(queue, ccb->ccb_h.pinfo.index); + + /* + * If there are some CCBs on TAILQ, find the best one and move it + * to the emptied space in the queue. + */ + bccb = TAILQ_FIRST(&ccbq->queue_extra_head); + if (bccb == NULL) + return; + TAILQ_FOREACH(cccb, &ccbq->queue_extra_head, xpt_links.tqe) { + if (bccb->pinfo.priority > cccb->pinfo.priority || + (bccb->pinfo.priority == cccb->pinfo.priority && + GENERATIONCMP(bccb->pinfo.generation, >, + cccb->pinfo.generation))) + bccb = cccb; + } + TAILQ_REMOVE(&ccbq->queue_extra_head, bccb, xpt_links.tqe); + ccbq->queue_extra_entries--; + camq_insert(queue, &bccb->pinfo); } static __inline union ccb * -- cgit v1.3