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