diff --git a/db/nfree.in b/db/nfree.in
index 5b54c63a920f1df515557c2355da4d1190195d0b..635b2571594a764d5fd48985f702782d02a14f88 100755
--- a/db/nfree.in
+++ b/db/nfree.in
@@ -50,6 +50,7 @@ my @nodes;
 my @freed_nodes=();
 my @dynanodes=();
 my $error = 0;
+my %mustzero=();
 
 $| = 1;  # Turn off line buffering on output
 
@@ -110,34 +111,20 @@ if (@ARGV) {
 	if ($n =~ /^([-\w]+)$/) { $n = $1; }
 	else { die("*** $0:\n    Bad node name: $n.\n"); }
 
-	# Shark hack
-	if ($n =~ /(sh\d+)/ ) {
-	    # It's a shark - do the whole shelf if its not done already.
-	    my $shelf = $1;
-	    if ( ! (join(",", @nodes) =~ /,$shelf-\d,/)) {
-		# Shelf hasn't been done yet...
-		foreach my $n ( 1 .. 8 ) {
-		    push(@nodes, "$shelf-$n");
-		}
-	    }
-	    # End shark hack
-	} else {
-	    # its not a shark - just add it in...
-	    push(@nodes, $n);
-
-	    # if -x was specified, remove any 
-	    # mapping to a node which has a phys_nodeid of $n.
-	    if ($freeDependantVirtuals) {
-		my $result = 
-		    DBQueryFatal("SELECT r.node_id FROM reserved AS r ".
-				 "LEFT JOIN nodes AS n ".
-				 "ON r.node_id=n.node_id ".
-				 "WHERE n.phys_nodeid='$n' AND ".
-				 "r.eid='$eid' AND r.pid='$pid'");
-		while (my ($dependantVirtual) = $result->fetchrow_array()) {
-		    if (defined $dependantVirtual && $dependantVirtual ne $n) {
-			push(@nodes, $dependantVirtual);
-		    }
+	push(@nodes, $n);
+
+	# if -x was specified, remove any 
+	# mapping to a node which has a phys_nodeid of $n.
+	if ($freeDependantVirtuals) {
+	    my $result = 
+		DBQueryFatal("SELECT r.node_id FROM reserved AS r ".
+			     "LEFT JOIN nodes AS n ".
+			     "ON r.node_id=n.node_id ".
+			     "WHERE n.phys_nodeid='$n' AND ".
+			     "r.eid='$eid' AND r.pid='$pid'");
+	    while (my ($dependantVirtual) = $result->fetchrow_array()) {
+		if (defined $dependantVirtual && $dependantVirtual ne $n) {
+		    push(@nodes, $dependantVirtual);
 		}
 	    }
 	}
@@ -183,6 +170,16 @@ foreach my $n (@nodes) {
 	next;
     }
 
+    #
+    # Remember if the node's disk must be zeroed
+    #
+    my $rowref = $result->fetchrow_hashref();
+    if ($rowref->{'mustwipe'}) {
+	$mustzero{$n} = $rowref->{'mustwipe'};
+    } else {
+	$mustzero{$n} = 0;
+    }
+
     if ( $moveToOldReserved ) {
 	# Move to holding reservation. Node is not free, but is no longer
 	# owned by the pid/eid, so cannot be mucked with.
@@ -251,6 +248,7 @@ foreach my $n (@freed_nodes) {
     if ($isvirt || !$imageable) {
 	# VIRTNODE HACK: Virtual nodes are special. Do not clean or reload.
 	$mustclean = 0;
+	$mustzero{$n} = 0;
     }
     elsif (defined($clean)) {
 	# If def_boot_osid set, then $clean is defined. Otherwise not set
@@ -354,9 +352,10 @@ foreach my $n (@freed_nodes) {
 	DBQueryFatal("select node_id,image_id from scheduled_reloads " .
 		     "where node_id='$n'");
 
-    # XXX force reload hack!
-    if ( !$TESTMODE && ((!$isvirt && $imageable) || $result->numrows() ||
-                        TBNodeType($n) eq "garcia")) { # XXX Garcia hack
+    if (!$TESTMODE &&
+	((!$isvirt && $imageable) || # XXX force reload hack!
+	 $result->numrows() || $mustzero{$n} ||
+	 TBNodeType($n) eq "garcia")) { # XXX Garcia hack
 	print "Moving $n to $reloadpid/$pendingeid.\n";
 	
 	DBQueryWarn("update reserved set pid='$reloadpid',eid='$pendingeid',".
diff --git a/sql/database-create.sql b/sql/database-create.sql
index d16835f0cd860a73c22057ac270db4b083560de9..c66c6671f48df218fd59db8a3e421d2aaca7e3f8 100644
--- a/sql/database-create.sql
+++ b/sql/database-create.sql
@@ -67,6 +67,7 @@ CREATE TABLE comments (
 CREATE TABLE current_reloads (
   node_id varchar(32) NOT NULL default '',
   image_id varchar(45) NOT NULL default '',
+  mustwipe tinyint(4) NOT NULL default '0',
   PRIMARY KEY  (node_id)
 ) TYPE=MyISAM;
 
@@ -1490,6 +1491,7 @@ CREATE TABLE reserved (
   old_eid varchar(32) NOT NULL default '',
   cnet_vlan int(11) default NULL,
   inner_elab_role enum('boss','ops','node') default NULL,
+  mustwipe tinyint(4) NOT NULL default '0',
   PRIMARY KEY  (node_id),
   UNIQUE KEY vname (pid,eid,vname),
   KEY old_pid (old_pid,old_eid)
diff --git a/sql/database-migrate.txt b/sql/database-migrate.txt
index d74034e42b639fbddb2abd8023a364beca90be46..aeaa2de43bda6b260948eedc5744e76168d5ee1f 100644
--- a/sql/database-migrate.txt
+++ b/sql/database-migrate.txt
@@ -2518,3 +2518,12 @@ last_net_act,last_cpu_act,last_ext_act);
 
         alter table users add wikiname tinytext;
         alter table groups add wikiname tinytext;
+
+1.321: DB support for disk wipe-age.  If 'mustwipe' is set in the reserved
+       table entry for a node, then when nfree'd, the disk must be reloaded
+       and all free blocks zeroed to prevent information leakage.
+
+	alter table reserved add mustwipe tinyint(4) NOT NULL default '0';
+	alter table current_reloads add mustwipe \
+	    tinyint(4) NOT NULL default '0';
+      
diff --git a/tbsetup/libosload.pm.in b/tbsetup/libosload.pm.in
index 31a766e37ffcaf2275f452fa23b4a7bb0220cca4..39103e5d1820309647b49cf3eeb86e5a4c7d06c4 100755
--- a/tbsetup/libosload.pm.in
+++ b/tbsetup/libosload.pm.in
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -wT
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2005 University of Utah and the Flux Group.
 # All rights reserved.
 #
 # Osload library. Basically the backend to the osload script, but also used
@@ -54,6 +54,7 @@ sub osload ($$) {
     my @nodes       = ();
     my $noreboot    = 0;
     my $asyncmode   = 0;
+    my $zerofree    = 0;
 
     # Locals
     my %retries	    = ();
@@ -84,6 +85,9 @@ sub osload ($$) {
     if (defined($args->{'asyncmode'})) {
 	$asyncmode = $args->{'asyncmode'};
     }
+    if (defined($args->{'zerofree'})) {
+	$zerofree = $args->{'zerofree'};
+    }
     
     #
     # Figure out who called us. Root and admin types can do whatever they
@@ -197,6 +201,7 @@ sub osload ($$) {
 		"*** osload ($node): No filename associated with $imageid!\n";
 	    goto failednode;
 	}
+
 	if (! -R $imagepath) {
 	    if ($ELABINELAB) {
 		#
@@ -210,6 +215,12 @@ sub osload ($$) {
 			    "Frisbee Launcher ($imageid) failed!\n";
 		    goto failednode;
 		}
+		if (! -R $imagepath) {
+		    print STDERR
+			"*** osload ($node): ".
+			    "Frisbee Launcher get not fetch $imagepath ($imageid)!\n";
+		    goto failednode;
+		}
 	    }
 	    else {
 		print STDERR 
@@ -324,6 +335,7 @@ sub osload ($$) {
 	    $reload_mode = "UISP";
 	    $reload_func = \&SetupReloadUISP;
 	    $reboot_required = 0; # We don't reboot motes to reload them
+	    $zerofree = 0; # and we don't zero "the disk"
 	} else {
 	    $reload_mode = "Frisbee";
 	    $reload_func = \&SetupReloadFrisbee;
@@ -339,13 +351,14 @@ sub osload ($$) {
 	    'func'    => $reload_func,
 	    'imageid' => $imageid,
 	    'osid'    => $defosid,
-	    'reboot'  => $reboot_required
+	    'reboot'  => $reboot_required,
+	    'zerofree'=> $zerofree
 	};
 
 	print "Setting up reload for $node (mode: $reload_mode)\n";
 
 	if (!$TESTMODE) {
-	    if (&$reload_func($node, $imageid,$defosid) < 0) {
+	    if (&$reload_func($node, $imageid, $defosid, $zerofree) < 0) {
 		print STDERR
 		"*** osload ($node): Could not set up reload. Skipping.\n";
 		goto failednode;
@@ -465,7 +478,7 @@ sub osload ($$) {
 
 		# Possible race with reboot?
 		if (&{$reload_info->{'func'}}($node, $reload_info->{'imageid'},
-		    $reload_info->{'osid'}) < 0) {
+		    $reload_info->{'osid'}, $reload_info->{'zerofree'}) < 0) {
 		    print(STDERR
 			  "*** osload ($node): ".
 			  "Could not set up reload. Skipping.\n");
@@ -529,7 +542,32 @@ sub WaitTillReloadDone($$$@)
 	sleep(5);
 	foreach my $node (@nodes) {
 	    if (! $done{$node}) {
-		my $maxwait = $maxwaits{$reload_info->{$node}{'imageid'}};
+		my $maxwait;
+
+		#
+		# If we have to zero fill free space, then the
+		# wait time has to be proportional to the disk
+		# size.  In other words, a really, really, really
+		# long time.  Lets assume 20MB/sec to blast zeros,
+		# so 50 seconds/GB.  What the heck, lets call it
+		# 1GB/minute.  Did I mention how this would take
+		# a really long time?
+		#
+		if ($reload_info->{$node}{'zerofree'}) {
+		    my $disksize;
+		    my $query_result =
+			DBQueryWarn("select HD from node_types,nodes ".
+				    "where nodes.type=node_types.type".
+				    " and node_id='$node'");
+		    if ($query_result && $query_result->numrows) {
+			($disksize) = $query_result->fetchrow_array();
+		    }
+		    $disksize = 20
+			if (!$disksize);
+		    $maxwait = ($disksize * 60);
+		} else {
+		    $maxwait = $maxwaits{$reload_info->{$node}{'imageid'}};
+		}
 		
 		my $query_result =
 		    DBQueryWarn("select * from current_reloads ".
@@ -604,9 +642,9 @@ sub WaitTillReloadDone($$$@)
 }
 
 # Setup a reload. 
-sub SetupReloadFrisbee($$$)
+sub SetupReloadFrisbee($$$$)
 {
-    my ($node, $imageid, $osid_notused) = @_;
+    my ($node, $imageid, $osid_notused, $zerofree) = @_;
     my $osid = $FRISBEEOSID;
 
     #
@@ -628,7 +666,8 @@ sub SetupReloadFrisbee($$$)
     #
     $query_result = 
 	DBQueryWarn("replace into current_reloads ".
-		    "(node_id, image_id) values ('$node', '$imageid')");
+		    "(node_id, image_id, mustwipe) values ".
+		    "('$node', '$imageid', $zerofree)");
     return -1
 	if (!$query_result);
 
@@ -650,9 +689,9 @@ sub SetupReloadFrisbee($$$)
 # this differs from a Frisbee reload in one key way - it does the reload
 # right here in this code, rather than setting up a reload for later.
 #
-sub SetupReloadUISP($$$)
+sub SetupReloadUISP($$$$)
 {
-    my ($node, $imageid, $osid) = @_;
+    my ($node, $imageid, $osid, $zerofree_unused) = @_;
 
     #
     # Get the path to the image
diff --git a/tbsetup/os_load.in b/tbsetup/os_load.in
index d50f265d9660304478079b621ba3b39e497cfa05..f29a018d34ad89c6fb97250c45b1246e2fed54b6 100755
--- a/tbsetup/os_load.in
+++ b/tbsetup/os_load.in
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -wT
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2005 University of Utah and the Flux Group.
 # All rights reserved.
 #
 use English;
@@ -24,14 +24,19 @@ sub usage()
 	  "Use -w to wait for the nodes to finish booting.\n".
 	  "Use -r to supress rebooting nodes - you'll need to to it yourself\n".
 	  "Use -e to reload all the nodes in an experiment.\n" .
-	  "Use -l to get a list of images you are permitted to load.\n");
+	  "Use -l to get a list of images you are permitted to load.\n".
+	  "Use -z <style> to zero all unallocated blocks on the disk\n".
+	  "       style==0: don't zero (same as not using -z)\n".
+	  "       style==1: let frisbee do the zeroing\n".
+	  "       style==2: zero disk before running frisbee\n");
     exit(-1);
 }
-my $optlist   = "swldi:e:p:m:r";
+my $optlist   = "swldi:e:p:m:rz:";
 my $waitmode  = 1;
 my $listonly  = 0;
 my $debug     = 0;
 my $noreboot  = 0;
+my $zerofree  = 0;
 my @nodes     = ();
 my $imagepid;
 my $imagename;
@@ -81,6 +86,8 @@ $waitmode = 2
     if (defined($options{"w"}));
 $noreboot = 1
     if (defined($options{"r"}));
+$zerofree = $options{"z"}
+    if (defined($options{"z"}));
 
 #
 # Figure out which nodes. Choice of nodes on command line, or all nodes in an
@@ -223,6 +230,7 @@ my %failednodes = ();
 $osloadargs{'debug'}    = $debug;
 $osloadargs{'waitmode'} = $waitmode;
 $osloadargs{'noreboot'} = $noreboot;
+$osloadargs{'zerofree'} = $zerofree;
 $osloadargs{'nodelist'} = [ @nodes ];
 # No imageid means to load the default image.
 $osloadargs{'imageid'}  = $imageid
diff --git a/tbsetup/reload_daemon.in b/tbsetup/reload_daemon.in
index 7f51265932037cb860c241cab37acb1d150e97e9..64df1f1ffba82e8681bab0a89ec5eeba7354063d 100644
--- a/tbsetup/reload_daemon.in
+++ b/tbsetup/reload_daemon.in
@@ -64,8 +64,8 @@ my $reboot	= "$TB/bin/node_reboot";
 my $tbrsync     = "$TB/bin/tbrsync";
 my $logfile	= "$TB/log/reloadlog";
 my $debug	= 0;
-my $retry_time  = 15; # in minutes
-my $warn_time   = 30; # in minutes
+my $retry_time  = 20;              # in minutes
+my $warn_time   = $retry_time * 2; # in minutes
 my %retried     = ();
 my %warned	= ();
 my %failed	= ();
@@ -131,10 +131,14 @@ while (1) {
     # First, look for nodes that have been in the reloading experiment for
     # longer than $retry_time, and try rebooting them
     #
+    # XXX we count on mustwipe having the value 0, 1, 2 to represent
+    # ever slower forms of wipeage.  For retry_time of 20 minutes that
+    # yields waits of 20, 40 and 60 minutes.
+    #
     $query_result =
-	DBQueryWarn("select node_id from reserved where pid='$RELOADPID' " .
-		    "and eid='$RELOADEID' and " .
-		    "(CURRENT_TIMESTAMP - INTERVAL $retry_time MINUTE) ".
+	DBQueryWarn("select node_id,mustwipe from reserved " .
+		    "where pid='$RELOADPID' and eid='$RELOADEID' and " .
+		    "(CURRENT_TIMESTAMP - INTERVAL $retry_time * (mustwipe + 1) MINUTE)".
 		    "  > rsrv_time");
 
     if (! $query_result) {
@@ -142,7 +146,7 @@ while (1) {
 	next;
     }
 
-    while (($node) = $query_result->fetchrow){ 
+    while (($node, $mustwipe) = $query_result->fetchrow) {
 	$idle=0;
 	#
 	# If this was a node that failed os_load, then instead of rebooting,
@@ -150,7 +154,7 @@ while (1) {
 	# 
 	if ($failed{$node}) {
 	    print "$node failed an earlier os_load. Trying again\n";
-	    push(@retry_list, $node);
+	    push(@retry_list, [$node, $mustwipe]);
 	    delete $failed{$node};
 	    # Skip any reboots. 
 	    $retried{$node} = $time;
@@ -187,22 +191,25 @@ while (1) {
     # Next, we do the same thing for nodes in the reloading experiment for
     # longer than $warn_time, and warn the admins.
     #
+    # XXX again, we scale by the value of mustwipe.
+    #
     $query_result =
-	DBQueryWarn("select node_id from reserved where pid='$RELOADPID' " .
-		    "and eid='$RELOADEID' and " .
-		    "(CURRENT_TIMESTAMP - INTERVAL $warn_time MINUTE) > ".
-		    "   rsrv_time");
+	DBQueryWarn("select node_id,mustwipe from reserved " .
+		    "where pid='$RELOADPID' and eid='$RELOADEID' and " .
+		    "(CURRENT_TIMESTAMP - INTERVAL $warn_time * (mustwipe + 1) MINUTE)".
+		    "  > rsrv_time");
     
     if (! $query_result) {
 	print "DB Error. Waiting a bit.\n";
 	next;
     }
 
-    while (($node) = $query_result->fetchrow){ 
+    while (($node, $mustwipe) = $query_result->fetchrow) {
 	$idle=0;
 	if (!$warned{$node}) {
+	    my $toolong = $warn_time * ($mustwipe + 1);
 	    notify("Node $node has been in $RELOADPID/$RELOADEID for " .
-	    "more than $warn_time minutes");
+		   "more than $toolong minutes");
 	}
 	$warned{$node} = $time;
     }
@@ -227,7 +234,8 @@ while (1) {
     my $CLASSCLAUSE = "(n.class='pc' or n.class='pct')";
     
     $query_result =
-	DBQueryWarn("select a.node_id,b.pid,b.eid from reserved as b ".
+	DBQueryWarn("select a.node_id,b.pid,b.eid,b.mustwipe ".
+		    "from reserved as b ".
 		    "left join nodes as a on a.node_id=b.node_id ".
 		    "left join last_reservation as l on l.node_id=a.node_id ".
 		    "left join node_types as n on n.type=a.type where ".
@@ -249,18 +257,19 @@ while (1) {
 
     # Grab all the nodes that match
     my @pending_list = @retry_list;
-    while (%hrow  = $query_result->fetchhash()) {
+    while (%hrow = $query_result->fetchhash()) {
 	$node = $hrow{'node_id'};
 	$pid  = $hrow{'pid'};
 	$eid  = $hrow{'eid'};
+	$mustwipe = $hrow{'mustwipe'};
 	if ($pid eq $RELOADPID && $eid eq $PENDINGEID) {
-	    push(@pending_list,$node);
+	    push(@pending_list, [$node,$mustwipe]);
 	} else {
-	    push(@other_list,$node);
+	    push(@other_list, [$node,$mustwipe]);
 	}
     }
 
-    my $nodes = join(" ", (@pending_list, @other_list));
+    my $nodes = join(" ", map { $_->[0] } @pending_list, @other_list);
     print "Trying to reload $nodes at ".`date`;
 
     #
@@ -273,7 +282,9 @@ while (1) {
 	#
 	my %images = ();
 	my %imagenodes = ();
-	foreach $node (@pending_list) {
+	foreach $ref (@pending_list) {
+	    ($node, $mustwipe) = @{$ref};
+
 	    $query_result =
 	      DBQueryWarn("select image_id from scheduled_reloads " .
 			  "where node_id='$node'");
@@ -297,15 +308,26 @@ while (1) {
             }
             # XXX End Garcia Hack
 
+	    #
+	    # We need to divide up nodes not only by the image they are
+	    # to load (imageid) but also by if and how the disk should be
+	    # zeroed (mustzero).  So we really have a hash of hashes each
+	    # of which is an array of nodes.  However, my perl skilz are
+	    # not up to that so just combine the imageid and mustwipe into
+	    # a single hash key ('/' is illegal in both, so we use it as
+	    # the separator).
+	    #
+	    my $idid = "$imageid/$mustwipe";
+
 	    $images{$node} = $imageid;
-	    if (defined(@{$imagenodes{$imageid}})) {
-		push(@{$imagenodes{$imageid}},$node);
+	    if (defined(@{$imagenodes{$idid}})) {
+		push(@{$imagenodes{$idid}},$node);
 	    } else {
-		$imagenodes{$imageid} = [$node];
+		$imagenodes{$idid} = [$node];
 	    }
 	    if ($debug) {
-		print "$node => $images{$node} == $imageid (".
-		  join(",",@{$imagenodes{$imageid}}).")\n";
+		print "$node ($mustwipe) => $images{$node} == $imageid (".
+		  join(",",@{$imagenodes{$idid}}).")\n";
 	    }
 	}
 	
@@ -315,17 +337,19 @@ while (1) {
 	# We change the reservation EID over and fire up an os_load
 	# directly.
 	#
-	my $cond = join(" or ",map("node_id='$_'",@pending_list));
+	my $cond = "node_id in (" .
+	    join(",", map("'$_->[0]'", @pending_list)) . ")";
 	if (! DBQueryWarn("update reserved set ".
 			  "rsrv_time=now(),eid='$RELOADEID' ".
 			  "where $cond")) {
-	    print "Could not update EID for ".join(" ",@pending_list).
-	      ". Waiting a bit.\n";
+	    print "Could not update EID for " .
+		join(" ", map("$_->[0]", @pending_list)) .
+		    ". Waiting a bit.\n";
 	    next;
 	} else {
 	    print "Pending nodes moved to $RELOADEID at ".`date`;
 
-	    foreach my $n (@pending_list) {
+	    foreach my $n (map("$_->[0]", @pending_list)) {
 		TBSetNodeHistory($n, TB_NODEHISTORY_OP_MOVE, $UID,
 				 $RELOADPID, $RELOADEID);
 	    }
@@ -335,11 +359,13 @@ while (1) {
 
 	# Now run an os_load for each image
 	
-	foreach $imageid (keys %imagenodes) {
+	foreach my $idid (keys %imagenodes) {
 
-	    my $nodelist = join(" ",@{$imagenodes{$imageid}});
+	    my $nodelist = join(" ",@{$imagenodes{$idid}});
 	    my $os_load_flags = "";
 
+	    ($imageid, $mustzero) = split("/", $idid);
+
             # XXX Garcia Hack - gross..
             # We special-case garcia loading for now until the subnode->node
             # dependancies are worked out inside os_load.
@@ -351,7 +377,7 @@ while (1) {
                 if (system("$tbrsync upload $gimagepath $nodelist") == 0) {
                     if (system("$reboot $nodelist") == 0) {
                         # rsync and reboot succeeded, so free 'em up.
-                        foreach my $gnode (@{$imagenodes{$imageid}}) {
+                        foreach my $gnode (@{$imagenodes{$idid}}) {
                             freefromreloading($gnode);
                         }
                         print "garcia reload done at ".`date`;
@@ -380,7 +406,14 @@ while (1) {
 	    # the node's type
 	    #
 	    if ($imageid) {
-		$os_load_flags .= " -m $imageid ";
+		$os_load_flags .= " -m $imageid";
+	    }
+
+	    #
+	    # Handle optional zeroing of the disk
+	    #
+	    if ($mustzero) {
+		$os_load_flags .= " -z $mustzero";
 	    }
 
 	    print "Running '$os_load $os_load_flags $nodelist' at ".`date`;
@@ -396,7 +429,7 @@ while (1) {
 
 		# Record the failure list. If we get to the 15 minute
 		# retry, call os_load again instead of rebooting.
-		foreach my $node (@{$imagenodes{$imageid}}) {
+		foreach my $node (@{$imagenodes{$idid}}) {
 		    $failed{$node} = $time;		    
 		}
 	    }
@@ -407,6 +440,8 @@ while (1) {
     }
 	
     if (@other_list > 0 ) {
+	my $nodes = join(" ", map { $_->[0] } @other_list);
+
 	#
 	# Call sched_reload with the "force" option, which says that if
 	# sched_reload cannot reserve the node (cause someone just got it)
@@ -417,11 +452,11 @@ while (1) {
 	# default, and sched_reload will pick that up from the database
 	# in the absence of a -i option. 
 	#
-	if (system("$sched_reload -f @other_list")) {
+	if (system("$sched_reload -f $nodes")) {
 	    #
 	    # Could not get it. Wait and go around again.
 	    #
-	    print "$sched_reload failed on @other_list. Waiting a bit.\n";
+	    print "$sched_reload failed on $nodes. Waiting a bit.\n";
 	    next;
 	}
 
diff --git a/tmcd/freebsd/rc.frisbee b/tmcd/freebsd/rc.frisbee
index 4e8ea9615da578dd1b133ac26b89dd852fa99427..6516a7d56d3517f7b9d1bac0e5909d53f9a384a6 100755
--- a/tmcd/freebsd/rc.frisbee
+++ b/tmcd/freebsd/rc.frisbee
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2004 University of Utah and the Flux Group.
+# Copyright (c) 2000-2005 University of Utah and the Flux Group.
 # All rights reserved.
 #
 # Optional flag argument says "do not reboot"
@@ -49,6 +49,8 @@ PARTITION=${PARTITION:-'0'}
 PARTOS=`echo $LOADINFO | awk -F= '{ printf $4 }' | awk -F' ' '{ print $1 }'`
 DISK=`echo $LOADINFO | awk -F= '{ printf $5 }' | awk -F' ' '{ print $1 }'`
 DISK=${DISK:-'ad0'}
+ZFILL=`echo $LOADINFO | awk -F= '{ printf $6 }' | awk -F' ' '{ print $1 }'`
+ZFILL=${ZFILL:-'0'}
 
 if [ "$PARTITION" != "0" ]; then
 	SLICE="-s $PARTITION"
@@ -121,11 +123,20 @@ if [ x"$ADDRESS" != x ]; then
 		MCASTIF=""
 	fi
 	MCASTADDR="-m $MCAST -p $PORT"
+	#
+	# ZFILL==1: use frisbee
+	# ZFILL==2: separate disk-wipe pass (not yet implemented)
+	#
+	if [ "$ZFILL" != "0" ]; then
+	    ZFILL="-z"
+	else
+	    ZFILL=""
+	fi
 
-	echo "Running $BINDIR/frisbee $LOADIP $MEMARGS $SLICE $MCASTIF $MCASTADDR /dev/$DISK at `date`"
+	echo "Running $BINDIR/frisbee $LOADIP $MEMARGS $ZFILL $SLICE $MCASTIF $MCASTADDR /dev/$DISK at `date`"
 	$BINDIR/tmcc state RELOADING
 
-	$BINDIR/frisbee $LOADIP $MEMARGS $SLICE $MCASTIF $MCASTADDR /dev/$DISK
+	$BINDIR/frisbee $LOADIP $MEMARGS $ZFILL $SLICE $MCASTIF $MCASTADDR /dev/$DISK
 	case $? in
 	0)
 		echo "Frisbee run finished"
diff --git a/tmcd/tmcd.c b/tmcd/tmcd.c
index 0a6942adea8b04ee7711b9c1e294f1cc3eebeaad..09971c3d1d95c8fae98292106946d895773e3398 100644
--- a/tmcd/tmcd.c
+++ b/tmcd/tmcd.c
@@ -3259,17 +3259,17 @@ COMMAND_PROTOTYPE(doloadinfo)
 	char		buf[MYBUFSIZE];
 	char		*bufp = buf, *ebufp = &buf[sizeof(buf)];
 	char		*disktype;
-	int		disknum;
+	int		disknum, zfill;
 
 	/*
 	 * Get the address the node should contact to load its image
 	 */
-	res = mydb_query("select load_address,loadpart,OS,frisbee_pid "
+	res = mydb_query("select load_address,loadpart,OS,frisbee_pid,mustwipe "
 			 "  from current_reloads as r "
 			 "left join images as i on i.imageid = r.image_id "
 			 "left join os_info as o on i.default_osid = o.osid "
 			 "where node_id='%s'",
-			 4, reqp->nodeid);
+			 5, reqp->nodeid);
 
 	if (!res) {
 		error("doloadinfo: %s: DB Error getting loading address!\n",
@@ -3302,6 +3302,14 @@ COMMAND_PROTOTYPE(doloadinfo)
 
 	bufp += OUTPUT(bufp, ebufp - bufp,
 		       "ADDR=%s PART=%s PARTOS=%s", row[0], row[1], row[2]);
+
+	/*
+	 * Remember zero-fill free space indicator
+	 */
+	zfill = 0;
+	if (row[4] && row[4][0])
+		zfill = atoi(row[4]);
+
 	mysql_free_result(res);
 
 	/*
@@ -3326,9 +3334,10 @@ COMMAND_PROTOTYPE(doloadinfo)
 		if (row[1] && row[1][0])
 			disknum = atoi(row[1]);
 	}
-	OUTPUT(bufp, ebufp - bufp, " DISK=%s%d\n", disktype, disknum);
+	OUTPUT(bufp, ebufp - bufp, " DISK=%s%d ZFILL=%d\n",
+	       disktype, disknum, zfill);
 	mysql_free_result(res);
-	
+
 	client_writeback(sock, buf, strlen(buf), tcp);
 	if (verbose)
 		info("doloadinfo: %s", buf);