DM-MPIO Notes

DM-MPIO MultiPath on RHEL 5.2 IBM x3755 with EMC Clariion Notes - Boot from SAN

Setting Up DM-Multipath for RHEL5  - see Multipath on Ubuntu for notes on our wonderful experience with Ubuntu and multipath :)

 

For a fresh RHEL5.2 install start the installation with the kernel command line "linux mpath"
after first reboot you will need to boot into linux rescue mode from the install disk again because install does not properly create the grub-install
 
Then:
    ln -s /dev/sda /dev/root  (where /dev/sda is the boot volume)
    mount --bind /dev  /mnt/sysimage/dev
    chroot /mnt/sysimage
    mount /dev/sda1  /boot
    grub-install /dev/sda
 
Grub should now be properly setup and you should be able to reboot into your new OS and continue with the mpath configuration

 

 

Use the following procedures to set up DM-Multipath for active/active

 

    # cp /usr/share/doc/device-mapper-multipath-<version>/multipath.conf.annotated /etc/multipath.conf

 

Alternatively,

    # cp /usr/share/doc/device-mapper-multipath-<version>/multipath.conf.defaults /etc/multipath.conf

 

Determine local disk id for blacklist
    # multipath -v3 
Search for your local disk UID entry.  For example, /dev/sda  UID=.......
Replace the blacklist entry below with the UID in your configuration

 

Edit the /etc/multipath.conf file by uncommenting the necesarry sections/lines of the file.

Working Example for Clariion from an IBM x3755 with Qlogic 24xx hba after fresh install with RHEL 5.2 using "linux mpath" install option:

 

defaults {

       udev_dir        /dev
       polling_interval 10
       default_selector        "round-robin 0"
       no_path_retry    queue
       default_path_grouping_policy    multibus
       default_getuid_callout  "/sbin/scsi_id -g -u -s /block/%n"
       default_prio_callout    "/bin/true"
       default_features        "0"
       rr_min_io              100
       user_friendly_names    yes
       failback                immediate
}

 

blacklist {
   wwid SIBM_Serve_RAID5i_45D1B811
   }

devices {

        device {
               vendor                  "DGC"
               product                 "*"
                path_grouping_policy    group_by_priority
                getuid_callout          "/sbin/scsi_id -g -u -s /block/%n"
                path_checker            emc_clariion
                path_selector           "round-robin 0"
                features                "1 queue_if_no_path"
                no_path_retry           "300"
                hardware_handler        "1 emc"
                prio_callout            "/sbin/mpath_prio_emc /dev/%n"
        }
 }

multipaths {

     multipath {
       wwid     3600601606de0220046fe38b57324de11
       alias    rootvg
     }
}

Run the following commands:

# multipath -F
# multipath -v3

 

The default settings for DM-Multipath are compiled in to the system and do not need to be

explicitly set in the /etc/multipath.conf file.
The default value of path_grouping_policy is set to multibus, so in this example you do not
need to change the default value.
Save the configuration file and exit the editor.

 

  
You will see multipathed devices (/dev/mapper/mpath*) as installation devices.
 
Now edit /etc/lvm/lvm.conf and add a filter:
filter = [ "a/sda/", "a/mapper/", "r/.*/" ]
 
Edit /etc/fstab so that your boot lun does not get fsck:
change the line that mounts /boot to look similar to this
    /dev/mapper/mpath0p1    /boot                   ext3    noauto        0 0
 
  
Edit /etc/rc.sysinit and add the following immediately after 
    if strstr "$cmdline" noreadonlyroot ; then
            READONLY=no
    fi
 
    echo "TIME TO PUT SOME MPATH LINKING CRAP HERE!"
    ORIGINAL_IFS=$IFS
    IFS=`echo -en '\n\b'`
    MPATH_LABELS=`for d in /dev/mapper/* ; do echo -n "$d " ; e2label $d 2>&1 ; done | grep mapper | grep -v Bad`
    mkdir /dev/mpath_links 2>/dev/null
    rm -f /dev/mpath_links/*
    for mpath in $MPATH_LABELS; do
        mpath_device=`echo $mpath | awk '{print $1}'`
        mpath_label=`echo $mpath | awk '{print $2}'`
        mpath_link="/dev/mpath_links/$mpath_label"
        echo "Linking $mpath_device -> $mpath_link"
        ln -s $mpath_device $mpath_link
    done
    IFS=$ORIGINAL_IFS
    echo "DONE WITH CUSTOM MPATH LINKING"

 

Use tune2fs -L <label> to give your disks appropriate labels:
For example,
   tune2fs -L u01 /dev/mapper/mpath2p1
    tune2fs -L u02 /dev/mapper/mpath3p1
 
Edit /etc/fstab to use the mpath_links directory for mounting devices properly (where u01 and u02 match the labels you just created above):
For example,
    /dev/mpath_links/u01    /u01                    ext3    defaults        0 0
     /dev/mpath_links/u02    /u02                    ext3    defaults        0 0
 
Reboot.
 
 
 
 
For existing RHEL5.2 server: before setting up DM-Multipath on your system, ensure that your system has been updated and
includes the device-mapper-multipath package.

 

# rpm -qa |grep device-mapper

     device-mapper-event-1.02.28-2.el5
     device-mapper-multipath-0.4.7-23.el5
     device-mapper-1.02.28-2.el5
     device-mapper-1.02.28-2.el5
 
Execute the following commands:
 # modprobe dm-multipath 
 # modprobe dm-round-robin
 # service multipathd start

 # chkconfig --add multipathd

 # chkconfig multipathd on
 
Adding a multipathed LVM device
Remember to use the /dev/mapper device names for creating lvm volumes and in /etc/fstab:
 
# kpartx -a /dev/mapper/mpath2  
# pvcreate /dev/mapper/mpath2
# vgcreate datavg /dev/mapper/mpath2
# lvcreate -L 900M -n datalv datavg
# mke2fs -j /dev/datavg/datalv
# ls /dev/mapper/
Now there is a datavg-datalv to mount in /dev/mapper 
/dev/VolGroup00/LogVol00 /                       ext3    defaults        1 1
/dev/mapper/datavg-datalv      /data            ext3    defaults        1 1
LABEL=/boot             /boot                   ext3    defaults        1 2

  

Adding an alias 

# scsi_id -p 0x83 -g -s /block/sdb

3600601606de0220046fe38b57324de11

Then I simply add a section to my multipath.conf file that looks like the following:

multipaths {

        multipath {
                wwid                    3600601606de0220046fe38b57324de11
                alias                   rootvg
        }
}

So now, instead of /dev/mapper/3600601606de0220046fe38b57324de11 my dm-multipath device will be called /dev/mapper/rootvg and thus my volumes

will be changed as follows:

   /dev/mapper/rootvg-datalv  --  /data
 
 
 when I do a multipath -ll  I only see the multipath devices that I added and not the /dev/VolGroup00.... that were created at install time.  This appears to be ok because testing cable pulls, kernel upgrades, and reboots all work consistently and repeatedly.
 

 More to come as I do more testing

 
 

4.3. Moving root/swap from single path device to multipath device for Boot From SAN

 

  1. Before you start with this procedure, make sure
  2. a) your /etc/multipath.conf works properly in your current setup.
    • - appropriate blacklist (make sure your root is not blacklisted)
    • - special config stanzas for your storage
    • - etc.,
  • b) your root device is referred by LABEL rather than the scsi name in both /etc/fstab and in your boot loader configuration file.  i.e. root=LABEL=/ in grub.conf
  •     and that your LABEL is created using the /dev/mapper device!!!!  DON'T use /dev/sd... when creating labels!!!
  • c) alternatively just point to the /dev/mapper entries in fstab instead of using labels

Edit lvm.conf, add preferred devices stanza and change filter to reject SAN related /dev/sd* devices.  If these are not explicitly ignored, the mkinitrd script has an internal state inconsistency and won't look for a multipath config at all.

Before creating the initrd make sure that vgscan can see your boot lun (example: filter = [ "a/then after mkinitrd is created it is safe to fix with a filter such as the one below...

For example,  filter = [ "a/sda/", "a/mapper/", "a/mpath/", "r/.*/"  ]

Edit /sbin/mkinitrd

Add the lines from the wiki post found below:

# - look for "use_multipath=0" and change it to "use_multipath=1"
# - look for the line with "echo Creating multipath devices"
# - add the following line immediately below the above line (before the for loop)

    * emit "/bin/multipath -v 0 $wwid"

# use the wwid that was saved in step (1) Add a line for every disk/wwid noted down in step (2)

 

THEN - there is a bug in mkinitrd that this will be exposed in RHEL5.2  2.6.18-92.el5, add the following line immediately before line 368:

[ ! -d 'slaves' ] && break or diff the file below against your own mkinitrd to see the changes...

 

Delete this file: /etc/blkid/blkid.tab

Make the initrd, the hardware handler for the clariion is used by multipath, BUT mkinitrd skips it (this is what I found out with high speed footage). 

 

Explicitly include the dm_emc module in the mkinitrd command:

mkinitrd -f --with=dm_emc --rootdev /dev/mapper/sanvg-rootlv /boot/initrd-$(uname -r).mpath.img $(uname -r)

---

You can verify your mkinitrd file by copying to /tmp/initfiles or somewhere with a .gz extension and gzip -d the file

Then cpio -i < initrd-$(uname -r).mpath.img.gz

 

grep filter etc/lvm/lvm.conf and verify your updated filter exists

cat multipath.conf and verify it is the same as your updated file

ls lib and verify that dm-multipath.ko dm-emc.ko exist

ls bin and verify that  kpartx mpath_prio_emc multipath and  lvm exist

cat init and verify that /bin/multipath -v 0 36006016017811900cc8...... line is before the mkrootdev -t ext3 -o defaults,ro /dev/mapper/... line

      and that the lvm vgchange -ay --ignorelockingfailure entry includes your boot lun i.e. sanvg in our case.

 

After all this the details of the boot multipath device will NOT be hidden under the abstracted /dev/root.  It will be seen and can be managed as any other multipath or lvm device:

 

 

From http://sources.redhat.com/lvm2/wiki/MultipathUsageGuide

 

Procedure above (Red Hat) gives details on how to use linux mpath to install on a multipathed storage device. What if you have already installed Red Hat on a SCSI disk (instead of a dm device) that has multiple paths.

 

This section gives details on how to move your root and sdev/sd?? to /dev/mappper/mpath??

 

This procedure is tested on RHEL 5.1. If you are trying on a different wap from /release of RHEL, your mileage may vary.

 
  1. Before you start with this procedure, make sure
    • a) your /etc/multipath.conf works properly in your current setup.
      • - appropriate blacklist (make sure your root is not blacklisted)
      • - special config stanzas for your storage
      • - etc.,
    • b) your root device is referred by LABEL rather than the scsi name in both /etc/fstab and in your boot loader configuration file.  i.e. root=LABEL=/ in grub.conf
  2. run "/sbin/scsi_id -g -u -s /block/$your_disk_name", and save the wwid
    • repeat this step for all disks that are multipathed and used in /etc/fstab (/, /home, /boot, swap etc.,).
  3. save /sbin/mkinitrd, we will be making some changes to this file.
    • cp /sbin/mkinitrd /sbin/mkinitrd.save
  4. edit /sbin/mkinitrd:
    • - look for "use_multipath=0" and change it to "use_multipath=1"
    • - look for the line with "echo Creating multipath devices"
    • - add the following line immediately below the above line (before the for loop)
      • emit "/bin/multipath -v 0 $wwid"
    • use the wwid that was saved in step (1) Add a line for every disk/wwid noted down in step (2)
  5. Run mkinitrd to generate a new initrd image
    • - mkinitrd /boot/initrd-mpath-$(uname -r) $(uname -r)
  6. Change the boot loader configuration file:
    • - In your boot loader config file (yaboot.conf or grub.conf or lilo.conf), add a new stanza with the new initrd image and the original kernel.
      • i.e copy the original stanza as is and modify only the initrd line to be initrd-mpath-$(uname -r) (of course with uname -r expanded)
    • - add an option "fastboot" to the kernel command line. It can be added to the "append" string in the stanza.
  7. Reboot.
  8. Run mkinitrd with rootdev to generate a new initrd image
    • - mkinitrd -f --rootdev LABEL=$ROOTLABEL /boot/initrd-mpath-$(uname -r) $(uname -r)
      • Note: -f is to forcefully overwrite the old initrd image
      • Note: Use your root device's label and _not_ $ROOTLABEL
  9. Remove the file /etc/blkid/blkid.tab, which has labels for non-multipathed block devices.
    • - rm /etc/blkid/blkid.tab
      • Note: Don't worry about removing this, it will be created the next time system is rebooted.
  10. Remove the option "fastboot" from the kernel command line (added in step (6) above).
  11. restore the original mkinitrd (saved in step (3))
    • mv /sbin/mkinird.save /sbin/mkinitrd
    • optionally you can save the modified one for your future reference
  12. Reboot again.
  13. Verification: Your devices should be under dm-multipath's control. Verify it by running "df" and/or "cat /proc/swaps".
 
Ran into some problems with booting by label and fixed by adding the following to rc.sysinit at line 513 just after
 if strstr "$cmdline" noreadonlyroot ; then
        READONLY=no
fi

echo "TIME TO PUT SOME MPATH LINKING CRAP HERE!"

ORIGINAL_IFS=$IFS
IFS=`echo -en '\n\b'`
MPATH_LABELS=`for d in /dev/mapper/mpath*p* ; do echo -n "$d " ; e2label $d 2>&1
 ; done | grep mapper | grep -v Bad`
mkdir /dev/mpath_links 2>/dev/null
rm -f /dev/mpath_links/*

for mpath in $MPATH_LABELS; do

        mpath_device=`echo $mpath | awk '{print $1}'`
        mpath_label=`echo $mpath | awk '{print $2}'`
        mpath_link="/dev/mpath_links/$mpath_label"
        echo "Linking $mpath_device -> $mpath_link"
        ln -s $mpath_device $mpath_link
done

IFS=$ORIGINAL_IFS

echo "DONE WITH CUSTOM MPATH LINKING"
 
 
Then i changed fstab to use  /dev/mpath_links/...
 

MKINITRD FILE
 

#!/bin/bash --norc
#
# mkinitrd
#
# Copyright 2005 Red Hat, Inc.
#
# Written by Erik Troan <ewt@redhat.com>
#
# Contributors:
#       Elliot Lee <sopwith@cuc.edu>
#       Miguel de Icaza <miguel@nuclecu.unam.mx>
#       Christian 'Dr. Disk' Hechelmann <drdisk@ds9.au.s.shuttle.de>
#       Michael K. Johnson <johnsonm@redhat.com>
#       Pierre Habraken <Pierre.Habraken@ujf-grenoble.fr>
#       Jakub Jelinek <jakub@redhat.com>
#       Carlo Arenas Belon (carenas@chasqui.lared.net.pe>
#       Keith Owens <kaos@ocs.com.au>
#       Bernhard Rosenkraenzer <bero@redhat.com>
#       Matt Wilson <msw@redhat.com>
#       Trond Eivind Glomsrød <teg@redhat.com>
#       Jeremy Katz <katzj@redhat.com>
#       Preston Brown <pbrown@redhat.com>
#       Bill Nottingham <notting@redhat.com>
#       Guillaume Cottenceau <gc@mandrakesoft.com>
#       Peter Jones <pjones@redhat.com>
 
export MALLOC_PERTURB_=204
 
PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH
export PATH
 
. /etc/rc.d/init.d/functions
 
LC_COLLATE=C
export LC_COLLATE
# Set the umask. For iscsi, the initrd can contain platintext
# password (chap secret), so only allow read by owner.
umask 077
 
VERSION=5.1.19.6
 
PROBE="yes"
MODULES=""
MODLOOPS=""
PREMODS=""
PREINTERFACES=""
NET_LIST=""
DHCPDEVS=""
 
ncryptodevs=0
ncryptoparts=0
ncryptolvs=0
ncryptoraids=0
 
CFG_DIR=${MKINITRD_CONFIG_DIR:-/etc/sysconfig/mkinitrd}
cfgs="$CFG_DIR/*[^~]"
for cfg in $cfgs ; do
    [ -x $cfg ] && . $cfg
done
 
CONFMODS="$MODULES"
MODULES=""
ARCH=$(uname -m | sed -e 's/s390x/s390/')
 
compress=1
allowmissing=""
target=""
kernel=""
force=""
verbose=""
img_vers=""
builtins=""
modulefile=/etc/modules.conf
[ "$ARCH" == "s390" ] && withusb=0 || withusb=1
[ "$MULTIPATH" == "no" ] && withmpath=0 || withmpath=1
[ "$DMRAID" == "no" ] && withdmraid=0 || withdmraid=1
rc=0
 
IMAGESIZE=8000
PRESCSIMODS="sd_mod"
fstab="/etc/fstab"
 
vg_list=""
net_list="$NET_LIST"
 
vecho()
{
    NONL=""
    if [ "$1" == "-n" ]; then
        NONL="-n"
        shift
    fi
    [ -n "$verbose" ] && echo $NONL "$@"
}
 
error()
{
    NONL=""
    if [ "$1" == "-n" ]; then
        NONL="-n"
        shift
    fi
    echo $NONL "$@" >&2
}
 
usage () {
    if [ "$1" == "-n" ]; then
        cmd=echo
    else
        cmd=error
    fi
 
    $cmd "usage: `basename $0` [--version] [--help] [-v] [-f] [--preload <module>]"
    $cmd "       [--force-ide-probe] [--force-scsi-probe | --omit-scsi-modules]"
    $cmd "       [--image-version] [--force-raid-probe | --omit-raid-modules]"
    $cmd "       [--with=<module>] [--force-lvm-probe | --omit-lvm-modules]"
    $cmd "       [--builtin=<module>] [--net-dev=<interface>]"
    $cmd "       [--without-usb] [--without-multipath] [--without-dmraid]"
    $cmd "       [--fstab=<fstab>] [--nocompress] <initrd-image> <kernel-version>"
    $cmd ""
    $cmd "       (ex: `basename $0` /boot/initrd-2.2.5-15.img 2.2.5-15)"
 
    if [ "$1" == "-n" ]; then
        exit 0
    else
        exit 1
    fi
}
 
moduledep() {
    vecho -n "Looking for deps of module $1"
    deps=$(modprobe --set-version $kernel --show-depends $1 2>/dev/null| awk '/^insmod / { print gensub(".*/","","g",$2) }' | while read foo ; do [ "${foo%%.ko}" != "$1" ] && echo -n "${foo%%.ko} " ; done)
    [ -n "$deps" ] && vecho ": $deps" || vecho
}
 
