hammer2 - Fix DIO_INPROG race.
authorMatthew Dillon <dillon@apollo.backplane.com>
Sun, 1 Mar 2015 19:46:12 +0000 (11:46 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sun, 1 Mar 2015 19:46:12 +0000 (11:46 -0800)
* It is possible when a chained DIO_INPROG is present for the DIO to become
  GOOD and for the dio->refs ref to be release, but not yet have finished
  its INPROG processing due to the chaining.

  In this situation, a temporary user of the DIO will get/put it and hit
  an important sanity assertion in putblk.

* Fix by disallowing the DIO_GOOD shortcut in hammer2_io_getblk() if the
  DIO is still DIO_INPROG.

sys/vfs/hammer2/hammer2_io.c

index ea1cb24..6fa6880 100644 (file)
@@ -142,8 +142,18 @@ hammer2_io_getblk(hammer2_mount_t *hmp, off_t lbase, int lsize,
                /*
                 * Issue the iocb immediately if the buffer is already good.
                 * Once set GOOD cannot be cleared until refs drops to 0.
+                *
+                * There is a race here if a chained DIO_INPROG is present
+                * (typically DIO_INPROG and DIO_WAITING are both set
+                *  along with GOOD).  The DIO can become GOOD but not
+                * yet have finished its INPROG processing, causing an
+                * assertion in putblk later on.
+                *
+                * To deal with this we do not take the shortcut if INPROG
+                * is still set.
                 */
-               if (refs & HAMMER2_DIO_GOOD) {
+               if ((refs & (HAMMER2_DIO_GOOD | HAMMER2_DIO_INPROG)) ==
+                   HAMMER2_DIO_GOOD) {
                        iocb->callback(iocb);
                        break;
                }