Whamcloud - gitweb
1167495700d7c4bdba9942474f5461bd21c9799d
[fs/lustre-release.git] / lustre / tests / metadata-updates.sh
1 #!/bin/bash
2
3 # A Metadata Update Test tests that
4 # metadata updates are properly completed when
5 # multiple clients create/delete files and modify the attributes of files.
6
7 set -e
8
9 LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
10 . $LUSTRE/tests/test-framework.sh
11 init_test_env $@
12 . ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
13
14 TRACE=${TRACE:-"+x"}
15
16 TESTDIR=${TESTDIR:-$DIR/d0.$(basename $0 .sh)}
17
18 NODES_TO_USE=${NODES_TO_USE:-$CLIENTS}
19
20 [ -z $CLIENTS ] && NODES_TO_USE=$(hostname)
21
22 FILE=testfile
23 FILE_SIZE=1024
24 CURRENT_MODE=0644
25 NEW_MODE=0222
26 NEW_ATIME="2001-01-01 GMT"
27 NEW_MTIME="2005-05-05 GMT"
28
29 test_UID=$(id -u)
30 test_GID=$(id -g)
31
32 NUM_FILES=1000
33
34 WRITE_DISJOINT=${WRITE_DISJOINT:-$(which write_disjoint 2> /dev/null)} || true
35 WRITE_DISJOINT_FILE=$TESTDIR/f0.write_disjoint_file
36 NUMLOOPS=1000
37
38 log "===== $0 ====== "
39
40 check_and_setup_lustre
41
42 cleanup_prepare () {
43
44     do_nodes $NODES_TO_USE "set $TRACE;
45 DIR=$TESTDIR/\\\$(hostname);
46 TESTFILE=\\\$DIR/$FILE;
47 rm -f \\\$TESTFILE;
48 rmdir \\\$DIR 2>/dev/null;
49 mkdir -p \\\$DIR" || return ${PIPESTATUS[0]}
50     return 0;
51 }
52
53 do_mknod () {
54     echo "Creating file(s) by mknod (2) ... "
55
56     do_nodes $NODES_TO_USE "set $TRACE;
57 TESTFILE=$TESTDIR/\\\$(hostname)/$FILE;
58 mcreate \\\$TESTFILE; " || return ${PIPESTATUS[0]}
59     return 0
60 }
61
62 do_write () {
63     do_nodes $NODES_TO_USE "set $TRACE;
64 TESTFILE=$TESTDIR/\\\$(hostname)/$FILE;
65 dd if=/dev/zero of=\\\$TESTFILE bs=$FILE_SIZE count=1 2>/dev/null || exit 54;
66 echo \\\$(hostname) | dd of=\\\$TESTFILE conv=notrunc 2>/dev/null || exit 55; 
67 md5sum \\\$TESTFILE; " || return ${PIPESTATUS[0]}
68     return 0
69 }
70
71 do_check_data () {
72     local sums=$1
73     local HOST
74     echo "Checking file(s) data ... md5sum : "
75     echo "$sums"
76
77     do_nodes --verbose $NODES_TO_USE "echo \\\"$sums\\\" | md5sum --check $sum" || \
78         return ${PIPESTATUS[0]}
79     return 0
80 }
81
82 do_truncate () {
83     echo "Truncating file(s) ... "
84
85      do_nodes $NODES_TO_USE "set $TRACE;
86 TESTFILE=$TESTDIR/\\\$(hostname)/$FILE;
87 truncate \\\$TESTFILE 0" || return ${PIPESTATUS[0]} 
88
89     FILE_SIZE=0
90     return 0
91 }
92
93 # check st_uid, st_gid, st_size, st_mode
94 get_stat () {
95     local attr="$test_UID $test_GID $FILE_SIZE $CURRENT_MODE"
96
97     echo "Checking file(s) attributes ... "
98
99     do_nodes --verbose $NODES_TO_USE "set $TRACE;
100 for HOST in ${NODES_TO_USE//,/ } ; do 
101     TESTFILE=$TESTDIR/\\\$HOST/$FILE;
102     tmp=\\\$(stat -c \\\"%u %g %s 0%a\\\" \\\$TESTFILE);
103     echo \\\"\\\$TESTFILE [ uid gid size mode ] expected : $attr ;  got : \\\$tmp \\\";
104     if [ x\\\"\\\$tmp\\\" != x\\\"$attr\\\" ] ; then
105         echo \\\"Wrong file attributes\\\";
106         exit 56;
107     fi;
108 done " || return ${PIPESTATUS[0]}
109     return 0 
110 }
111
112 do_chmod () {
113     echo "Performing chmod 0$NEW_MODE ..."
114
115     do_nodes $NODES_TO_USE "set $TRACE;
116 TESTFILE=$TESTDIR/\\\$(hostname)/$FILE;
117 chmod $NEW_MODE \\\$TESTFILE" || return ${PIPESTATUS[0]}
118  
119     CURRENT_MODE=$NEW_MODE
120     return 0
121 }
122
123 do_change_timestamps () {
124     echo "Changing atime, mtime ..."
125
126     do_nodes $NODES_TO_USE " set $TRACE;
127 TESTFILE=$TESTDIR/\\\$(hostname)/$FILE;
128 touch -c --date=\\\"$NEW_ATIME\\\" -a \\\$TESTFILE;
129 touch -c --date=\\\"$NEW_MTIME\\\" -m \\\$TESTFILE " || return ${PIPESTATUS[0]}
130     return 0
131 }
132
133 # check st_atime, st_mtime
134 do_check_timestamps () {
135     local atime=$(date --date="$NEW_ATIME" +%s)
136     local mtime=$(date --date="$NEW_MTIME" +%s)
137
138     local times="$atime $mtime"
139
140     echo "Checking atime, mtime ... "
141
142     do_nodes --verbose $NODES_TO_USE "set $TRACE;
143 for HOST in ${NODES_TO_USE//,/ } ; do 
144     TESTFILE=$TESTDIR/\\\$HOST/$FILE;
145     tmp=\\\$(stat -c \\\"%X %Y\\\" \\\$TESTFILE);
146     if [ x\\\"\\\$tmp\\\" != x\\\"$times\\\" ] ; then
147        echo \\\"\\\$TESTFILE [ atime mtime ] expected : $times ;  got : \\\$tmp \\\";
148        RC=57;
149     fi;
150 done;
151 exit \\\$RC" || return ${PIPESTATUS[0]}
152     return 0 
153 }
154
155 do_fill_dir () {
156     echo "Filling up directories ... files : f1 ... f$NUM_FILES) ... "
157
158     do_nodes $NODES_TO_USE "set $TRACE;
159 TESTFILE=$TESTDIR/\\\$(hostname)/$FILE;
160 rm -f \\\$TESTFILE;
161 DIR=$TESTDIR/\\\$(hostname);
162 for i in \\\$(seq $NUM_FILES) ; do
163     touch \\\$DIR/f\\\$i;
164 done " || return ${PIPESTATUS[0]}
165     return 0
166 }
167
168 check_dir_contents () {
169     local num_files=${1:-1}
170
171     echo "Checking dir contents ... (should exist files : f$num_files ... f$NUM_FILES) ... "
172     do_nodes $NODES_TO_USE "set $TRACE;
173 for HOST in ${NODES_TO_USE//,/ } ; do 
174     DIR=$TESTDIR/\\\$HOST;
175     for i in \\\$(seq $NUM_FILES -1 $num_files) ; do
176         if ! [ -f \\\$DIR/f\\\$i ] ; then
177             echo \\\"ERROR: file \\\$DIR/f\\\$i should exist\\\";
178             RC=1;
179         fi;
180     done;
181     for i in \\\$(seq $(($num_files - 1 ))) ; do
182         if [ -f \\\$DIR/f\\\$i ] ; then
183             echo \\\"ERROR: deleted file \\\$DIR/f\\\$i exists\\\";
184             RC=1;
185         fi;
186     done;
187 done;
188 exit \\\$RC " || return ${PIPESTATUS[0]}
189     return 0
190 }
191
192 do_partial_delete () {
193     local num_files=$1
194
195     echo "Deleting files ... f1 ... f$num_files ... "
196     do_nodes $NODES_TO_USE "set $TRACE;
197 DIR=$TESTDIR/\\\$(hostname);
198 for i in \\\$(seq $num_files) ; do
199     if ! rm -f \\\$DIR/f\\\$i ; then
200         exit 1;
201     fi;
202 done " || return ${PIPESTATUS[0]}
203     return 0
204 }
205
206 STATUS=0
207
208 chmod 0777 $MOUNT   || exit 1
209 mkdir -p $TESTDIR   || exit 1
210 chmod 0777 $TESTDIR || exit 1
211
212 cleanup_prepare     || error_exit "cleanup failed"
213
214 # create file(s) (mknod (2)), write data, check data, check file attributes
215 echo "Part 1. create file(s) (mknod (2)), write data, check data, check file attributes."
216 do_mknod              || error_exit "mknod failed"
217 echo "Writing data to file(s) ... store md5sum ... "
218 sums="$(do_write)"    || error_exit "write data failed"
219 do_check_data "$sums" || error_exit "md5sum verification failed"
220 get_stat              || { error_noexit "attributes check failed" ; STATUS=1; }
221
222 # file(s) attributes modification
223 echo "Part 2. file(s) attributes modification."
224 do_chmod              || error_exit "chmod failed"
225 get_stat              || { error_noexit "wrong attributes after chmod"; STATUS=1; }
226
227 do_change_timestamps  || error_exit "timestamps change failed"
228 do_check_timestamps   || { error_noexit "wrong timestamps"; STATUS=1; }
229
230 # truncate file(s) to 0 size, check new file size
231 echo "Part 3. truncate file(s) to 0 size, check new file size."
232 do_truncate     || error_exit"truncate failed"
233 get_stat        || { error_noexit "wrong attributes after truncate"; STATUS=1; }
234
235 # directory content solidity
236 echo "Part 4. directory content solidity: fill up directory, check dir content, remove some files, check dir content."
237 do_fill_dir        || error_exit "dir creation failed"
238 check_dir_contents || { error_noexit "dir contents check failed"; STATUS=1; }
239
240 do_partial_delete $(($NUM_FILES / 2))      || error_exit "delete failed"
241 check_dir_contents $(($NUM_FILES / 2 + 1)) ||
242     { error_noexit "dir contents check after delete failed"; STATUS=1; }
243
244 # "write_disjoint" test
245 echo "Part 5. write_disjoint test: see lustre/tests/mpi/write_disjoint.c for details"
246 if [ -f "$WRITE_DISJOINT" ]; then
247     set $TRACE
248     MACHINEFILE=${MACHINEFILE:-$TMP/$(basename $0 .sh).machines}
249     generate_machine_file $NODES_TO_USE $MACHINEFILE
250     mpi_run -np $(get_node_count ${NODES_TO_USE//,/ }) -machinefile $MACHINEFILE \
251     $WRITE_DISJOINT -f $WRITE_DISJOINT_FILE -n $NUMLOOPS || STATUS=1
252 else
253     skip "$0 : write_disjoint not found "
254 fi
255
256 equals_msg `basename $0`: test complete, cleaning up
257 rm -rf $TESTDIR
258 rm -f $MACHINEFILE
259 check_and_cleanup_lustre
260 exit $STATUS