locatemodule() {
    fmPath=$(modprobe --set-version $kernel --show-depends $1 2>/dev/null | awk '/^insmod / { print $2; }' | tail -1)
    if [ -n "$fmPath" -a -f "$fmPath" ]; then
        return 0
    fi
    for modExt in o.gz o ko ; do
        for modDir in /lib/modules/$kernel/updates /lib/modules/$kernel ; do
            if [ -d $modDir ]; then
                fmPath=$(findone $modDir -name $1.$modExt)
                if [ -n "$fmPath" -a -f "$fmPath" ]; then
                    return 0
                fi
            fi
        done
    done
    return 1
}
 
findone() {
    echo nash-find "$@" | /sbin/nash --force --quiet \
        | /bin/awk '{ print $1; exit; }'
}
 
findall() {
    echo nash-find "$@" | /sbin/nash --force --quiet
}
 
resolve_device_name() {
    echo nash-resolveDevice "$1" | /sbin/nash --forcequiet
}
 
find_dm_in_sysblock() {
        devname=$(resolve_device_name $1)
        [ -z "$devname" ] && return 1
        majmin=$(get_numeric_dev dec $devname)
        [ -z "$majmin" ] && return 1
        findall /sys/block -name dev | while read device ; do \
                  echo "$majmin" | cmp -s $device && echo $device ; done \
                  | sed -e 's,/dev$,,'
}
 
is_mpath() {
    major=$(echo $1 | cut -d: -f1)
    minor=$(echo $1 | cut -d: -f2)
    for target in $(dmsetup -C -j $major -m $minor table 2>/dev/null | \
            grep -v "No devices found" | awk ' { print $3 }') ; do
        [ "$target" == "multipath" ] && return 0
    done
    return 1
}
 
get_disk_vendor() {
    local vendor=$(scsi_id -g -u -s ${1#/sys} -x | grep ^ID_VENDOR= | \
        sed 's/^ID_VENDOR=//')
    [ -n "$vendor" ] || vendor=$(scsi_id -g -ppre-spc3-83 -u -s ${1#/sys} -x \
        | grep ^ID_VENDOR= | sed 's/^ID_VENDOR=//')
    [ -z "$vendor" ] && return 1
    echo ${vendor}
}
 
# this sucks; we need a generic way to get the hardware handler
is_emc() {
    local syspath=$1
    local devpath=$2
    local majmin=$(cat ${syspath}/dev)
    local major=$(echo $1 | cut -d: -f1)
    local minor=$(echo $1 | cut -d: -f2)
    if dmsetup -C -j $major -m $minor table 2>/dev/null | \
            grep -v "No devices found" | grep -q " emc " ; then
        return 0
    fi
    if [ "$(get_disk_vendor ${syspath})" == "DGC" ]; then
        return 0
    fi
    return 1
}
 
find_mpath_deps() {
    local devpath="/dev/$(echo $1 | sed -e 's,.*/\([^/]\+\),\1,' )"
    local arg2="$2"
    local majmin=$(cat $1/dev)
    local ret=1
    if [ "${arg2}" == "yes" ]; then
        if is_emc ${1} ${devpath} ; then
            ret=0
        fi
    fi
    if is_mpath ${majmin} ; then
        arg2=yes
    fi
    slaves="$1/slaves/*"
    for slave in $slaves ; do
        [ -e $slave ] || continue
        find_mpath_deps $(readlink $slave) ${arg2} && ret=0
    done
    if [ "$2" == "yes" ]; then
        echo $devpath
    fi
    return $ret
}
 
findmodule() {
    skiperrors=""
 
    if [ $1 == "--skiperrors" ]; then
        skiperrors=--skiperrors
        shift
    fi
 
    if [ $1 == "--loop" ]; then
        MODLOOPS=" $MODLOOPS$2 "
        shift
        shift
    fi
 
    local modName=$1
 
    if [ "$modName" = "off" -o "$modName" = "null" ]; then
        return
    fi
 
    if [ "$modName" != "${modName##-}" ]; then
        skiperrors=--skiperrors
        modName="${modName##-}"
    fi
 
    case "$MODULES " in
        *"/$modName.ko "*) return ;;
    esac
 
    if echo $builtins | egrep -q '(^| )'$modName'( |$)' ; then
        vecho "module $modName assumed to be built in"
        return
    fi
 
    # special cases
    if [ "$modName" = "i2o_block" ]; then
        findmodule i2o_core
        findmodule -i2o_pci
        modName="i2o_block"
    elif [ "$modName" = "ppa" ]; then
        findmodule parport
        findmodule parport_pc
        modName="ppa"
    elif [ "$modName" = "sbp2" ]; then
        findmodule ieee1394
        findmodule ohci1394
        modName="sbp2"
    elif [ "$modName" = "gfs2" ]; then
        case " $MODLOOPS " in
            *" gfs2 "*) ;;
            *)
                findmodule --loop gfs2 lock_nolock
                case " $MODULES " in
                    *"/gfs2.ko "*) return ;;
                esac
                ;;
        esac
    elif [ "$modName" = "nfs" ]; then
        findmodule sunrpc
        modName="nfs"
    elif [ "$modName" = "usb-storage" -o "$modName" = "ub" ]; then
        usbModName="$modName"
    fi
 
    if [ -n "$usbModName" \
            -a "$modName" != "uhci-hcd" \
            -a "$modName" != "ohci-hcd" \
            -a "$modName" != "ehci-hcd" ]; then
        withusb=1
        findmodule ehci-hcd
        findmodule ohci-hcd
        findmodule uhci-hcd
 
        usbModName=""
    fi
 
    moduledep $modName
    for i in $deps; do
        findmodule $i
    done
 
    locatemodule $modName
 
    if [ ! -f "$fmPath" ]; then
        if [ -n "$skiperrors" ]; then
            return
        fi
 
        # ignore the absence of the scsi modules
        for n in $PRESCSIMODS; do
            if [ "$n" = "$modName" ]; then
                return;
            fi
        done;
 
        if [ -n "$allowmissing" ]; then
            error "WARNING: No module $modName found for kernel $kernel, continuing anyway"
            return
        fi
 
        error "No module $modName found for kernel $kernel, aborting."
        exit 1
    fi
 
    # only need to add each module once
    MODULES="$MODULES $fmPath"
 
    # need to handle prescsimods here -- they need to go _after_ scsi_mod
    if [ "$modName" = "scsi_mod" ]; then
        for n in $PRESCSIMODS ; do
            findmodule $n
        done
    fi
}
 
inst() {
    if [ "$#" != "2" ];then
        echo "usage: inst <file> <destination>"
        return
    fi
    vecho "$1 -> $2"
    mkdir -p $(dirname $2)
    cp $1 $2
}
 
readlink() {
    echo nash-readlink "$1" | /sbin/nash --force --quiet
}
 
access() {
    echo nash-access "$@" | /sbin/nash --force --quiet
}
 
slavestried=""
findstoragedriverinsys () {
    while [ ! -L device ]; do
        if [ -d slaves ]; then
            for slave in slaves/* ; do
                [ "$slave" == "slaves/*" ] && continue
                slavename=${slave##*/}
                case " $slavestried " in
                    *" $slavename "*)
                        continue
                        ;;
                    *)
                        slavestried="$slavestried $slavename"
                        pushd $slave >/dev/null 2>&1
                        findstoragedriverinsys
                        popd >/dev/null 2>&1
                        ;;
                esac
            done
        fi
        [ "$PWD" = "/sys" ] && return
        cd ..
    done
    cd $(readlink ./device)
    if is_iscsi $PWD; then
        handleiscsi "$PWD"
        return
    fi
    if echo $PWD | grep -q /virtio-pci/ ; then
        findmodule virtio_pci
    fi
    while [ "$PWD" != "/sys/devices" ]; do
        deps=
        if [ -f modalias ]; then
            moduledep $(cat modalias)
        fi
 
        [ -z "$deps" -a -L driver/module ] && \
            deps=$(basename $(readlink driver/module))
        for driver in $deps ; do
            findmodule $driver
        done
        cd ..
    done
}
 
findstoragedriver () {
    for device in $@ ; do
        case " $handleddevices " in
            *" $device "*)
                continue ;;
            *) handleddevices="$handleddevices $device" ;;
        esac
        if [[ "$device" =~ "^md[0-9]+" ]]; then
            vecho "Found RAID component $device"
            handleraid "$device"
            continue
        fi
