Subject: Re: updating, build and install order
To: NetBSD-current Discussion List <current-users@netbsd.org>
From: Robert Elz <kre@munnari.OZ.AU>
List: current-users
Date: 06/22/2003 02:43:21
    Date:        Sat, 21 Jun 2003 14:32:14 -0400 (EDT)
    From:        "Greg A. Woods" <woods@weird.com>
    Message-ID:  <m19Tn9q-000B44C@proven.weird.com>

  | I think the second sync will just return immediately, at least in V7:

no.

  | update()
  | {
  | 	register struct inode *ip;
  | 	register struct mount *mp;
  | 	register struct buf *bp;
  | 	struct filsys *fp;
  | 
  | 	if(updlock)
  | 		return;
  |         updlock++;
  | [[ .... ]]
  | 	updlock = 0;
  | 	bflush(NODEV);
  | }

Note that updlock is cleared inside update() - the sync() sys call doesn't
return until update() has returned, so updlock has nothing to do with
consecutive calls of sync() that way - it is (was) there to avoid parallel
calls of sync from attempting to be executed at the same time.

You need to look deeper than that - and you'll see that the code grabs
the super block for each mount point then writes it using bwrite(), which
queues the block to the driver - once the I/O is done, brelse() would
clear the busy bit.

Any later attempt to grab the block would stall until the busy flag was
cleared - that is, the 2nd call of sync (after the first had returned) could
not return until the block(s) from the first had actually been written to
disc.

When I look at this again, I'm not quite so sure that the effect of
this is/was to guarantee that all I/O was done by the time the second
sync call returned - but I do recall analysing this in much more
detail in the past, and that was my conclusion then.   For now I
think I'll trust that rather than my 10 minutes of checking the 5th edn
code again now (by the time 7th edition appeared, sync**3 was well and
truly entrenched, no point looking at anything that recent for guidance,
I also doubt that almost anyone use ASR33's on 7th edn systems).

It does look clear that my simple "lock the super block" isn't quite how it
worked, but I think that's still the basic principle (that is, in order
to do the scan that update() does, completely, everything that the first
sync() caused to be marked busy has to have become unbusy again).

  | However in Xenix I'm pretty sure even the first sync wouldn't return
  | until all the buffers were flushed, so in Xenix "sync;halt" really was
  | sufficient,

Xenix was also way later.   Further, in the days from which sync**3 dates,
there was no "halt", that was accomplished by turning the key.

  | I was thinking more of the time it took to physically press the keys
  | than the time it took for the thing to print (or even the baud rate).  :-)

If you don't know that it is/was easily possible to press the keys of
an ASR33 faster than it could transmit the character codes, I doubt
that you used one very much.   They were big, and clunky, and the
keys seemed to have to travel miles (it was still miles in those days)
to register, but 10 characters a second isn't very fast.

It was hard to keep up for very long (finger tiredness) but for short
command strings (sync return) 3 times, that wasn't an issue.

  | I remember this because when I first heard that bit of folklore about
  | typing sync three times I had just recently had the "opportunity" to use
  | an ASR33 for a little while and I was well aware of just how long it
  | would take to type "sync<LF>" three times and then type "halt<LF>".

If you were just starting, then yes, but if you used one daily for real
work (or actually, more for a multi-player shoot-em-up game) typing on
the things was OK - the limiting factor really was the 10 ch/sec.  That
is, you'd have to wait...

kre