Page MenuHomeFreeBSD

Don't set BIO_DONE if a bio_done handler is provided
ClosedPublic

Authored by markj on Jan 6 2017, 7:48 PM.
Tags
None
Referenced Files
Unknown Object (File)
Tue, Apr 2, 7:42 PM
Unknown Object (File)
Tue, Apr 2, 5:58 PM
Unknown Object (File)
Mar 3 2024, 7:31 AM
Unknown Object (File)
Mar 3 2024, 7:08 AM
Unknown Object (File)
Feb 9 2024, 7:07 PM
Unknown Object (File)
Dec 28 2023, 4:43 PM
Unknown Object (File)
Dec 20 2023, 3:11 AM
Unknown Object (File)
Dec 3 2023, 5:28 PM
Subscribers
None

Details

Summary

This change re-applies r273143. The original motivation for this change
was to fix callers of biowait(), all of which follow the pattern:

bp->bio_done = NULL;
g_io_request(bp);
biowait(bp);
g_destroy_bio(bp);

(Note that the biowait() calls in ZFS are not compiled on FreeBSD.)

Because the g_disk optimization in r256880 introduced a trick where
the bio_done handler is overridden once the request is dispatched, it
was racy to set BIO_DONE before the g_disk bio_done handler completed.
This g_disk handler takes care to call biodone() with the original
bio_done handler, and this will wake up waiters in biowait(). However,
with r273638 there is no code to exercise this race.

Isilon's FS uses biowait() on BIOs with a non-NULL bio_done handler.
This is done e.g., to serialize updates to a superblock-like state
block. The bio_done handler is responsible for ensuring that waiters are
awoken. Right now it does so by setting bio_done = NULL and calling
biodone() again. With this use-case, it is also incorrect to set BIO_DONE
before calling the handler.

The cause of the corruption mentioned in r273638 is not clear to me, but
I believe that r273143 on its own cannot be the cause. It is
intrinsically racy to set BIO_DONE in common code when a bio_done handler
is provided.

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

markj retitled this revision from to Don't set BIO_DONE if a bio_done handler is provided.
markj edited the test plan for this revision. (Show Details)
markj updated this object.

Does this require all the bio_done handlers to set BIO_DONE?

In D9070#187375, @imp wrote:

Does this require all the bio_done handlers to set BIO_DONE?

No. BIO_DONE is only relevant when there is a possibility that a thread has called biowait() on the BIO. Currently, all callers dispatch BIOs with bp->bio_done = NULL, so BIO_DONE is still set in biodone() as expected. If any GEOMs use the trick of "chaining" bio_done handlers by inserting their own, they are also responsible for ensuring the original bio_done handler is called, which is still responsible for setting BIO_DONE as needed.

mav edited edge metadata.

While motivation with double biodone() call can be questioned, I agree that setting BIO_DONE without any locking in case of bio_done() present is just calling for problems.

This revision is now accepted and ready to land.Jan 7 2017, 1:36 PM
This revision was automatically updated to reflect the committed changes.