Problems with use of M_NOWWAIT in ATA
Matthew Dillon
dillon at apollo.backplane.com
Fri Nov 28 12:57:33 PST 2003
Soren, while fixing some issues in DFly related to the ATA driver I
found a serious problem in your driver... actually, it appears to be
in ata-ng -stable and -current as well.
The problem is that you are using M_NOWAIT all over the place. M_NOWAIT
allows malloc() to fail if/when resources are temporarily exhausted.
In DFly this can occur more often because it causes malloc() to return
NULL if cannot lock the kernel_map, but I believe malloc() can return
NULL in -current and -stable as well (e.g. if the VM page free list is
empty).
Also, at least in the 4.8 ATA driver, the driver tries to revert to PIO
mode if it cannot allocate a DMA buffer. This is bad because PIO
might not necessarily work. It just isn't appropriate to revert to PIO
mode under any circumstances other then a hardware DMA failure. In
-current you are using bus dma tags and I don't know whether that solves
the issue, but even in -CURRENT you are allocating request structures
with M_NOWAIT (in ata_alloc_request()) and that is just plain not right.
You are virtually guarenteed to corrupt any filesystem trying to issue
a write for which ata_alloc_request() fails. It *CANNOT* fail.
I know the problem is complicated somewhat by the fact that you cannot
simply replace that code with a blocking wait without creating a deadlock
situation. What you really need to do is create a request pipeline and
block up-front to wait for an I/O operation to complete which frees up
an existing request (e.g. before getting the tag). If you do not want
to block in ad_start() you can place the original io buffer on a
queue and reissue when requests/DMA memory are freed up by completing
I/O's.
I am going to be hacking this up in DFly and I'll email you a patch set
when I'm done. This is just a head's up that there are some serious
issues in the ATA driver code related to memory allocation.
-Matt
More information about the freebsd-hackers
mailing list