Showing posts with label linux. Show all posts
Showing posts with label linux. Show all posts

Wednesday, September 28, 2022

Multiple stage servers in open build service

 The open build service publisher has a configuration variable in BSConfig.pm, where you can define a rsync server to publish the built repos to.

Unfortunately, the documentation apart from the actual code (in src/backend/bs_publish function sync_to_stage) seems scarce, so let's document one non-standard usage here.

"Standard" (IMO) usage, one rsync staging server:

our $stageserver = 'rsync://my-rsync/obs-repos-module';

 But now, for a transition phase, I need multiple rsync servers that are all synced to. The format for this is a perl array variable reference that contains pairs of "project name regex, array of sync servers". This also allows to sync different repositories to different rsync servers for example.

The simplest use of this is "sync all repos to multiple rsync servers" and is configured like this:

our $stageserver = ['.*', ['rsync://rsync1/module1', 'rsync://rsync2/module2', 'rsync://rsync3/module3']];

 With this configuration, bs_publish will send all repos to the three mentioned rsync URLs in turn.

Sunday, February 13, 2022

Make Hibernation Great Again!

 I have now put the fixes from the last two blogposts into a github repository: https://github.com/seife/make-hibernate-great-again so that you can just clone it, examine what it does and then run

sudo make install

followed by

sudo dracut -f

This should do the following:

  • let resume actually work (by enabling the dracut resume module)
  • make hibernate more verbose (switch to an empty text console and increase the kernel's log level before hibernation, restore after resume)
  • make resume more verbose
Have fun!

I have also packaged it in obs://home:seife:testing, but I do not really advise to use this repo on anything but my own machines ;-) 

 

 


Friday, February 11, 2022

"hibernation fix" part 2: verbose resume

Now that I fixed hibernation to resume at all, I found another thing I had added to my old install long ago.
The "problem" is, that resume from hibernation is very quiet. So all you see is the GRUB messages "loading kernel", "loading initrd", then nothing, just the disk light may be blinking for quite some time, and if resume is successful, you'll see the unlock prompt of your screenlock.
That's a bit too little "user interface" for my taste.

The reason it is like this is, that the kernel's progress messages (in 10% steps) are printed with level "pr_info":

    if (!(nr_pages % m))
        pr_info("Image loading progress: %3d%%\n",
                                     nr_pages / m * 10);

But the default "quiet" boot suppresses KERN_INFO messages, which is good because without that, you cannot find the prompt for unlocking your crypted filesystems amongst all those KERN_INFO messages during boot... so how to fix it?

We can just adapt the systemd-hibernate-resume.service to increase the kernel log level just before starting to resume, via a dropin file in /etc/systemd/system/systemd-hibernate-resume.service.d/10-resume-verbose.conf:

[Service]
ExecStartPre=/bin/sh -c "echo 7 > /proc/sys/kernel/printk"
ExecStartPost=/bin/sh -c "echo 1 > /proc/sys/kernel/printk"

Also, add the file to your dracut config, so that it is actually included in the initrd:

install_items+=" /etc/systemd/system/systemd-hibernate-resume@.service.d/10-resume-verbose.conf "

now rebuild your initrd with "dracut -f" and enjoy :-)

Oh, and of course this only helps if you do not use things like plymouth which actually hide everything interesting during boot. Update 2022-02-12: it also works with plymouth, because image loading kicks in before plymouth can hide the interesting bits.

Wednesday, February 09, 2022

dracut: fix hibernate after fresh install

Just for fun, I finally installed a fresh Tumbleweed on one of my machines to actually find out if I'm missing out on new features that are masked by just always updating the old installation.

One feature that I had missed was, that hibernation was no longer working. Or, to be more exact, hibernation was working, but resume was not. Investigating the issue, I found that dracut's "resume" module was not included in the initramfs, which in turn lead to initramfs not even trying to resume.

The dracut mechanism has some logic to actually find out if suspend and resume is configured, and when it decides it is not, it will just skip adding the "useless" resume module.

Unfortunately, the check is faulty IMHO. It checks, if the resume device is configured in the kernel, and if it is, it adds the module to dracut. The problem is, that this kernel config is written by the resume code in the initrd... so during installation this is not the case, and as a result the module is not added to initrd, which leads to the config not being set on next reboot... 

The trivial fix is to call dracut once with the option to include the resume module:

dracut -a resume -f

After a reboot, the kernel config will be set and in the future the resume module will always be included in the initrd.
For an even saver setup, adding

add_dracutmodules+=" resume "

