Fix fdblocks accounting, need to consider cleared agfl blocks too; add shortcut ...
[xfstests-dev.git] / tools / ag-wipe
1 #!/usr/bin/perl -w
2 use strict;
3 use IO::File;
4 use Getopt::Std;
5
6 #
7 #  Copyright (c) 2003 Silicon Graphics, Inc.  All Rights Reserved.
8 #  
9 #  This program is free software; you can redistribute it and/or modify it
10 #  under the terms of version 2 of the GNU General Public License as
11 #  published by the Free Software Foundation.
12 #  
13 #  This program is distributed in the hope that it would be useful, but
14 #  WITHOUT ANY WARRANTY; without even the implied warranty of
15 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 #  
17 #  Further, this software is distributed without any warranty that it is
18 #  free of the rightful claim of any third person regarding infringement
19 #  or the like.  Any license provided herein, whether implied or
20 #  otherwise, applies only to this software file.  Patent licenses, if
21 #  any, provided herein do not apply to combinations of this program with
22 #  other software, or any other product whatsoever.
23 #  
24 #  You should have received a copy of the GNU General Public License along
25 #  with this program; if not, write the Free Software Foundation, Inc., 59
26 #  Temple Place - Suite 330, Boston MA 02111-1307, USA.
27 #  
28 #  Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
29 #  Mountain View, CA  94043, or:
30 #  
31 #  http://www.sgi.com 
32 #  
33 #  For further information regarding this notice, see: 
34 #  
35 #  http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
36 #
37
38 #
39 # Modify a filesystem's superblock and AGF metadata structures
40 # so that only a subset of the allocation groups will be used.
41 # Intended use is in testing large virtual devices (eg. loop)
42 # with extremely large filesystems, where we want to ensure
43 # high allocation groups are used as much as possible (where
44 # the block addresses are large).
45 #
46
47 my @sbprint = ( '"print fdblocks"', '"print agcount"' );
48 my @agfprint = ( '"print freeblks"', '"print flcount"' );
49 my @agfcommands = ( '"write freeblks 0"',
50                         '"write longest 0"', '"write flcount 0"',
51                         '"write bnolevel 1"', '"write cntlevel 1"',
52                         '"write flfirst 0"', '"write fllast 0"' );
53 my @bnoprint = ( '"addr bnoroot"', '"print numrecs"' );
54 my @bnocommands = ( '"addr bnoroot"', '"write numrecs 0"',
55                         '"write leftsib -1"', '"write rightsib -1"' );
56 my @cntprint = ( '"addr cntroot"', '"print numrecs"' );
57 my @cntcommands = ( '"addr cntroot"', '"write numrecs 0"',
58                         '"write leftsib -1"', '"write rightsib -1"' );
59
60 my %opt;
61 getopts('cf:l:v', \%opt);
62 die "Usage: ag-wipe [-f firstAG] [-l lastAG] [-cv] device\n" unless (@ARGV == 1);
63 my $device = shift @ARGV;
64 die "$device: no such file\n" unless (-e $device);
65 my $clearall = defined($opt{'c'}) ? 1 : 0;
66 my $verbose = defined($opt{'v'}) ? 1 : 0;
67 my $nagfirst = defined($opt{'f'}) ? $opt{'f'} : 0;
68 my $naglast = defined($opt{'l'}) ? $opt{'l'} : 0;
69
70 sub xfs_db {
71         my $xfsdb = "xfs_db -x $device";
72         my %hash;
73
74         foreach (@_) {
75                 $xfsdb .= ' -c ' . $_;
76         }
77         print $xfsdb, "\n" if ($verbose);
78
79         die unless open(DB, "$xfsdb 2>/dev/null |");
80         while (<DB>) {
81                 if (/^(\S+) = (.*)$/) {
82                         print if ($verbose);
83                         $hash{$1} = $2;
84                 }
85         }
86         return %hash;
87 }
88
89 my %sb = xfs_db 'sb', @sbprint;
90 print "=== Initially ", $sb{'fdblocks'}, " blocks free across ",
91         $sb{'agcount'}, " AGs\n";
92 if ($clearall && ($nagfirst || $naglast)) {
93         print STDERR "  o Clearall specified with first/last AG, quiting\n";
94         exit(1);
95 }
96 if ($nagfirst >= $sb{'agcount'}) {
97         print "  o First AG number is too large, quiting\n";
98         exit(1);
99 }
100 if ($naglast >= $sb{'agcount'}) {
101         print "  o Last AG number is too large, quiting\n";
102         exit(1);
103 }
104 if ($naglast - $nagfirst < 0) {
105         print "  o No AGs to clear, quiting\n";
106         exit(1);
107 }
108 if ($clearall) {
109         $naglast = $sb{'agcount'} - 2;
110 }
111
112 print "=== Wiping ", $naglast - $nagfirst + 1,
113         " AGs starting from AG #", $nagfirst, "\n";
114
115 my $ag = $nagfirst;
116 while ($ag <= $naglast) {
117         my %btree;
118         my %agf;
119
120         print "  o AG#", $ag, " AGF fields\n";
121
122         %agf = xfs_db "'agf $ag'", @agfprint;
123         xfs_db "'agf $ag'", @agfcommands;
124
125         my $blockcnt = $agf{'freeblks'} + $agf{'flcount'};
126         $sb{'fdblocks'} -= $blockcnt;
127         print "     cleared ", $blockcnt, " blocks from AG#", $ag, "\n";
128
129         %btree = xfs_db "'agf $ag'", @bnoprint;
130         xfs_db "'agf $ag'", @bnocommands;
131         print "     cleared ", $btree{'numrecs'}, " BNO btree records in AG#",
132                 $ag, "\n";
133
134         %btree = xfs_db "'agf $ag'", @cntprint;
135         xfs_db "'agf $ag'", @cntcommands;
136         print "     cleared ", $btree{'numrecs'}, " CNT btree in AG#",
137                 $ag, "\n";
138         $ag++;
139 }
140
141 print "=== Updating final freespace count, ", $sb{'fdblocks'}, " blocks\n";
142 xfs_db "'sb 0'", "'write fdblocks $sb{'fdblocks'}'"