[PATCH 2/2] reIPL support for s390 (#512195).

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Mark Hamzy <hamzy@xxxxxxxxxx>

Basically this is a back-port of d00ef216099104c03c400f56fb21e19089df4a7d.
For those not capable of reading huge hashes, the previous sentence
means this patch brings the RHEL 5.5 reIPL support in line with what we
currently have upstream in both Fedora and RHEL-6 for rebooting (err, I
mean re-"IPL"ing) s390x VMs after installation.
---
 anaconda               |   10 +++
 dispatch.py            |    3 +
 installclass.py        |    1 +
 iutil.py               |  178 ++++++++++++++++++++++++++++++++++++++++++++++++
 iw/congrats_gui.py     |   13 +++-
 loader2/linuxrc.s390   |   28 +-------
 loader2/loader.c       |   44 +++++++-----
 packages.py            |   22 ++++++
 textw/complete_text.py |    9 ++-
 upgradeclass.py        |    1 +
 10 files changed, 263 insertions(+), 46 deletions(-)

diff --git a/anaconda b/anaconda
index 82f8ad0..ca23c11 100755
--- a/anaconda
+++ b/anaconda
@@ -480,6 +480,8 @@ class Anaconda:
         self.rescue_mount = True
         self.rescue = False
         self.updateSrc = None
+        self.canReIPL = False
+        self.reIPLMessage = None
 
     def setDispatch(self):
         self.dispatch = dispatch.Dispatcher(self)
@@ -988,3 +990,11 @@ if __name__ == "__main__":
             isys.ejectCdrom(drive)
 
     del anaconda.intf
+
+    if rhpl.getArch() in ['s390', 's390x']:
+        if anaconda.canReIPL:
+            log.info("reipl configuration successful => reboot")
+            os.kill(os.getppid(), signal.SIGUSR2)
+        else:
+            log.info("reipl configuration failed => halt")
+            os.kill(os.getppid(), signal.SIGUSR1)
diff --git a/dispatch.py b/dispatch.py
index ddf7885..8c86677 100644
--- a/dispatch.py
+++ b/dispatch.py
@@ -42,6 +42,8 @@ from backend import doPostSelection, doRepoSetup, doBasePackageSelect
 from backend import doPreInstall, doPostInstall, doInstall
 from backend import writeConfiguration
 
+from packages import doReIPL
+
 import logging
 log = logging.getLogger("anaconda")
 
@@ -82,6 +84,7 @@ installSteps = [
     ("bootloadersetup", bootloaderSetupChoices, ),
     ("bootloader", ),
     ("bootloaderadvanced", ),
+    ("reipl", doReIPL, ),
     ("networkdevicecheck", networkDeviceCheck, ),
     ("network", ),
     ("timezone", ),
diff --git a/installclass.py b/installclass.py
index a1fd556..9a34363 100644
--- a/installclass.py
+++ b/installclass.py
@@ -142,6 +142,7 @@ class BaseInstallClass:
 		 "partitiondone",
 		 "bootloadersetup",                 
 		 "bootloader",
+                 "reipl",
                  "networkdevicecheck",
 		 "network",
 		 "timezone",
diff --git a/iutil.py b/iutil.py
index 289f5c7..8b3e6b9 100644
--- a/iutil.py
+++ b/iutil.py
@@ -14,12 +14,16 @@
 #
 
 import os, isys, string, stat
+import signal
 import os.path
 from errno import *
 import rhpl
 import warnings
 import subprocess
 from flags import flags
+from constants import *
+from rhpl.translate import _
+import re
 
 import logging
 log = logging.getLogger("anaconda")
@@ -529,4 +533,178 @@ def getScsiDeviceByWwpnLunid(wwpn, lunid):
         tgt = ""
     return tgt
 
+def writeReiplMethod(reipl_path, reipl_type):
+    filename = "%s/reipl_type" % (reipl_path,)
 
+    try:
+        f = open(filename, "w")
+    except Exception, e:
+        message = "Error: On open, cannot set reIPL method to %s (%s: %s)" % (reipl_type,filename,e,)
+        log.warning(message)
+        raise Exception (message)
+
+    try:
+        f.write(reipl_type)
+        f.flush()
+    except Exception, e:
+        message = "Error: On write, cannot set reIPL method to %s (%s: %s)" % (reipl_type,filename,e,)
+        log.warning(message)
+        raise Exception (message)
+
+    try:
+        f.close()
+    except Exception, e:
+        message = "Error: On close, cannot set reIPL method to %s (%s: %s)" % (reipl_type,filename,e,)
+        log.warning(message)
+        raise Exception (message)
+
+def reIPLonCCW(iplsubdev, reipl_path):
+    device = "<unknown>"
+
+    try:
+        iplbits = re.split ('([0-9]+)', iplsubdev)
+        if len (iplbits) != 3:
+            message = "Error: %s splits into %s but not like we expect" % (iplsubdev,iplbits,)
+            log.warning(message)
+            raise Exception (message)
+
+        device = os.readlink("/sys/block/" + iplbits[0] + "/device").split('/')[-1]
+
+        writeReiplMethod(reipl_path, 'ccw')
+
+        try:
+            f = open("%s/ccw/device" % (reipl_path,), "w")
+            f.write(device)
+            f.close()
+        except Exception, e:
+            message = "Error: Could not set %s as reIPL device (%s)" % (device,e,)
+            log.warning(message)
+            raise Exception (message)
+
+        try:
+            f = open("%s/ccw/loadparm" % (reipl_path,), "w")
+            f.write("\n")
+            f.close()
+        except Exception, e:
+            message = "Error: Could not reset loadparm (%s)" % (e,)
+            log.warning(message)
+            raise Exception (message)
+
+        try:
+            f = open("%s/ccw/parm" % (reipl_path,), "w")
+            f.write("\n")
+            f.close()
+        except Exception, e:
+            message = "Warning: Could not reset parm (%s)" % (e,)
+            log.warning(message)
+            # do NOT raise an exception since this might not exist or not be writable
+
+    except Exception, e:
+        try:
+            message = e.args[0]
+        except:
+            message = e.__str__ ()
+        return (message,
+                (_("After shutdown, please perform a manual IPL from DASD device %s to continue "
+                   "installation") % (device,)))
+
+    return None
+
+def reIPLonFCP(iplsubdev, reipl_path):
+    fcpvalue = { "device": "<unknown>", "wwpn": "<unknown>", "lun": "<unknown>" }
+
+    try:
+        iplbits = re.split ('([0-9]+)', iplsubdev)
+        if len (iplbits) != 3:
+            message = "Error: %s splits into %s but not like we expect" % (iplsubdev,iplbits,)
+            log.warning(message)
+            raise Exception (message)
+
+        syspath = "/sys/block/" + iplbits[0] + "/device"
+
+        fcpprops = [ ("hba_id", "device"), ("wwpn", "wwpn"), ("fcp_lun", "lun") ]
+
+        # Read in values to change.
+        # This way, if we can't set FCP mode, we can tell the user what to manually reboot to.
+        for (syspath_property, reipl_property) in fcpprops:
+            try:
+                f = open(syspath + "/" + syspath_property, "r")
+                value = f.read().strip()
+                fcpvalue[reipl_property] = value
+                f.close()
+            except Exception, e:
+                message = "Error: reading FCP property %s for reIPL (%s)" % (syspath_property,e,)
+                log.warning(message)
+                raise Exception (message)
+
+        writeReiplMethod(reipl_path, 'fcp')
+
+        # Write out necessary parameters.
+        for (syspath_property, reipl_property) in fcpprops:
+            try:
+                f = open("%s/fcp/%s" % (reipl_path, reipl_property,), "w")
+                f.write(fcpvalue[reipl_property])
+                f.close()
+            except Exception, e:
+                message = "Error: writing FCP property %s for reIPL (%s)" % (reipl_property,e,)
+                log.warning(message)
+                raise Exception (message)
+
+        defaultprops = [ ("bootprog", "0"), ("br_lba", "0") ]
+
+        # Write out default parameters.
+        for (reipl_property, default_value) in defaultprops:
+            try:
+                f = open("%s/fcp/%s" % (reipl_path, reipl_property,), "w")
+                f.write (default_value)
+                f.close()
+            except Exception, e:
+                message = "Error: writing default FCP property %s for reIPL (%s)" % (reipl_property,e,)
+                log.warning(message)
+                raise Exception (message)
+
+    except Exception, e:
+        try:
+            message = e.args[0]
+        except:
+            message = e.__str__ ()
+        return (message,
+                (_("After shutdown, please perform a manual IPL from FCP %(device)s with WWPN %(wwpn)s "
+                   "and LUN %(lun)s to continue installation") % (fcpvalue)))
+
+    return None
+
+def reIPL(anaconda, loader_pid):
+    instruction = _("After shutdown, please perform a manual IPL from the device "
+                    "now containing /boot to continue installation")
+
+    reipl_path = "/sys/firmware/reipl"
+
+    iplfs = anaconda.id.fsset.getEntryByMountPoint("/boot")
+    if iplfs is None:
+        iplfs = anaconda.id.fsset.getEntryByMountPoint("/")
+
+    if iplfs is None:
+        message = _("Could not get information for mount point /boot or /")
+        log.warning(message)
+        return (message, instruction)
+
+    try:
+        ipldev = iplfs.device.device
+    except:
+        ipldev = None
+
+    if ipldev is None:
+        message = _("Error determining mount point type")
+        log.warning(message)
+        return (message, instruction)
+
+    message = (_("The mount point /boot or / is on a disk that we are not familiar with"), instruction)
+    if ipldev.startswith("dasd"):
+        message = reIPLonCCW(ipldev, reipl_path)
+    elif ipldev.startswith("sd"):
+        message = reIPLonFCP(ipldev, reipl_path)
+
+    # the final return is either None if reipl configuration worked (=> reboot),
+    # or a two-item list with errorMessage and rebootInstr (=> shutdown)
+    return message
diff --git a/iw/congrats_gui.py b/iw/congrats_gui.py
index 3cf9ffb..32c12ab 100644
--- a/iw/congrats_gui.py
+++ b/iw/congrats_gui.py
@@ -34,8 +34,10 @@ class CongratulationWindow (InstallWindow):
         # this mucks around a bit, but it's the weird case and it's
         # better than adding a lot of complication to the normal
 	ics.cw.mainxml.get_widget("nextButton").hide()
-	ics.cw.mainxml.get_widget("rebootButton").show()
-	ics.cw.mainxml.get_widget("rebootButton").grab_focus()
+
+	self.rebootButton = ics.cw.mainxml.get_widget("rebootButton")
+	self.rebootButton.show()
+	self.rebootButton.grab_focus()
 
     def getNext(self):
 	# XXX - copy any screenshots over
@@ -54,8 +56,13 @@ class CongratulationWindow (InstallWindow):
             hbox.pack_start (a, False, False, 36)
 
         bootstr = ""
-        if rhpl.getArch() == "s390":
+        if rhpl.getArch() in ['s390', 's390x']:
             floppystr = ""
+            if not anaconda.canReIPL:
+                self.rebootButton.set_label(_("Shutdown"))
+            if not anaconda.reIPLMessage is None:
+                floppystr = anaconda.reIPLMessage
+
         else:
             floppystr = _("Remove any media used during the installation "
                           "process and press the \"Reboot\" button to "
diff --git a/loader2/linuxrc.s390 b/loader2/linuxrc.s390
index 2856f96..fae5187 100644
--- a/loader2/linuxrc.s390
+++ b/loader2/linuxrc.s390
@@ -83,35 +83,13 @@ function checkipv4()
 
 function doshutdown()
 {
+    echo $"about to exec shutdown"
     exec /sbin/shutdown
     exit 0
 }
 
 function doreboot()
 {
-    # find out the location of /boot and use it to re-ipl
-    boot="$(cat /proc/mounts | grep " /mnt/sysimage/boot " | awk -F" " '{print $1}')"
-    if [ -z $boot ]; then
-        # use root if /boot not used
-        boot="$(cat /proc/mounts | grep " /mnt/sysimage " | awk -F" " '{print $1}')"
-    fi
-
-    # lookup dasd disk
-    echo $boot | grep "dasd" > /dev/null
-    if [ $? -eq 0 ]; then
-        type="ccw"
-        boot="$(basename $boot)"
-        # strip partition number from dasd device
-        boot="$(echo ${boot%[0-9]})"
-        id="$(basename $(readlink /sys/block/$boot/device))"
-        echo $type > /sys/firmware/reipl/reipl_type
-        echo $id > /sys/firmware/reipl/$type/device
-    else
-        # scsi re-ipl only supported on newer machines
-        doshutdown
-        exit 0
-    fi
-
     echo $"about to exec shutdown -r"
     exec /sbin/shutdown -r
     exit 0
@@ -3149,7 +3127,9 @@ EOF
         /sbin/loader
     fi
 
-    doreboot
+    # A shutdown needs to be performed here to avoid a loop booting back into the installer
+    echo $"Finishing up with doshutdown"
+    doshutdown
 
 fi # testing
 
diff --git a/loader2/loader.c b/loader2/loader.c
index 4299ab3..5ef268b 100644
--- a/loader2/loader.c
+++ b/loader2/loader.c
@@ -118,6 +118,8 @@ uint64_t flags = LOADER_FLAGS_SELINUX | LOADER_FLAGS_NOFB;
 int num_link_checks = 5;
 int post_link_sleep = 0;
 
+static pid_t init_pid = 1;
+
 static struct installMethod installMethods[] = {
     { N_("Local CDROM"), "cdrom", 0, CLASS_CDROM, mountCdromImage },
     { N_("Hard drive"), "hd", 0, CLASS_HD, mountHardDrive },
@@ -1384,6 +1386,11 @@ void loaderSegvHandler(int signum) {
     exit(1);
 }
 
+void loaderUsrXHandler(int signum) {
+    logMessage(INFO, "Sending signal %d to process %d\n", signum, init_pid);
+    kill(init_pid, signum);
+}
+
 static int anaconda_trace_init(void) {
 #if 0
     int fd;
@@ -1455,6 +1462,26 @@ int main(int argc, char ** argv) {
         { 0, 0, 0, 0, 0, 0, 0 }
     };
 
+    /* get init PID if we have it */
+    if ((f = fopen("/var/run/init.pid", "r")) != NULL) {
+        char linebuf[256];
+        memset(linebuf, '\0', sizeof(linebuf));
+
+        while (fgets(linebuf, sizeof(linebuf) - 1, f) != NULL) {
+            errno = 0;
+            init_pid = strtol((const char *) &linebuf, NULL, 10);
+            if (errno == EINVAL || errno == ERANGE) {
+                logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+                init_pid = 1;
+            }
+        }
+
+        fclose(f);
+    }
+
+    signal(SIGUSR1, loaderUsrXHandler);
+    signal(SIGUSR2, loaderUsrXHandler);
+
     /* Make sure sort order is right. */
     setenv ("LC_COLLATE", "C", 1);	
 
@@ -1952,23 +1979,6 @@ int main(int argc, char ** argv) {
             waitpid(pid, &status, 0);
         }
 
-#if defined(__s390__) || defined(__s390x__)
-        /* FIXME: we have to send a signal to linuxrc on s390 so that shutdown
-         * can happen.  this is ugly */
-        FILE * f;
-        f = fopen("/var/run/init.pid", "r");
-        if (!f) {
-            logMessage(WARNING, "can't find init.pid, guessing that init is pid 1");
-            pid = 1;
-        } else {
-            char * buf = malloc(256);
-            char *ret;
-
-            ret = fgets(buf, 256, f);
-            pid = atoi(buf);
-        }
-        kill(pid, SIGUSR2);
-#endif
         stop_fw_loader(&loaderData);
         return rc;
     }
diff --git a/packages.py b/packages.py
index c05f5fa..a1a6e56 100644
--- a/packages.py
+++ b/packages.py
@@ -409,3 +409,25 @@ def selectLanguageSupportGroups(grpset, instLanguage):
 
     if grp.usecount > 0:
         grpset.groups["language-support"].select()
+
+def doReIPL(anaconda):
+    if not rhpl.getArch() in ['s390', 's390x']:
+        return DISPATCH_NOOP
+
+    messageInfo = iutil.reIPL(anaconda, os.getppid())
+
+    # @TBD seeing a bug here where anaconda.canReIPL and anaconda.reIPLMessage are
+    # not initialized even though they were in Anaconda.__init__()
+    if messageInfo is None:
+        anaconda.canReIPL = True
+
+        anaconda.reIPLMessage = None
+    else:
+        anaconda.canReIPL = False
+
+        (errorMessage, rebootInstr) = messageInfo
+
+        # errorMessage intentionally not shown in UI
+        anaconda.reIPLMessage = rebootInstr
+
+    return DISPATCH_FORWARD
diff --git a/textw/complete_text.py b/textw/complete_text.py
index 0eeae37..6ada0b9 100644
--- a/textw/complete_text.py
+++ b/textw/complete_text.py
@@ -22,10 +22,15 @@ class FinishedWindow:
   
   def __call__ (self, screen, anaconda):
         bootstr = ""
+        buttonstr = _("Reboot")
 
-        if rhpl.getArch() == "s390":
+        if rhpl.getArch() in ['s390', 's390x']:
           floppystr = _("Press <Enter> to end the installation process.\n\n")
           bottomstr = _("<Enter> to exit")
+          if not anaconda.canReIPL:
+            buttonstr = _("Shutdown")
+          if not anaconda.reIPLMessage is None:
+            floppystr = anaconda.reIPLMessage + "\n\n" + floppystr
         else:
           floppystr = _("Remove any media used during the installation "
                         "process and press <Enter> to reboot your system."
@@ -44,6 +49,6 @@ class FinishedWindow:
                 "http://www.redhat.com/docs/.";) %(productName,)
 
         rc = ButtonChoiceWindow (screen, _("Complete"), txt,
-                                 [ _("Reboot") ], help = "finished", width=60)
+                                 [ buttonstr ], help = "finished", width=60)
 
         return INSTALL_OK
diff --git a/upgradeclass.py b/upgradeclass.py
index 107ad61..121cce5 100644
--- a/upgradeclass.py
+++ b/upgradeclass.py
@@ -43,6 +43,7 @@ class InstallClass(baseclass):
                     "upgradecontinue",
                     "reposetup",
                     "upgbootloader",
+                    "reipl",
                     "checkdeps",
 		    "dependencies",
 		    "confirmupgrade",
-- 
1.6.5.5

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list

[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux