Whamcloud - gitweb
LU-691 Fix OST index errors in test suite - sanity 133c defect
[fs/lustre-release.git] / lustre / tests / lfsck.sh
1 #!/bin/bash
2 #
3 # test e2fsck and lfsck to detect and fix filesystem corruption
4 #
5 #set -vx
6 set -e
7
8 LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
9 . $LUSTRE/tests/test-framework.sh
10 init_test_env $@
11 . ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
12
13 NUMFILES=${NUMFILES:-10}
14 NUMDIRS=${NUMDIRS:-4}
15 OSTIDX=${OSTIDX:-0} # the OST index in LOV
16 OBJGRP=${OBJGRP:-0} # the OST object group
17
18 [ -d "$SHARED_DIRECTORY" ] || \
19     { skip "SHARED_DIRECTORY should be specified with a shared directory \
20 which can be accessable on all of the nodes" && exit 0; }
21
22 which getfattr &>/dev/null || { skip_env "could not find getfattr" && exit 0; }
23 which setfattr &>/dev/null || { skip_env "could not find setfattr" && exit 0; }
24
25 if [ ! -x `which $LFSCK_BIN` ]; then
26     log "$($E2FSCK -V)"
27     error "e2fsprogs does not support lfsck"
28 fi
29
30 MOUNT_2=""
31 check_and_setup_lustre
32
33 assert_DIR
34
35 SAMPLE_FILE=$TMP/$(basename $0 .sh).junk
36 dd if=/dev/urandom of=$SAMPLE_FILE bs=1M count=1
37
38 # Create some dirs and files on the filesystem.
39 create_files_sub() {
40     local test_dir=$1
41     local num_dirs=$2
42     local file_name=$3
43     local first_num=$4
44     local last_num=$5
45     local d e f
46
47     for d in $(seq -f d%g $first_num $last_num); do
48         echo "creating files in $test_dir/$d"
49         for e in $(seq -f d%g $num_dirs); do
50             mkdir -p $test_dir/$d/$e || error "mkdir $test_dir/$d/$e failed"
51             for f in $(seq -f test%g $num_dirs); do
52                 cp $file_name $test_dir/$d/$e/$f || \
53                     error "cp $file_name $test_dir/$d/$e/$f failed"
54             done
55         done
56     done
57 }
58
59 create_files() {
60     local test_dir=$1
61     local num_dirs=$2
62     local num_files=$3
63     local f
64
65     # create some files on the filesystem
66     local first_num=1
67     local last_num=$num_dirs
68     create_files_sub $test_dir $num_dirs /etc/fstab $first_num $last_num
69
70     # create files to be modified
71     for f in $(seq -f $test_dir/testfile.%g $((num_files * 3))); do
72         echo "creating $f"
73         cp $SAMPLE_FILE $f || error "cp $SAMPLE_FILE $f failed"
74     done
75
76     # create some more files
77     first_num=$((num_dirs * 2 + 1))
78     last_num=$((num_dirs * 2 + 3))
79     create_files_sub $test_dir $num_dirs /etc/hosts $first_num $last_num
80
81     # these should NOT be taken as duplicates
82     for f in $(seq -f $test_dir/d$last_num/linkfile.%g $num_files); do
83         echo "linking files in $test_dir/d$last_num"
84         cp /etc/hosts $f || error "cp /etc/hosts $f failed"
85         ln $f $f.link || error "ln $f $f.link failed"
86     done
87 }
88
89 # Get the objids for files on the OST (given the OST index and object group).
90 get_objects() {
91     local obdidx=$1
92     shift
93     local group=$1
94     shift
95     local ost_files="$@"
96     local ost_objids
97     ost_objids=$($LFS getstripe $ost_files | \
98                 awk '{if ($1 == '$obdidx' && $4 == '$group') print $2 }')
99     echo $ost_objids
100 }
101
102 # Get the OST nodet name (given the OST index).
103 get_ost_node() {
104     local obdidx=$1
105     local ost_uuid
106     local ost_node
107     local node
108
109     ost_uuid=$(ostuuid_from_index $obdidx)
110
111     for node in $(osts_nodes); do
112         do_node $node "lctl get_param -n obdfilter.*.uuid" | grep -q $ost_uuid
113         [ ${PIPESTATUS[1]} -eq 0 ] && ost_node=$node && break
114     done
115     [ -z "$ost_node" ] && \
116         echo "failed to find the OST with index $obdidx" && return 1
117     echo $ost_node
118 }
119
120 # Get the OST target device (given the OST facet name and OST index).
121 get_ost_dev() {
122     local node=$1
123     local obdidx=$2
124     local ost_name
125     local ost_dev
126
127     ost_name=$(ostname_from_index $obdidx)
128     ost_dev=$(do_node $node "lctl get_param -n obdfilter.${ost_name}.mntdev")
129     [ ${PIPESTATUS[0]} -ne 0 ] && \
130         echo "failed to find the OST device with index $obdidx on $facet" && \
131         return 1
132
133     if [[ $ost_dev = *loop* ]]; then
134         ost_dev=$(do_node $node "losetup $ost_dev" | \
135                 sed -e "s/.*(//" -e "s/).*//")
136     fi
137
138     echo $ost_dev
139 }
140
141 # Get the file names to be duplicated or removed on the MDS.
142 get_files() {
143     local flavor=$1
144     local test_dir=$2
145     local num_files=$3
146     local first last
147     local test_file
148
149     case $flavor in
150     dup)
151         first=$((num_files + 1))
152         last=$((num_files * 2))
153         ;;
154     remove)
155         first=$((num_files * 2 + 1))
156         last=$((num_files * 3))
157         ;;
158     *) echo "get_files(): invalid flavor" && return 1 ;;
159     esac
160
161     local files=""
162     local f 
163     for f in $(seq -f testfile.%g $first $last); do
164         test_file=$test_dir/$f
165         files="$files $test_file"
166     done
167     files=$(echo $files | sed "s#$DIR/##g")
168     echo $files
169 }
170
171 # Remove objects associated with files.
172 remove_objects() {
173     local node=$1
174     shift
175     local ostdev=$1
176     shift
177     local group=$1
178     shift
179     local objids="$@"
180     local tmp
181     local i
182     local rc
183
184     echo "removing objects from $ostdev on $facet: $objids"
185     tmp=$(mktemp $SHARED_DIRECTORY/debugfs.XXXXXXXXXX)
186     for i in $objids; do
187         echo "rm O/$group/d$((i % 32))/$i" >> $tmp
188     done
189
190     do_node $node "$DEBUGFS -w -f $tmp $ostdev"
191     rc=${PIPESTATUS[0]}
192     rm -f $tmp
193
194     return $rc
195 }
196
197 # Remove files from MDS.
198 remove_files() {
199     do_rpc_nodes $(facet_host $1) remove_mdt_files $@
200 }
201
202 # Create EAs on files so objects are referenced from different files.
203 duplicate_files() {
204     do_rpc_nodes $(facet_host $1) duplicate_mdt_files $@
205 }
206
207 #********************************* Main Flow **********************************#
208
209 init_logging
210
211 # get the server target devices
212 get_svr_devs
213
214 if is_empty_fs $MOUNT; then
215     # create test directory
216     TESTDIR=$DIR/d0.$TESTSUITE
217     mkdir -p $TESTDIR || error "mkdir $TESTDIR failed"
218
219     # create some dirs and files on the filesystem
220     create_files $TESTDIR $NUMDIRS $NUMFILES
221
222     # get the objids for files in group $OBJGRP on the OST with index $OSTIDX
223     OST_REMOVE=$(get_objects $OSTIDX $OBJGRP \
224                 $(seq -f $TESTDIR/testfile.%g $NUMFILES))
225
226     # get the node name and target device for the OST with index $OSTIDX
227     OSTNODE=$(get_ost_node $OSTIDX) || error "get_ost_node by index $OSTIDX failed"
228     OSTDEV=$(get_ost_dev $OSTNODE $OSTIDX) || \
229         error "get_ost_dev $OSTNODE $OSTIDX failed"
230
231     # get the file names to be duplicated on the MDS
232     MDS_DUPE=$(get_files dup $TESTDIR $NUMFILES) || error "$MDS_DUPE"
233     # get the file names to be removed from the MDS
234     MDS_REMOVE=$(get_files remove $TESTDIR $NUMFILES) || error "$MDS_REMOVE"
235
236     stopall -f || error "cleanupall failed"
237
238     # remove objects associated with files in group $OBJGRP
239     # on the OST with index $OSTIDX
240     remove_objects $OSTNODE $OSTDEV $OBJGRP $OST_REMOVE || \
241         error "removing objects failed"
242
243     # remove files from MDS
244     remove_files $SINGLEMDS $MDTDEV $MDS_REMOVE || error "removing files failed"
245
246     # create EAs on files so objects are referenced from different files
247     duplicate_files $SINGLEMDS $MDTDEV $MDS_DUPE || \
248         error "duplicating files failed"
249     FSCK_MAX_ERR=1   # file system errors corrected
250 else # is_empty_fs $MOUNT
251     FSCK_MAX_ERR=4   # file system errors left uncorrected
252 fi
253
254 # Test 1a - check and repair the filesystem
255 # lfsck will return 1 if the filesystem had errors fixed
256 # run e2fsck to generate databases used for lfsck
257 generate_db
258
259 # remount filesystem
260 REFORMAT=""
261 check_and_setup_lustre
262
263 # run lfsck
264 rc=0
265 run_lfsck || rc=$?
266 if [ $rc -eq 0 ]; then
267     echo "clean after the first check"
268 else
269     # run e2fsck again to generate databases used for lfsck
270     generate_db
271
272     # run lfsck again
273     rc=0
274     run_lfsck || rc=$?
275     if [ $rc -eq 0 ]; then
276         echo "clean after the second check"
277     else
278         error "lfsck test 2 - finished with rc=$rc"
279     fi
280 fi
281
282 complete $(basename $0) $SECONDS
283 check_and_cleanup_lustre
284 exit_status