to /etc/dracut.conf.d/99-local.conf might be even better.

Of course I wanted to report a bug about the issue, then found out that there are plenty already:

Tuesday, January 05, 2021

Ethernet on the BananaPi M2 Zero

Even though it does not look like it does, the BPI-M2 Zero also has a wired ethernet interface. Unfortunately, it is disabled by default in its device tree blob.

But enabling it is easy:

# copy into /root
cp /boot/dtb/sun8i-h2-plus-bananapi-m2-zero.dtb .
# decompile
dtc -I dtb sun8i-h2-plus-bananapi-m2-zero.dtb \
    -O dts -o sun8i-h2-plus-bananapi-m2-zero.dts
# edit
vi sun8i-h2-plus-bananapi-m2-zero.dts # :-)
# compile
dtc -i dts sun8i-h2-plus-bananapi-m2-zero.dts \
    -O dtb -o /boot/custom.dtb
How do you need to edit the DTB file?

In the "ethernet@1c30000" block, you need to apply this "diff":

-       status = "disabled";
+       status = "okay";
+       phy-handle = <0x4d>;
+       phy-mode = "mii";
        phandle = <0x4b>;

The "phy-handle" value is taken from the "phandle" of the "ethernet-phy@1" block a few lines down. Then another change is adding an alias for ethernet0 to the "aliases" block:

       aliases { 

              serial0 = "/soc/serial@1c28000";
              serial1 = "/soc/serial@1c28400";
+             ethernet0 = "/soc/ethernet@1c30000";
       };

Ethernet will work without that, but we'll need this for setting the MAC address later.

Now reboot and try it out in a temporary way. Either by:

  • interrupting u-boot and doing setenv fdtfile custom.dtb (no "saveenv" yet!), then "boot"
  • editing the GRUB menu, adding an additional line after "initrd..." that reads devicetree /boot/custom.dtb
Check if the ethernet device eth0 appears after boot. If it does, the u-boot method can be persisted by issuing a saveenv command after the setenv.

Persisting the MAC address:
At my first tries I noticed that the MAC address was randomly assigned on every boot, in later experiments I could not reproduce this anymore but it looked like the MAC was at least reassigned on every deployment. I have no idea if this has to do with saving the environment in u-boot or if there is something in the userspace (a systemd service maybe?) that makes the MAC address semi-persistent. I decided to fix the MAC address once and for all, since I'm running a static DHCP setup, this is pretty important for my use case.

Because of the "ethernet0" alias in the device tree, persisting the MAC address is easy. All you need to do is setenv ethaddr 22:33:44:55:66:77 in u-boot and then persist this with saveenv and you are done. Note that u-boot has some precautions to disallow changing the MAC address later by accident so you are not able to easily undo this later. You can always remove "/boot/efi/uboot.env" in your booted system or by inserting the SD card into another machine and start from scratch.

Sunday, January 03, 2021

GRUB, u-boot, kernels and DTB loading (on the BPi M2 Zero and others)

While I was experimenting with the BananaPi M2 Zero board, I soon needed to adopt its device tree file (dtb).

Fortunately, the friendly members of the openSUSE:Factory:ARM community quickly hinted me at the grub2 "devicetree" command which can be specified similar to "linux" or "initrd" to name a file that's loaded as device tree.

Unfortunately, there is no way to make this really persistent, short of editing the grub generator scripts which will get lost on every grub2 update.

The other option would be to decompile the board's DTB file ("/boot/dtb/sun8i-h2-plus-bananapi-m2-zero.dtb" in my case), change and then recompile it, replacing the original file. This has two downsides: first, it will get overwritten with every update of the "dtb-sun8i" package (no idea how often this will be the case) and second, you might want to have the original file as fallback ready. In general, editing package managed files is not a good idea in my book, if it can be avoided it should be.

So I looked into the "who loads which device tree file" and found out that actually the dtb is loaded by u-boot, even before grub starts. U-boot has the name of the board built-in and thus the file name it is looking for. Additionally it has a search list of directories that it searches to find the dtb file. So the simplest way to apply your own dtb file would probably be to put it, with the original file name into the search path after the original file. I tried this approach at first, but then went for explicitly specifying a different filename, which is just not as subtle in case you need to debug this years later ;-)

So the method is relatively easy:

  1. put your modified dtb file into /boot, I named it custom.dtb.
  2. boot into u-boot, interrupt booting on the serial console
  3. in u-boot console, enter setenv fdtfile custom.dtb
  4. in u-boot console, enter saveenv
That's it. Now boot and verify that your dtb file is used.

Note that the u-boot environment is saved on the EFI partition of the SD card (first partition, FAT format) as file "uboot.env". If you need to reset the environment to the built-in defaults, then you can always mount the SD card in another machine and move away or delete uboot.env.


Saturday, January 02, 2021

openSUSE Tumbleweed on the Banana Pi BPI-M2 ZERO

This is the first post of a small series about openSUSE on the Banana Pi BPI-M2 ZERO.

Preface

I recently got myself a Banana Pi M2 Zero board while ordering other stuff at an electronics distributor. The M2 zero is the same form factor and feature set as the Raspberry Pi Zero W (the GPIO pin headers are said to be compatible, it has WiFi and Bluetooth built in and an USB OTG port). The CPU is an Allwinner H2+, a quad-core ARM processor running a 1GHz clock speed, RAM size is 512MB. Processing power is probably comparable to a Raspberry Pi 2 board.

I bought the M2 Zero to use it with an RTLSDR stick to receive the signal of my outside RF temperature sensor. This worked with the Raspberry Pi Zero W, but was a bit too much for the slower CPU which has other more important things to do anyway (playing internet radio ;-), so the M2 Zero was a cheap, more powerful alternative. The box will be running headless and thus I do not care about support for graphics and multimedia anyway.

In the end, I switched the RF receiver to a RaspyRFM board whih is using less energy and simpler to use than an RTLSDR stick just to receive some sensors and now the M2 Zero board is free for tinkering...


openSUSE on the M2 Zero

There was already an image available for the Banana Pi M2 Plus (called "sinovoipbpim2plus"), which is the "bigger brother" of the M2 zero, but that image did not boot. Experimenting with the u-boot image from armbian lead to success in "openSUSE Tumbleweed boots with armbian u-boot". Thanks to the friendly openSUSE ARM community, a matching u-boot version for the M2 Zero was built quickly and I could submit the updated image in OBS to get an image ready for the board (called "sinovoipbpim2zero").

Some small things are still to be sorted out, this is why I would suggest you use the image from the home:seife:bananapi repository for now. Since the board has only WiFi networking (more on that in a later post...), you'll need a serial console wired up for initial setup and I strongly suggest to use at least the "openSUSE-Tumbleweed-ARM-X11-..." image and not the JeOS image, since JeOS does not contain NetworkManager and using WiFi with wicked (actually using anything with wicked) is not fun.

So put the image on the SD card, connect the serial console, boot the box up. Log in as root. WiFi connection is easily established then:

nmcli dev wifi connect YOUR_SSID password YOUR_PASSWORD

That's it, have fun! ;-)



Addon note: When I started to write this post, my home:seife:bananapi repo was necessary for actually getting WiFi to work (contained a fixed kernel-firmware package). This has all been submitted to upstream or openSUSE:Factory:ARM now. All that's "special" in my repo now is a slightly extended package selection in the image (the "dtc" package is included) and a fixed config.sh script that makes NetworkManager actually work correctly, including name resolution, see boo#1180234 for details), so the image from openSUSE:Factory:ARM should be "good enough" for most uses already and in the near future I'll probably retire the home:seife:bananapi project or use it just for development stuff).

Tuesday, June 23, 2020

Brother MFC-L2710DW Printer / Scanner and Linux

I needed a new scanner, my old HP PSC-1510 finally broke..
I wanted a multi-function device with ethernet, non-color laser printer with duplex printing and a scanner with ADF. For ease of use, I wanted a "scan to network drive" and "scan to email" capable device, so that my users at home can easily help themselves without me having to scan every document for them.

The Brother MFC-L2710DW seemed to fit the bill pretty well.
Only after having it all set up, I found out that the "Scan to email" only works with a Windows PC, and apparently only with the device connected via usb, by somehow firing up Outlook to send the mail, and the "scan to network drive" also seems to work the same way.

The next thing I found out is, that the printer works with CUPS, but you need a binary only driver from Brother (at least if you follow all the HOWTOs on the internet) and the scanner unit also seemed to need a binary only sane backend. Not much more and I would have almost immediately put up the device on ebay just to get rid of it as fast as possible.

But then I noticed that the thing is AirPrint and AirScan capable and I found out that no MacOS drivers were included...

