Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 06 Mar 2015 14:45:14 +0000
From:      bugzilla-noreply@freebsd.org
To:        freebsd-bugs@FreeBSD.org
Subject:   [Bug 198356] Possible infinite sleep in mmc_wait_for_req()
Message-ID:  <bug-198356-8@https.bugs.freebsd.org/bugzilla/>

next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198356

            Bug ID: 198356
           Summary: Possible infinite sleep in mmc_wait_for_req()
           Product: Base System
           Version: 10.1-STABLE
          Hardware: arm
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: freebsd-bugs@FreeBSD.org
          Reporter: soutade@gmail.com

This is the current code of sys/dev/mmc/mmc.c.

  372 static void
  373 mmc_wakeup(struct mmc_request *req)
  374 {
  375         struct mmc_softc *sc;
  376 
  377         sc = (struct mmc_softc *)req->done_data;
  378         MMC_LOCK(sc);
  379         req->flags |= MMC_REQ_DONE;
  380         MMC_UNLOCK(sc);
  381         wakeup(req);
  382 }
  383 
  384 static int
  385 mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req)
  386 {
  387 
  388         req->done = mmc_wakeup;
  389         req->done_data = sc;
  390         if (mmc_debug > 1) {
  391                 device_printf(sc->dev, "REQUEST: CMD%d arg %#x flags
%#x",
  392                     req->cmd->opcode, req->cmd->arg, req->cmd->flags);
  393                 if (req->cmd->data) {
  394                         printf(" data %d\n", (int)req->cmd->data->len);
  395                 } else
  396                         printf("\n");
  397         }
  398         MMCBR_REQUEST(device_get_parent(sc->dev), sc->dev, req);
  399         MMC_LOCK(sc);
  400         while ((req->flags & MMC_REQ_DONE) == 0)
  401                 msleep(req, &sc->sc_mtx, 0, "mmcreq", 0);
  402         MMC_UNLOCK(sc);
  403         if (mmc_debug > 2 || (mmc_debug > 0 && req->cmd->error !=
MMC_ERR_NONE))
  404                 device_printf(sc->dev, "CMD%d RESULT: %d\n", 
  405                     req->cmd->opcode, req->cmd->error);
  406         return (0);
  407 }

As I understand :

When the MMC stack sends a command, it goes into mmc_wait_for_req(), that
defines callback mmc_wakeup(). This callback should sets MMC_REQ_DONE flag and
wakeup sleeped thread when request is completed. Request is sent to driver at
line 398, then it locks the mutex, test flag and goes to sleep.

But, in my case, I got an interrupt after flag test (line 400) and before "req"
has been added to the sleepqueue. It results that mmc_wakeup() is called, it
sets flag and try to wakeup, but didn't find "req" in the sleepqueue. In theory
this behaviour is protected by MMC_LOCK, but the two calls (mmc task and
interrupt) has the same thread id, so anyone is being suspended.

To fix this, I suggest setting a timeout in msleep() instead of 0.

I marked it for version 10.1-STABLE, but 11.0-CURRENT has the same code.

-- 
You are receiving this mail because:
You are the assignee for the bug.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-198356-8>