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