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