vecho "Looking for driver for device $device"
        if [[ "$device" =~ ^(dm-|mapper/) ]]; then
            device=$(resolve_dm $device)
            vecho "Found DM device $device"
            majmin=$(get_numeric_dev dec "/dev/$device")
            sysfs=$(find_dm_in_sysblock /dev/$device)
            handledm $(echo "$majmin" |cut -d : -f 1) $(echo "$majmin" |cut -d : -f 2)
        else
            sysfs=$(findone -type d /sys/block -name $device)
        fi
        [ -z "$sysfs" ] && return
        pushd $sysfs >/dev/null 2>&1
        findstoragedriverinsys
        popd >/dev/null 2>&1
    done
}
 
findnetdriver() {
    for device in $@ ; do
        case " $handleddevices " in
            *" $device "*)
                continue ;;
            *) handleddevices="$handleddevices $device" ;;
        esac
        if [ -f /sys/class/net/$device/device/modalias ]; then
            modalias=$(cat /sys/class/net/$device/device/modalias)
   moduledep $modalias
   for driver in $deps ; do
findmodule $driver
   done
elif [ "$(basename $(readlink /sys/class/net/$device/device/bus) 2>/dev/null)" = "xen" ]; then
   findmodule xennet # FIXME: hack for xennet sucking
else
   findmodule $(ethtool -i $device | awk '/^driver:/ { print $2 }')
  fi
    done
}
 
iscsi_get_rec_val() {
 
    # The open-iscsi 742 release changed to using flat files in
    # /var/lib/iscsi.
 
    result=$(/sbin/iscsiadm --show -m session -r ${1} | grep "^${2} = ")
    result=${result##* = }
}
 
ibft_get_rec_val() {
    result=$(/sbin/iscsiadm -m fw 2>/dev/null | grep "^${1} = ")
    result=${result##* = }
}
 
iscsi_set_parameters() {
    path=$1
    vecho setting iscsi parameters
 
    # Check once before getting explicit values, so we can output a decent
    # error message.
 
    if ! /sbin/iscsiadm -m session -r ${path} >/dev/null ; then
        echo Unable to find iscsi record for $path
        exit 1
    fi
 
    nit_name=$(grep "^InitiatorName=" /etc/iscsi/initiatorname.iscsi | \
        sed -e "s/^InitiatorName=//")
 
 
    iscsi_get_rec_val $path "node.name"; tgt_name=${result}
    iscsi_get_rec_val $path "node.tpgt"; tpgt=${result}
    iscsi_get_rec_val $path "node.conn\[0\].address"; tgt_ipaddr=${result}
    iscsi_get_rec_val $path "node.conn\[0\].port"; tgt_port=${result}
 
    # Note: we get chap secrets (passwords) in plaintext, and also store
    # them in the initrd.
 
    iscsi_get_rec_val $path "node.session.auth.username"
    chap=${result}
    if [ -n "${chap}" -a "${chap}" != "<empty>" ]; then
        chap="-u ${chap}"
        iscsi_get_rec_val $path "node.session.auth.password" 
        chap_pw="-w ${result}"
    else
chap=""
    fi
 
    iscsi_get_rec_val $path "node.session.auth.username_in"
    chap_in=${result}
    if [ -n "${chap_in}" -a "${chap_in}" != "<empty>" ]; then
        chap_in="-U ${chap_in}"
        iscsi_get_rec_val $path "node.session.auth.password_in" 
        chap_in_pw="-W ${result}"
    else
chap_in=""
    fi
}
 
iscsi_is_ibft() {
    path=$1
 
    iscsi_get_rec_val $path "node.name"; tgt_name=${result}
    iscsi_get_rec_val $path "node.conn\[0\].address"; tgt_ipaddr=${result}
    iscsi_get_rec_val $path "node.conn\[0\].port"; tgt_port=${result}
 
    found_name=no
    found_ipaddr=no
    found_port=no
    res=$(iscsiadm -m fw 2>/dev/null | while read key equal value ; do
            if [ "$key" == "node.name" ]; then
                [ "$value" == "$tgt_name" ] && found_name=yes
            elif [[ "$key" =~ "node.conn\[[[:alnum:]]+\].address" ]]; then
                [ "$value" == "$tgt_ipaddr" ] && found_ipaddr=yes
            elif [[ "$key" =~ "node.conn\[[[:alnum:]]+\].port" ]]; then
                [ "$value" == "$tgt_port" ] && found_port=yes
            fi
            if [ "$found_name" == "yes" -a \
                    "$found_ipaddr" == "yes" -a "$found_port" == "yes" ]; then
                echo yes
                break
            fi
        done)
    if [ "$res" == "yes" ]; then
        return 0
    else
        return 1
    fi
}
 
emit_iscsi_device() {
    dev=${1##iscsi_device_}
    emit "echo Attaching to iSCSI storage"
 
    inst /sbin/iscsistart "$MNTIMAGE/sbin/iscsistart"
    if iscsi_is_ibft $dev ; then
        emit "/bin/iscsistart -b"
    else
        iscsi_set_parameters $dev
        # recid is not really used, just use 0 for it
        emit "/bin/iscsistart -t ${tgt_name} -i ${nit_name} \
            -g ${tpgt} -a ${tgt_ipaddr} ${chap} ${chap_pw} \
            ${chap_in} ${chap_in_pw}"
    fi
}
 
is_iscsi() {
    path=$1
    if echo $path | grep -q "/platform/host[0-9]*/session[0-9]*/target[0-9]*:[0-9]*:[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*"; then
        return 0
    else 
        return 1
    fi
}
 
handleiscsi() {
    vecho "Found iscsi component $1"
    findmodule iscsi_tcp
    findmodule sd_mod
 
    # We call iscsi_set_parameters once here to figure out what network to
    # use (it sets tgt_ipaddr), and once again to emit iscsi values,
    # not very efficient.
    if iscsi_is_ibft $1 ; then
findmodule iscsi_ibft
for mac in $(cat /sys/firmware/ibft/ethernet*/mac) ; do
   netdev=$(/sbin/ip -o link list | grep $mac | \
sed 's/^[^ ]\+ \([^ ]\+\): .*$/\1/g')
            addnetdev $netdev
        done
    else
        iscsi_set_parameters $1
        netdev=$(/sbin/ip route get to $tgt_ipaddr | \
            sed 's|.*dev \(.*\).*|\1|g' | awk '{ print $1; exit }')
        addnetdev $netdev
    fi
    iscsi_devs="$iscsi_devs $1"
 
    MODULES="$MODULES iscsi_device_$1"
}
 
handleraid() {
    local start=0
 
    if [ -n "$noraid" -o ! -f /proc/mdstat ]; then
        return 0
    fi
 
    levels=$(awk "/^$1[ ]*:/ { print\$4 }" /proc/mdstat)
    devs=$(gawk "/^$1[ ]*:/ { print gensub(\"\\\\[[0-9]*\\\\]\",\"\",\"g\",gensub(\"^md.*raid[0-9]*\",\"\",\"1\")) }" /proc/mdstat)
 
    for level in $levels ; do
        case $level in
        linear)
            findmodule linear
            start=1
            ;;
        multipath)
            findmodule multipath
            start=1
            ;;
        raid[01456] | raid10)
            findmodule $level
            start=1
            ;;
        *)
            error "raid level $level (in /proc/mdstat) not recognized"
            ;;
        esac
    done
    findstoragedriver $devs
    if [ "$start" = 1 ]; then
        raiddevices="$raiddevices $1"
    fi
    return $start
}
 