Long story short: AirScan is some http based protocol (named eSCL) for basic scanning. With some curl magic you can scan (from standard glass or ADF) to either (at least) JPEG or PDF. When scanning from ADF, you even get a multi-page PDF directly. There is an "escl" backend in latest SANE (but not in Leap 15.2). However, this did not work well for me. Then I found the excellent "sane-airscan" project on github which works fine, and which serves both as a working SANE backend and as a good documentation on the protocol, which I used to write a standalone tool "simple-airscan" in python, which I'll probably put into a small simple webfrontend, so that my users can help theirselves with their scanning needs.

Ok, scanning works. What about printing?
Airprint has some "driverless" mode, which I was unable to configure with YaST, but it was easy to configure after I enabled the CUPS web frontend. This works without any ugly brother binary only drivers and prints just fine.

So now both the scanner and the printer work just fine without any brother software ;-)

Links:
https://github.com/seife/airscan-simple - my simple python scanning tool.
https://github.com/alexpevzner/sane-airscan - the excellent sane-airscan backend for SANE.
https://wiki.debian.org/CUPSDriverlessPrinting - the debian wiki has extensive information on driverless printing

Thursday, March 26, 2020

Windows 10 update error 0x800f0922

First: sorry for the OT ;-)

A Thinkpad of mine that has Windows 10 co-installed was refusing all cumulative Windows updates since about 6 months, always performing everything, rebooting, counting up to 99%, then failing with error 0x800f0922 and rolling back.
Now this Windows instance is not really used and thus not booted on a regular base, but I'd still rather keep it up to date in case I somewhen really need it for something.

So I searched the internet for error 0x800f0922... and tried almost everything that was mentioned as a possible fix:

  • resetting windows update
  • uninstalling various pieces of software
  • in general, random changing of different settings ;-)
Nothing helped. Until I found a short comment under some blog post hidden in the vast voids of the internet, that mentioned that the problem could be solved by not booting via grub but instead directly activating the windows boot partition.

Could it be that easy? Yes. Rebooted into Linux, deactivated /dev/sda3 and activated /dev/sda1 with fdisk, rebooted and Windows is now updating happily ever after...

Tuesday, January 21, 2020

Fun with grub2-install "not a directory"

These days, I came across spontaneous kiwi image build failures in a private OBS instance.
The images were SLES15-SP1, they had not been touched for quite some time, rebuilds were only triggered due to new packages in the update channel.
The error was grub2-install failing with the error message "not a directory".
Looking at the recent changes in the update repo showed no obvious reason (some python packages that had nothing to do with grub2-install), so I started to investigate...

... 3 days later, after following some detours, I finally found the issue.

grub2-install scans the installation device for filesystems, and probes all known (to grub2) fs types. The probe of "minix_be" fails fatally. Sometimes.

After building my own grub2 package with lots of debug-printf's, I finally found out, that the minix fs detection of grub2 is a little "fragile". It does the following (pseudo code):
  • grub_mount_minix(device) || return "not minix fs"
  • grub_minix_find_file("/") || fatal_error()
The problem is, that grub_mount_minix() only does pretty simple magic numbers checks, which can lead to false positives.

Comparing the superblock structures of ext[234] and minix filesystems (from the grub2 source code) side by side, you see this:

struct grub_minix_sblock         |struct grub_ext2_sblock
{                                |{
  grub_uint16_t inode_cnt;       |  grub_uint32_t total_inodes;
  grub_uint16_t zone_cnt;        |
  grub_uint16_t inode_bmap_size; |  grub_uint32_t total_blocks;
  grub_uint16_t zone_bmap_size;  |
  grub_uint16_t first_data_zone; |  grub_uint32_t reserved_blocks;
  grub_uint16_t log2_zone_size;  |
  grub_uint32_t max_file_size;   |  grub_uint32_t free_blocks;
  grub_uint16_t magic;           |  grub_uint32_t free_inodes;
};

This already hints at the issue: at the same disk location where ext2 stores the free inodes number, minix stores its magic number, which is used by grub to detect if it is a minix file system.

Now if you happen to have an ext3 file system with a free_inodes number whose lower 16 bits resemble one of the GRUB_MINIX_MAGIC numbers, chances are grub_mount_minix() will succeed, but then the attempt to acces the root directory will fail with a fatal error.

This is a plain grub2 bug, which I will probably report upstream and try to get fixed.
However, I need a fix to have my images build again, and the chances of getting a fix into SLES15-SP1 are ... low (and it is a daunting task, even if you are reporting this bug as a big SLES customer), so I built a workaround in my (locally built, lucky me...) python-kiwi package.

It basically does the following, before calling the "chroot grub2-install ...".

