Return to BSD News archive
Newsgroups: comp.os.386bsd.bugs Path: sserve!newshost.anu.edu.au!munnari.oz.au!uunet!elroy.jpl.nasa.gov!swrinde!cs.utexas.edu!utah-morgan!hellgate.utah.edu!fcom.cc.utah.edu!cs.weber.edu!terry From: terry@cs.weber.edu (A Wizard of Earth C) Subject: Re: Nethack Message-ID: <1993Jul3.055522.4000@fcom.cc.utah.edu> Sender: news@fcom.cc.utah.edu Organization: Weber State University, Ogden, UT References: <20cab6$b2d@binkley.cs.mcgill.ca> <C990xF.43n@sneaky.lonestar.org> <C9J9H8.Ltu@sneaky.lonestar.org> Date: Sat, 3 Jul 93 05:55:22 GMT Lines: 124 In article <C9J9H8.Ltu@sneaky.lonestar.org> gordon@sneaky.lonestar.org (Gordon Burditt) writes: >Ok, I managed to duplicate the "nethack problem" in a much simpler program. >System: 386bsd, patchkit 0.2.3. [ ... ] >Now, run gub twice. The second time, you get password file data for the >before AND after printouts. The modified page is hanging around >somewhere in the system between executions. >No, this highly useful program :-( is NOT being used by more than one >user at a time, and it doesn't fork(), and the sticky bit isn't set. >% cmp bug gub >The changes DO NOT get written back to the executable. Maybe >some other bug does this, but this one doesn't. >% cp bug gub >Run gub. You get the correct BEFORE printout this time. >Somehow the data hanging around in the system got flushed or fixed. >Run gub. The problem is back again. >% cmp bug gub >Changes still not written back to executable ... > >The bar and baz variables are needed to make sure the page foo is on >is not written to by ordinary store instructions as well as read(). > > >Now, the question I have is, with this bug in the system, why does >it stay up for more than 10 minutes? Why can I run the compiler >without it crashing? > >Is there a 486-specific fix for this (set the WP bit in the cr0 register? >anything else needed or is that alone enough?) This would probably be enough if the process creation code didn't depend on it being unenforced during create. Given exactly the behaviour you have described (note: it is *still* possible for a write-back to occur to the swap store file given the particular conditions in place during a system shutdown), the problem is obvious. The question is which of the three things that aren't being done are the root cause: 1) Data pages for the process are being written, but aren't being marked dirty like they should be. 2) When the reference count drops to 0 on an in core vnode, the FS cache buffers associated with it aren't marked invalid and returned to the pool. This is a result of the way vnodes are shared between all processes (and is incidently a pain in the ass, since it limits the maximum size of on disk inode data to 188 bytes, a nice binary number -- NOT!). The only fix would be to make the vnode a field in the inode instead of the other way around and set up the hash function to have a list of per file system inodes containing the vnodes that get passed around. The vnode code itself sucks out (in vgoneall() in vfs_subr.c, the stupid thing is removed from the hash chain without the inode hash being cleaned out until later -- vgoneall is called on the swap store vnode in exit() which is called from rexit() which is called from the exit system call). 3) When the hash list is checked on open in iget() in ufs_inode.c, if the thing isn't found, the initialization doesn't make sure that all associated cache buffers are freed (this could be argued to be a problem in getnewvnode(), since the problem is probably common to all file systems). Since you haven't made any other references to files, you get the same vnode as before and ... the cache chain serendipitously points to the pages at the addresses you expect. You can probably amuse yourself for hours by writing two programs and watching them contaminate each other. As to why the compiler doesn't have this behaviour, it's probably because it does all of the following: 1) Explicitly calls exit(); the "exit by running off the end of the program" cleanup seems to have a bug as well. 2) It opens a bunch of vnodes after the one it's using (you do this too, but you put them back on the freelist in the same order so that when your program exits, it's vnode is always the first one). 3) It jumps around enough in it's memory that the modified data is forced to swap (otherwise you'd run out of memory fast) instead of just hanging around off the vnode. So: 1) Put used vnodes on the end of the haslist instead of the start (this is a false fix, since the vnode you are using may be the last free one -- oh c'mon! it *could* happen). 2) Change the vnode allocation/deallocation interface (this needs to be done anyway to allow real file systems to be written). 3) Fix the copyin/copyout programs to write dirty and check and fake page faults (there's a fix for this, but it generates false faults). 4) Set the flag on the 486 and fix the process start code. 5) Fix the process exit code so the non-exit() call process exit will work correctly. 6) Fix getnewvnode() so that it invalidates the buffers (if not actually deallocating them). 7) Fix the process swapping so that it comes from swap rather than the program image (this will also get rid of the bizarre crashes that can occur when you are out of memory, allow real system dumps without needing more memory than swap has, and speed up swapping at the cost of slowing down startup slightly, since copy to swap can be done on an as-needed basis and the current trade off is "optimizing the boot code at the expense of the program"). Suffice it to say, it's a rather involved set of problems, not just a single problem, and there are people working on it, but no, there's not a fix yet (but actually explicitly calling exit() might help for right now. Terry Lambert terry@icarus.weber.edu --- Any opinions in this posting are my own and not those of my present or previous employers.