resolve_dm() {
    # resolve device mapper nodes to something of the form /dev/mapper/foo
    if [[ ! "$1" =~ ^dm- ]]; then
echo $1
return 0
    fi
    majmin=$(cat /sys/block/$1/dev)
    for dmdev in /dev/mapper/* ; do
dmnum=$(get_numeric_dev dec $dmdev)
if [ "$dmnum" = "$majmin" ]; then
   echo ${dmdev#/dev/}
   break
fi
    done
}
 
 
handledm() {
    major=$1
    minor=$2
    while read dmstart dmend dmtype r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 ; do
        case "$dmtype" in
            crypt)
             slavedev=$(findall /sys/block -name dev \
  | while read device ; do \
                                echo "$r3" \
                                    | cmp -s $device && echo $device ; \
                             done \
                           | sed -e 's,.*/\([^/]\+\)/dev,\1,;s,!,/,' )
                slavedev=$(resolve_dm ${slavedev##/dev/})
                cryptsetup isLuks "/dev/$slavedev" 2>/dev/null || continue
                vecho "device is LUKS, slave is $slavedev"
                find_base_dm_mods
                findmodule dm-crypt
                for mod in $(echo $r0 | tr ':-' '  ') ; do
                    findmodule --skiperrors $mod
                done
                dmname=$(dmsetup info -j $major -m $minor -c --noheadings -o name)
                slavedev=$(resolve_dm $slavedev)
 
                # determine if $slavedev is an LV
                #  if so, add the device to latecryptodevs
                #  if not, add the device to cryptodevs
                local vg=$(lvm.static lvs --ignorelockingfailure --noheadings -o vg_name /dev/$slavedev 2>/dev/null)
 
                if [ -n "$vg" ]; then
                    eval cryptolv${ncryptolvs}='"'/dev/$slavedev $dmname'"'
                    let ncryptolvs++
                elif grep -q "^$slavedev :" /proc/mdstat ; then
                    eval cryptoraid${ncryptoraids}='"'/dev/$slavedev $dmname'"'
                    let ncryptoraids++
                else
                    eval cryptopart${ncryptoparts}='"'/dev/$slavedev $dmname'"'
                    let ncryptoparts++
                fi
 
                let ncryptodevs++
                handlelvordev "/dev/$slavedev"
                ;;
        esac
    done << EOF
        $(dmsetup table -j $major -m $minor 2>/dev/null)
EOF
}
 
dmmods_found="n"
find_base_dm_mods()
{
    [ "$dmmods_found" == "n" ] || return
    findmodule -dm-mod
    
    # DM requires all of these to be there in case someone used the
    # feature.  broken.  (#132001)
    findmodule -dm-mirror
    findmodule -dm-zero
    findmodule -dm-snapshot
    dmmods_found="y"
}
 
handlelvordev() {
    local vg=`lvm.static lvs --ignorelockingfailure --noheadings -o vg_name $1 2>/dev/null`
    if [ -n "$vg" ]; then
        vg=`echo $vg` # strip whitespace
        case " $vg_list " in
        *" $vg "*)
            ;;
        *)
            vg_list="$vg_list $vg"
            for device in `lvm.static vgdisplay --ignorelockingfailure -v $vg 2>/dev/null | sed -n 's/PV Name//p'`; do
                findstoragedriver ${device##/dev/}
            done
            ;;
        esac
    else
        findstoragedriver ${1##/dev/}
    fi
}
 
handlenetdev() {
    local dev=$1
 
    source /etc/sysconfig/network
    if [ ! -f /etc/sysconfig/network-scripts/ifcfg-$dev ]; then
        error "unable to find network device configuration for $dev"
    else
        source /etc/sysconfig/network-scripts/ifcfg-$dev
    fi
 
    if [ x"$BOOTPROTO" = x ]; then
        error "bootproto not specified for $dev, assuming DHCP"
        BOOTPROTO=dhcp
    fi
 
    [ -n "$IPADDR" ] && IPSTR="$IPSTR --ip $IPADDR"
    [ -n "$NETMASK" ] && IPSTR="$IPSTR --netmask $NETMASK"
    [ -n "$GATEWAY" ] && IPSTR="$IPSTR --gateway $GATEWAY"
    [ -n "$ETHTOOL_OPTS" ] && IPSTR="$IPSTR --ethtool \"$ETHTOOL_OPTS\""
    [ -n "$MTU" ] && IPSTR="$IPSTR --mtu $MTU"
    if [ -n "$IPADDR" ]; then
        [ -z "$DOMAIN" ] && DOMAIN=$(awk '/^search / { print gensub("^search ","",1) }' /etc/resolv.conf)
        if [ -z "$DNS1" ]; then
            DNS1=$(awk '/^nameserver / { ORS="" ; if (x > 0) print "," ; printf "%s", $2 ; x = 1}' /etc/resolv.conf)
        fi
    fi
    [ -n "$DOMAIN" ] && IPSTR="$IPSTR --domain \"$DOMAIN\""
    if [ -n "$DNS1" ]; then
        if [ -n "$DNS2" ]; then
            IPSTR="$IPSTR --dns $DNS1,$DNS2"
        else
            IPSTR="$IPSTR --dns $DNS1"
        fi
    fi
    prenetwork=""
    if [ -n "$HWADDR" ]; then
prenetwork="netname $HWADDR $dev"
    fi
    network="network --device $dev --bootproto $BOOTPROTO $IPSTR"
    if [ "$BOOTPROTO" = "dhcp" ]; then
        postnetwork="rename /var/lib/dhclient/dhclient.leases /var/lib/dhclient/dhclient-$dev.leases"
        DHCPDEVS="$DHCPDEVS $dev"
        mkdir -p $MNTIMAGE/var/lib/dhclient
    fi
}
 
addnetdev() {
    dev=$1
 
    vecho "Adding network device $dev"
    findnetdriver $dev
    MODULES="$MODULES network_device_$netdev"
    net_list="$net_list $netdev"
}
 
handlenfs() {
    remote=${1%%:*}
    remoteip=$(host $remote | awk '/ address / { print $4 }')
    # assume, if it didn't resolve, that it's an IP
    [ -z "$remoteip" ] && remoteip=$remote
    netdev=`/sbin/ip route get to $remoteip |sed 's|.*dev \(.*\).*|\1|g' |awk '{ print $1; exit }'`
    addnetdev $netdev
}
 
while [ $# -gt 0 ]; do
    case $1 in
        --fstab*)
            if [ "$1" != "${1##--fstab=}" ]; then
                fstab=${1##--fstab=}
            else
                fstab=$2
                shift
            fi
            ;;
 
        --with-usb*)
            if [ "$1" != "${1##--with-usb=}" ]; then
                usbmodule=${1##--with-usb=}
            else
                usbmodule="usb-storage"
            fi
            basicmodules="$basicmodules $usbmodule"
            unset usbmodule
            ;;
 
        --without-usb)
            withusb=0
            ;;
 
        --without-multipath)
            withmpath=0
            ;;
 
        --without-dmraid)
            withdmraid=0
            ;;
 
        --with*)
            if [ "$1" != "${1##--with=}" ]; then
                modname=${1##--with=}
            else
                modname=$2
                shift
            fi
 
            basicmodules="$basicmodules $modname"
            ;;
 
        --builtin*)
            if [ "$1" != "${1##--builtin=}" ]; then
                modname=${1##--builtin=}
            else
                modname=$2
                shift
            fi
            builtins="$builtins $modname"
            ;;
 
        --version)
            echo "mkinitrd: version $VERSION"
            exit 0
            ;;
 
        -v)
            verbose=-v
            ;;
 
        --nocompress)
            compress=""
            ;;
 
        --ifneeded)
            # legacy
            ;;
 
        -f)
            force=1
            ;;
        --preload*)
            if [ "$1" != "${1##--preload=}" ]; then
                modname=${1##--preload=}
            else
                modname=$2
                shift
            fi
            PREMODS="$PREMODS $modname"
            ;;
        --force-scsi-probe)
            forcescsi=1
            ;;
        --omit-scsi-modules)
            PRESCSIMODS=""
            noscsi=1
            ;;
        --force-raid-probe)
            forceraid=1
            ;;
        --omit-raid-modules)
            noraid=1
            ;;
        --force-lvm-probe)
            forcelvm=1
            ;;
        --omit-lvm-modules)
            nolvm=1
            ;;
        --force-ide-probe)
            forceide=1
            ;;
        --image-version)
            img_vers=yes
            ;;
        --allow-missing)
            allowmissing=yes
            ;;
        --net-dev*)
            if [ "$1" != "${1##--net-dev=}" ]; then
                PREINTERFACES="$PREINTERFACES ${1##--net-dev=}"
            else
                PREINTERFACES="$PREINTERFACES $2"
                shift
            fi
            ;;
        --noresume)
            noresume=1
            ;;
--rootdev*)
            if [ "$1" != "${1##--rootdev=}" ]; then
                rootdev="${1##--rootdev=}"
            else
                rootdev="$2"
                shift
            fi
   ;;
--rootfs*)
            if [ "$1" != "${1##--rootfs=}" ]; then
                rootfs="${1##--rootfs=}"
            else
                rootfs="$2"
                shift
            fi
   ;;
--rootopts*)
            if [ "$1" != "${1##--rootopts=}" ]; then
                rootopts="${1##--rootopts=}"
            else
                rootopts="$2"
                shift
            fi
   ;;
--loopdev*)
            if [ "$1" != "${1##--loopdev=}" ]; then
                loopdev="${1##--loopdev=}"
            else
                loopdev="$2"
                shift
            fi
   ;;
--loopfs*)
            if [ "$1" != "${1##--loopfs=}" ]; then
                loopfs="${1##--loopfs=}"
            else
                loopfs="$2"
                shift
            fi
   ;;
--loopopts*)
            if [ "$1" != "${1##--loopopts=}" ]; then
                loopopts="${1##--loopopts=}"
            else
                loopopts="$2"
                shift
            fi
   ;;
--looppath*)
            if [ "$1" != "${1##--looppath=}" ]; then
                looppath="${1##--looppath=}"
            else
                looppath="$2"
                shift
            fi
   ;;
        --help)
            usage -n
            ;;
        *)
            if [ -z "$target" ]; then
                target=$1
            elif [ -z "$kernel" ]; then
                kernel=$1
            else
                usage
            fi
            ;;
    esac
 
    shift
done
 
if [ -z "$target" -o -z "$kernel" ]; then
    usage
fi
 
if [ -n "$img_vers" ]; then
    target="$target-$kernel"
fi
 
if [ -z "$force" -a -f $target ]; then
    error "$target already exists."
    exit 1
fi
 
if [ -n "$forcescsi" -a -n "$noscsi" ]; then
    error "Can't both force scsi probe and omit scsi modules"
    exit 1
fi
 
if [ -n "$forceraid" -a -n "$noraid" ]; then
    error "Can't both force raid probe and omit raid modules"
    exit 1
fi
 