  • statvfs() to get the free_inodes number
  • check if the lower 16 bits resemble one of the MINIX_MAGIC numbers
    • if it does, touch a temporary file in
    • unmount and mount again to update the superblock (I missed this at first and wondered why it did not work)
    • unlink the temporary file
  • continue as before
This workaround is ugly as hell, but it does work for me.

P.S.: the detours included first noticing that almost every change I made to the image, like wrapping grub2-install into a wrapper script for debugging) made the issue go away (because of a different free_inodes number), so I always needed to check after every change that the issue was still present, then finding that copying the locales in grub2-install actually triggers an ENOTDIR - "Not a directory", because it misses special handling the /usr/share/locale/locale.alias file. Of course I thought "this is the issue" and patched it out of grub2, just to find that the original problem still persisted... then overnight package updates in SLES15-SP1 making this problem go away and reappear seemingly random... you guess it 😄

Friday, June 01, 2018

GRUB2 submenus revisited

After my last post quite some time ago, I had to revisit this issue again and found that there is a much easier way to "fix" the problem: Just add

GRUB_DISABLE_SUBMENU="y"
in /etc/default/grub, recreate your grub.cfg and voila: the submenus are gone.

Thursday, March 09, 2017

grub2-set-default and submenus

At work, I was investigating why "grub2-set-default" apparently did not work for booting older kernels on a SLES12-SP1 system (openSUSE has the same configuration). A colleague found out, that it worked once he removed the "submenu" wrap around the additional installed kernels.

Today, after some googling, I found out that even though you have unique "menuentry" titles, a plain "grub2-set-default my\ menu\ entry" still does not work, unless you give the path to the submenu.

This is done in grub2 syntax like this:
grub2-set-default "1>openSUSE Leap 42.2, with Linux 4.4.46-11-default"
The "1>" tells grub2 to look for the menuentry in the submenu, which is the second toplevel item. For SUSE / openSUSE the second toplevel item is always, AFAICT, the "Advanced options for $VERSION" menu, where the additional kernels live.

An alternative for my case would have been
grub2-set-default "1>1"
Which would be "the second entry from the submenu which is the second toplevel item" (counting from zero). But you need to look at the config file and count the entries.

The entries have an additional ID that looks like it is costructed like:
gnulinux-$(uname -r)-advanced-${UUID_OF_ROOTFS}
 in my case:
gnulinux-4.4.46-11-default-advanced-b073628b-5ddc-4a2d-9943-0f2999dfdaaa
Still looks unwieldy, but you might be able to automatically determine that from a script.

Monday, December 26, 2016

Silent night - or "how I accidentally disabled email delivery"

My private email domains are hosted on a linux server where I have shell access (but not as root) which processes them with procmail, stores them locally and finally forwards them all to a professionally hosted email server with IMAP access and all that blinky stuff.
The setup is slightly convulted (aka "historically grown") but works well for me.

But the last days have been quiet on the email front. Not even the notorious spammers spamming my message-ids (how intelligent!) have apparently be trying to contact me. Now that's suspicious, so I decided to look into that.

A quick testmail from my gmail account did not seem to come through. Now the old test via telnet to port 25... had to look up the SMTP protocol, it's a long time ago I had to resort to this. First try: greylisting... come back later. Second try:
250 Ok: queued as F117E148DE4
Check the mails on the server: did not get through.

Now a few more words on the setup: as I wrote, all mail is forwarded to that professionally hosted IMAP server, where I read it usually with Thunderbird or, if things get bad, with the web frontend.
But since all emails are also stored on the server with shell access, I get them from there from time to time via imap-over-ssh, using fetchmail and the mailsync tool.

BTW, the fetchmail setup for such a thing is:
poll myacc via shellservername.tld with proto imap:
    plugin "ssh -C %h bin/imapd" auth ssh;
    user seife there is seife here options keep stripcr
    folders Mail/inbox Mail/s3e-spam Mail/thirdfolder
    mda "/usr/bin/procmail -f %F -d %T"
So while trying to check mail, I'm regularly running:
fetchmail && mailsync myacc
(first fetchmail, since it passes the mails to procmail which does the same folder-sorting as was done on the mail server already and is much faster than mailsync, which comes second to do the synchronization stuff: delete mails on the server that have been deleted locally etc.)
All looks normal, apart from no new mails arriving.
Until suddenly I noticed, that mailsync was synchronizing a folder named "spamassassin.lock". WTF?

 Investigating... On the server, there really is an (emtpy) mailbox named "Mail/spamassassin.lock".
