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