copyin/copyout--put in locore.s, use user's segment
	-- Worse than I thought.  Bug in i386 allows ring 0 code to write
	to a read-only mapping.  So COW is a bust when one would expect
	it to work for a copyout.  Walk translations manually?  Bleh.
	Use copy-on-reference for i386.
	Nah, ignore it and use the new bits of the i486 and later.

X TLB staleness--how split HAT/portable?  Assume TLB shootdown is
X relatively cheap and if not assume HAT will do the gyrations
X necessary?
	-- Yes

X Should HAT update ref/mod bits in c_flags?
	-- Moved this to pp_flags.  It's done above the HAT.

X Make sure users can't send M_RESVD messages
	-- Done.  Allow M_TIME as I don't feel like renumbering it now.

X How hand msg_err() answers around?
	-- In the m_err field in a sysmsg, which is copied into
	 the thread's error field when in the thread's context.

X Make msg_send() and msg_connect() handle the case of the port dying
X with their stuff queued.  Does a lock on the port give a guarantee
X that any transition to state P_DEAD will guarantee an answer to their
X queued message first?
	-- client handles sysmsg; server handles segments received.
	 Server gets away from client by zeroing the p_port field.
	 Server enumerates clients through his circular linked list
	 of portrefs.

X Have to have server use portref's segref array--multiple outstanding
X requests on a server allows several requests worth of mapped data
X to be present.
	-- The segrefs which are currently attached is kept in a per-
	 *thread* variable.  A thread must either finish with its use
	 of the data before its next receipt, or must copy it to
	 someplace more permanent.

X Change the psop_writeslot so that the asynch flag is instead a pointer
X to a function--NULL means synchronous.  Then pageout pushes can use
X a routine to free/clean the page, exit pushes can simply free, and
X so forth.
	-- Done.  iodone_free() and iodone_unlock() will do free/unlock
	or unlock on completion.

X Add a FS_ABSWRITE and FS_ABSREAD to combine a seek and a write.  Needed
X for many things, including swap I/O's.
	-- Added for floppy driver.  Must ensure handled for disk drivers
	when they're written.  Still nice to add to all handlers that
	offer seek.

X Add the second argument to msg.c and msgcon.c handling.
	-- Done.

X Add optimization to add the cache translation *each time* someone faults
X a slot translation in.  Currently we only add when going from !PP_V->PP_V;
X this works, but will guarantee that the page must be brought in from
X its server if the cache view is ever paged out.  Should be done by keeping
X a flag with the perpage, and clearing it when these cache translations
X are deleted.
	-- Bogus concept.  We allow caching by letting pages reside under
	a pset with a ref count of 0.  The pageout daemon is reponsible
	for reaping these as memory situations demand.

X Add machinery to page stealer to raid cache pviews who are the last
X reference to the pset.  We need them as we don't tag the page otherwise,
X but we should clear them out over time.  Note that the pages can be
X stolen just fine; it's the pview itself that we need to reclaim at
X some point.
	-- There is no such thing, though I still need to add something
	to lazily keep psets around, even though they're not currently
	mapped.  Trick is that this has to be unified with a mechanism
	for mapping a pset to a given server and inode number.

X Add code to manage T_KERN bit of thread flags
	-- Skip it.  Not worth the trouble.

Add code to qio_msg_send to handle case of a "copyout".  A bcopy()
to ptov(pfn) should suffice?  Who would use it?

X Add handling for M_DUP messaging.  How correlate back to new portref
X being created?
	-- Done.  The p_msg field of the portref tells us that it's an
	M_DUP, and it tells us (in m_arg) what's being created.

Convert m_connect() (and others?) to use kernmsg_send().  I think I
can make the code quite a bit smaller.

X Add code to put a proc on the "cheated" queue.
	-- Done.  Also have to keep a CPU hog counter, as otherwise
	a CPU hog gets bumped once by a "cheated" process, and becomes
	a "cheated" process itself.

X Should "allprocs" be doubly-linked?
	-- Done.  Useful for at least one flavor of pstat() to keep
	marker for place in proc list.  Also gives the obvious benefit
	of an O(1) removal on exit().

Once up, should invalidate all vaddr's above heap

X Clean up scheduling node on exit
	-- Done.  "memleak" function of kdb is your friend....