Next place to look for is .procmailrc, and there it is: a rule like:

:0fw: spamassassin.lock
* < 1048576
| $HOME/perl/bin/spamassassin
And since everything in procmail apparently per default is relative to $MAILDIR, the lockfile was placed there. Probably a mailsync process came along, exactly at the moment the lockfile was existing and persisted it, and after that, no mail ever went past this point.

Solution was easy: remove the lockfile, make sure it does not get re-synchronized with next mailsync run and reconfigure procmail to use $HOME/spamassassin.lock instead. Now the silent times are over, spam is piling up again.

Thursday, July 28, 2016

When "# needsrootforbuild" in OBS does not work...

...always remember, that you also need to change /usr/lib/obs/server/BSConfig.pm:

# Allow to build as root, exceptions per package
# the keys are actually anchored regexes
our $norootexceptions = {
        "my-project/root-package" => 1,
        "dev-projects.*/other-package" => 1,
};
I already forgot that and wondered why it worked for "root-package", but not for "other-package" (which was not yet added...)

Monday, July 11, 2016

"Ghost" keystrokes with libvirt/KVM, SPICE and Windows guests

After offline resizing the image and file system of a Windows guest VM running on KVM, like this:

dd if=/dev/zero of=wxp.img bs=1M seek=10240 count=0
fdisk -c=dos wxp.img # resize partition, activate(!)
losetup -Pf wxp.img
ntfsresize /dev/loop0p1
losetup -d /dev/loop0

Windows (as expected) wanted to run a file system check on next boot. And on the following boot. And... every time.
I investigated and found out, that the CHKDSK prompted for "skip this check with any key press" and apparently a key was pressed at every boot, even though I did not touch anything.

Long story short: apparently the SPICE drivers, which this VM is using, are creating "ghost" devices and events during boot, which are interpreted as key presses by Windows. The solution was pretty simple: shut down the VM, switch the configuration from "SPICE server" to "VNC server", boot, wait for the CHKDSK to finish, shut down, switch back to "SPICE server".

Friday, November 27, 2015

Use your distro's kernel in OBS

The Open Build Service has the nifty feature that you can tell it to use a specific kernel to boot the worker VMs that build your software. To use that, you don't need any special setup, just a package which contains a kernel and an initrd:

   /.build.kernel.kvm # used by KVM workers
   /.build.kernel.xen # used by Xen workers
   /.build.initrd.kvm
   /.build.initrd.xen

So you just need this package and make sure it is installed in the VM using the VMinstall: tag in the project config.
If the build service worker script detects that after preparing the VM, such a kernel and initrd are present, they will be used for booting the worker VM that finally builds your package or image. If it is *not* detected, then the kernel the worker server is running with (usually a SUSE kernel) will also be used for the VM.

In the openSUSE Buildservice instance, all "recent" SUSE distributions are configured for that: they use the kernel-obs-build package, which gets created automatically when building the kernel rpms.

Now I am right now using a buildservice instance for cross-distribution package- and imagebuilds. The challenges of trying to build RHEL/CentOS 7 images with KIWI in OBS warrant at least one additional blog post, but one thing I noticed was, that some of the kiwi stuff, when done with a CentOS 7 userland, apparently also needs a CentOS kernel, otherwise kiwi's parted calls, for example, will exit with code 1 (without issuing an error message, btw).
So I have built a kernel-obs-build from the CentOS 7 kernel and configured my OBS instance to use it, which brought me quite some steps further to building CentOS images with KIWI in OBS.
The code (or rather: the spec files) to "convert" the CentOS kernel to an OBS kernel is at https://github.com/seife/kernel-obs-build, a short README on how  to use it is included.

Note that right now it only works with KVM workers as I was not able to get the worker code to boot the kernel correctly in a Xen VM, even though drivers are all there, the reason is probably that the obs worker scripts rely on some of the specifics of a Xen-specific kernel (e.g. the device name of the block devices being passed through to the VM from the config, which is not true for a generic PV-capable kernel).
But I guess this will improve soon, now that openSUSE has dropped the kernel-xen package, they will face the same issues and hopefully someone will fix them ;)

Sunday, March 15, 2015

FITRIM/discard with qemu/kvm for thin provisioning

My notebook computer is running with an SSD, and usually I'm creating logical volumes for the KVM VM's I install on it for testing purposes. On my normal file systems, I regularly run "fstrim" manually, to help the SSD firmware figure out which blocks can be reused. However, the LV's of the virtual machines usually stayed un-TRIM'ed. I had heard, that KVM/QEMU now supports the discard commands, but had not yet gotten to testing it.
I finally got to figuring out how it works:

First, you need to switch the VM to using virtio-scsi instead of virtio-blk:

Before:
<disk type='block' device='disk'>
  <driver name='qemu' type='raw'/>
  <source dev='/dev/main/factory'/>
  <target dev='vda' bus='virtio'/>
  <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/
</disk>
After:
<disk type='block' device='disk'>
  <driver name='qemu' type='raw'/>
  <source dev='/dev/main/factory'/>
  <target dev='sda' bus='scsi'/>
  <address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='scsi' index='0' model='virtio-scsi'/>
Note the added scsi controller, and the only things you need to change are "target" and "address", if your source is different, that's ok.
Now check that your VM still boots. If it does not, then it is missing the virtio-scsi driver in the initrd. Reboot with the old configuration and build an initrd that includes all drivers, or at least the virtio-scsi driver. Another possible problem is the change from "/dev/vda1" to "/dev/sda1", check your fstab and use UUID or filesystem label for booting. Both problems did not occur to me on a stock Factory install (it uses UUID by default and had all drivers in initrd), but a hand-built kernel (built with "make localmodconfig"...) failed to boot, so be prepared.

Now you are using virtio-scsi for your device, but fstrim will still give you a "operation not supported" message. You'll need another parameter in your VM's configuration:
<driver name='qemu' type='raw' discard='unmap'/>
Restart the VM, and...
factory-vm:~ # fstrim -v /
/: 8,7 GiB (9374568448 bytes) trimmed
factory-vm:~ # 
Now what about thin-provisioning?
I converted the same VM from LV to a plain raw file.
This is the file on the host, it is sparse:
susi:/local/libvirt-images # ls -lh factory.raw
-rw-r----- 1 qemu qemu 20G Mar 15 14:05 factory.raw
susi:/local/libvirt-images # du -sh factory.raw
12G     factory.raw
Now let's delete some stuff inside the VM and run fstrim:
factory-vm:~ # du -sh /home/seife/linux-2.6/
3.9G    /home/seife/linux-2.6/
factory-vm:~ # rm -rf /home/seife/linux-2.6/
factory-vm:~ # fstrim -v /
/: 12.7 GiB (13579157504 bytes) trimmed
Checking again on the host:
susi:/local/libvirt-images # ls -lh factory.raw
-rw-r----- 1 qemu qemu 20G Mar 15 14:08 factory.raw
susi:/local/libvirt-images # du -sh factory.raw
6.4G    factory.raw
So this is really neat, as you now can free up space on the host after cleaning up in the VM. Maybe I should reconsider my "put all VMs into logical volumes" strategy again, as this wastes quite some valuable SSD space in my case.

Friday, November 21, 2014

Speeding up openSUSE 13.2 boot

I bought my wife a "new" old Thinkpad (T400, Core2 duo) to replace her old compaq nc6000 (Pentium M Dothan). Of course I installed it with openSUSE 13.2. Everything works fine. However, we soon found out that it takes ages to boot, something around 50 seconds, which is much more than the old machine (running 13.1 on an IDE SSD vs 13.2 on a cheap SATA SSD in the T400).
Investigating, I found out that in 13.2 the displaymanager.service is now a proper systemd service with all the correct dependencies instead of the old 13.1 xdm init script.
At home, I'm running NIS and autofs for a few NFS shares and an NTP server for the correct time.
The new displaymanager.service waits for timesetting, user account service and remote file systems, which takes lots of time.
So I did:
systemctl disable ypbind.service autofs.service ntpd.service
In order to use them anyway, I created a short NetworkManager dispatcher script which starts / stops the services "manually" if an interface goes up or down.
This brings the startup time (until the lightdm login screen appears) down to less than 11 seconds.
The next thing I found was that the machine would not shut down if an NFS mount was active. This was due to the fact that the interfaces were already shut down before the autofs service was stopped or (later) the NFS mounts were unmounted.
It is totally possible that this is caused by the violation in proper ordering I introduced by the above mentioned hack, but I did not want to go back to slow booting. So I added another hack:

  • create a small script /etc/init.d/before-halt.local which just does umount -a -t nfs -l (a lazy unmount)
  • create a systemd service file /etc/systemd/system/before-halt-local.service which is basically copied from the halt-local.service, then edited to have Before=shutdown.target instead of After=shutdown.target and to refer to the newly created before-halt.local script. Of course I could have skipped the script, but I might later need to add other stuff, so this is more convenient.
  • create the directory /etc/systemd/system/shutdown.target.wants and symlink ../before-halt-local.service into it.
And voila - before all the shutdown stuff starts, the nfs mounts are lazy unmounted and shutdown commences fast.

Hibernate Filesystem Corruption in openSUSE 13.2

UPDATE: This bug is fixed with the dracut update to version dracut-037-17.9.1

I was never very fond of dracut, but I did not think it would be so totally untested: openSUSE Bug #906592. Executive summary: hibernate will most likely silently corrupt (at least) your root filesystem during resume from disk.
If you are lucky, a later writeback from buffers / cache will "fix" it, but the way dracut resumes the system is definitely broken and I already had the filesystem corrupted on my test VM, while investigating the issue, so it is not only a theoretical problem.

Until this bug is fixed: Do not hibernate on openSUSE 13.2.

Good luck!

Thursday, November 20, 2014

pam_systemd on a server? WTF?

I noticed lots of spam in my system logs:

20141120-05:15:01.9 systemd[1]: Starting user-30.slice.
20141120-05:15:01.9 systemd[1]: Created slice user-30.slice.
20141120-05:15:01.9 systemd[1]: Starting User Manager for UID 30...
20141120-05:15:01.9 systemd[1]: Starting Session 1817 of user root.
20141120-05:15:01.9 systemd[1]: Started Session 1817 of user root.
20141120-05:15:01.9 systemd[1]: Starting Session 1816 of user wwwrun.
20141120-05:15:01.9 systemd[1]: Started Session 1816 of user wwwrun.
20141120-05:15:01.9 systemd[22292]: Starting Paths.
20141120-05:15:02.2 systemd[22292]: Reached target Paths.
20141120-05:15:02.2 systemd[22292]: Starting Timers.
20141120-05:15:02.2 systemd[22292]: Reached target Timers.
20141120-05:15:02.2 systemd[22292]: Starting Sockets.
20141120-05:15:02.2 systemd[22292]: Reached target Sockets.
20141120-05:15:02.2 systemd[22292]: Starting Basic System.
20141120-05:15:02.2 systemd[22292]: Reached target Basic System.
20141120-05:15:02.2 systemd[22292]: Starting Default.
20141120-05:15:02.2 systemd[22292]: Reached target Default.
20141120-05:15:02.2 systemd[22292]: Startup finished in 21ms.
20141120-05:15:02.2 systemd[1]: Started User Manager for UID 30.
20141120-05:15:02.2 CRON[22305]: (wwwrun) CMD (/usr/bin/php -f /srv/www/htdocs/owncloud/cron.php)
20141120-05:15:02.4 systemd[1]: Stopping User Manager for UID 30...
20141120-05:15:02.4 systemd[22292]: Stopping Default.
20141120-05:15:02.4 systemd[22292]: Stopped target Default.
20141120-05:15:02.4 systemd[22292]: Stopping Basic System.
20141120-05:15:02.4 systemd[22292]: Stopped target Basic System.
20141120-05:15:02.4 systemd[22292]: Stopping Paths.
20141120-05:15:02.4 systemd[22292]: Stopped target Paths.
20141120-05:15:02.4 systemd[22292]: Stopping Timers.
20141120-05:15:02.4 systemd[22292]: Stopped target Timers.
20141120-05:15:02.4 systemd[22292]: Stopping Sockets.
20141120-05:15:02.4 systemd[22292]: Stopped target Sockets.
20141120-05:15:02.4 systemd[22292]: Starting Shutdown.
20141120-05:15:02.4 systemd[22292]: Reached target Shutdown.
20141120-05:15:02.4 systemd[22292]: Starting Exit the Session...
20141120-05:15:02.4 systemd[22292]: Received SIGRTMIN+24 from PID 22347 (kill).
20141120-05:15:02.4 systemd[1]: Stopped User Manager for UID 30.
20141120-05:15:02.4 systemd[1]: Stopping user-30.slice.
20141120-05:15:02.4 systemd[1]: Removed slice user-30.slice.

This is a server only system. I investigated who is starting and tearing down a sytemd instance for every cronjob, every user login etc.
After some searching, I found that pam_systemd is to blame: it seems to be enabled by default. Looking into the man page of pam_systemd, I could not find anything in it that would be useful on a server system so I disabled it, and pam_gnome_keyring also while I was at it:
pam-config --delete --gnome_keyring --systemd
...and silence returned to my logfiles again.