if [ -n "$forcelvm" -a -n "$nolvm" ]; then
    error "Can't both force LVM probe and omit LVM modules"
    exit 1
fi
 
if [ ! -d /lib/modules/$kernel ]; then
    error 'No modules available for kernel "'${kernel}'".'
    exit 1
fi
 
if [ $UID != 0 ]; then
    error "mkinitrd must be run as root."
    exit 1
fi
 
vecho "Creating initramfs"
modulefile=/etc/modprobe.conf
 
# find a temporary directory which doesn't use tmpfs
if [ -z "$loopfs" ]; then
    TMPDIR="/tmp"
else
    TMPDIR=""
    for t in /tmp /var/tmp /root ${PWD}; do
        if [ ! -d $t ]; then continue; fi
        if ! access -w $t ; then continue; fi
    
        fs=$(df -T $t 2>/dev/null | awk '{line=$1;} END {printf $2;}')
        if [ "$fs" != "tmpfs" ]; then
            TMPDIR=$t
            break
        fi
    done
fi
 
if [ -z "$TMPDIR" ]; then
    error "no temporary directory could be found."
    exit 1
fi
 
if [ $TMPDIR = "/root" -o $TMPDIR = "${PWD}" ]; then
    error "WARNING: using $TMPDIR for temporary files"
fi
 
for n in $PREMODS; do
        findmodule $n
done
 
for n in $PREINTERFACES ; do
    findnetdriver $n
    MODULES="$MODULES network_device_$n"
    net_list="$net_list $n"
done
 
if [ "$withusb" -eq 1 ]; then
    findmodule ehci-hcd
    findmodule ohci-hcd
    findmodule uhci-hcd
fi
 
if [ "x$PROBE" == "xyes" ]; then
    [ -z "$rootfs" ] && rootfs=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $3; }}' $fstab)
    [ -z "$rootopts" ] && rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' $fstab)
    [ -z "$rootopts" ] && rootopts="defaults"
 
    # in case the root filesystem is modular
    findmodule -${rootfs}
 
    [ -z "$rootdev" ] && rootdev=$(awk '/^[ \t]*[^#]/ { if ($2 == "/") { print $1; }}' $fstab)
    # check if it's nfsroot
    if [ "$rootfs" == "nfs" -a "x$net_list" == "x" ]; then
        handlenfs $rootdev
    # check if it's root by label
    elif [ "$rootdev" != "${rootdev##LABEL=}" -o \
            "$rootdev" != "${rootdev##UUID=}" ]; then
        rootopts=$(echo $rootopts | sed -e 's/^r[ow],//' \
                                        -e 's/,_netdev//' \
                                        -e 's/_netdev//' \
                                        -e 's/,_rnetdev//' \
                                        -e 's/_rnetdev//' \
                                        -e 's/,r[ow],$//' \
                                        -e 's/,r[ow],/,/' \
                                        -e 's/^r[ow]$/defaults/' \
                                        -e 's/$/,ro/')
        devname=$(resolve_device_name $rootdev)
        majmin=$(get_numeric_dev dec $devname)
        if [[ "$devname" =~ ^/dev/mapper/ ]]; then
            vecho "Found root device $devname for $rootdev"
            rootdev=$devname
        elif [ -n "$majmin" ]; then
            dev=$(findall /sys/block -name dev | while read device ; do \
                  echo "$majmin" | cmp -s $device && echo $device ; done \
                  | sed -e 's,.*/\([^/]\+\)/dev,\1,' )
            if [ -n "$dev" ]; then
                vecho "Found root device $dev for $rootdev"
                rootdev=$dev
            fi
        fi
    else
        rootopts=$(echo $rootopts | sed -e 's/^r[ow],//' \
                                        -e 's/,_netdev//' \
                                        -e 's/_netdev//' \
                                        -e 's/,_rnetdev//' \
                                        -e 's/_rnetdev//' \
                                        -e 's/,r[ow],$//' \
                                        -e 's/,r[ow],/,/' \
                                        -e 's/^r[ow]$/defaults/' \
                                        -e 's/$/,ro/')
    fi
    [ "$rootfs" != "nfs" ] && handlelvordev $rootdev
 
    # find the first swap dev which would get used for swsusp
    swsuspdev=$(awk '/^[ \t]*[^#]/ { if ($3 == "swap") { print $1; exit }}' $fstab)
    if [ -n "$swsuspdev" ]; then
        if [[ "$swsuspdev" =~ ^(LABEL=|UUID=) ]]; then
            swsuspdev=$(resolve_device_name $swsuspdev)
        fi
        handlelvordev $swsuspdev
    fi
fi
 
if [ -n "$forcescsi" -o -z "$noscsi" -a "x$PROBE" == "xyes" ]; then
    if [ ! -f $modulefile ]; then
        modulefile=/etc/conf.modules
    fi
 
    if [ -f $modulefile ]; then
        scsimodules=`grep "alias[[:space:]]\+scsi_hostadapter" $modulefile | grep -v '^[ ]*#' | LC_ALL=C sort -u | awk '{ print $3 }'`
 
        if [ -n "$scsimodules" ]; then
            for n in $scsimodules; do
    # for now allow scsi modules to come from anywhere.  There are some
    # RAID controllers with drivers in block/
                findmodule $n
            done
        fi
    fi
fi
 
# If we have ide devices and module ide, do the right thing
ide=/proc/ide/ide*
if [ -n "$forceide" -o -n "$ide" -a "x$PROBE" == "xyes" ]; then
    findmodule -ide-disk
fi
 
# If we have dasd devices, include the necessary modules (S/390)
if [ "x$PROBE" == "xyes" -a -d /proc/dasd ]; then
    findmodule -dasd_mod
    findmodule -dasd_eckd_mod
    findmodule -dasd_fba_mod
fi
 
# Loopback root support
# loopdev : device or nfs server:path file is on
# looppath : filename
# loopfs : filesystem of loopdev
# loopots : options to mount loopfs
 
if [ -n "${loopfs}" ] || [[ "$rootopts" =~ "loop" ]]; then
     # FIXME: probe this somehow?
rootdev=/dev/loop0
[ -z "$rootopts" ] && rootopts="defaults"
findmodule loop
findmodule -${loopfs}
if [ "$loopfs" == "nfs" -a "x$net_list" == "x" ]; then
   handlenfs $loopdev
fi
# FIXME: label support
[ "$loopfs" != "nfs" ] && handlelvordev $loopdev
fi
 
# If we use LVM or dm-based raid, include dm-mod
testdm=""
[ -n "$vg_list" ] && testdm="yes"
[ -n "$forceraid" -o -n "$forcelvm" ] && testdm="yes"
[ -z "$nolvm" -o -z "$noraid" ] && testdm="yes"
[ "x$PROBE" != "xyes" ] && testdm=""
 
MNTIMAGE=`mktemp -d ${TMPDIR}/initrd.XXXXXX`
IMAGE=`mktemp ${TMPDIR}/initrd.img.XXXXXX`
RCFILE=$MNTIMAGE/init
 
cemit()
{
    cat >> $RCFILE
}
 
emit()
{
    NONL=""
    if [ "$1" == "-n" ]; then
        NONL="-n"
        shift
    fi
    echo $NONL "$@" >> $RCFILE
}
 
use_multipath=1
use_emc=1
use_xdr=0
if [ -n "$testdm" -a -x /sbin/dmsetup -a -e /dev/mapper/control ]; then
    dmout=$(/sbin/dmsetup ls 2>/dev/null)
 
    if [ "$dmout" != "No devices found" -a "$dmout" != "" ]; then
        sysroot=$(find_dm_in_sysblock ${rootdev})
        rootdevs=""
        if [ "${withmpath}" -eq 1 -a -n "${sysroot}" ]; then
            for rd in ${sysroot} ; do 
                somedeps=$(find_mpath_deps ${rd})
                [ "$?" == "0" ] && use_emc=1
                [ -z "$somedeps" ] && continue
                for dep in ${somedeps} ; do
                    majmin=$(get_numeric_dev dec ${dep})
                    [[ ${majmin} =~ ^9: ]] && continue
                    [[ ${dep} =~ ^/dev/xvd.+ ]] && continue
                    case " ${rootdevs} " in
                        *" ${dep} "*) continue ;;
                        *) rootdevs="${rootdevs} ${dep}" ;;
                    esac
                done
            done
        fi
        if [ -z "$rootdevs" ]; then
            rootdevs="$rootdev"
        fi
        root_wwids=""
        if [ "${withmpath}" -eq "1" ]; then
            for rootdev in ${rootdevs} ; do
                disk=$(find_dm_in_sysblock ${rootdev} | sed -e 's,^/sys,,')
                wwid=$(/sbin/scsi_id -g -u -s ${disk})
                if [ -z "${wwid}" ]; then
                    # Could be EMC unit requiring special option
                    wwid=$(/sbin/scsi_id -g -ppre-spc3-83 -u -s ${disk})
                fi
                if [ -n "${wwid}" ]; then
                    case " ${root_wwids} " in
                        *" ${wwid} "*) continue ;;
                        *) root_wwids="${root_wwids} ${wwid}" ;;
                    esac
                fi
            done
            if [ -n "$root_wwids" ]; then
                use_multipath=1
            fi
        fi
 
        find_base_dm_mods
    
        # If we use dm-multipath devices, include the needed modules
        if [ "$use_multipath" == "1" ]; then
            findmodule -dm-multipath
            findmodule -dm-round-robin
            if [ "$use_emc" == "1" ]; then
                findmodule -dm-emc
            fi
        fi
    fi
    # could be using xDR multipath on s390
    if [ "${ARCH}" = "s390" ]; then
        if [ -x /sbin/xdrgetuid ]; then
   dasdlist="$(cd /dev ; /bin/ls -1 dasd?)"
            if [ ! -z "${dasdlist}" ]; then
                for dasddev in ${dasdlist} ; do
                    if [ ! -z "$(/sbin/xdrgetuid -p ${dasddev} | grep "^xdr")" ]; then
                        use_multipath=1
                        use_xdr=1
                        break
                    fi
                done
            fi
        fi
    find_base_dm_mods
    findmodule multipath
    findmodule dm-multipath
    findmodule -dm-round-robin
    fi