X Implement mmap()
	-- Done.

X In fork() the portref array is mutexed across the entire dup_port()
X 	using p_sema from the proc structure.  This is at least overkill,
X 	perhaps worse.  The code should use find_portref(), scanning the
X 	old portref array and attempting to get portrefs through the
X 	usual interface.  This shares more code, and considerably narrows
X 	the time for which the proc sema must be held.
	-- Done.  Became acute with pstat() interlocking against such
	processes.  Now is released as we step along.

XAdd a flag for pviews to tell if they should be copied/inherited on
X	a fork().  Make sure transient pviews from msg_receive()'s
X	are *not* inherited.
	-- I think the SHARED flag (in the pset?) does the job.

XRethink struct core's c_long vs. c_atl fields.  They are mutually
X	exclusive in use except for cases of M_CONNECT messages,
X	where the user temporarily maps the permissions of the
X	connecting process.  Perhaps it would be worth adding some
X	code to handle this differently... would it be worth it
X	to regain 4 bytes per 4K (0.1%) overhead?
	-- Revamped.  The attach lists of pviews have moved up to
	the perpage struct--c_atl only indicates the primary pset.
	This keeps the temporary user mapping of a memory pset from
	trashing our malloc state.

Add check to enable_dma() for conflict in DMA channels

Check abort in wd/rw.c to see if we do the right thing when we're
	DMA'ing into the would-be-aborters address space.
	Definitely a problem... f_abort is set but not used.
	The code does not really flag queued versus active;
	aborting queued would be easy.  Active is going to require
	waiting for the completion interrupt... probably not worth
	hosing down the controller to try and speed that up.

XCheck whether the right nodes get flagged dirty when we create
X	a node within a dir.  Does the dir node need to be flagged?
X	(DOSFS)
	I believe this is all working OK now.

Xrmdir seems hosed.  We need to throw away the clusters under the file,
X	but we hash off this cluster number for the case of directories.
X	I also don't seem to be updating the node's length field before
X	letting deref_node() clear it.  (DOSFS)
	Fixed.  Fiddled with ordering of what gets cleared where.

Caching of executables is indefinite.  Need two things: first, a way
	for the page stealer to tear down & reclaim stuff which hasn't
	been used for a while.  Second, need a way for a server to
	get rid of a cache entry for a file being removed.
	-- 2nd part done; DOS initiates an unhash and returns EAGAIN.
	unlink() will try 2 times, with a 0.1 sec sleep in between.
	First part is nasty, since kernel would need to close connection
	with server.  Bum server could hang up the kernel.
	Is this true?  MSG_DISCONNECT doesn't require a server ack.

X Some problems with mutexing of semaphores and treatment of priorities.
X 	I don't think we're honoring PRIHI right now.  Also, I think
X 	p_sema needs to take the runq lock sooner, to provide mutexing
X 	between sleeping and being handed an event.
	-- PRIHI does the right thing now.  I think semaphores are taking
	lock at the right time.

Definitely a problem with free_proc() letting go of the root of our
	page table before we're off it.  idle_stack() needs to get onto
	its own root page table--the one we use to boot will suffice,
	I think.  idle_stack(), once fixed, needs to be called before
	we ever call free_proc().
	*** Hmm, further thoughts.  If we had an idle_vas(), we could
	safely abandon a per-process address space without hitting
	the tedium of losing the stack (and thus all local variables).
	The kernel view is stable, so we could idle_vas(), free_proc(),
	and proceed at our leisure.
	Definitely steal that initial root page table--it should be
	nearly right already.

X vm_fault.c's description of fault handling is out of date.
X	Done.

XDOSFS can't uncache an executable after it's been renamed.  Problem appears
X	to be that "inode number" changes after rename, and thus can't
X	hunt down the right node to clear.
	-- Fixed.  inode number can simply be node address; more efficient,
	and keeps inum from changing due to rename.

XVM can't reclaim cached pages which have no current attach list entry.
X	We currently allow valid pset slots with ref count of 0.  Should
X	probably have pset_fod type psets keep a cache pseudo-vas and then
X	free memory under a pset when ref count goes to 0.
	-- Fixed.  Caching is done by always leaving a reference around
	  to a pseudo-pview under the pset.  Pageout can flush this
	  reference out just like others, and a ->0 ref frees the page.

