#!/bin/bash # Copyright (c) 2016 Red Hat, Inc. All rights reserved. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Author: guazhang source tc.sh || exit 1 rpm -q mdadm || yum install -y mdadm JOURNAL_SUPPORT=0 info=`mdadm --create --help | grep -o "write-journal"` if [ "$info" = "write-journal" ]; then JOURNAL_SUPPORT=1 fi #Install fio from upstream function install_fio() { git_url=git://git.kernel.org/pub/scm/linux/kernel/git/axboe/fio.git tok yum install libaio-devel zlib-devel -y tok git clone $git_url tlog "INFO: Installing Fio" tok "cd fio &&./configure && make && make install" tok which fio if [ $? -ne 0 ]; then tlog "FAIL: Fio not succesffully installed" exit 1 fi tlog "INFO: Fio succesfully installed" } #Install dt function install_dt () { wget http://www.scsifaq.org/RMiller_Tools/ftp/dt/dt-source.tar.gz tar xvf dt-source.tar.gz cd dt.d-WIP/ cp -p Makefile.linux Makefile make cp dt /usr/bin } #----------------------------------------------------------------------------# # MD_Create_RAID () # Usage: # Create md raid. # Parameter: # $level # like 0, 1, 3, 5, 10, 50 # $dev_list # like 'sda sdb sdc sdd' # $raid_dev_num # like 3 # $spar_dev_num # like 2 # $chunk # like 64 # Returns: # Return code: # 0 on success # 1 if something went wrong. # Return string: # RETURN_STR # $md_raid like '/dev/md0' # MD_DEVS # $raid_dev_list like '/dev/sda /dev/sdb' #----------------------------------------------------------------------------# function MD_Create_RAID (){ EX_USAGE=64 # Bad arg format if [ $# -lt 3 ]; then echo 'Usage: MD_Create_RAID $level $dev_list $raid_dev_num \ [$spar_dev_num] [$chunk]' exit "${EX_USAGE}" fi # variable definitions RETURN_STR='' MD_DEVS='' local level=$1 local dev_list=$2 local raid_dev_num=$3 local bitmap=$4 local spar_dev_num=${5:-0} local chunk=${6:-512} local bitmap_chunksize=${7:-64M} local dev_num=0 local raid_dev='' local spar_dev='' local md_raid="" local mtdata=${8:-1.2} local ret=0 # start to create echo "INFO: Executing MD_Create_RAID() to create raid $level" # check if the given disks are more the needed for i in $dev_list; do dev_num=$((dev_num+1)) done if [ $dev_num -lt $(($raid_dev_num+$spar_dev_num)) ]; then echo "FAIL: Required devices are more than given." exit 1 fi # get free md device name, only scan /dev/md[0-15]. for i in `seq 1 30`; do ls -l /dev/md$i > /dev/null 2>&1 if [ $? -ne 0 ]; then md_raid=/dev/md$i break fi done # get raid disk list. for i in `seq 1 $raid_dev_num`; do tmp_dev=`echo $dev_list | cut -d " " -f $i` raid_dev="$raid_dev /dev/$tmp_dev" done echo "INFO: Created md raid with these raid devices \"$raid_dev\"." # get spare disk list. if [ $spar_dev_num -ne 0 ]; then for i in `seq $((raid_dev_num+1)) $((raid_dev_num+spar_dev_num))`; do tmp_dev=`echo $dev_list | cut -d " " -f $i` spar_dev="$spar_dev /dev/$tmp_dev" done echo "INFO: Created md raid with these spare disks \"$spar_dev\"." fi sleep 5 # create md raid if [ $bitmap -eq 1 ]; then if [ $spar_dev_num -ne 0 ]; then mdadm --create --run $md_raid --level $level --metadata $mtdata \ --raid-devices $raid_dev_num $raid_dev \ --spare-devices $spar_dev_num $spar_dev --chunk $chunk --bitmap=internal --bitmap-chunk=$bitmap_chunksize else mdadm --create --run $md_raid --level $level --metadata $mtdata \ --raid-devices $raid_dev_num $raid_dev --chunk $chunk --bitmap=internal --bitmap-chunk=$bitmap_chunksize fi elif [ $bitmap -eq 2 ];then touch /home/bitmap_md_$level echo "INFO:bitmap backup in /home/bitmap_md_$level" bitmap_dir="/home/bitmap_md_$level" if [ $spar_dev_num -ne 0 ]; then mdadm --create --run $md_raid --level $level --metadata $mtdata \ --raid-devices $raid_dev_num $raid_dev \ --spare-devices $spar_dev_num $spar_dev --chunk $chunk --bitmap=$bitmap_dir --force --bitmap-chunk=$bitmap_chunksize else mdadm --create --run $md_raid --level $level --metadata $mtdata \ --raid-devices $raid_dev_num $raid_dev --chunk $chunk --bitmap=$bitmap_dir --force --bitmap-chunk=$bitmap_chunksize fi else if [ $spar_dev_num -ne 0 ]; then mdadm --create --run $md_raid --level $level --metadata $mtdata \ --raid-devices $raid_dev_num $raid_dev \ --spare-devices $spar_dev_num $spar_dev --chunk $chunk else mdadm --create --run $md_raid --level $level --metadata $mtdata \ --raid-devices $raid_dev_num $raid_dev --chunk $chunk fi fi if [ $? -ne 0 ]; then ret=$? echo "INFO:create $md_raid failed.will remove all raid disk " exit 1 fi echo "create `date +%s` mdadm -CR $md_raid -l $level -e $mtdata -n $raid_dev_num \"$raid_dev\" -x=$spar_dev_num $spar_dev bitmap=$bitmap --chunk $chunk --bitmap-chunk=$bitmap_chunksize" echo "INFO:cat /proc/mdstat######################" cat /proc/mdstat lsblk trun "ls /dev/md* |egrep md[0-9]+" echo "INFO:mdadm -D $md_raid #########################" mdadm --detail $md_raid # define global variables MD_DEVS="$raid_dev $spar_dev" RETURN_STR="$md_raid" return $ret } ####################### End of functoin MD_Create_RAID #----------------------------------------------------------------------------# # MD_Create_RAID_Journal () # Usage: # Create md raid with journal. # Parameter: # $level # like 4, 5, 6 # $dev_list # like 'sda sdb sdc sdd' # $raid_dev_num # like 3 # $spar_dev_num # like 2 # $chunk # like 64 # Returns: # Return code: # 0 on success # 1 if something went wrong. # Return string: # RETURN_STR # $md_raid like '/dev/md0' # MD_DEVS # $raid_dev_list like '/dev/sda /dev/sdb' #----------------------------------------------------------------------------# function MD_Create_RAID_Journal (){ EX_USAGE=64 # Bad arg format if [ $# -lt 3 ]; then echo 'Usage: MD_Create_RAID_Journal $level $dev_list $raid_dev_num \ [$spar_dev_num] [$chunk]' exit "${EX_USAGE}" fi # variable definitions RETURN_STR='' MD_DEVS='' local level=$1 local dev_list=$2 local raid_dev_num=$3 local bitmap=$4 local spar_dev_num=${5:-0} local chunk=${6:-512} local bitmap_chunksize=${7:-64M} local mtdata=${8:-1.2} local dev_num=0 local raid_dev='' local spar_dev='' local md_raid="" local ret=0 # start to create echo "INFO: Executing MD_Create_RAID_Journal() to create raid $level" # check if the given disks are more the needed for i in $dev_list; do dev_num=$((dev_num+1)) done if [ $dev_num -lt $(($raid_dev_num+$spar_dev_num)) ]; then echo "FAIL: Required devices are more than given." exit 1 fi # get free md device name, only scan /dev/md[0-15]. for i in `seq 0 15`; do ls -l /dev/md$i > /dev/null 2>&1 if [ $? -ne 0 ]; then md_raid=/dev/md$i break fi done # take the first disk as journal disk tmp_dev=`echo $dev_list | cut -d " " -f 1` journal_dev="/dev/$tmp_dev" echo "INFO: Created md raid with write journal disk \"$journal_dev\"." # get raid disk list. for i in `seq 2 $raid_dev_num`; do tmp_dev=`echo $dev_list | cut -d " " -f $i` raid_dev="$raid_dev /dev/$tmp_dev" done echo "INFO: Created md raid with these raid devices \"$raid_dev\"." # get spare disk list. if [ $spar_dev_num -ne 0 ]; then for i in `seq $((raid_dev_num+1)) $((raid_dev_num+spar_dev_num))`; do tmp_dev=`echo $dev_list | cut -d " " -f $i` spar_dev="$spar_dev /dev/$tmp_dev" done echo "INFO: Created md raid with these spare disks \"$spar_dev\"." fi #There is one write journal disk, so change the raid_dev_num-- ((raid_dev_num--)) # create md raid # prepare the parameter BITMAP="" SPAR_DEV="" if [ $bitmap -eq 1 ]; then BITMAP="--bitmap=internal --bitmap-chunk=$bitmap_chunksize" fi if [ $spar_dev_num -ne 0 ]; then SPAR_DEV="--spare-devices $spar_dev_num $spar_dev" fi if [ -n "$journal_dev" ]; then WRITE_JOURNAL="--write-journal $journal_dev" fi tok "mdadm --create --run $md_raid --level $level --metadata $mtdata --raid-devices $raid_dev_num $raid_dev $WRITE_JOURNAL $SPAR_DEV $BITMAP --chunk $chunk" ret=$? echo "create raid time `date +%s` mdadm -CR $md_raid --level $level --metadata $mtdata --raid-devices $raid_dev_num $raid_dev $WRITE_JOURNAL $SPAR_DEV $BITMAP --chunk $chunk " cat /proc/mdstat mdadm --detail $md_raid # define global variables MD_DEVS="$journal_dev $raid_dev $spar_dev" RETURN_STR="$md_raid" return $ret } ####################### End of functoin MD_Create_RAID_Journal #----------------------------------------------------------------------------# # MD_Save_RAID () # Usage: # Save md raid configuration. # Parameter: # NULL # Returns: # Return code: # 0 on success # 1 if something went wrong. # Return string: # NULL #----------------------------------------------------------------------------# function MD_Save_RAID (){ echo "INFO: Executing MD_Save_RAID()" echo "DEVICE $MD_DEVS" > /etc/mdadm.conf if [ $? -ne 0 ]; then echo "FAIL: Failed to save md device info to /etc/mdadm.conf" fi mdadm --detail --scan >> /etc/mdadm.conf if [ $? -ne 0 ]; then echo "FAIL: Failed to save md state info to /etc/mdadm.conf" fi return 0 } ####################### End of functoin MD_Save_RAID #----------------------------------------------------------------------------# # MD_Clean_RAID () # Usage: # Clean md raid. # Parameter: # $md_name # like '/dev/md0' # Returns: # Return code: # 0 on success # 1 if something went wrong. # Return string: # NULL #----------------------------------------------------------------------------# function MD_Clean_RAID (){ EX_USAGE=64 # Bad arg format if [ $# -ne 1 ]; then echo 'Usage: MD_Clean_RAID $md_name' exit "${EX_USAGE}" fi echo "INFO: Executing MD_Clean_RAID() against this md device: $md_name" local md_name=$1 echo "mdadm --stop $md_name" mdadm --stop $md_name st=$? while [ $st -ne 0 ]; do echo "INFO:mdadm stop failed" sleep 10 rm -rf /etc/mdadm.conf for i in $(cat /proc/mdstat |grep "inactive" |awk '{print $1}') ;do mdadm --stop "/dev/$i" done mdadm --stop $md_name st=$? done sleep 10 echo "clean devs : $MD_DEVS" for dev in $MD_DEVS; do echo "mdadm --zero-superblock $dev" `mdadm --zero-superblock $dev` done #`mdadm --zero-superblock "$MD_DEVS"` echo "ret is $?" rm -rf /etc/mdadm.conf sleep 10 echo "ls $md_name" tnot "ls $md_name" if [ $? = 1 ];then tlog "mdadm --stop command can't delete md node name $md_name in /dev node" trun "ls /dev/md*" trun "cat /proc/mdstat" else tlog "mdadm --stop can delete md node name $md_name in /dev" # rm -rf $md_name fi return 0 } ####################### End of functoin MD_Clean_RAID #----------------------------------------------------------------------------# # MD_Get_State_RAID () # Usage: # get md raid status # Parameter: # $md_name # like "/dev/md0" # Returns: # Return code: # 0 on success # 1 if something went wrong. # Return string: # RETURN_STR # $state, like 'clean, resyncing' #----------------------------------------------------------------------------# function MD_Get_State_RAID (){ EX_USAGE=64 # Bad arg format if [ $# -lt 1 ]; then echo 'Usage: MD_Get_State_RAID $md_name' exit "${EX_USAGE}" fi RETURN_STR='' local md_name=$1 local state='' local start_times=0 local end_times=0 local spend_times=0 # echo "INFO: Executing MD_Get_State_RAID() against this md array: $md_name" start_times=$(date +%s) echo " $start_times start_time against this md array: $md_name " # echo "mdadm --detail $md_name | grep "State :" | cut -d ":" -f 2 | cut -d " " -f 2" state=`mdadm --detail $md_name | grep "State :" | cut -d ":" -f 2 | cut -d " " -f 2` sta=$? if [ -z "$state" ]; then echo "`date +%s` first_time_failed get raid statu #############################+++++++++++++++++++++++++" while [ $sta ];do state=`mdadm --detail $md_name | grep "State :" | cut -d ":" -f 2 | cut -d " " -f 2` sta=$? end_times=$(date +%s) spend_times=$((end_times - start_times)) if [[ $spend_times -gt 10 ]];then echo "get raid status spend $spend_times and exit " ls /dev/md* |egrep md[0-9]+ cat /proc/mdstat exit 1 fi done echo "$spend_times spend raid statu_time #############################" fi echo "state is $state" RETURN_STR="$state" return 0 } ####################### End of functoin MD_Get_State_RAID #----------------------------------------------------------------------------# # MD_IO_Test () # Usage: # IO test using dt against block level # Parameter: # $dt_target # like "/dev/md0" # Returns: # Return code: # 0 on success # 1 if something went wrong. # Return string: # NULL #----------------------------------------------------------------------------# function MD_IO_Test (){ EX_USAGE=64 # Bad arg format if [ $# -lt 1 ]; then echo 'Usage: MD_IO_Test $dt_target' exit "${EX_USAGE}" fi # this parameter should be change to 7200 during a real testing cycle local dt_runtime=72 local dt_logfile="" test -f /tmp/dt_XXXXXXXX.log || `mktemp /tmp/dt_XXXXXXXX.log` dt_logfile="/tmp/dt_XXXXXXXX.log" local dt_target=$1 echo -n "INFO: dt against ${dt_target} is running with " echo "runtime: ${dt_runtime}s, log file is: ${dt_logfile}" echo "dt slices=16 disable=eof,pstats flags=direct \ oncerr=abort min=b max=256k \ pattern=iot iodir=reverse prefix='%d@%h (pid %p)' \ of=${dt_target} log=${dt_logfile} \ runtime=${dt_runtime}" `dt slices=16 disable=eof,pstats flags=direct \ oncerr=abort min=b max=256k \ pattern=iot iodir=reverse prefix='%d@%h (pid %p)' \ of=${dt_target} log=${dt_logfile} \ runtime=${dt_runtime}` if [ $? -ne 0 ]; then echo "FAIL: Failed to run dt testing against $dt_target" exit 1 fi return 0 } ####################### End of functoin MD_IO_Test function create_loop_devices (){ Create_Loop_Devices $@ } # ---------------------------------------------------------# # Create_Loop_Devices () # Usage: # Create loop devices. We will find out the free number # of loop to bind on tmp file. # Parameter: # $count #like "12" # $size_mib #like "1024" # Returns: # Return code: # 0 on success # 1 if something went wrong. # Return string: # RETURN_STR like 'loop9 loop10' # ---------------------------------------------------------# function Create_Loop_Devices (){ EX_USAGE=64 # Bad arg format if [ $# -ne 2 ]; then echo 'Usage: Create_Loop_Devices $count $size_mib' exit "${EX_USAGE}" fi RETURN_STR='' local count="$1" local size_mib="$2" local loop_dev_list='' for X in `seq 1 ${count}`;do local loop_file_name=$(mktemp /tmp/loop.XXXXXX) dd if=/dev/zero of=${loop_file_name} count=$size_mib bs=1M 1>/dev/null 2>&1 local loop_dev_name=$(losetup -f) #BUG: RHEL5 only support 8 loop device and we need to check whether we are run out of it local command="losetup ${loop_dev_name} ${loop_file_name} 1>/dev/null 2>&1" eval "${command}" if [ $? -eq 0 ];then loop_dev_list="${loop_dev_list}${loop_dev_name} " else echo "FAIL: Failed to create loop devices with command: ${command}" return 1 fi done loop_dev_list=$(echo "${loop_dev_list}" | sed -e 's/ $//') echo "${loop_dev_list}" #Back capability loop_dev_list=$(echo "${loop_dev_list}" | sed -e 's/\/dev\///g') RETURN_STR="${loop_dev_list}" return 0 } function get_disks() { disk_num=$1 disk_size=$2 LOOP_DEVICE_LIST=$(create_loop_devices $disk_num $disk_size) for i in $(seq 1 $disk_num); do disk_temp=$(echo $LOOP_DEVICE_LIST | cut -d " " -f $i) disk_temp=$(echo $disk_temp | cut -d "/" -f 3) devlist="$devlist $disk_temp" done RETURN_STR="$devlist" } function remove_disks() { disks=$1 for disk in $disks; do try_num=1 disk="/dev/"$disk echo "losetup -d $disk" losetup -d $disk state=$? while [ $state -ne 0 ]; do if [ $try_num -eq 4 ]; then echo "FAIL: After tried 3 times losetup -d $disk" return 1 fi sleep 1 losetup -d $disk state=$? ((try_num++)) done done rm -rf /tmp/loop.* } local_clean(){ local md_name="" (mdadm -E /dev/sd[b-i]1 |grep "raid") || (cat /proc/mdstat |grep "inactive") || (ls /dev/md* |egrep md[0-9]+) if [ $? = 0 ];then echo "have some md don't clean" ls /dev/md* |egrep md[0-9]+ for md_name in "$(ls /dev/md* |egrep md[0-9]+)" ;do trun "mdadm --stop $md_name" sleep 5 tlog "$md_name have stop" done rm -rf /etc/mdadm.conf trun "mdadm -Ss";sleep 5 trun "mdadm --zero-superblock /dev/sd[b-i]1" trun "mdadm --zero-superblock /dev/sd[b-i]" trun "cat /proc/mdstat" lsblk fi echo "INFO:need to remove partition first" for i in b c d e f g h i ;do mdadm --zero-superblock "/dev/sd$i" sleep 1 gdisk /dev/sd$i &> /dev/null <