I have found and fixed the bug; I did not disable interrupts while DOS was copying data from the cached read-ahead blocks, and newly arriving read-ahead blocks were arriving at the same time, stepping on what was being copied from the cache.
It was very timing specific but still I should have seen this. I normally test on a virtual machine and move to real hardware afterwards. The virtual machine is basically infinitely fast, so it should expose timing problems, and then the PCjr is as slow as it gets, so it should also expose timing problems. A Pentium 133 exposed the timing problems in this case.
I'll post updated versions after I get more testing time on the code. Also, I've started sketching out how to make writes faster too, but that's a few months away before it is safe to share.
-Mike