Updating Hyper-V drivers after a kernel upgrade on CentOS

Dec 26 2009

A few days ago I was updating a CentOS machine that happens to be running on Microsoft's Hyper-V platform. Everything went very smooth. So I tried to reboot the machine, because I wanted to make sure that everything worked fine after a reboot.

The reboot

Apparently the kernel was updated too and the system did not boot with the new kernel. Since I have no access to the Hyper V environment itself, I needed to call my hosting provider (I only have shell access to the server). The restarted the machine and chose to boot the old kernel (which still worked). This was only a temporary solution because after a reboot the machine would still try to boot the new kernel.

Linux Integration Components

After some investigation I found out that I needed to install the Linux Integration Components for Hyper-V in the new kernel. It turns out that these integration components must be installed for each kernel that you want to boot into. There is one problem however, the integration components will only be installed in the currently running kernel by default. Since I have no access to the Hyper V environment and the machine has no ethernet connection without the components, I needed to find another way to install the components into the new kernel. I called my hosting provider again and they wanted to help me, but they would charge me around € 90,- for this (simple) task. I decided to find another solution myself.

Installing the Linux Integration Components into a non-running kernel

There are a few good tutorials for installing the Linux Integration Components in the currently running kernel, but I couldn't find proper documentation. It turns out that the scripts (and makefiles) that install the components make intensive use of the "uname -r" command to find out for which kernel the integration components should be installed. This means taht by default it's not possible to install the components into another kernel. I found the following solution:

  • Create a checkpoint for your Hyper-V machine (if you can), so that you can always restore the machine to the current state in case something goes wrong.
  • Find the kernel that you want to boot in by listing the installed kernels.
    rpm -q kernel
  • In my case I got the following output:
    kernel-2.6.18-128.el5
    kernel-2.6.18-128.7.1.el5
    kernel-2.6.18-164.9.1.el5
    
    In my case the running kernel was "2.6.18-128.7.1.el5" and I wanted to boot into the newest kernel "2.6.18-164.9.1.el5".
  • Backup your linux integration components setup directory:
    cp -R Linux_IC_V2 Linux_IC_V2-backup
    And change directory to the Linux integration components setup directory (in my case the components are installed in /root/Linux_IC_V2):
    cd Linux_IC_V2
  • The setup script assumes that you've already booted the new kernel when you are installing the new drivers. I think that it would be a lot easier if the kernel version could be passed as an argument to the script. But this is not the case so we need to adjust some files in the setup directory, you can find out which files need to be changed by using grep:
    grep -iR "uname -r" *
    In my case the following files where found:
    drivers/dist/blkvsc/Makefile
    drivers/dist/blkvsc/Makefile
    drivers/dist/vmbus/Makefile
    drivers/dist/vmbus/Makefile
    drivers/dist/tools/scripts/updategrub.pl
    drivers/dist/tools/scripts/updateinitrd.p
    drivers/dist/Makefile
    drivers/dist/Makefile
    drivers/dist/Makefile
    drivers/dist/storvsc/Makefile
    drivers/dist/storvsc/Makefile
    drivers/dist/netvsc/Makefile
    drivers/dist/netvsc/Makefile
    drivers/dist/makefile.common
    setup.pl
    
  • Now we need to edit all those files (you can use your favorite editor) and make sure that we replace "uname -r" with the new kernel version. So in my case I replaced
    shell uname -r
    with:
    shell echo "2.6.18-164.9.1.el5"
    in the Makefiles. And in the perl scripts you can replace
    `uname -r`
    with:
    "2.6.18-164.9.1.el5"
  • Now it is time to install the integration components in the kernel:
    ./setup.pl drivers
  • If the previous step was successful, we can check /boot/grub/menu.lst to make sure that we are booting the new kernel on reboot.
  • We should now be able to boot into the new kernel!
    reboot

I hope this post was useful for you, because I have spent quite some hours tackling this specific problem. I have learned a lot about the Hyper-V platform in those hours though...

7 Responses to "Updating Hyper-V drivers after a kernel upgrade on CentOS" Feed for this Entry

  1. Oleg says:

    Joris,
    Your solution is great, but… it didn’t work for me.
    Am I missing something?

    # rpm -q kernel
    -----------------------
    kernel-2.6.18-164.6.1.el5
    kernel-2.6.18-164.11.1.el5

    #uname –r
    2.6.18-164.6.1.el5

    # alias uname='~/uname.sh'
    # uname -r
    2.6.18-164.11.1.el5

    # ./updateinitrd.pl
    2.6.18-164.6.1.el5

    Where updateinitrd.pl
    ----------------
    #!/usr/bin/env perl
    my $kernel_ver = `uname -r`;
    print "\t$kernel_ver\n";
    ----------------

    How did you manage to export alias?
    Oleg

  2. Joris van de Sande says:

    Oleg,

    At the moment I am at work and cannot test your code.

    You can also change all occurences of `uname -r` to the name of your new kernel (kernel-2.6.18-164.11.1.el5) in all files in the Linux Integration package. Make sure that you backup the files of the package first, so that you can always revert to the original files.

    I hope it works for you too. This is how I did it the first time. If you need any more help, don't hesitate to ask me!

  3. Ken says:

    This just simply doesn't work for me. The solution makes perfect sense and I have the aliased uname -r working fine. However, when Perl goes to parse the file, it calls the binary directly and bypasses the alias on my system. I don't know if there is a perl setting that can be changed somewhere to make this work?

  4. Roland says:

    Here's what worked for me...

    Rename /bin/uname to /bin/uname.orig

    Create new file /bin/uname with the following content:

    #!/usr/bin/perl -w if (@ARGV print "2.6.18-164.15.1.el5\n"; } else { print `/bin/uname.orig @ARGV`; }

    Replace the the kernel version as required in the perl script.

    Then run your "./setup.pl drivers" as needed.

    After you're done remove /bin/uname and move /bin/uname.orig back to /bin/uname

    There may be more elegant solutions, but this beats having to edit all the driver files.

  5. Angel Abad Cerdeira says:

    Replacing the default "uname" is a very good idea, I got it like this:

    #!/usr/bin/perl -w

    if ($ARGV[0] eq "-r") {
    print "2.6.18-194.3.1.el5\n";
    }
    else {
    print `/bin/uname.org @ARGV`;
    }

  6. Joe says:

    Many, many thanks! This really saved the day for me!

  7. Jørn-Morten says:

    Fixed in http://support.microsoft.com/kb/2387594