svn commit: r254406 - projects/camlock/sys/cam
Alexander Motin
mav at FreeBSD.org
Fri Aug 16 09:28:10 UTC 2013
Author: mav
Date: Fri Aug 16 09:28:09 2013
New Revision: 254406
URL: http://svnweb.freebsd.org/changeset/base/254406
Log:
Add safety belt in case of CCB memory allocation failed: queue the periph
to taskqueue where it can safely sleep waiting for memory. That is better
then just quit, leaving periph stuck forever.
Modified:
projects/camlock/sys/cam/cam_periph.h
projects/camlock/sys/cam/cam_xpt.c
Modified: projects/camlock/sys/cam/cam_periph.h
==============================================================================
--- projects/camlock/sys/cam/cam_periph.h Fri Aug 16 09:12:42 2013 (r254405)
+++ projects/camlock/sys/cam/cam_periph.h Fri Aug 16 09:28:09 2013 (r254406)
@@ -35,6 +35,7 @@
#include <cam/cam_sim.h>
#ifdef _KERNEL
+#include <sys/taskqueue.h>
#include <cam/cam_xpt.h>
@@ -119,6 +120,7 @@ struct cam_periph {
#define CAM_PERIPH_INVALID 0x08
#define CAM_PERIPH_NEW_DEV_FOUND 0x10
#define CAM_PERIPH_RECOVERY_INPROG 0x20
+#define CAM_PERIPH_RUN_TASK 0x40
#define CAM_PERIPH_FREE 0x80
uint32_t scheduled_priority;
uint32_t immediate_priority;
@@ -130,6 +132,7 @@ struct cam_periph {
TAILQ_ENTRY(cam_periph) unit_links;
ac_callback_t *deferred_callback;
ac_code deferred_ac;
+ struct task periph_run_task;
};
#define CAM_PERIPH_MAXMAPS 2
Modified: projects/camlock/sys/cam/cam_xpt.c
==============================================================================
--- projects/camlock/sys/cam/cam_xpt.c Fri Aug 16 09:12:42 2013 (r254405)
+++ projects/camlock/sys/cam/cam_xpt.c Fri Aug 16 09:28:09 2013 (r254406)
@@ -230,7 +230,9 @@ static void xpt_async_bcast(struct asyn
static path_id_t xptnextfreepathid(void);
static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus);
static union ccb *xpt_get_ccb(struct cam_periph *periph);
-static void xpt_run_allocq(struct cam_periph *periph);
+static union ccb *xpt_get_ccb_nowait(struct cam_periph *periph);
+static void xpt_run_allocq(struct cam_periph *periph, int sleep);
+static void xpt_run_allocq_task(void *context, int pending);
static void xpt_run_devq(struct cam_devq *devq);
static timeout_t xpt_release_devq_timeout;
static void xpt_release_simq_timeout(void *arg) __unused;
@@ -984,6 +986,7 @@ xpt_add_periph(struct cam_periph *periph
struct cam_ed *device;
int32_t status;
+ TASK_INIT(&periph->periph_run_task, 0, xpt_run_allocq_task, periph);
device = periph->path->device;
status = CAM_REQ_CMP;
if (device != NULL) {
@@ -3046,7 +3049,7 @@ xpt_schedule(struct cam_periph *periph,
devq = periph->sim->devq;
if (new_priority < periph->scheduled_priority) {
periph->scheduled_priority = new_priority;
- xpt_run_allocq(periph);
+ xpt_run_allocq(periph, 0);
}
}
@@ -3099,10 +3102,23 @@ xpt_schedule_dev(struct camq *queue, cam
}
static void
-xpt_run_allocq(struct cam_periph *periph)
+xpt_run_allocq_task(void *context, int pending)
+{
+ struct cam_periph *periph = context;
+
+ cam_periph_lock(periph);
+ periph->flags &= ~CAM_PERIPH_RUN_TASK;
+ xpt_run_allocq(periph, 1);
+ cam_periph_unlock(periph);
+ cam_periph_release(periph);
+}
+
+static void
+xpt_run_allocq(struct cam_periph *periph, int sleep)
{
struct cam_ed *device;
struct cam_devq *devq;
+ union ccb *ccb;
uint32_t prio;
devq = periph->sim->devq;
@@ -3112,22 +3128,26 @@ xpt_run_allocq(struct cam_periph *periph
periph->periph_allocating = 1;
CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_allocq(%p)\n", periph));
device = periph->path->device;
+ ccb = NULL;
+restart:
while ((prio = min(periph->scheduled_priority,
periph->immediate_priority)) != CAM_PRIORITY_NONE &&
- (periph->periph_allocated < device->ccbq.total_openings ||
- prio <= CAM_PRIORITY_OOB)) {
- union ccb *ccb;
+ (periph->periph_allocated - (ccb != NULL ? 1 : 0) <
+ device->ccbq.total_openings || prio <= CAM_PRIORITY_OOB)) {
- if ((ccb = xpt_get_ccb(periph)) == NULL) {
- /*
- * Malloc failure in alloc_ccb
- */
- /*
- * XXX add us to a list to be run from free_ccb
- * if we don't have any ccbs active on this
- * device queue otherwise we may never get run
- * again.
- */
+ if (ccb == NULL &&
+ (ccb = xpt_get_ccb_nowait(periph)) == NULL) {
+ if (sleep) {
+ ccb = xpt_get_ccb(periph);
+ goto restart;
+ }
+ if (periph->flags & CAM_PERIPH_RUN_TASK) {
+ break;
+ }
+ cam_periph_acquire(periph);
+ periph->flags |= CAM_PERIPH_RUN_TASK;
+ taskqueue_enqueue(xsoftc.xpt_taskq,
+ &periph->periph_run_task);
break;
}
xpt_setup_ccb(&ccb->ccb_h, periph->path, prio);
@@ -3144,7 +3164,10 @@ xpt_run_allocq(struct cam_periph *periph
("calling periph_start()\n"));
periph->periph_start(periph, ccb);
}
+ ccb = NULL;
}
+ if (ccb != NULL)
+ xpt_release_ccb(ccb);
periph->periph_allocating = 0;
}
@@ -3713,7 +3736,7 @@ xpt_release_ccb(union ccb *free_ccb)
xpt_free_ccb(free_ccb);
periph->periph_allocated--;
cam_ccbq_release_opening(&device->ccbq);
- xpt_run_allocq(periph);
+ xpt_run_allocq(periph, 0);
}
/* Functions accessed by SIM drivers */
@@ -4430,13 +4453,11 @@ xpt_free_ccb(union ccb *free_ccb)
/*
* Get a CAM control block for the caller. Charge the structure to the device
- * referenced by the path. If the this device has no 'credits' then the
- * device already has the maximum number of outstanding operations under way
- * and we return NULL. If we don't have sufficient resources to allocate more
- * ccbs, we also return NULL.
+ * referenced by the path. If we don't have sufficient resources to allocate
+ * more ccbs, we return NULL.
*/
static union ccb *
-xpt_get_ccb(struct cam_periph *periph)
+xpt_get_ccb_nowait(struct cam_periph *periph)
{
union ccb *new_ccb;
@@ -4448,6 +4469,19 @@ xpt_get_ccb(struct cam_periph *periph)
return (new_ccb);
}
+static union ccb *
+xpt_get_ccb(struct cam_periph *periph)
+{
+ union ccb *new_ccb;
+
+ cam_periph_unlock(periph);
+ new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_WAITOK);
+ cam_periph_lock(periph);
+ periph->periph_allocated++;
+ cam_ccbq_take_opening(&periph->path->device->ccbq);
+ return (new_ccb);
+}
+
union ccb *
cam_periph_getccb(struct cam_periph *periph, u_int32_t priority)
{
@@ -4459,7 +4493,7 @@ cam_periph_getccb(struct cam_periph *per
ccb_h->pinfo.priority != priority) {
if (priority < periph->immediate_priority) {
periph->immediate_priority = priority;
- xpt_run_allocq(periph);
+ xpt_run_allocq(periph, 0);
} else
cam_periph_sleep(periph, &periph->ccb_list, PRIBIO,
"cgticb", 0);
More information about the svn-src-projects
mailing list