Date: Fri, 16 Aug 2013 09:28:09 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r254406 - projects/camlock/sys/cam Message-ID: <201308160928.r7G9S9kr094170@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308160928.r7G9S9kr094170>