tvarious bug fixes - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
commit 1a8f27c35024af7b4ed857a388d20f0a4a560db0
parent a796abef1632f379ced703b1b2e691d8f63436e2
Author: rsc 
Date:   Fri, 14 May 2004 15:14:21 +0000

various bug fixes

Diffstat:
  A man/man1/graph.1                    |     148 +++++++++++++++++++++++++++++++
  A man/man1/plot.1                     |      61 +++++++++++++++++++++++++++++++
  A man/man5/venti.conf.5               |      87 +++++++++++++++++++++++++++++++
  A man/man8/venti.8                    |     232 ++++++++++++++++++++++++++++++
  A man/man8/ventiaux.8                 |     504 +++++++++++++++++++++++++++++++
  A sky/.cvsignore                      |       2 ++
  M src/cmd/acme/exec.c                 |       2 +-
  M src/cmd/acme/rows.c                 |       4 +++-
  M src/cmd/acme/text.c                 |       5 ++++-
  A src/lib9/rendez-futex.c             |     167 +++++++++++++++++++++++++++++++
  M src/libdraw/md-alloc.c              |       8 +++++++-
  M src/libfs/fs.c                      |      14 +++++++++++---
  M src/libfs/ns.c                      |       3 +++
  M src/libthread/fdwait.c              |       8 ++++++--