fi
 
if [ "$withdmraid" == "1" ]; then
    findmodule dm-mem-cache
    findmodule dm-region_hash
    findmodule dm-message
    findmodule dm-raid45
fi
 
for n in $basicmodules; do
    findmodule $n
done
 
for n in $CONFMODS; do
    findmodule $n
done
 
vecho "Using modules: $MODULES"
 
 
if [ -z "$MNTIMAGE" -o -z "$IMAGE" ]; then
    error "Error creating temporaries.  Try again"
    exit 1
fi
 
mkdir -p $MNTIMAGE
mkdir -p $MNTIMAGE/lib/firmware
mkdir -p $MNTIMAGE/bin
mkdir -p $MNTIMAGE/etc
mkdir -p $MNTIMAGE/dev
mkdir -p $MNTIMAGE/proc
mkdir -p $MNTIMAGE/sys
mkdir -p $MNTIMAGE/sysroot
ln -s bin $MNTIMAGE/sbin
 
if [ -e /etc/fstab.sys ]; then
    inst /etc/fstab.sys "$MNTIMAGE/etc/fstab.sys"
fi
inst /sbin/nash "$MNTIMAGE/bin/nash"
inst /sbin/insmod.static "$MNTIMAGE/bin/insmod"
ln -s /sbin/nash $MNTIMAGE/sbin/modprobe
 
for MODULE in $MODULES; do
    if [[ "$MODULE" =~ "^iscsi_device_" ]]; then
        continue
    fi
    if [[ "$MODULE" =~ "^network_device_" ]] ; then
        continue
    fi
    if [ -x /usr/bin/strip ]; then
        /usr/bin/strip -g $verbose $MODULE -o $MNTIMAGE/lib/$(basename $MODULE)
    else
        cp $verbose -a $MODULE $MNTIMAGE/lib
    fi
    for fw in $(/sbin/modinfo -F firmware $MODULE 2>/dev/null); do
        if [ -f /lib/firmware/$fw ]; then
            cp $verbose -a /lib/firmware/$fw $MNTIMAGE/lib/firmware/
        fi
    done
done
 
# mknod'ing the devices instead of copying them works both with and
# without devfs...
mkdir $MNTIMAGE/dev/mapper
 
mknod $MNTIMAGE/dev/ram0 b 1 0
mknod $MNTIMAGE/dev/ram1 b 1 1
ln -sf ram1 $MNTIMAGE/dev/ram
 
mknod $MNTIMAGE/dev/null c 1 3
mknod $MNTIMAGE/dev/zero c 1 5
mknod $MNTIMAGE/dev/systty c 4 0
if ! echo "$(uname -m)" | grep -q "s390"; then 
  for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 ; do
    mknod $MNTIMAGE/dev/tty$i c 4 $i
  done
fi
for i in 0 1 2 3 ; do
    mknod $MNTIMAGE/dev/ttyS$i c 4 $(($i + 64))
done
mknod $MNTIMAGE/dev/tty c 5 0
mknod $MNTIMAGE/dev/console c 5 1
mknod $MNTIMAGE/dev/ptmx c 5 2
mknod $MNTIMAGE/dev/rtc c 10 135
if [ "$(uname -m)" == "ia64" ]; then
    mknod $MNTIMAGE/dev/efirtc c 10 136
fi
 
# FIXME -- this can really go poorly with clvm or duplicate vg names.
# nash should do lvm probing for us and write its own configs.
if [ -n "$vg_list" ]; then
    inst /sbin/lvm.static "$MNTIMAGE/bin/lvm"
    if [ -f /etc/lvm/lvm.conf ]; then
        cp $verbose --parents /etc/lvm/lvm.conf $MNTIMAGE/
    fi
fi
 
if [ "$use_multipath" == "1" ]; then
    # For multipath command
    inst /sbin/multipath.static $MNTIMAGE/bin/multipath
    if [ -f /etc/multipath.conf ]; then
        inst /etc/multipath.conf $MNTIMAGE/etc/multipath.conf
    fi
    if [ -f /var/lib/multipath/bindings ]; then
        inst /var/lib/multipath/bindings $MNTIMAGE/var/lib/multipath/bindings
    fi
    inst /sbin/scsi_id $MNTIMAGE/bin/scsi_id
    inst /etc/scsi_id.config $MNTIMAGE/etc/scsi_id.config
    # This includes all mpath_prio checkers in the image (~2.5M)
    # Alternately we can only include those that are used by the
    # current mpath config. This would require users to rebuild 
    # the initrd if migrating/adding controllers from different
    # storage vendors
    for M in /sbin/mpath_prio_*.static ; do
        inst ${M} $MNTIMAGE/${M%%.static};
    done
    mkdir -p $MNTIMAGE/tmp
 
    # For kpartx command which creates device maps for disk partitions
    # and creates device files
    inst /sbin/dmsetup.static $MNTIMAGE/bin/dmsetup
    inst /sbin/kpartx.static $MNTIMAGE/bin/kpartx
fi
 
if [ "$use_xdr" == "1" ]; then
    inst /sbin/xdrgetuid $MNTIMAGE/bin/xdrgetuid
    inst /sbin/xdrgetprio $MNTIMAGE/bin/xdrgetprio
    if [ -f /etc/xdrdevices.conf ]; then
        inst /etc/xdrdevices.conf $MNTIMAGE/etc/xdrdevices.conf
    fi
    # ugly hack for starters because the xdr-tools are not static
    inst /lib64/libc.so.6 $MNTIMAGE/lib64/libc.so.6
    inst /lib/ld64.so.1 $MNTIMAGE/lib/ld64.so.1
fi
 
if [ "$withdmraid" == "1" ]; then
    # Only dmraid is needed to set up dmraid volume
    inst /sbin/dmraid.static "$MNTIMAGE/bin/dmraid"
    inst /sbin/kpartx.static "$MNTIMAGE/bin/kpartx"
fi
 
findkeymap () {
    local MAP=$1
 
    if [ ! -f "$MAP" ]; then
        MAP=$(find /lib/kbd/keymaps -type f -name $MAP -o -name $MAP.\* | head -n1)
    fi
 
    case " $KEYMAPS " in
        *" $MAP "*)
            return
    esac
 
    KEYMAPS="$KEYMAPS $MAP"
 
    case $MAP in
        *.gz)
            cmd=zgrep
            ;;
        *.bz2)
            cmd=bzgrep
            ;;
        *)
            cmd=grep
            ;;
    esac
 
    for INCL in $($cmd "^include " $MAP | cut -d' ' -f2 | tr -d '"'); do
        for FN in $(find /lib/kbd/keymaps -type f -name $INCL\*); do
            findkeymap $FN
        done
    done
}
 
if [ $ncryptodevs -ne 0 ]; then
    inst /sbin/cryptsetup "$MNTIMAGE/sbin/cryptsetup"
 
    KEYTABLE=
    KEYMAP=
    LOADKEYS=
    if [ -f /etc/sysconfig/console/default.kmap ]; then
        KEYMAP=/etc/sysconfig/console/default.kmap
    else
        if [ -f /etc/sysconfig/keyboard ]; then
            . /etc/sysconfig/keyboard
        fi
        if [ -n "$KEYTABLE" -a -d "/lib/kbd/keymaps" ]; then
            KEYMAP="$KEYTABLE.map"
        fi
    fi
 
    if [ -n "$KEYMAP" -a -x /bin/loadkeys.static ]; then
        LOADKEYS=loadkeys
        if [ -f /etc/sysconfig/i18n ]; then
            . /etc/sysconfig/i18n
        fi
        if [ "${LANG}" != "${LANG%%.UTF-8}" -o "${LANG}" != "${LANG%%.utf8}" ]; then
            LOADKEYS="loadkeys -u"
        fi
 
        inst /bin/loadkeys.static "$MNTIMAGE/bin/loadkeys"
        findkeymap $KEYMAP
 
        for FN in $KEYMAPS; do
            inst $FN "$MNTIMAGE$FN"
            case "$FN" in
                *.gz)
                    gzip -d "$MNTIMAGE$FN"
                    ;;
                *.bz2)
                    bzip2 -d "$MNTIMAGE$FN"
                    ;;
            esac
        done
    else
        vecho "Not including any keymaps"
    fi
