Tuesday, November 27, 2012

IPMI SOL, newer AMI BIOS, and CentOS 6

SOL means "serial over LAN", but there are some similarities to the more popular interpretation. Here's the combination to get everything working with newer American Megatrends Inc. BIOSs.  First, set up the BIOS by enabling the "Serial Port for Out-of-Band Management/Windows Emergency Management Services (EMS)":
You don't need to customize anything in the Settings, but here's a screenshot anyway:
CentOS (well, and Redhat) 6 changed the configuration of serial ports from using /etc/inittab to using files in /etc/init.  So, create a /etc/init/ttyS1.conf that contains:
# ttyS1 - agetty
#
# This service maintains a agetty on ttyS1.

stop on runlevel [S016]
start on runlevel [23]

respawn
exec agetty /dev/ttyS1 19200 vt102
Do a "initctl start ttyS1" to start the getty.  Add ttyS1 to /etc/sercuretty if you want to allow root logins on that port (that bit didn't change).  You should then be able to use ipmitool for all your SOL needs.

Device br0 does not seem to be present, delaying initialization.

I recently received this error on a CentOS Linux machine handed off to me. A bit of a head scratcher. Getting on the console and running ifup by hand looked like:
# bash -x ./ifup-eth ifcfg-br0
+ . /etc/init.d/functions
++ TEXTDOMAIN=initscripts
++ umask 022
++ PATH=/sbin:/usr/sbin:/bin:/usr/bin
++ export PATH
++ '[' -z '' ']'
++ COLUMNS=80
++ '[' -z '' ']'
+++ /sbin/consoletype
++ CONSOLETYPE=pty
[...] The interesting part showed up a little later:
+ CONFIG=ifcfg-ifcfg-br0
+ '[' -f ifcfg-ifcfg-br0 ']'
+ CONFIG=ifcfg-br0
+ '[' -f ifcfg-br0 ']'
+ return
+ source_config
+ CONFIG=ifcfg-br0
+ DEVNAME=br0
+ . /etc/sysconfig/network-scripts/ifcfg-br0
++ DEVICE=br0
++ ONBOOT=yes
++ TYPE=bridge
++ BOOTPROTO=static
++ IPADDR=128.117.26.2
++ NETMASK=255.255.255.0
++ NM_CONTROLLED=no
+ '[' -r keys-br0 ']'
The eagle-eyed will have already spotted the error, the following helps the rest of us:
+ alias=
+ '[' 1 -eq 0 ']'
+ return 2
+ '[' -n '' ']'
+ '[' bridge = Bridge ']'
+ '[' bridge = Tap ']'
+ is_available br0
+ '[' -z br0 ']'
+ '[' -d /sys/class/net/br0 ']'
+ '[' -n '' ']'
++ modprobe -c
++ awk 'BEGIN { alias = ""; }
$1 == "alias" && $2 == "br0" { alias = $3; }
$1 == "install" { install[$2] = $3; }
END {
    cmd = install[alias];
    print alias;
    if (alias == "" || alias == "off" || cmd == "/bin/true" || cmd == ":")
        exit 1;
    exit 0;
}'
+ alias=
+ '[' 1 -eq 0 ']'
+ return 2
+ '[' -n '' ']'
+ net_log 'Device br0 does not seem to be present, delaying initialization.'
+ local 'message=Device br0 does not seem to be present, delaying initialization.'
+ local level=
+ local name=
+ '[' -z 'Device br0 does not seem to be present, delaying initialization.' ']'
+ '[' -z '' ']'
+ level=err
+ '[' -z '' ']'
+ name=./ifup-eth
+ echo Device br0 does not seem to be present, delaying initialization.
Device br0 does not seem to be present, delaying initialization.
+ '[' -x /usr/bin/logger ']'
+ /usr/bin/logger -p daemon.err -t ./ifup-eth 'Device br0 does not seem to be present, delaying initialization.'
+ return 0
+ exit 1
See the obvious "bridge = Bridge"? Well, maybe not if you're not at one with such things. Nonetheless, it takes a capital 'B' Bridge in /etc/sysconfig/network-scripts/ifcfg-br0

"Abyss" watch instructions translation

I saw a co-worker's "Abyss" watch from ThinkGeek and had to have one.  I ordered from Amazon, and here are the instructions for setting the time:
Note the completely made-up words.  Happily, the reverse side had instructions in Mandarin, and I have easy access to a native speaker/reader.  The instructions really are: tap face eight times and hold for three seconds to set the hours.  Hope this helps someone and hope that more companies employ better translators, or at least use google translate.

Friday, November 9, 2012

dd and the power of programming

I recently needed to extract part of a large (~8GB) file. The canonical method is to use dd. On a Linux system, the performance was abysmal. Here is the straight dd result.
# dd if=one.img of=two.img bs=1 skip=32768 count=8587192319
8587192319 bytes (8.6 GB) copied, 12442.3 s, 690 kB/s
That's 3.45 hours for those keeping track at home. Using /dev/shm helped.
# dd if=/dev/shm/one.img of=/dev/shm/two.img bs=1 skip=32768 count=8587192319
8587192319 bytes (8.6 GB) copied, 6232.88 s, 1.4 MB/s
That helped, but it's still 1.73 hours. Okay, so we all know the 1 byte block size is killing the performance. We also all know 8587192319 = 41809 205391, so let's bump up the block size.
# dd if=one.img of=two.img bs=205391 skip=32768 count=41809
9054+1 records in
9054+1 records out
1859682304 bytes (1.9 GB) copied, 1.59914 s, 1.2 GB/s
Clearly, much faster but also wrong: it should copy 8.6 GB. Let's reverse the numbers and try again.
# dd if=one.img of=two.img bs=41809 skip=32768 count=205391
172688+1 records in
172688+1 records out
7219937280 bytes (7.2 GB) copied, 29.4616 s, 245 MB/s
Closer, but still wrong. Something is wrong with dd's math. So, I wrote a Java program that takes an input file name, an output file name, and pairs of skip/write values. Here is the result.
# time java Chopper one.img two.img 32768 8587192319
Skipped 32768 bytes.
Writing 8587192319 bytes.

real    0m10.656s
user    0m1.744s
sys     0m8.933s
So, 10.7 seconds versus 3.45 hours. Here's the program.
/*
** Argrments: input file, output file, pairs of skip/write bytes
*/

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Chopper
{
    private static void readAndWrite (FileInputStream in, FileOutputStream out,
        long length)
    {
        /*
        ** Keep this sized to fit in an int for the read below.  Besides, 8K
        ** is a typical disk block size.
        */
        final long BUFFSIZE = 8192;
        byte buffer[] = new byte[(int) BUFFSIZE];

        for (;;)
        {
            int read = 0;
            int count = (int) (BUFFSIZE > length ? length : BUFFSIZE);

            try
            {
                read = in.read (buffer, 0, count);
                out.write (buffer, 0, read);
            }
            catch (IOException IOE)
            {
                System.out.println (IOE);
                return;
            }

            length -= read;

            if (length <= 0)
                break;
        }
    }

    public static void main (String args[])
    {
        FileInputStream in = null;
        FileOutputStream out = null;

        try
        {
            in = new FileInputStream (args[0]);
            out = new FileOutputStream (args[1]);
        }
        catch (IOException IOE)
        {
            System.out.println (IOE);
            return;
        }

        int i = 2;

        while (i < args.length)
        {
            try
            {
                long skipped = in.skip (Long.parseLong (args[i++]));
                System.out.println ("Skipped " + skipped + " bytes.");
            }
            catch (IOException IOE)
            {
                System.out.println (IOE);
                return;
            }

            long write = Long.parseLong (args[i++]);

            System.out.println ("Writing " + write + " bytes.");
            readAndWrite (in, out, write);
        }
    }
}