153 lines
7.4 KiB
Groff
153 lines
7.4 KiB
Groff
|
yes I know this is not in mandoc format..
|
||
|
|
||
|
The slices are stackable..
|
||
|
With alternating layers of handler(driver)/slice/handler/slice/handler/slice
|
||
|
The "Slice" is implemented as a common structure shared between three
|
||
|
pieces of code. Each slice in the stack can be thought of in OO terms as
|
||
|
an instance of the 'slice' object. Methods include all the 'device' node
|
||
|
methods exported via the cdevsw[], bdevsw[] and devfs interfaces. Thus
|
||
|
whenever a handler exports a slice object, a unique node is made available
|
||
|
to the users via the device system, to access that slice, as if it were a
|
||
|
disk in it's own right. Since the interface is implemented by the same
|
||
|
code no matter where in the stack it occurs, all partitions and devices
|
||
|
which are exported by the slice code, exhibit almost identical behavior.
|
||
|
Theoretically, it should be possible to treat a partition of a device, as
|
||
|
if it were a separate device, as it should exhibit the same behavior as
|
||
|
the device itself (except for size).
|
||
|
|
||
|
The diagram below exhibits the form of one layer of the stack. Each handler
|
||
|
can decide how many slices to export on the upper side, and
|
||
|
how many slices to connect to on the lower side. If A slice can not be
|
||
|
further subdivided, there may not be an upper handler.
|
||
|
|
||
|
[upper handler] (optional)
|
||
|
^
|
||
|
|
|
||
|
|
|
||
|
v |------ raw (char) device
|
||
|
[common slice information]<---------->[slice device]
|
||
|
^ |------ block device
|
||
|
|
|
||
|
|
|
||
|
v
|
||
|
[lower handler] (may be a device driver)
|
||
|
|
||
|
Each of these 3 items share some knowledge of the internal structure and
|
||
|
contents of the slice structure. They also know each other's published
|
||
|
interfaces. This may change as the design settles down and it becomes more
|
||
|
obvious which parts can be hidden.
|
||
|
|
||
|
The slices are created bottom up.
|
||
|
When the driver decides that there is media that should be made available,
|
||
|
it creates a 'slice' object to represent it. This slice object comes with a
|
||
|
set of methods for exporting and implementing a device. The action of creating
|
||
|
a slice therefor creates the interface through which a user can access that
|
||
|
device. A driver might even export such slice before the media is present,
|
||
|
in order to make a device node available to the user. (e.g. the floppy
|
||
|
driver would make /dev/rfd0 available even if there was no media present,
|
||
|
simply because it has no way of detecting that the media has been added.
|
||
|
Attempts to open or access that node would result in the usual EIO
|
||
|
errors.
|
||
|
|
||
|
i.e. the device probes, and creates a static 'slice' that is associated with
|
||
|
the device.. The static slice can't be removed unless the driver does so,
|
||
|
thought if the media is changed the size of the slice may change.
|
||
|
|
||
|
|
||
|
Some time after the media has been detected, or deduced to be present,
|
||
|
the driver would ask the system to try interpret the contents of the
|
||
|
media. It does this by passing the slice to the generic code. The generic
|
||
|
code will ask all the possible handlers to see if that slice (or virtual
|
||
|
disk) has the structure it requires. Sometimes the driver (or lower handler,
|
||
|
for that is what the driver is from the point of view of the slice) Will 'seed'
|
||
|
the slice with a 'hint' which will make the generic code narrow it's requests
|
||
|
to a particular handler, or group of handlers.
|
||
|
|
||
|
When a slice object attaches an handler to one of it's slices, that handler
|
||
|
might elect to further export more slices, each representing some different
|
||
|
view of the slice. This could result on a multi layer stack of slices and
|
||
|
handlers, depending on the contents of the device. Whether a handler will
|
||
|
elect to further divide a slice given to it is solely up to that handler. No
|
||
|
other code has jurisdiction over that decision.
|
||
|
|
||
|
Because a device may need to know that it is being used, it is important
|
||
|
that open() events be cascaded down towards the device. Handlers that
|
||
|
export multiple slices upwards must pass down the union of all the open
|
||
|
states of those slices.
|
||
|
|
||
|
A lower level handler can decide that the slices it has exported are no
|
||
|
longer valid. This can occur for several reasons. For example a write to a
|
||
|
low level slice might change the structures defining a higher level slice,
|
||
|
or a driver (the lowest level handler) might notice that the media on which
|
||
|
a slice is based, has been removed, or in some other way become
|
||
|
unavailable. The handler must be able to invalidate the slice(es) affected,
|
||
|
and know that the system will cascade that invalidation upwards as needed.
|
||
|
A higher handler may decide to no pass on the invalidation if it calculates
|
||
|
that higher level services can still be provided without the particular
|
||
|
lower slice being present, (e.g. a RAID handler).
|
||
|
|
||
|
Access to various layers is controlled by a strict protocol to avoid
|
||
|
accidental system damage. There is a single sysctl variable that can
|
||
|
disable the enforcement of this protocol, however it should ony be used
|
||
|
in special (e.g. system instalation) circumstances. The basic protocol
|
||
|
is that a higher level device cannot be opened while one of it's lower
|
||
|
layers is open for writing. Similarly, a lower layer cannot be openned for
|
||
|
writing while an upper layer is open at all. Two devices at different
|
||
|
layers can be openned at the same time if there is no direct
|
||
|
decendancy between the two. In an analogue, we might say that 'cousins'
|
||
|
can be openned independantly, but anscestors and descendents cannot.
|
||
|
The sysctl variable kern.slicexclusive has 3 values.
|
||
|
0 disables the checks metioned above. 1 enables them, and 2
|
||
|
enables eve more draconian rules in which even READ opens are disabled.
|
||
|
|
||
|
Further rules govern the interaction of the block and raw versions of a
|
||
|
slice. For example, if a block device is open for read/write, it's raw
|
||
|
device can not be written to (in mode 1)
|
||
|
|
||
|
[think about upwards permission inherritance for subslices]
|
||
|
|
||
|
|
||
|
[setting up new configurations]
|
||
|
A disk exports simply a raw slice. It has no preference as to what goes on it..
|
||
|
(preferences are stored in the slice's probehints structure.)
|
||
|
To slice it into fdisk type:
|
||
|
1/ set the hints to "mbr", through an ioctl on that device. (e.g. rsd0)
|
||
|
2/ Run the "mbr" code's constructor. this will initialise the slice.
|
||
|
The "mbr" code will actually write an mbr to the slice,
|
||
|
with default values. (so it will recognise it in the future).
|
||
|
(this is why the claim is separate from the constructor). The claim()
|
||
|
is nondestructive. The constructor KNOWS it owns the slice.
|
||
|
3/ Send ioctls to the device that are redirected UP to the new handler.
|
||
|
These ioctls allow "type specific templates" and manipulation
|
||
|
of slice tables. Each hander interprets these to suit it's own table
|
||
|
format. This uses the sl_h_upconfig() method, which is basically an
|
||
|
ioctl entrypoint, but which is not automatically cascaded up.
|
||
|
|
||
|
|
||
|
rc should have the following added to it to make the system 'safe'
|
||
|
when multi-user mode is entered.
|
||
|
|
||
|
*** /etc/rc.orig Sat Apr 18 14:34:48 1998
|
||
|
--- /etc/rc Sat Apr 18 14:38:32 1998
|
||
|
***************
|
||
|
*** 82,87 ****
|
||
|
--- 82,96 ----
|
||
|
exit 1
|
||
|
fi
|
||
|
|
||
|
+ ###DEVFS
|
||
|
+ # put the storage slices into safe mode.
|
||
|
+ # 0 == unsafe. One char, one blk and one subslice can all be openned R/W.
|
||
|
+ # 1 = readonly. If a subslice is open, a blk and chr can be openned R/O.
|
||
|
+ # If a slice is open R/W, subslices cannot be openned.
|
||
|
+ # 2 = exclusive. If a subslice is open, a blk or chr cannot be openned.
|
||
|
+ # and visa versa.
|
||
|
+ sysctl -w kern.slicexclusive=1
|
||
|
+
|
||
|
# If there is a global system configuration file, suck it in.
|
||
|
if [ -f /etc/rc.conf ]; then
|
||
|
. /etc/rc.conf
|
||
|
|
||
|
|
||
|
|