fi
 
echo -n >| $RCFILE
cemit << EOF
#!/bin/nash
 
mount -t proc /proc /proc
setquiet
echo Mounting proc filesystem
echo Mounting sysfs filesystem
mount -t sysfs /sys /sys
echo Creating /dev
mount -o mode=0755 -t tmpfs /dev /dev
mkdir /dev/pts
mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts
mkdir /dev/shm
mkdir /dev/mapper
echo Creating initial device nodes
mknod /dev/null c 1 3
mknod /dev/zero c 1 5
mknod /dev/systty c 4 0
mknod /dev/tty c 5 0
mknod /dev/console c 5 1
mknod /dev/ptmx c 5 2
mknod /dev/rtc c 10 135
EOF
if [ "$(uname -m)" == "ia64" ]; then
    emit "mknod /dev/efirtc c 10 136"
fi
 
# XXX really we need to openvt too, in case someting changes the
# color palette and then changes vts on fbcon before gettys start.
# (yay, fbcon bugs!)
if ! echo "$(uname -m)" | grep -q "s390"; then 
    for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 ; do
        emit "mknod /dev/tty$i c 4 $i"
    done
fi
 
for i in 0 1 2 3 ; do
    emit "mknod /dev/ttyS$i c 4 $(($i + 64))"
done
 
emit "echo Setting up hotplug."
emit "hotplug"
 
emit "echo Creating block device nodes."
emit "mkblkdevs"
 
usb_mounted="prep"
scsi=""
for MODULE in $MODULES; do
    text=""
 
    if [[ "$MODULE" =~ "^iscsi_device_" ]] ; then
        emit_iscsi_device "${MODULE##iscsi_device_}"
        continue
    elif [[ "$MODULE" =~ "^network_device_" ]] ; then
netdev="${MODULE##network_device_}"
        emit "echo Bringing up $netdev"
        handlenetdev "$netdev"
if [ -n "$prenetwork" ]; then
            emit $prenetwork
        fi
        emit $network
        if [ -n "$postnetwork" ]; then
            emit $postnetwork
        fi
        continue
    fi
 
    module=`echo $MODULE | sed -e "s|.*/||" -e "s/.k\?o$//"`
    fullmodule=`echo $MODULE | sed "s|.*/||"`
 
    options=`sed -n -e ':a' -e '/\\\\$/N; s/\\\\\n//; ta' -e "s/^options[ ][ ]*$module[ ][ ]*//p" $modulefile 2>/dev/null`
    
    if [ -n "$options" ]; then
        vecho "Adding module $module$text with options $options"
    else
        vecho "Adding module $module$text"
    fi
 
    # we mount usbfs before the first module *after* the HCDs
    if [ "$usb_mounted" == "prep" ]; then
        if [[ "$module" =~ ".hci[_-]hcd" ]]; then
            usb_mounted="no"
        fi
    elif [ "$usb_mounted" == "no" ]; then
        if [[ ! "$module" =~ ".hci[_-]hcd" ]]; then
            usb_mounted=yes
            emit "mount -t usbfs /proc/bus/usb /proc/bus/usb"
        fi
    fi
 
    emit "echo \"Loading $fullmodule module\""
    emit "insmod /lib/$fullmodule $options"
        
    # Hack - we need a delay after loading usb-storage to give things
    #        time to settle down before we start looking a block devices
    if [ "$module" = "usb-storage" -o "$module" = "ub" ]; then
emit "echo Waiting for driver initialization."
emit "stabilized /proc/bus/usb/devices"
    fi
    if [ "$module" = "sbp2" ]; then
emit "echo Waiting for driver initialization."
emit "stabilized /sys/bus/ieee1394/drivers/sbp2"
    fi
    if [ "$module" = "scsi_mod" ]; then
scsi="yes"
    fi
    if [ "$module" = "zfcp" -a -f /etc/zfcp.conf ]; then
        emit "echo Waiting 2 seconds for driver initialization."
        emit "sleep 2"
        cat /etc/zfcp.conf | grep -v "^#" | tr "A-Z" "a-z" | while read DEVICE TWO THREE FOUR FIVE; do
   if [ -z "$FIVE" ]; then
WWPN=$TWO
FCPLUN=$THREE
   else
WWPN=$THREE
FCPLUN=$FIVE
   fi
   cemit <<EOF 
echo -n $WWPN > /sys/bus/ccw/drivers/zfcp/${DEVICE/0x/}/port_add
echo -n $FCPLUN > /sys/bus/ccw/drivers/zfcp/${DEVICE/0x/}/$WWPN/unit_add
echo -n 1 > /sys/bus/ccw/drivers/zfcp/${DEVICE/0x/}/online
EOF
        done
    fi
done
unset usb_mounted
 
if [ -n "$scsi" ]; then
    emit "echo Waiting for driver initialization."
    emit "stabilized --hash --interval 1000 /proc/scsi/scsi"
fi
 
# HACK: module loading + device creation isn't necessarily synchronous...
# this will make sure that we have all of our devices before trying
# things like RAID or LVM
emit "mkblkdevs"
 
#if [ -n "$vg_list" ]; then
#    emit "echo Making device-mapper control node"
#    emit "mkdmnod"
#fi
 
if [ "$use_multipath" == "1" ]; then
    emit "echo Creating multipath devices"
    emit "/bin/multipath -v 0"
    if [ "$use_xdr" == "1" ]; then
    emit "echo Setting up XDR dm device"
    emit "/bin/multipath -v 0"
    fi
    emit "dmsetup ls --target multipath --exec 'kpartx -a -p p'"
fi
 
if [ "$withdmraid" == "1" ]; then
    emit "echo Scanning and configuring dmraid supported devices"
    for x in $(/sbin/dmraid.static -ay -i -p -t 2>/dev/null | \
               egrep -iv "^no " | awk -F ':' '{ print $1 }') ; do
        dmname=$(resolve_dm_name $x)
        [ -z "$dmname" ] && continue
        emit "dmraid -ay -i -p \"$dmname\""
        emit "kpartx -a -p p \"/dev/mapper/$dmname\""
    done
fi
 
emitcrypto()
{
    emit "echo Setting up disk encryption: $1"
    emit "cryptsetup luksOpen $1 $2"
}
 
if [ -n "$KEYMAP" -a -n "$LOADKEYS" ]; then
    emit "echo Loading keymap."
    emit "$LOADKEYS $KEYMAP"
fi
 
for cryptdev in ${!cryptopart@} ; do
    emitcrypto `eval echo '$'$cryptdev`
done
 
if [ -n "$raiddevices" ]; then
    for dev in $raiddevices; do
        cp -a /dev/${dev} $MNTIMAGE/dev
        emit "raidautorun /dev/${dev}"
    done
fi
 
for cryptdev in ${!cryptoraid@} ; do
    emitcrypto `eval echo '$'$cryptdev`
done
 
if [ -n "$vg_list" ]; then
    emit "echo Scanning logical volumes"
    emit "lvm vgscan --ignorelockingfailure"
    emit "echo Activating logical volumes"
    emit "lvm vgchange -ay --ignorelockingfailure $vg_list"
fi
 
for cryptdev in ${!cryptolv@} ; do
    emitcrypto `eval echo '$'$cryptdev`
done
 
if [ -z "$noresume" -a -n "$swsuspdev" ]; then
    emit "resume $swsuspdev"
fi
 
if [ -n "$loopfs" ]; then
    emit "echo Mounting loop backing store."
    emit "mkdir /tmpmount"
    emit "mount -t $loopfs -o ${loopopts:-defaults} $loopdev /tmpmount"
    emit "echo Creating loop device."
    emit "losetup /dev/loop0 /tmpmount/$looppath"
fi
 
emit "echo Creating root device."
# mkrootdev does "echo /dev/root /sysroot ext3 defaults,ro 0 0 >/etc/fstab"
emit "mkrootdev -t $rootfs -o $rootopts $rootdev"
rootdev=/dev/root
 
emit "echo Mounting root filesystem."
emit "mount /sysroot"
 
if [ -n "$loopfs" ]; then
     emit "Cleaning up loop mount."
     emit "umount /tmpmount"
fi
 
emit "echo Setting up other filesystems."
emit "setuproot"
 
for dev in $DHCPDEVS ; do
    emit "echo Copying DHCP lease for $dev"
    emit "cp /var/lib/dhclient/dhclient-$dev.leases /sysroot/dev/.dhclient-$dev.leases"
done
 
emit "echo Switching to new root and running init."
emit "switchroot"
 
chmod +x $RCFILE
 
(cd $MNTIMAGE; findall . | cpio --quiet -c -o) >| $IMAGE || exit 1
 
if [ -n "$compress" ]; then
    gzip -9 < $IMAGE >| $target || rc=1
else
    cp -a $IMAGE $target || rc=1
fi
rm -rf $MNTIMAGE $IMAGE
if [ -n "$MNTPOINT" ]; then rm -rf $MNTPOINT ; fi
 
exit $rc
 
# vim:ts=8:sw=4:sts=4:et

 

 

No comments: