The moose release will not have objectserver to kick around any more. mediad/banyan is tightly coupled to the objectserver, so new mediad needs new functions and interfaces to provide the functionality that objectserver previously provided.
The moose's floppy is on a parallel port, not SCSI. Mediad/banyan is 100% SCSI oriented. Moose mediad must also support non-SCSI devices such as the floppy.
Mediad/banyan stops monitoring devices when an application such as cdplayer or SoftWindows takes exclusive use of a device, and is unable to update the desktop's icon states. Moose mediad should continue to sniff device state and update its clients even when those apps are running.
Mediad/banyan supports 3 types of filesystem on 7 types of device. It has 3 * 7 = 21 places where it recognizes a particular filesystem on a particular device. That's getting unwieldy to maintain. We expect more devices and more filesystems in the future, so new mediad should not require M *N places where filesytems are recognized. Instead, we should have an M + N design.
Also, moose mediad should let us release support for a new device, e.g. in a patch, without re-releasing all devices. That should prevent, or at least reduce, rev locking between devices.
Under Irix, a particular device can be referred to by several different names. E.g., /dev/scsi/sc0d4l0, /dev/rdsk/dks0d4vol, and /dev/dsk/dks0d4s7 all refer to the same disk. Mediad recognizes device name aliases in an ad hoc way, and this is a continuing maintenance problem.
Mediad/banyan assumes that every disk has exactly one file system on it. That's not true in the case of partitioned disks nor hybrid CD-ROMs. Moose mediad should be able to mount any/all partitions, and should let the user control which one(s) are mounted.
In the first release, it will not be possible to mount more than one partition at a time.
Moose mediad should use no more system resources (memory, CPU, I/O bandwidth) than mediad/banyan. Mediad/banyan's CPU and I/O consumption are negligible, so the only real concern is resident size.
Moose mediad's basic design metaphor is a device, filesystem, and client interface independent core with many ancillary modules. The core implements mediad's basic logic and has interfaces to all the ancillary modules. The ancillary modules are either in the form of DSOs, where we want to be able to field-extend various modules, or linked into the mediad executable, where we don't want field-extensibility.
Rather than referring to devices by name (/dev/whatever) or by SCSI controller/ID/LUN, moose mediad defines a DeviceAddress as an abstract type, whose concrete subtypes are SCSIAddress and ParallelAddress. More subtypes can be defined as needed. The SCSIAddress is, sure enough,
composed of <controller, ID, LUN>. Since moose has a single parallel port, a ParallelAddress is unique. DeviceAddresses
may be compared for equality, using operator ==. There are routines to convert a H/W inventory record or a SCSI triple to a DeviceAddress.
A PartitionAddress on a device is defined as the tuple <DeviceAddress, format, number>, where DeviceAddress is as defined above, format is an enum of the known filesystem formats, and number is the partition number of that particular format. Partition numbers are
defined per-format. E.g., DOS uses 1-4 for primary partitions and 5-8 for
extended partitions. The constant PartitionAddress::WholeDisk can be used as a partition number. Note that a PartitionAddress does not
specify sector numbers. In some cases, an address exists when there is no specific device to attach it to,
and no specific sector numbers. Weird, but necessary.
Both DeviceAddress and PartitionAddress are values. By that I mean that instances can be created and destroyed without side effects.
Each supported device has a separate DSO containing the code that knows how to talk to that specific device and also describing that device's features. Each DSO has a routine named "instantiate" which looks at a DeviceInfo record and decides whether that DSO knows that device. If so, the instantiate routine returns a pointer to new Device object. Otherwise, it returns nil.
Device objects are derived from class Device. Look at Device.H to see the exact interface of a device.
Each supported filesystem format has a separate DSO containing the code
that can recognize that format. Each format DSO has an "inspect" routine
that is called to inspect a device for filesystems of that format. When
the inspect routine finds one or more filesystems, it instantiates Partitions
by calling Partition::create(), then instantiates Volumes by calling SimpleVolume::create().
The mediad core scans the hardware inventory and attempts to instantiate a Device subclass on each record in the inventory. When it finds a supported device, it creates a DeviceMonitor to watch that device. The DeviceMonitor accesses the hardware through the Device subclass. The DeviceMonitor also generates events on insertion, ejection, mount, and dismount, and responds to commands to eject, lock or unlock devices.
There are three client interfaces. They are the CompatClient, the MonitorClient, and FsdClient interfaces. CompatClient is the same interface as mediad/banyan supported. MonitorClient is a new interface which describes the state of all removable devices and volumes in the system, and generates events when that state changes. FsdClient monitors changes to /etc/fsd.auto through the miracle of fam, and changes mediad's behavior when that file changes.
Mediad supports most of the command line arguments implemented by mediad/banyan. It also is hard-linked to the /usr/sbin/eject command, and it can also be invoked by inetd, in the case where a remote MonitorClient wants to see the system state, but mediad isn't already running.
Since mediad is object oriented, it makes sense to describe its design in terms of its objects. Each class is described in detail in its header file.
These classes provide nifty support functions for the rest of mediad.
Several classes are subclasses of Enumerable. By subclassing Enumerable, a class gets a variety of methods for enumerating
its instances. To access all elements sequentially, use first(), next(), prev() and last(). To access elements nonsequentially, use index(), nth() and count().
The Scheduler is based on select(2). A module can create a Task to be executed at some time or at regular intervals, or it can create an IOHandler, which will be called when a descriptor becomes ready for I/O. IOHandler is abstract - the three concrete subclasses are ReadHandler, WriteHandler, and ExceptHandler.
FAMonitor is an abstract class of "filesystem entity monitored by FAM". The two subclasses are FileMonitor and DirectoryMonitor. When the file or directory is changed, the FAMonitor's callback is called.
DSReq is a wrapper around the dsreq_t; see dslib(3X). The DSReq has the property that it automatically opens and closes the /dev/scsi device - there's no need to keep track of who opened it and who closes
it, and there's no way to introduce bugs by forgetting to put dsclose() into one code path.
The Log class logs messages to syslog or to standard error.
These are described above in the Design Overview section.
When mediad is probing for devices, it creates a DeviceInfo record and hands it to each of the device DSOs' instantiate routines. The DeviceInfo is a grab bag of potentially useful info. It includes a H/W inventory record, a DeviceAddress, and, for SCSI devices, the result of a SCSI INQUIRY command.
Device is the abstract superclass from which device objects are derived. It has a bunch of methods for obtaining info about the device and for controlling the device.
Devices are enumerated. Whenever a MonitorClient receives an event, mediad sends it a list of all Device objects. So a Device object is only created when there's a real device that mediad is really monitoring.
Each device has three methods for returning its name. The methods are short_name(), ftr_name() and dev_name(). This is ugly, but necessary.
The short name is the common name of the device. It corresponds to objectserver's resourceObject name attribute. Prepend a "/" to it to form the device's default mount point. The short name has no punctuation characters. (e.g., CDROM, floppy2)
The ftr name is the name as it appears in the file type rules. Devices don't necessarily have unique ftr names. For example, three CD-ROM drives would all have cdrom as their ftr name.
The dev name is the name of the /dev entry that should be used to open that device. The dev_name method takes
a filesystem format and a partition number as an argument. So, for example, CDROM::fmt_name(FMT_CDDA, WholeDisk) returns /dev/scsi/sc<whatever>, while CDROM::fmt_name(FMT_EFS, 7) returns /dev/dsk/dks<whatever>s7.
A Partition is a piece of a disk. A partition has a format associated with it, either one of the filesystem formats or "raw". It also has sector info: sector size, starting sector, and number of sectors. The last two are 64 bit integers.
Every device with media has one partition in raw format that describes the total capacity of the media.
Partitions are enumerated. Whenever a MonitorClient receives an event, mediad sends it a list of all Partition objects. So a Partition object is only created when there's a real partition on a disk.
A Volume is a lot like a filesystem. Volume is an abstract base class. A volume
has one or more Partitions, a label, and info about how to mount it, in
the form of a struct mntent.
SimpleVolume is the concrete subclass of Volume. It's a volume with one partition. Mediad does not currently support multi-partition volumes, but the structure is in place to add that support by defining a new subclass of Volume.
Volumes are enumerated. Whenever a MonitorClient receives an event, mediad sends it a list of all Volume objects. So a Volume object is only created when there's a real volume on disk(s). The volume doesn't have to be mounted.
MediaDaemon is the object that probes for devices in the system and creates DeviceMonitors to monitor them. There is exactly one MediaDaemon object.
DeviceMonitor is the object that monitors one device. It wakes up periodically and checks the device's state. When a medium is inserted, the DeviceMonitor calls each of the FormatDSOs to inspect the medium. The FormatDSOs may create Volumes and Partitions. When a medium is ejected, the DeviceMonitor destroys any Volumes or Partitions associated with that device.
A DeviceMonitor responds to several commands, activate(), deactivate(), suspend(), resume(), and eject(). Eject is obvious. Activate/deactivate occur in response to libmediad's release/get exclusive use functions. Suspend/resume occur when mon=on/off is set in /etc/fsd.auto.
These are silly classes that maintain a list of all the device DSOs and format DSOs. Both DSO libraries look in /usr/lib/devicelib, and find all files matching a pattern, either dev_*.so or fmt_*.so, respectively.
DSO is the abstract base class for a Dynamic Shared Object. It has methods to load/unload, and to look up a symbol. These are just thin wrappers around dlopen, dlclose and dlsym. The concrete subclasses are DeviceDSO and FormatDSO.
DeviceDSO has a method, instantiate(), that calls the DSO's instantiation routine. DeviceDSO maintains a reference
count of the number of instances each DSO has so that a DSO won't be unloaded
while instances exist.
FormatDSO has a method, inspect(), that calls the DSO's inspection routine.
The CompatListener listens for client connections from clients using the mediad/banyan interface. It listens on a Unix domain socket. When it gets a connection, it creates a CompatClient object. There is only one CompatListener object.
The CompatClient object handles a single session with an old-style client. Each session consists of a single request-response pair. These are the requests.
The RPCListener listens for RPC connections from monitor clients. When it gets one, it creates a MonitorClient object. There is only one RPCListener object. The protocol used is TCP/IP, so mediad will accept connections from remote clients. (But only if the share_devices chkconfig option is on.)
A MonitorClient object handles a single session with a monitor client. When it first connects, and when certain events happen, it sends a message to the client. These are the events.
Each MonitorClient registers itself to receive callbacks from the mediad core. The callbacks occur when a DeviceMonitor detects that a medium has been inserted, ejected, or reformatted, and when mediad mounts or dismounts a filesystem.
The message sent to the client is XDR-encoded. It has two main parts: an event record and the system state. The event record has an event code and either a device number (for an MCE_INSERTION, MCE_EJECTION, or MCE_REFORMAT event) or a volume number (for MCE_MOUNT or MCE_DISMOUNT). The system state is a list of all devices, all partitions, and all volumes known to mediad, along with a variety of attributes about each.
The FSDMonitor is not yet implemented. It will monitor /etc/fsd.auto for changes using fam, and it will update mediad's state appropriately. I'm not sure how it will work yet.
This section to be written. Ought to describe what the DSOs do in detail, as they are above.
Ditto.
This section to be written. CDs are ugly, and our CD support is ugly too.
Mediad can be invoked several different ways. The executable figures out how it was invoked and does the right thing.
Normally, mediad is started at boot time from /etc/init.d/mediad. In this mode, it scans the system for monitorable devices and, if it finds any, sits and monitors them.
Mediad may also be invoked by inetd(1M), in response to a monitor client's attempt to connect. In this case, mediad tries to forward the connection to the real mediad, and if it can't, it replies that there are no removable devices.
Mediad is also linked to the eject command. When invoked as eject, mediad tries to send an eject message to the real mediad, using the CompatClient interface. If there is no other mediad running, mediad probes the specific device requested, finds its DeviceDSO, and tells the DeviceDSO to eject the medium. This has the advantage that the same code is executed whether or not mediad is running, and eject is automatically extended to new devices when mediad is.
Mediad can be invoked from the command line with a variety of options. Some of the more common ones are:
This section is to be written. Briefly, the exclusive use problem has been solved, by changing all the clients that use it. Icons should be live all the time. (It's not tested yet.)