* 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.
/*
* 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;
}