-
Notifications
You must be signed in to change notification settings - Fork 202
/
qemu
executable file
·365 lines (309 loc) · 10.2 KB
/
qemu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
#!/bin/bash
. $LKP_SRC/lib/kexec.sh
. $LKP_SRC/lib/http.sh
. $LKP_SRC/lib/qemu.sh
. $LKP_SRC/lib/unit.sh
. $LKP_SRC/lib/job-init.sh
. $LKP_SRC/lib/lkp_cmd.sh
script_name=$(basename $0)
[ -n "$SUDO_USER" ] && HOME=$(eval "echo ~$SUDO_USER")
usage()
{
cat <<EOF
Usage: lkp $script_name [-o RESULT_ROOT] [-p VDISK_PATH] [-s SSH_PORT] [-k bzImage] [-m modules.cgz] [-e] job.sh
options:
-o RESULT_ROOT dir for storing all results
-s SSH_PORT forward ssh port to host
-p VDISK_PATH specify vdisk path
-k bzImage specify bzImage as kernel image
-m modules.cgz specify kernel modules
-e use external network (download from 01.org)
Note:
This script uses qemu to start a VM to run LKP test-job.
It downloads kernel, initrd, bm_initrd, modules_initrd through LKP_SERVER,
and generates lkp-initrd locally and creates job-initrd with 'job.sh' you specified.
You can check test results in dir '/tmp/vm_test_result/' or a RESULT_ROOT you specified.
EOF
exit 1
}
get_job_env()
{
[[ $1 ]] || return
[[ $2 ]] || return
job_script=$(realpath $1) env=$2 bash -c 'source $job_script && export_top_env > /dev/null 2>&1 && eval echo \$$env'
}
validate_options()
{
local job_script=$1
local need_module
need_module="$(get_job_env $job_script 'need_modules')" || return
[[ "$need_module" = "true" ]] && {
[[ ! $opt_modules ]] && echo "kernel module is required, please specify it with '-m'" && return 1
[[ ! -e $opt_modules ]] && echo "$opt_modules is not existed" && return 1
}
return 0
}
create_lkp_home()
{
[[ -e $HOME/.lkp ]] && return
cat <<-EOF
The approx. disk space requirements are
10M simple boot test in rootfs openwrt
50M simple boot test in rootfs debian
1G plan to run a number of different tests
100G or more IO tests
Please enter a dir with enough disk space, or simply press Enter to accept the default.
You may still symlink $HOME/.lkp to a more suitable place in future.
EOF
local dir
read -p "$HOME/.lkp => " dir
[[ $dir ]] && {
dir=$(realpath $dir)
mkdir -p $dir || exit
ln -sT $dir $HOME/.lkp || exit
}
mkdir -p $HOME/.lkp/cache
mkdir -p $HOME/.lkp/result
mkdir -p $HOME/.lkp/qemu-img
}
replace_script_partition_val()
{
local disk_names=(/dev/vd{a..z})
local job_script="$1"
local nr_hdd_vdisk="$(echo $hdd_partitions | wc -w)"
local nr_ssd_vdisk="$(echo $ssd_partitions | wc -w)"
local nr_swap_vdisk="$(echo $swap_partitions | wc -w)"
local nr_rootfs_vdisk="$(echo $rootfs_partition | wc -w)"
[[ $nr_hdd_partitions ]] || nr_hdd_partitions=$nr_hdd_vdisk
[[ $nr_ssd_partitions ]] || nr_ssd_partitions=$nr_ssd_vdisk
VDISK_NUM=$((nr_hdd_partitions+nr_ssd_partitions+nr_swap_vdisk+nr_rootfs_vdisk))
[[ "$hdd_partitions$ssd_partitions$swap_partitions$rootfs_partition" =~ '/dev/vda' ]] && return
if ((VDISK_NUM)); then
local index=0
local vdisk_hdd_val="${disk_names[@]:$index:$nr_hdd_partitions}"
index=$((index+nr_hdd_partitions))
local vdisk_ssd_val="${disk_names[@]:$index:$nr_ssd_partitions}"
index=$((index+nr_ssd_partitions))
local vdisk_rootfs_val="${disk_names[@]:$index:$nr_rootfs_vdisk}"
index=$((index+nr_rootfs_vdisk))
local vdisk_swap_val="${disk_names[@]:$index:$nr_swap_vdisk}"
sed -i -e "s%export hdd_partitions=.*%export hdd_partitions='${vdisk_hdd_val}'%" \
-e "s%export ssd_partitions=.*%export ssd_partitions='${vdisk_ssd_val}'%" \
-e "s%export swap_partitions=.*%export swap_partitions='${vdisk_swap_val}'%" \
-e "s%export rootfs_partition=.*%export rootfs_partition='${vdisk_rootfs_val}'%" \
$job_script
fi
}
create_job_initrd()
{
local job_sh=$CACHE_DIR/${job_file%.yaml}.sh
[[ -d $CACHE_DIR/$job_initrd_dir ]] && rm -rf "$CACHE_DIR/$job_initrd_dir"
mkdir -p $CACHE_DIR/$job_initrd_dir
cp $job_script $job_sh
chmod +x $job_sh
local archive=$CACHE_DIR/job
(
cd $CACHE_DIR || exit
{
local dir=
for d in $(echo $job_initrd_dir | tr '/' ' ')
do
dir="$dir""$d"/
echo $dir
done
find ${job_initrd_dir#/}/*
} | cpio -o -H newc -F $archive.cpio
gzip -n -9 $archive.cpio
mv -f $archive.cpio.gz $job_initrd
)
}
get_qemu_kernel_initrd()
{
local lkp_initrd
local job_initrd
local final_initrd=$CACHE_DIR/final_initrd
[[ $opt_kernel_image ]] || download_kernel
lkp_initrd='' job_initrd='' download_initrd
local user_lkp_initrd=$1
local user_job_initrd=$2
cat "$concatenate_initrd" "$user_lkp_initrd" "$user_job_initrd" > "$final_initrd"
initrd_option="-initrd $final_initrd"
}
# limit $1 to MemAvailable/2
max_sane_qemu_memory()
{
local mem_kb="$(to_kb $1)"
export_meminfo
[[ $MemAvailable ]] ||
(( MemAvailable = MemFree + (Active_file/2) + Inactive_file ))
(( mem_kb > MemAvailable / 2 )) && mem_kb=$((MemAvailable / 2))
echo $((mem_kb >> 10))M
}
setup_vdisk_root()
{
vm_name=$testbox
if [[ "$opt_vdiskpath" ]]; then
[[ -d "$opt_vdiskpath" ]] || {
echo "$opt_vdiskpath: no such directory"
exit 1
}
VDISK_ROOT="$opt_vdiskpath"
else
VDISK_ROOT=/tmp/vdisk-$USER
[[ -d $VDISK_ROOT ]] || mkdir -p $VDISK_ROOT
fi
}
while getopts "o:p:s:k:m:e" opt
do
case $opt in
o ) opt_result_root="$OPTARG" ;;
s ) opt_ssh="$OPTARG" ;;
p ) opt_vdiskpath="$OPTARG" ;;
k ) opt_kernel_image="$OPTARG" ;;
m ) opt_modules="$OPTARG" ;;
e ) HTTP_PREFIX=https://download.01.org/0day-ci/lkp-qemu ;;
? ) usage ;;
esac
done
shift $(($OPTIND-1))
unset DISPLAY
job_script=$1
[ -n "$job_script" ] || usage
sed -i 's/\r//' $job_script
sed -i 's/LKP_SERVER=.*$/LKP_LOCAL_RUN=1/g' $job_script
# lkp-src makepkg use current user name to generate path to save code
# switch to current user here if job_script specified user=lkp to fix lkp qemu running error:
# rc.local[297]: /etc/init.d/lkp-bootstrap: 75: /etc/init.d/lkp-bootstrap: /lkp/lkp/src/bin/lkp-setup-rootfs: not found
sed -i 's/user=lkp/user=$(whoami)/g' $job_script
sed -i 's/export user=['\'']lkp['\'']/user=$(whoami)/g' $job_script
validate_options $job_script || exit 1
create_lkp_user
create_lkp_home
export CACHE_DIR=$HOME/.lkp/cache
mkdir -p $CACHE_DIR
. $job_script export_top_env
replace_script_partition_val $job_script
[[ $job_file ]] || job_file=${job_script%.sh}.yaml
if [[ $opt_modules ]]; then
modules_initrd=$opt_modules
ln -sf "$(realpath $opt_modules)" $CACHE_DIR/$(basename $opt_modules)
else
unset modules_initrd # modules_initrd has existed in job.sh, need to flush it
fi
create_lkp_src_initrd()
{
if [[ "$kconfig" =~ ^(i386|x86_64)- ]]; then
local arch=${kconfig%%-*}
else
local arch=$(arch)
fi
if [ -d $LKP_SRC/.git ]; then
local head_commit=$(cd $LKP_SRC && git rev-list -n1 HEAD)
local diff_id=$(cd $LKP_SRC && git diff | git patch-id | cut -f1 -d' ')
local src_sig=${head_commit:0:12}_${diff_id:0:12}
else
local src_sig=$(ls -lR $LKP_SRC|md5sum|cut -c1-12)
fi
lkp_initrd=$CACHE_DIR/lkp-$arch-$src_sig.cgz
[[ -f $lkp_initrd ]] || {
LKP_USER="$user"
archive="${CACHE_DIR}"
pushd "$LKP_SRC/pkg/lkp-src"
PACMAN=true BUILDDIR=/tmp/$USER CARCH=$arch PKGEXT=.cgz CGZDEST="$CACHE_DIR/lkp-$arch.cgz" \
$LKP_SRC/sbin/makepkg --config $LKP_SRC/etc/makepkg.conf -e
[[ -f $CACHE_DIR/lkp-$arch.cgz ]] || {
echo "Failed to pack: $CACHE_DIR/lkp-$arch.cgz"
exit 1
}
mv $CACHE_DIR/lkp-$arch.cgz $lkp_initrd
popd
}
}
create_lkp_src_initrd
# create job_initrd.cgz
job_sig=$(md5sum $job_script | cut -c1-5)
job_initrd=$CACHE_DIR/${job_file%.yaml}-$job_sig.cgz
job_initrd_dir=${job_file%/*}
[[ -f $job_initrd ]] || create_job_initrd
# if job.sh not include bootloader_append entry, add default content
if [ -n "$bootloader_append" ]; then
bootloader_append=$(echo "$bootloader_append" | tr '\n' ' ' | sed -e 's/ttyS[1-9],/ttyS0,/g')
else
bootloader_append="root=/dev/ram0 job=$job_file user=$user ARCH=x86_64 kconfig=x86_64-rhel commit=051d101ddcd268a7429d6892c089c1c0858df20b branch=linux-devel/devel-hourly-2015033109 max_uptime=1247 RESULT_ROOT=$result_root earlyprintk=ttyS0,115200 rd.udev.log-priority=err systemd.log_target=journal systemd.log_level=warning debug apic=debug sysrq_always_enabled rcupdate.rcu_cpu_stall_timeout=100 panic=-1 softlockup_panic=1 nmi_watchdog=panic oops=panic load_ramdisk=2 prompt_ramdisk=0 console=ttyS0,115200 console=tty0 vga=normal rw"
fi
# create vm result path
if [ -z $opt_result_root ]; then
# create real result_root layout similar to the one in /result
_result_root=$HOME/.lkp/$(dirname $result_root)
for i in {0..1000}
do
vm_result_path=$_result_root/$i
[[ -d $vm_result_path ]] || break
done
if [ $i -eq 1000 ]; then
echo "!!!Exceed maximum result root number (1000), please delete some old results"
exit 1
fi
echo "result_root: $vm_result_path"
else
vm_result_path=$opt_result_root
fi
mkdir -p $vm_result_path
if [[ $HTTP_PREFIX ]]; then
: # use environment value
elif [[ $HOSTNAME = inn ]]; then
LKP_SERVER=inn
elif grep -q intel.com /etc/resolv.conf; then
LKP_SERVER=0day.sh.intel.com
else
LKP_SERVER=
HTTP_PREFIX=https://download.01.org/0day-ci/lkp-qemu
fi
LKP_USER="lkp"
: ${QEMU_MODEL:='qemu-system-x86_64'}
run_kvm()
{
trap - EXIT
local job_script=$1
local mem_mb="$(max_sane_qemu_memory $memory)"
local mount_tag=9p/virtfs_mount
local need_mem
need_mem="$(get_job_env $job_script 'need_memory')" || return
[[ "$need_mem" != "" ]] && {
local need_mem_mb="$(to_mb $need_mem)"
local testsuite
testsuite="$(get_job_env $job_script 'suite')" || return
[[ "$need_mem_mb" -gt "${mem_mb: : -1}" ]] && echo "Warning: test suite $testsuite needs memory: ${need_mem_mb}Mb, actual memory: ${mem_mb: : -1}Mb"
}
netdev_option="-device e1000,netdev=net0 "
netdev_option+="-netdev user,id=net0"
KVM_COMMAND=(
$QEMU_MODEL -enable-kvm
-fsdev local,id=test_dev,path=$vm_result_path,security_model=none -device virtio-9p-pci,fsdev=test_dev,mount_tag=$mount_tag
-kernel ${opt_kernel_image:-$kernel_file}
-append "$bootloader_append ip=dhcp result_service=$mount_tag"
$initrd_option
-smp $nr_cpu
-m $mem_mb
-no-reboot
-watchdog i6300esb
-rtc base=localtime
$qemu_netdev_option
$qemu_console_option
$QEMU_DRIVE_OPTION
)
echo "exec command: ${KVM_COMMAND[@]}"
"${KVM_COMMAND[@]}"
}
# lkp qemu alway log guest to stdout
setup_qemu_console()
{
qemu_console_option="-display none -monitor null -serial stdio"
}
get_qemu_kernel_initrd $lkp_initrd $job_initrd
setup_qemu_console
setup_qemu_netdev
setup_vdisk_root
setup_qemu_drives
run_kvm $job_script
cleanup_qemu_drives