X There are a couple more pset operations which should be vectors instead
X	of special cases in a switch statement.
	-- Done.  I think all the appropriate ones are vectors now.

XSystem call interruption via t_qsav is screwed.  *Any* semaphore op--for
X	page fault, system call, whatever--can longjmp back out through
X	this.  Need to set it up so only system calls can have this
X	happen.
	-- Fixed.  Got rid of t_qsav entirely.  Sometimes you carry
	assumptions from past OS's even when it really doesn't make
	a whole lot of sense.

Need to set up message operation interruption so even a completely
	hosed server can't hang a client.  Client should be able to
	interrupt operation without blocking ; client should be able
	to disconnect without blocking.  DMA is a special case.
	For M_READ this should be OK, but what about writing?
	You can't make the buffer disappear.  Let the server continue
	to reference it?

X DOS file ID is OK for purposes of caching executables, but hoses things
X 	like "du" which want to know if a particular file is a link to
X 	one which has already been examined.  Well no, you can't have
X 	hard links under DOS, but you still need to return a unique
X 	per-file ID.  Blk # of first cluster would be OK, except that
X 	zero-length files don't have any blocks, so what ID do they
X 	get?  We used to use the cluster # of the containing dir OR'ed
X 	in with the directory slot, but this caused the ID to change
X 	on a rename.  It was then impossible to unhash a renamed a.out
X 	which was kernel cached.
	-- Fixed.  You're pretty much stuck with containing dir
	cluster #, plus dir entry.  To deal with caching, you simply
	have to uncache the executable before moving it (which the
	DOS server does for you).

Time to do a new level of path walk optimization.  chdir() should try
	to hold an open port_t on the cwd, to spare walking the prefix
	for each new file operation.  This is made tricky by things
	like chdir'ing to /vsta/foo, and holding "foo" open, but if
	the fstab has a /vsta/foo/bar mount point, you need to stop
	using the cached port_t when you walk from foo down into bar.
	This cwd port_t probably needs to be dropped on an exec().
	Further notes:
		Probably need to keep a pointer to the winning mnttab.
		If this is optimized correctly, you can use the cached
			cwd port even if they specify an absolute path
			(but its initial part matches the cwd)
		This implies a full mnttab scan, but you probably need
			to do this anyway just to see if there's a
			more-specific mnttab match than the cwd.  Keeping
			the cwd mntent lets you compare it to what falls
			out of the mnttab scan.

And for a *really* big change, FS_OPEN2 should be done; it takes the
	entire path string, and walks it down within the server, rather
	than feeding path elements one at a time.  Return should
	indicate success, or how far down before the error occurred (for
	ESYMLINK, for instance).

There's more than one race condition left in exit.  The "last" flag,
	when "false", doesn't give much protection.  Imagine a thread
	exit()'ing, and it isn't "last".  But it's preempted, and
	the last thread exits during this preemption.  So the process
	will be scrubbed before the "!last" thread finishes, which
	breaks at least the way the scheduling data structures are
	cleaned up.

Also, again in do_exit(), there are definite problems with free'ing
	memory during the exit path.  In cases where memory moves back
	into the system pool, the thread can block with its data
	structures partially destroyed.  Bad.

And since we're ragging on do_exit(), note that ephemeral threads
	should not determine the exit() status of the process.  The
	exit status should be determined by the exit value of the last
	non-ephemeral thread.

SIGCHLD emulation is done with a second (ephemeral) thread.  This is fine,
	except that this second thread needs to wait on the kernel
	for child completions, and then needs to feed them into the
	POSIX waitpid() emulation.  But this code isn't thread safe,
	so you might race with the main thread.  It also malloc()'s
	data for such completions, and malloc() isn't thread safe either.

On the issue of SIGCHLD, perhaps it really is time to make libc thread
	safe?

There needs (after all) to be a hook for voluntary shutdown.  DOS and
	VSTa filesystems don't need it, and I want to minimize the
	dependencies (OS's in general, and VSTa in particular, do
	tend to crash...).  But the "clean" flag if we ever do a BSD
	filesystem would need to use this hook.

wd disk driver seems to mis-handle large I/O's.  This is masked
	because it currently has a MAXIO parameter which defends
	it, but for DMA, there's no real reason to enforce such
	a cap.

X Need to add LBA support to wd; this is a fairly standard mechanism
X 	which is really quite nice.
	Done.  It was even easier than I expected!

I have a partially completed port of mgr-0.69.  We should eventually
	finish the port and upgrade VSTa's mgr to be current with
	everybody else's.

On the subject of partially completed ports, I also have a mostly
	complete gcc 2.8.1 port.  I'm not aware of any pressing need
	to upgrade, but I think 2.8.1 has some bug fixes in things
	like "long long" which we may eventually want.

X It's basically impossible to have more shared libraries, because almost
X 	any additional shared library will depend on the libc one.  This
X 	isn't too hard to fix; mmap() needs to be able to understand that
X 	when you try to mmap a file at a given position, and that same
X 	file is already mapped there, that it should just return success.
X 	Then subsequent shared libraries can just be linked against the
X 	stubs of earlier ones.  This means a shared library needs to
X 	declare which other libraries it needs, but I think that's OK.
	Done.  libm, libregex, and libtermcap use it.

The base shared library mechanism isn't flexible enough to handle an
	open ended collection of potential shared libraries.  We should
	use the current mechanism for a "core" set, and then support
	PIC style shared libraries for an arbitrary number of additional
	ones.

X Now that we have a palatable nroff, we should convert all man pages
X 	to the standard -man macro set.
	Done.

There's a long and mostly hidden bug which should be put to rest.  Dave
	Hudson found it and recommended the right fix many moons ago.
	The data and BSS segments are concatenated, so that if there's
	spare room at the end of data, BSS symbols are pulled back into
	some of this area.  The problem is that data and BSS are two
	distinct VM regions, with distinct attributes.  If a large data
	structure straddles them, and then is used as a kernel argument
	(i.e., do a msg_send/msg_receive across the whole data structure),
	you get an EFAULT, because to the kernel it looks like you're
	trying to violate the range check of a region.
	Fix is to change the link map to pad out data, and don't let
	BSS symbols be pulled back into it.  This wastes some memory,
	but it fixes the problem neatly, and it at worst wastes a
	single page of memory.

I think b_elem in "struct bucket" is unused.  Remove it.  Are there
	others?

b_pages counts up the # of pages used for a particular bucket size.
	We should think about free'ing some pages back to the main
	free list if that bucket appears to have enough resources
	anyway.

There's a deadlock which can happen when two threads in one process
	are used to implement a certain kind of server.  The problem
	is when one thread is a client of the server, which the
	other thread is running.  If the client has a request pending,
	and you kill the entire process, you may find that the server
	thread is gone, and the client thread--because a request
	was pending--is blocked trying to get an interrupted operation
	acknowledged from the (now dead) server.  If the server thread
	were not in the same process, then process cleanup would have
	cleared the server port automatically.  But since it is, the
	kernel doesn't know but that the other thread may be the next
	to take over handling of server actions.

	The fix is probably to keep count of the number of threads
	which are not blocked on a port served from the process of
	the threads.  When this count reaches 0, each server port
	in the process should be closed.

I've been trying to get a handle on a bug which hoses the first text
	page of the console server.  It looks like a couple 32-bit
	values scrozz a couple spots of text--in practice, always
	a bit of code needed when you switch virtual console screens.
	The interesting bit is that these values are stack pointer
	values for the kernel stack of the console server thread
	itself.  Some really funky condition, and very hard to
	reproduce.
	X Fixed.  __end was being set before common symbols were
	X folded in, resulting in GRUB being told to insert the boot
	X modules too low in memory (on top of kernel BSS, in fact)

In a release or so, /bin/ovim should go away.

The pipe server should be made to buffer data rather than always
	lock a writer until there's a reader for his data.  It should
	still, of course, do a direct writer->reader I/O op for
	cases where the reader is present at the time of the write.

There's a little tidying to be done with environment variable emulation.
	The /env server has a "fork" wstat which doesn't appear to be
	used.  With the change where fork() no longer even necessarily
	clone()'s open connections, there really needs to be a way for
	children /env/# entries to not propagate back to parents.  So
	this seems like a need for wstat("fork") to come back in the
	start.c code at a minimum, along with an explicit clone() of
	the /env/ mount point port.
