41 lines
1.8 KiB
Plaintext
41 lines
1.8 KiB
Plaintext
|
$FreeBSD$
|
||
|
|
||
|
For the lack of a better place to put them, this file will contain
|
||
|
notes on some of the more intricate details of geom.
|
||
|
|
||
|
-----------------------------------------------------------------------
|
||
|
Locking of bio_children and bio_inbed
|
||
|
|
||
|
bio_children is used by g_std_done() and g_clone_bio() to keep track
|
||
|
of children cloned off a request. g_clone_bio will increment the
|
||
|
bio_children counter for each time it is called and g_std_done will
|
||
|
increment bio_inbed for every call, and if the two counters are
|
||
|
equal, call g_io_deliver() on the parent bio.
|
||
|
|
||
|
The general assumption is that g_clone_bio() is called only in
|
||
|
the g_down thread, and g_std_done() only in the g_up thread and
|
||
|
therefore the two fields do not generally need locking. These
|
||
|
restrictions are not enforced by the code, but only with great
|
||
|
care should they be violated.
|
||
|
|
||
|
It is the responsibility of the class implementation to avoid the
|
||
|
following race condition: A class intend to split a bio in two
|
||
|
children. It clones the bio, and requests I/O on the child.
|
||
|
This I/O operation completes before the second child is cloned
|
||
|
and g_std_done() sees the counters both equal 1 and finishes off
|
||
|
the bio.
|
||
|
|
||
|
There is no race present in the common case where the bio is split
|
||
|
in multiple parts in the class start method and the I/O is requested
|
||
|
on another GEOM class below: There is only one g_down thread and
|
||
|
the class below will not get its start method run until we return
|
||
|
from our start method, and consequently the I/O cannot complete
|
||
|
prematurely.
|
||
|
|
||
|
In all other cases, this race needs to be mitigated, for instance
|
||
|
by cloning all children before I/O is request on any of them.
|
||
|
|
||
|
Notice that cloning an "extra" child and calling g_std_done() on
|
||
|
it directly opens another race since the assumption is that
|
||
|
g_std_done() only is called in the g_up thread.
|