#!/bin/bash
#
# flashcache	Init Script to manage cachedev loads
. /etc/tos/scripts/scripts

BACKEND_DISK=$2 #/dev/md0,/dev/vg0/lv0
Usage="Usage: $0 {start|stop|status|forcestop} {/dev/md0|/dev/vg0/lv0}\n"
if [ -z "$2" ]; then
    echo -e $Usage
    exit 1
fi

DMSETUP=$(which dmsetup)
RETVAL=0
CACHE_CONFIG="$TOS_FLASHCACHE/cache.conf"

load_drive() {
    #Load the module
    local has_mod="$(lsmod | grep flashcache)"
    if [ ! -z "${has_mod}" ]; then
        return
    fi
    insmod /lib/modules/$TOS_KERNEL/kernel/flashcache.ko
    RETVAL=$?
    if [ $RETVAL -ne 0 ]; then
        mount_device "$BACKEND_DISK"
        echo "Module Load Error: flashcache. Exited with status - $RETVAL"
        exit $RETVAL
    fi
}

is_lvm() {
    local fs=$(blkid -o value -s TYPE $blk)
    [ "$fs" = "LVM2_member" ] && return 1
    return 0
}

find_real_device() {
    local blk=$1
    echo "$blk" | egrep -q -E "^/dev/md[0-9]+" >/dev/null
    if [ $? -eq 0 ]; then
        is_lvm $blk
        if [ $? -eq 1 ]; then
            vgs=$(timeout 5 pvs -o vg_name $blk --noheadings 2>/dev/null | sed s/[[:space:]]//g)
            blk=$(timeout 5 vgs -o lv_path $vgs --noheadings 2>/dev/null | sed s/[[:space:]]//g)
        fi
    fi
    echo $blk
}

service_all_stop() {
    sync
    # disabled service
    ter_service all stop nginx >/dev/null 2>&1
}

service_all_start() {
    ter_service all start nginx >/dev/null 2>&1
}

mount_device() {
    local blk=$1
    local fs=$(blkid -o value -s TYPE $blk)
    if [ "$fs" = "LVM2_member" ]; then
        local vgs=$(timeout 5 pvs -o vg_name $blk --noheadings 2>/dev/null | sed s/[[:space:]]//g)
        blk=$(timeout 5 vgs -o lv_path $vgs --noheadings 2>/dev/null | sed s/[[:space:]]//g)
        echo -e "$blk" | while read line; do
            AutoMountDevice $line
        done
    else
        AutoMountDevice $blk
    fi
}

find_ssd_raid() {
    local raid=""
    local md_uuid=$1
    for blk in /dev/md*; do
        [ ! -b $blk ] && continue
        local uuid=$(mdadm -D $blk --export 2>/dev/null | awk -F= '/MD_UUID/ {print $2}')
        [ "$uuid" != "$md_uuid" ] && continue
        raid=$blk
        break
    done
    echo $raid
}

# `device` for cache target device
flashcacheRebuild() {
    local blk=$1
    local UUID=$(GetDeviceUUID "$blk")
    local SORT=$(GetVolumeSort $blk)
    if [ -z "$SORT" ]; then
        echo "Error: can't get sort from /etc/volume/volume.conf" >&2
        return 1
    fi
    local CACHENAME=fc${SORT}
    local SECTION=$(iniparse -c -f "$CACHE_CONFIG" -s $UUID)
    if [ ! -z "$SECTION" ]; then
        local CACHE_MODEL=$(iniparse -c -f "$CACHE_CONFIG" -s "${UUID}" -k cache_model)
        local CACHESIZE=$(iniparse -c -f "$CACHE_CONFIG" -s "${UUID}" -k cache_capacity)
        local MD_UUID=$(iniparse -c -f "$CACHE_CONFIG" -s "${UUID}" -k md_uuid)
        local CACHE_DEV=$(find_ssd_raid "$MD_UUID")
        if [ -b "$CACHE_DEV" ]; then
            echo "flashcache_create -p $CACHE_MODEL -b 4k -s $CACHESIZE $CACHENAME $CACHE_DEV $blk"
            echo "y" | flashcache_create -p $CACHE_MODEL -b 4k -s $CACHESIZE $CACHENAME $CACHE_DEV $blk
            sleep 1
            if [ -b /dev/mapper/$CACHENAME ]; then
                mount_device "/dev/mapper/$CACHENAME"
                return 0
            fi
            echo "Error: flashcache_create faild in flashcacheRebuild" >&2
        else
            echo "Error: can't find cache raid by $MD_UUID" >&2
        fi
    fi
    return 1
}

service_start() {
    #lvm reloading...
    vgscan
    #vgchange -ay >/dev/null 2>&1

    echo "Starting Flashcache..."
    load_drive
    #flashcache_load the cachedev for back mode
    flashcache_scan
    local devices=$(find_real_device $1)
    echo -e "$devices" | while read device; do
        local SORT=$(GetVolumeSort $device)
        if [ -z "$SORT" ]; then
            echo -e "blockdevice: $device\nError: can't get sort from /etc/volume/volume.conf" >&2
            return 1
        fi
        local CACHENAME=fc${SORT}
        if [ -b /dev/mapper/$CACHENAME ]; then
            ter_flashcache -blk $CACHENAME -fast >/dev/null
            mount_device "/dev/mapper/$CACHENAME"
            touch "/var/lock/subsys/$CACHENAME"
        elif [ -e "$CACHE_CONFIG" ]; then
            flashcacheRebuild "$device"
            if [ $? -ne 0 ]; then #ssd缓存挂载失败，执行挂载卷
                mount_device "$device"
            fi
        else
            mount_device "$device"
        fi
    done
    service_all_start
}

service_stop() {
    local devices=$(find_real_device $1)
    [ -z "$devices" ] && return 1
    service_all_stop

    echo -e "$devices" | while read device; do
        local UUID=$(GetDeviceUUID $device)
        local SORT=$(GetVolumeSort $device)
        if [ -z "$SORT" ]; then
            echo -e "blockdevice: $device\nError: can't get sort from /etc/volume/volume.conf" >&2
            return 1
        fi
        local MNTPATH="/Volume${SORT}"
        local CACHENAME=fc${SORT}
        if [ ! -b /dev/mapper/$CACHENAME ]; then
            continue
        fi
        umountAll $MNTPATH
        # enable fast_remove, please add -fast for ter_flashcache
        local CACHEBLK=$(ter_flashcache -blk $CACHENAME -opt cache_dev)
        if [ $? -eq 0 ]; then
            echo "Flushing flashcache: Flushes to $BACKEND_DISK"
            $DMSETUP remove $CACHENAME
            #先要获取超级块，然后删除阵列，在删除超级快
            if [ -b "$CACHEBLK" ]; then
                local raidname=$(basename $CACHEBLK)
                local slaves=$(ls /sys/block/$raidname/slaves/ 2>/dev/null)
                mdadm -S $CACHEBLK >/dev/null 2>&1
                for blkname in $slaves; do
                    local partblk=/dev/$blkname
                    [ ! -b $partblk ] && continue
                    mdadm --zero-superblock $partblk >/dev/null
                done
            fi
            iniparse -d -f "$CACHE_CONFIG" -s "$UUID"
            mdadm -Ds >/etc/mdadm.conf
        fi
        #mounting ...
        mount_device "$device"
        #unlock subsys
        local SUBSYS_LOCK=/var/lock/subsys/$CACHENAME
        [ -e $SUBSYS_LOCK ] && rm -f $SUBSYS_LOCK
    done

    service_all_start
}

service_remove() {
    local devices=$(find_real_device $1)
    [ -z "$devices" ] && return 1
    service_all_stop

    echo -e "$devices" | while read device; do
        local UUID=$(GetDeviceUUID $device)
        local SORT=$(GetVolumeSort $device)
        if [ -z "$SORT" ]; then
            echo -e "blockdevice: $device\nError: can't get sort from /etc/volume/volume.conf" >&2
            return 1
        fi
        local MNTPATH="/Volume${SORT}"
        local CACHENAME=fc${SORT}
        if [ -b /dev/mapper/$CACHENAME ]; then
            umountAll $MNTPATH
            local CACHE_DEV=$(ter_flashcache -blk $CACHENAME -opt cache_dev -fast)
            if [ $? -eq 0 ]; then
                echo "$DMSETUP remove $CACHENAME"
                $DMSETUP remove $CACHENAME
                [ -b "$CACHE_DEV" ] && flashcache_destroy -f $CACHE_DEV
            fi
            if [ ! -b /dev/mapper/$CACHENAME ]; then
                iniparse -d -f $CACHE_CONFIG -s $UUID
            fi
            #unlock subsys
            local SUBSYS_LOCK=/var/lock/subsys/$CACHENAME
            [ -e $SUBSYS_LOCK ] && rm -f $SUBSYS_LOCK
        fi
    done
    service_all_start
}

service_status() {
    local devices=$(find_real_device $1)
    echo -e "$devices" | while read device; do
        local SORT=$(GetVolumeSort $device)
        if [ -z "$SORT" ]; then
            echo -e "blockdevice: $device\nError: can't get sort from /etc/volume/volume.conf" >&2
            return 1
        fi
        local CACHENAME=fc${SORT}
        local SUBSYS_LOCK=/var/lock/subsys/$CACHENAME
        [ -f $SUBSYS_LOCK ] && echo "Flashcache status: loaded" || echo "Flashcache status: NOT loaded"
        if [ -b /dev/mapper/$CACHENAME ]; then
            $DMSETUP status $CACHENAME
        fi
    done
}

case $1 in
start)
    service_start $2
    ;;
stop)
    service_stop $2
    ;;
remove)
    service_remove $2
    ;;
status)
    service_status $2
    ;;
forcestop)
    service_stop $2 --force
    ;;
*)
    echo -e $Usage
    exit 1
    ;;
esac
exit 0
