[comp.os.minix] Minix 68000. Multitasking File System.

colinm@runx.ips.oz (Colin McCormack) (07/03/88)

I have spent the last 7 months porting minix v1.2 to 68000 and am close to
completion.  I can run user programs like ls without too much trouble,
although there are still bugs to be worked on.  The target machine is a
locally produced 68000 and is unlikely to compete with the ST version.

At this point I thought I'd drop a line summarising the changes I made and
raising a few points of interest.

I made a lot of changes to the kernel/mm/fs.  The main followed on from a
decision to permit different link spaces for all tasks and processes.

I moved the proc, mproc and fproc structures out into ram and only keep a
pointer to them in kernel/mm/fs (this compiles to more efficient code on my
machine, since all pointers are 4 bytes and can be indexed without an
expensive multiplication).

I allowed kernel and mm to share the map structure to minimise the message
traffic that minix uses to keep the two copies in step.

I added a message exchange and some extra primitives to permit conditional
receives and resend message to self (not that these facilities are used
very often - minix messages are usually synchronous.)

I changed fs and all tasks to make devices configurable at boot time.

Build is also done at boot time.

The above were changes I _chose_ to make, not strictly changes that had to
be made to port to 68000.

I will eventually remove the arrays proc[], mproc[] and fproc[] entirely and
use bits in proc structures to indicate type of process.  The process number
will become a process pointer in this scenario (which is more efficient since
my C compiler uses 32 bit ints anyway).

The kernel is very much changed, most of the interrupt handling is done in
C now, in a general fashion, with all interrupts defined by a small control
block - this may be changed when I am in a position to assess its performance
impact.

Bruce Evans has pointed out that a lot of the time processes line up waiting
for disk i/o.  This is as you would expect, but the problem appears when you
consider that fs is not internally multitasking, so one process waiting for
a disk will hold up all other processes wanting to perform _any_ i/o, even
character device i/o (whereas character device i/o _can_ be performed by
several processes concurrently if the tasks handling the i/o are written
to support it).

The major difference between character and block i/o in fs is that all
character device i/o is performed on behalf of the client process which
requested it, whereas all block device i/o is done by the fs _on_behalf_of
the_fs_ since block i/o is always indirected through the cache.

For this reason, I doubt that block suspension can be handled in the same way
as character i/o suspension (also, I think that the character i/o suspend
logic in fs depends too much upon the task to implement it.)

Since this is proving to be a major bottleneck in fast processor
implementations of minix, I think it deserves some attention.

Let me point out at the outset that block device i/o is performed by the
fs functions get_block() and put_block() which are logically part of the
cache and are called in about 32 and 20 places (respectively) through fs.
This implies that any traditional method will have to maintain the context
of these 52 calls across a suspension.  I think this is a very complex
undertaking (The way it's often handled is via lots of interlocked
finite state machines with a central message-reader/coroutine-dispatcher
which I personally find repulsive.)

I suggest a different alternative (not fully worked out) for the perusal
of the comp.os.minix group.  Note that it relies on facilities nobody
has yet implemented (to my knowledge) in a complete or acceptable way.

Make cache a proper device handled by a task (as Bruce Evans will explain
there may be some benefit to having it handled by /dev/ram).  So all of
the get_ and put_block() calls will be sendrec()s to /dev/cache requesting
the cache device to return a block or store a block.

Let cache device send messages directly to any of the other block devices
and let it perform all of the necessary copying from the cache to the
nominated addresses.

Make all of fs data structures external to the fs data and bss space
(this implies that mm can malloc anywhere in ram and recover the space if
the owner dies, and that you 80x86 people can handle so-called "far" pointers).

Provide some interprocess synchronisation method like token-passing
(or semaphores, or critical regions - whichever you prefer) to sequentialise
access to the fs data structures .  Modify fs so that it handles all of the
data structures currently defined as globals in critical regions.

Finally: fork() a new fs for all block device i/o.

I would appreciate feedback on this suggestion.

Colin McCormack.

????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????