14 files changed, 1236 insertions(+), 9 deletions(-)
---
diff --git a/man/man1/graph.1 b/man/man1/graph.1
t@@ -0,0 +1,148 @@
+.TH GRAPH 1
+.CT 1 numbers graphics
+.SH NAME
+graph \- draw a graph
+.SH SYNOPSIS
+.B graph
+[
+.I option ...
+]
+.SH DESCRIPTION
+.I Graph
+with no options takes pairs of numbers from the
+standard input as abscissas
+.RI ( x -values)
+and ordinates
+.RI ( y -values)
+of a graph.
+Successive points are connected by straight lines.
+The graph is encoded on the standard output
+for display by
+.IR  plot (1)
+filters.
+.PP
+If an ordinate is followed by
+a nonnumeric string, that string is printed as a
+label beginning on the point.
+Labels may be surrounded with quotes
+.L
+" "
+in which case they may be empty or contain blanks
+and numbers;
+labels never contain newlines.
+.PP
+The following options are recognized,
+each as a separate argument.
+.TP
+.B  -a
+Supply abscissas automatically; no
+.IR x -values
+appear in the input.
+Spacing is given by the next
+argument (default 1).
+A second optional argument is the starting point for
+automatic abscissas (default 0, or 1
+with a log scale in
+.IR x ,
+or the lower limit given by
+.BR -x ).
+.TP
+.B  -b
+Break (disconnect) the graph after each label in the input.
+.TP
+.B  -c
+Character string given by next argument
+is default label for each point.
+.TP
+.B  -g
+Next argument is grid style,
+0 no grid, 1 frame with ticks, 2 full grid (default).
+.TP
+.B  -l
+Next argument is a legend to title the graph.
+Grid ranges
+are automatically printed as part
+of the title unless a
+.B -s
+option is present.
+.TP
+.B  -m
+Next argument is mode (style)
+of connecting lines:
+0 disconnected, 1 connected.
+Some devices give distinguishable line styles
+for other small integers.
+Mode \-1 (default) begins with style 1 and
+rotates styles for successive curves under option
+.BR -o .
+.TP
+.B -o
+(Overlay.)
+The ordinates for
+.I n
+superposed curves appear in the input
+with each abscissa value.
+The next argument is
+.IR n .
+.TP
+.B  -s
+Save screen; no new page for this graph.
+.TP
+.B -x l
+If
+.B l
+is present,
+.IR x -axis
+is logarithmic.
+Next 1 (or 2) arguments are lower (and upper)
+.I x
+limits.
+Third argument, if present, is grid spacing on
+.I x
+axis.
+Normally these quantities are determined automatically.
+.TP
+.B -y l
+Similarly for
+.IR y .
+.TP
+.B -e
+Make automatically determined
+.I x
+and
+.I y
+scales equal.
+.TP
+.B  -h
+Next argument is fraction of space for height.
+.TP
+.B  -w
+Similarly for width.
+.TP
+.B  -r
+Next argument is fraction of space to move right before plotting.
+.TP
+.B  -u
+Similarly to move up before plotting.
+.TP
+.B  -t
+Transpose horizontal and vertical axes.
+(Option
+.B -a
+now applies to the vertical axis.)
+.PP
+If a specified lower limit exceeds the upper limit,
+the axis
+is reversed.
+.SH SOURCE
+.B /sys/src/cmd/graph
+.SH "SEE ALSO"
+.IR plot (1), 
+.IR grap (1)
+.SH BUGS
+Segments that run out of bounds are dropped, not windowed.
+Logarithmic axes may not be reversed.
+Option
+.B -e
+actually makes automatic limits, rather than automatic scaling,
+equal.
diff --git a/man/man1/plot.1 b/man/man1/plot.1
t@@ -0,0 +1,61 @@
+.TH PLOT 1
+.SH NAME
+plot \- graphics filter
+.SH SYNOPSIS
+.B plot
+[
+.I file ...
+]
+.SH DESCRIPTION
+.I Plot
+interprets plotting instructions (see
+.IR  plot (6))
+from the
+.I files
+or standard input,
+drawing the results in a newly created
+.IR rio (1)
+window.
+Plot persists until a newline is typed in the window.
+Various options may be interspersed with the
+.I file
+arguments; they take effect at the given point in processing.
+Options are:
+.TP "\w'\fL-g \fIgrade\fLXX'u"
+.B -d
+Double buffer: accumulate the plot off-screen and write to the screen all at once
+when an erase command is encountered or at end of file.
+.TP
+.B -e
+Erase the screen.
+.TP
+.BI -c " col"
+Set the foreground color (see
+.IR plot (6)
+for color names).
+.TP
+.BI -f " fill"
+Set the background color.
+.TP
+.BI -g " grade"
+Set the quality factor for arcs.
+Higher grades give better quality.
+.TP
+.BI -p " col"
+Set the pen color.
+.TP
+.BI -w
+Pause until a newline is typed on standard input.
+.TP
+.B -C
+Close the current plot.
+.TP
+.B -W " x0,y0,x1,y1"
+Specify the bounding rectangle of plot's window.
+By default it uses a 512×512 window in the
+middle of the screen.
+.SH SOURCE
+.B /sys/src/cmd/plot
+.SH "SEE ALSO"
+.IR rio (1),
+.IR plot (6)
diff --git a/man/man5/venti.conf.5 b/man/man5/venti.conf.5
t@@ -0,0 +1,87 @@
+.TH VENTI.CONF 6
+.SH NAME
+venti.conf  \- a venti configuration file
+.SH DESCRIPTION
+A venti configuration file enumerates the various index sections and
+arenas that constitute a venti system.
+The components are indicated by the name of the file, typically
+a disk partition, in which they reside.  The configuration
+file is the only location that file names are used.  Internally,
+venti uses the names assigned when the components were formatted
+with 
+.I fmtarenas
+or 
+.I fmtisect
+(see
+.IR ventiaux (8)).
+In particular, by changing the configuration a
+component can be copied to a different file.
+.PP
+The configuration file consists of lines in the form described below.
+Lines starting with
+.B #
+are comments.
+.TP
+.BI index " name
+Names the index for the system.
+.TP
+.BI arenas " file
+.I File
+contains a collection of arenas, formatted using
+.IR fmtarenas .
+.TP
+.BI isect " file
+.I File
+contains an index section, formatted using
+.IR fmtisect .
+.PP
+After formatting a venti system using
+.IR fmtindex ,
+the order of arenas and index sections should not be changed.
+Additional arenas can be appended to the configuration.
+.PP
+The configuration file optionally holds configuration parameters
+for the venti server itself.
+These are:
+.TP
+.BI mem " cachesize
+.TP
+.BI bcmem " blockcachesize
+.TP
+.BI icmem " indexcachesize
+.TP
+.BI addr " ventiaddress
+.TP
+.BI httpaddr " httpaddress
+.TP
+.B queuewrites
+.PD
+See 
+.IR venti (8)
+for descriptions of these variables.
+.SH EXAMPLE
+.EX
+# a sample venti configuration file
+#
+# formatted with
+#        venti/fmtarenas arena. /tmp/disks/arenas
+#         venti/fmtisect isect0 /tmp/disks/isect0
+#         venti/fmtisect isect1 /tmp/disks/isect1
+#        venti/fmtindex venti.conf
+#
+# server is started with
+#        venti/venti
+
+# the name of the index
+index main
+
+# the index sections
+isect /tmp/disks/isect0
+isect /tmp/disks/isect1
+
+# the arenas
+arenas /tmp/disks/arenas
+.EE
+.SH "SEE ALSO"
+.IR venti (8),
+.IR ventiaux (8)
diff --git a/man/man8/venti.8 b/man/man8/venti.8
t@@ -0,0 +1,232 @@
+.TH VENTI 8
+.SH NAME
+venti \- an archival block storage server
+.SH SYNOPSIS
+.B venti/venti
+[
+.B -dsw
+]
+[
+.B -a
+.I ventiaddress
+]
+[
+.B -B
+.I blockcachesize
+]
+[
+.B -c
+.I config
+]
+[
+.B -C
+.I cachesize
+]
+[
+.B -h
+.I httpaddress
+]
+[
+.B -I
+.I icachesize
+]
+.PP
+.B venti/sync
+[
+.B -h
+.I host
+]
+.SH DESCRIPTION
+.I Venti
+is a block storage server intended for archival data.
+In a Venti server,
+the SHA1 hash of a block's contents acts as the block
+identifier for read and write operations.
+This approach enforces a write-once policy, preventing accidental or
+malicious destruction of data.  In addition, duplicate copies of a
+block are coalesced, reducing the consumption of storage and
+simplifying the implementation of clients.
+.PP
+Storage for
+.I venti
+consists of a data log and an index, both of which
+can be spread across multiple files.
+The files containing the data log are themselves divided into self-contained sections called arenas.
+Each arena contains a large number of data blocks and is sized to
+facilitate operations such as copying to removable media.
+The index provides a mapping between the a Sha1 fingerprint and
+the location of the corresponding block in the data log.
+.PP
+The index and data log are typically stored on raw disk partitions.
+To improve the robustness, the data log should be stored on
+a device that provides RAID functionality.  The index does
+not require such protection, since if necessary, it can
+can be regenerated from the data log.
+The performance of
+.I venti
+is typically limited to the random access performance
+of the index.  This performance can be improved by spreading the
+index accross multiple disks.  
+.PP
+The storage for
+.I venti
+is initialized using
+.IR fmtarenas ,
+.IR fmtisect ,
+and
+.I fmtindex
+(see
+.IR ventiaux (8)).
+A configuration file,
+.IR venti.conf (6),
+ties the index sections and data arenas together.
+.PP
+A Venti
+server is accessed via an undocumented network protocol.
+Two client applications are included in this distribution:
+.IR vac (1)
+and
+.IR vacfs (4).
+.I Vac
+copies files from a Plan 9 file system to Venti, creating an
+archive and returning the fingerprint of the root.
+This archive can be mounted in Plan 9 using 
+.IR vacfs .
+These two commands enable a rudimentary backup system.
+A future release will include a Plan 9 file system that uses
+Venti as a replacement for the WORM device of 
+.IR fs (4).
+.PP
+The
+.I venti
+server provides rudimentary status information via
+a built-in http server.  The URL files it serves are:
+.TP
+.B stats
+Various internal statistics.
+.TP
+.B index
+An enumeration of the index sections and all non empty arenas, including various statistics.
+.TP
+.B storage
+A summary of the state of the data log.
+.TP
+.B xindex
+An enumeration of the index sections and all non empty arenas, in XML format.
+.PP
+Several auxiliary utilities (see
+.IR ventiaux (8))
+aid in maintaining the storage for Venti.
+With the exception of
+.I rdarena ,
+these utilities should generally be run after killing the
+.I venti
+server.
+The utilities are:
+.TP
+.I checkarenas
+Check the integrity, and optionally fix, Venti arenas.
+.TP
+.I checkindex
+Check the integrity, and optionally fix, a Venti index.
+.TP
+.I buildindex
+Rebuild a Venti index from scratch.
+.TP
+.I rdarena
+Extract a Venti arena and write to standard output.
+.PD
+.PP
+Options to 
+.I venti
+are:
+.TP
+.BI -a " ventiaddress
+The network address on which the server listens for incoming connections.
+The default is
+.LR tcp!*!venti .
+.TP
+.BI -B " blockcachesize
+The size, in bytes, of memory allocated to caching raw disk blocks.
+.TP
+.BI -c " config
+Specifies the
+Venti
+configuration file.
+Defaults to
+.LR venti.conf .
+.TP
+.BI -C " cachesize
+The size, in bytes, of memory allocated to caching 
+Venti
+blocks.
+.TP
+.BI -d
+Produce various debugging information on standard error.
+.TP
+.BI -h " httpaddress
+The network address of Venti's built-in
+http
+server.
+The default is
+.LR tcp!*!http .
+.TP
+.BI -I " icachesize
+The size, in bytes, of memory allocated to caching the index mapping fingerprints
+to locations in 
+.IR venti 's
+data log.
+.TP
+.B -s
+Do not run in the background.
+Normally,
+the foreground process will exit once the Venti server
+is initialized and ready for connections.
+.TP
+.B -w
+Enable write buffering.  This option increase the performance of writes to
+.I venti
+at the cost of returning success to the client application before the
+data has been written to disk.
+The server implements a
+.I sync
+rpc that waits for completion of all the writes buffered at the time
+the rpc was received.
+Applications such as
+.IR vac (1)
+and the
+.I sync
+command described below
+use this rpc to make sure that the data is correctly written to disk.
+Use of this option is recommended.
+.PD
+.PP
+The units for the various cache sizes above can be specified by appending a
+.LR k ,
+.LR m ,
+or
+.LR g
+to indicate kilobytes, megabytes, or gigabytes respectively.
+The command line options override options found in the
+.IR venti.conf (6)
+file.
+.PP
+.I Sync
+connects to a running Venti server and executes a sync rpc
+(described with the
+.B -w
+option above). 
+If sync exits successfully, it means that all writes buffered at the
+time the command was issued are now on disk.
+.SH SOURCE
+.B /sys/src/cmd/venti
+.SH "SEE ALSO"
+.IR venti.conf (6),
+.IR ventiaux (8),
+.IR vac (1),
+.IR vacfs (4).
+.br
+Sean Quinlan and Sean Dorward,
+``Venti: a new approach to archival storage'',
+.I "Usenix Conference on File and Storage Technologies" ,
+2002.
diff --git a/man/man8/ventiaux.8 b/man/man8/ventiaux.8
t@@ -0,0 +1,504 @@
+.TH VENTIAUX 8
+.SH NAME
+buildindex,
+checkarenas,
+checkindex,
+conf,
+copy,
+fmtarenas,
+fmtindex,
+fmtisect,
+rdarena,
+rdarenablocks,
+read,
+wrarenablocks,
+write \- Venti maintenance and debugging commands
+.SH SYNOPSIS
+.B venti/buildindex
+[
+.B -B
+.I blockcachesize
+]
+[
+.B -Z
+]
+.I venti.config
+.I tmp
+.PP
+.B venti/checkarenas
+[
+.B -afv 
+]
+.I file
+.PP
+.B venti/checkindex
+[
+.B -f
+]
+[
+.B -B
+.I blockcachesize
+]
+.I venti.config
+.I tmp
+.PP
+.B venti/conf
+[
+.B -w
+]
+.I partition
+[
+.I configfile
+]
+.PP
+.B venti/copy
+[
+.B -f
+]
+.I src
+.I dst
+.I score
+[
+.I type
+]
+.PP
+.B venti/fmtarenas
+[
+.B -Z
+]
+[
+.B -a
+.I arenasize
+]
+[
+.B -b
+.I blocksize
+]
+.I name
+.I file
+.PP
+.B venti/fmtindex
+[
+.B -a
+]
+.I venti.config
+.PP
+.B venti/fmtisect
+[
+.B -Z
+]
+[
+.B -b
+.I blocksize
+]
+.I name
+.I file
+.PP
+.B venti/rdarena
+[
+.B -v
+]
+.I arenapart
+.I arenaname
+.PP
+.B venti/read
+[
+.B -h
+.I host
+]
+.I score
+[
+.I type
+]
+.PP
+.B venti/wrarena
+[
+.B -o
+.I fileoffset
+]
+[
+.B -h
+.I host
+]
+.I arenafile
+[
+.I clumpoffset
+]
+.PP
+.B venti/write
+[
+.B -h
+.I host
+]
+[
+.B -t
+.I type
+]
+[
+.B -z
+]
+.SH DESCRIPTION
+These commands aid in the setup, maintenance, and debugging of
+Venti servers.
+See
+.IR venti (8)
+and
+.IR venti.conf (6)
+for an overview of the data structures stored by Venti.
+.PP
+Note that the units for the various sizes in the following
+commands can be specified by appending
+.LR k ,
+.LR m ,
+or
+.LR g
+to indicate kilobytes, megabytes, or gigabytes respectively.
+.PP
+.I Buildindex
+populates the index for the Venti system described in
+.IR venti.config .
+The index must have previously been formatted using
+.IR fmtindex .
+This command is typically used to build a new index for a Venti
+system when the old index becomes too small, or to rebuild
+an index after media failure.
+Small errors in an index can usually be fixed with
+.IR checkindex .
+.PP
+The
+.I tmp
+file, usually a disk partition, must be large enough to store a copy of the index.
+This temporary space is used to perform a merge sort of index entries
+generated by reading the arenas.
+.PP
+Options to 
+.I buildindex
+are:
+.TP
+.BI -B " blockcachesize
+The amount of memory, in bytes, to use for caching raw disk accesses while running
+.IR buildindex .
+(This is not a property of the created index.)
+The default is 8k.
+.TP
+.B -Z
+Do not zero the index.
+This option should only be used when it is known that the index was already zeroed.
+.PD
+.PP
+.I Checkarenas
+examines the Venti arenas contained in the given
+.IR file .
+The program detects various error conditions, and optionally attempts
+to fix any errors that are found.
+.PP
+Options to 
+.I checkarenas
+are:
+.TP
+.B -a
+For each arena, scan the entire data section.
+If this option is omitted, only the end section of
+the arena is examined.
+.TP
+.B -f
+Attempt to fix any errors that are found.
+.TP
+.B -v
+Increase the verbosity of output.
+.PD
+.PP
+.I Checkindex
+examines the Venti index described in
+.IR venti.config .
+The program detects various error conditions including:
+blocks that are not indexed, index entries for blocks that do not exist,
+and duplicate index entries.
+If requested, an attempt can be made to fix errors that are found.
+.PP
+The
+.I tmp
+file, usually a disk partition, must be large enough to store a copy of the index.
+This temporary space is used to perform a merge sort of index entries
+generated by reading the arenas.
+.PP
+Options to 
+.I checkindex
+are:
+.TP
+.BI -B " blockcachesize
+The amount of memory, in bytes, to use for caching raw disk accesses while running
+.IR checkindex .
+The default is 8k.
+.TP
+.B -f
+Attempt to fix any errors that are found.
+.PD
+.PP
+.I Fmtarenas
+formats the given
+.IR file ,
+typically a disk partition, into a number of
+Venti
+arenas.
+The arenas are given names of the form
+.IR name%d ,
+where
+.I %d
+is replaced with a sequential number starting at 0.
+.PP
+Options to 
+.I fmtarenas
+are:
+.TP
+.BI -a " arenasize
+The arenas are of
+.I arenasize
+bytes.  The default is 512 megabytes, which was selected to provide a balance
+between the number of arenas and the ability to copy an arena to external
+media such as recordable CDs and tapes.
+.TP
+.BI -b " blocksize
+The size, in bytes, for read and write operations to the file.
+The size is recorded in the file, and is used by applications that access the arenas.
+The default is 8k.
+.TP
+.B -Z
+Do not zero the data sections of the arenas.
+Using this option reduces the formatting time
+but should only be used when it is known that the file was already zeroed.
+.PD
+.I Fmtindex
+takes the
+.IR venti.conf (6)
+file
+.I venti.config
+and initializes the index sections to form a usable index structure.
+The arena files and index sections must have previously been formatted
+using 
+.I fmtarenas
+and 
+.I fmtisect
+respectively.
+.PP
+The function of a Venti index is to map a SHA1 fingerprint to a location
+in the data section of one of the arenas.  The index is composed of
+blocks, each of which contains the mapping for a fixed range of possible
+fingerprint values.
+.I Fmtindex
+determines the mapping between SHA1 values and the blocks
+of the collection of index sections.  Once this mapping has been determined,
+it cannot be changed without rebuilding the index. 
+The basic assumption in the current implementation is that the index
+structure is sufficiently empty that individual blocks of the index will rarely
+overflow.  The total size of the index should be about 2% to 10% of
+the total size of the arenas, but the exact depends both the index block size
+and the compressed size of block stored to Venti.
+.PP
+.I Fmtindex
+also computes a mapping between a linear address space and
+the data section of the collection of arenas.  The
+.B -a
+option can be used to add additional arenas to an index.
+To use this feature,
+add the new arenas to
+.I venti.config
+after the existing arenas and then run
+.I fmtindex
+.BR -a .
+.PP
+A copy of the above mappings is stored in the header for each of the index sections.
+These copies enable
+.I buildindex
+to restore a single index section without rebuilding the entire index.
+.PP
+.I Fmtisect
+formats the given
+.IR file ,
+typically a disk partition, as a Venti index section with the specified
+.IR name .
+One or more formatted index sections are combined into a Venti
+index using 
+.IR fmtindex .
+Each of the index sections within an index must have a unique name.
+.PP
+Options to 
+.I fmtisect
+are:
+.TP
+.BI -b " blocksize
+The size, in bytes, for read and write operations to the file.
+All the index sections within a index must have the same block size.
+The default is 8k.
+.TP
+.B -Z
+Do not zero the index.
+Using this option reduces the formatting time
+but should only be used when it is known that the file was already zeroed.
+.PD
+.PP
+.I Rdarena
+extracts the named
+.I arena
+from the arena partition
+.I arenapart
+and writes this arena to standard output.
+This command is typically used to back up an arena to external media.
+The
+.B -v
+option generates more verbose output on standard error.
+.PP
+.I Wrarena
+writes the blocks contained in the arena
+.I arenafile
+(typically, the output of
+.IR rdarena )
+to a Venti server.
+It is typically used to reinitialize a Venti server from backups of the arenas.
+For example,
+.IP
+.EX
+venti/rdarena /dev/sdC0/arenas arena.0 >external.media
+venti/wrarena -h venti2 external.media
+.EE
+.LP
+writes the blocks contained in
+.B arena.0
+to the Venti server
+.B venti2
+(typically not the one using
+.BR /dev/sdC0/arenas ).
+.PP
+The
+.B -o
+option specifies that the arena starts at byte
+.I fileoffset
+(default
+.BR 0 )
+in
+.I arenafile .
+This is useful for reading directly from
+the Venti arena partition:
+.IP
+.EX
+venti/wrarena -h venti2 -o 335872 /dev/sdC0/arenas
+.EE
+.LP
+(In this example, 335872 is the offset shown in the Venti
+server's index list (344064) minus one block (8192).
+You will need to substitute your own arena offsets
+and block size.)
+.PP
+Finally, the optional
+.I offset
+argument specifies that the writing should begin with the
+clump starting at
+.I offset
+within the arena.
+.I Wrarena
+prints the offset it stopped at (because there were no more data blocks).
+This could be used to incrementally back up a Venti server
+to another Venti server:
+.IP
+.EX
+last=`{cat last}
+venti/wrarena -h venti2 -o 335872 /dev/sdC0/arenas $last >output
+awk '/^end offset/ { print $3 }' offset >last
+.EE
+.LP
+Of course, one would need to add wrapper code to keep track
+of which arenas have been processed.
+See
+.B /sys/src/cmd/venti/backup.example
+for a version that does this.
+.PP
+.I Read
+and
+.I write
+read and write blocks from a running Venti server.
+They are intended to ease debugging of the server.
+The default
+.I host
+is the environment variable
+.BR $venti ,
+followed by the network metaname
+.BR $venti .
+The
+.I type
+is the decimal type of block to be read or written.
+If no 
+.I type
+is specified for
+.I read ,
+all types are tried, and a command-line is printed to
+show the type that eventually worked.
+If no
+.I type
+is specified for
+.I write ,
+.B VtDataType
+(13)
+is used.
+.I Read
+reads the block named by
+.I score
+(a SHA1 hash)
+from the Venti server and writes it to standard output.
+.I Write
+reads a block from standard input and attempts to write
+it to the Venti server.
+If successful, it prints the score of the block on the server.
+.PP
+.I Copy
+walks the entire tree of blocks rooted at
+.I score ,
+copying all the blocks visited during the walk from
+the Venti server at network address
+.I src
+to the Venti server at network address
+.I dst .
+If
+.I type
+(a decimal block type for
+.IR score )
+is omitted, all types will be tried in sequence
+until one is found that works.
+The
+.B -f
+flag runs the copy in ``fast'' mode: if a block is already on
+.IR dst ,
+the walk does not descend below it, on the assumption that all its
+children are also already on
+.IR dst .
+Without this flag, the copy often transfers many times more
+data than necessary.
+.PP
+To make it easier to bootstrap servers, the configuration
+file can be stored at the beginning of any Venti partitions using
+.IR conf .
+A partition so branded with a configuration file can
+be used in place of a configuration file when invoking any
+of the venti commands.
+By default,
+.I conf
+prints the configuration stored in
+.IR partition .
+When invoked with the
+.B -w
+flag,
+.I conf
+reads a configuration file from 
+.I configfile
+(or else standard input)
+and stores it in
+.IR partition .
+.SH SOURCE
+.B /sys/src/cmd/venti
+.SH "SEE ALSO"
+.IR venti (8),
+.IR venti.conf (6)
+.SH BUGS
+.I Buildindex
+should allow an individual index section to be rebuilt.
+The merge sort could be performed in the space used to store the
+index rather than requiring a temporary file.
diff --git a/sky/.cvsignore b/sky/.cvsignore
t@@ -0,0 +1,2 @@
+*.scat
+constelnames
diff --git a/src/cmd/acme/exec.c b/src/cmd/acme/exec.c
t@@ -1308,7 +1308,7 @@ runproc(void *argvp)
         name[e-t] = 0;
         e = utfrrune(name, '/');
         if(e)
-                strcpy(name, e+1);
+                memmove(name, e+1, strlen(e+1)+1);        /* strcpy but overlaps */
         strcat(name, " ");        /* add blank here for ease in waittask */
         c->name = bytetorune(name, &c->nname);
         free(name);
diff --git a/src/cmd/acme/rows.c b/src/cmd/acme/rows.c
t@@ -663,12 +663,12 @@ rowload(Row *row, char *file, int initing)
                                 break;
                 wincleartag(w);
                 textinsert(&w->tag, w->tag.file->b.nc, r+n+1, nr-(n+1), TRUE);
-                free(r);
                 if(ndumped >= 0){
                         /* simplest thing is to put it in a file and load that */
                         sprint(buf, "/tmp/d%d.%.4sacme", getpid(), getuser());
                         fd = create(buf, OWRITE|ORCLOSE, 0600);
                         if(fd < 0){
+                                free(r);
                                 warning(nil, "can't create temp file: %r\n");
                                 goto Rescue2;
                         }
t@@ -679,6 +679,7 @@ rowload(Row *row, char *file, int initing)
                                 if(rune == '\n')
                                         line++;
                                 if(rune == (Rune)Beof){
+                                        free(r);
                                         Bterm(bout);
                                         free(bout);
                                         close(fd);
t@@ -696,6 +697,7 @@ rowload(Row *row, char *file, int initing)
                         winsettag(w);
                 }else if(dumpid==0 && r[ns+1]!='+' && r[ns+1]!='-')
                         get(&w->body, nil, nil, FALSE, XXX, nil, 0);
+                free(r);
                 if(fontr){
                         fontx(&w->body, nil, nil, 0, 0, fontr, nfontr);
                         free(fontr);
diff --git a/src/cmd/acme/text.c b/src/cmd/acme/text.c
t@@ -963,8 +963,11 @@ textshow(Text *t, uint q0, uint q1, int doselect)
         int nl;
         uint q;
 
-        if(t->what != Body)
+        if(t->what != Body){
+                if(doselect)
+                        textsetselect(t, q0, q1);
                 return;
+        }
         if(t->w!=nil && t->fr.maxlines==0)
                 colgrow(t->col, t->w, 1);
         if(doselect)
diff --git a/src/lib9/rendez-futex.c b/src/lib9/rendez-futex.c
t@@ -0,0 +1,167 @@
+/*
+     NAME
+          rendezvous - user level process synchronization
+
+     SYNOPSIS
+          ulong rendezvous(ulong tag, ulong value)
+
+     DESCRIPTION
+          The rendezvous system call allows two processes to synchro-
+          nize and exchange a value.  In conjunction with the shared
+          memory system calls (see segattach(2) and fork(2)), it
+          enables parallel programs to control their scheduling.
+
+          Two processes wishing to synchronize call rendezvous with a
+          common tag, typically an address in memory they share.  One
+          process will arrive at the rendezvous first; it suspends
+          execution until a second arrives.  When a second process
+          meets the rendezvous the value arguments are exchanged
+          between the processes and returned as the result of the
+          respective rendezvous system calls.  Both processes are
+          awakened when the rendezvous succeeds.
+
+          The set of tag values which two processes may use to
+          rendezvous-their tag space-is inherited when a process
+          forks, unless RFREND is set in the argument to rfork; see
+          fork(2).
+
+          If a rendezvous is interrupted the return value is ~0, so
+          that value should not be used in normal communication.
+
+ * This simulates rendezvous with shared memory, pause, and SIGUSR1.
+ */
+
+#include 
+typedef u32int u32;
+#include 
+#include 
+#define __user
+#include 
+#include 
+#include 
+
+enum
+{
+        VOUSHASH = 257,
+};
+
+typedef struct Vous Vous;
+struct Vous
+{
+        Vous *link;
+        Lock lk;
+        int pid;
+        ulong val;
+        ulong tag;
+};
+
+static Vous vouspool[2048];
+static int nvousused;
+static Vous *vousfree;
+static Vous *voushash[VOUSHASH];
+static Lock vouslock;
+
+static Vous*
+getvous(void)
+{
+        Vous *v;
+
+        if(vousfree){
+                v = vousfree;
+                vousfree = v->link;
+        }else if(nvousused < nelem(vouspool))
+                v = &vouspool[nvousused++];
+        else
+                abort();
+        return v;
+}
+
+static void
+putvous(Vous *v)
+{
+        lock(&vouslock);
+        v->link = vousfree;
+        vousfree = v;
+        unlock(&vouslock);
+}
+
+static Vous*
+findvous(ulong tag, ulong val, int pid)
+{
+        int h;
+        Vous *v, **l;
+
+        lock(&vouslock);
+        h = tag%VOUSHASH;
+        for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){
+                if(v->tag == tag){
+                        *l = v->link;
+                        unlock(&vouslock);
+                        return v;
+                }
+        }
+        v = getvous();
+        v->pid = pid;
+        v->link = voushash[h];
+        v->val = val;
+        v->tag = tag;
+        lock(&v->lk);
+        voushash[h] = v;
+        unlock(&vouslock);
+        return v;
+}
+
+#define DBG 0
+ulong
+rendezvous(ulong tag, ulong val)
+{
+        int me, vpid;
+        ulong rval;
+        Vous *v;
+
+        me = getpid();
+        v = findvous(tag, val, me);
+        if(v->pid == me){
+                if(DBG)fprint(2, "pid is %d tag %lux, sleeping\n", me, tag);
+                /*
+                 * No rendezvous partner was found; the next guy
+                 * through will find v and wake us, so we must go
+                 * to sleep.
+                 *
+                 * To go to sleep:
+                 *        1. disable USR1 signals.
+                 *        2. unlock v->lk (tells waker okay to signal us).
+                 *        3. atomically suspend and enable USR1 signals.
+                 *
+                 * The call to ignusr1() could be done once at 
+                 * process creation instead of every time through rendezvous.
+                 */
+                v->val = val;
+                unlock(&v->lk);
+                while(sys_futex((u32int*)&v->tag, FUTEX_WAIT, tag, nil, nil) < 0 && errno==EINTR)
+                        ;
+                rval = v->val;
+                if(DBG)fprint(2, "pid is %d, awake\n", me);
+                putvous(v);
+        }else{
+                /*
+                 * Found someone to meet.  Wake him:
+                 *
+                 *        A. lock v->lk (waits for him to get to his step 2)
+                 *        B. send a USR1
+                 *
+                 * He won't get the USR1 until he suspends, which
+                 * means it must wake him up (it can't get delivered
+                 * before he sleeps).
+                 */
+                vpid = v->pid;
+                lock(&v->lk);
+                rval = v->val;
+                v->val = val;
+                v->tag++;
+                unlock(&v->lk);
+                sys_futex((u32int*)&v->tag, FUTEX_WAKE, 1, nil, nil);
+        }
+        return rval;
+}
+
diff --git a/src/libdraw/md-alloc.c b/src/libdraw/md-alloc.c
t@@ -86,7 +86,13 @@ _allocmemimage(Rectangle r, u32int chan)
                 return nil;
 
         md->ref = 1;
-        md->base = poolalloc(imagmem, (2+nw)*sizeof(u32int));
+        /*
+         * The first two words are the md and the callerpc.
+         * Then nw words of data.
+         * The final word lets the drawing routines be a little
+         * sloppy about reading past the end of the block.
+         */
+        md->base = poolalloc(imagmem, (2+nw+1)*sizeof(u32int));
         if(md->base == nil){
                 free(md);
                 return nil;
diff --git a/src/libfs/fs.c b/src/libfs/fs.c
t@@ -86,19 +86,27 @@ fsunmount(Fsys *fs)
 void
 _fsdecref(Fsys *fs)
 {
-        Fid *f, *next;
+        Fid *f, **l, *next;
 
         qlock(&fs->lk);
         --fs->ref;
         //fprint(2, "fsdecref %p to %d\n", fs, fs->ref);
         if(fs->ref == 0){
                 close(fs->fd);
+                /* trim the list down to just the first in each chunk */
+                for(l=&fs->freefid; *l; ){
+                        if((*l)->fid%Fidchunk == 0)
+                                l = &(*l)->next;
+                        else
+                                *l = (*l)->next;
+                }
+                /* now free the list */
                 for(f=fs->freefid; f; f=next){
                         next = f->next;
-                        if(f->fid%Fidchunk == 0)
-                                free(f);
+                        free(f);
                 }
                 free(fs);
+                return;
         }
         qunlock(&fs->lk);
 }
diff --git a/src/libfs/ns.c b/src/libfs/ns.c
t@@ -23,8 +23,11 @@ nsmount(char *name, char *aname)
         fd = dial(addr, 0, 0, 0);
         if(fd < 0){
                 werrstr("dial %s: %r", addr);
+                free(addr);
                 return nil;
         }
+        free(addr);
+
         fcntl(fd, F_SETFL, FD_CLOEXEC);
 
         fs = fsmount(fd, aname);
diff --git a/src/libthread/fdwait.c b/src/libthread/fdwait.c
t@@ -174,8 +174,8 @@ _threadfdwait(int fd, int rw, ulong pc)
 
         struct {
                 Channel c;
-                Alt *qentry[2];
                 ulong x;
+                Alt *qentry[2];
         } s;
 
         threadfdwaitsetup();
t@@ -214,11 +214,15 @@ threadsleep(int ms)
         struct {
                 Channel c;
                 ulong x;
+                Alt *qentry[2];
         } s;
 
         threadfdwaitsetup();
         chaninit(&s.c, sizeof(ulong), 1);
-
+        s.c.qentry = (volatile Alt**)s.qentry;
+        s.c.nentry = 2;
+        memset(s.qentry, 0, sizeof s.qentry);
+        
         sleepchan[nsleep] = &s.c;
         sleeptime[nsleep++] = p9nsec()/1000000+ms;
         recvul(&s.c);