Bug 198356 - Possible infinite sleep in mmc_wait_for_req()
Summary: Possible infinite sleep in mmc_wait_for_req()
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 10.1-STABLE
Hardware: arm Any
: --- Affects Only Me
Assignee: freebsd-arm mailing list
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-03-06 14:45 UTC by Grégory Soutadé
Modified: 2015-07-08 14:18 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Grégory Soutadé 2015-03-06 14:45:14 UTC
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.