LiveUpgrade Troubleshooting

Solaris™ LiveUpgrade is a nice feature of Solaris, which lets one upgrade the currently running version of Solaris to a new realease or patch it without the need to bring the system into single user mode for a more or less long time. Also it allows one to switch back to the previous state, when something went wrong, without the neeed to backuot patches from the "male"functioning boot environment.

The main steps for LiveUpgrade are

However, especially when zones are used, LiveUpgrade has often issues which require you to manually fix the problems until they get fixed in the main release. This page tries to show most common problems and how to resolve them.

Debugging lucreate, lumount, luumount, luactivate, ludelete

If one of the lu* commands fails, the best thing to do is to find out what the command in question actually does. The follwing receipt shows a way how to get all information one usually needs to find the cause of the problem and finally to resolve it.

+ tcsh
setenv SNVR b103
setenv NBE snv_$SNVR

setenv CD /net/install/pool1/install/`uname -p`/Solaris_11_$SNVR
setenv JUMPDIR /net/install/pool1/install/jumpstart
setenv RPOOL `df / | grep -v ^Filesystem | cut -f1 -d/`
setenv ERR err.${NBE}.log
setenv OUT out.${NBE}.log
setenv DBG dbg.${NBE}.log
setenv TRC trc.${NBE}.log
setenv LU_DEBUG_OVERRIDE 11
echo 'proc:::exec-success { \
    printf("%d\t%s\n",timestamp,curpsinfo->pr_psargs); \
}' >/tmp/exe.d
setenv DTRACE "dtrace -s /tmp/exe.d -o $TRC -c"
setenv GAWK "gawk -f  /local/misc/etc/tsortd.gawk"

cd /var/tmp
rm -f $TRC $DBG $OUT $ERR

$DTRACE "lucreate -n $NBE -p $RPOOL -l $ERR -o $OUT" |& tee $DBG
$GAWK $TRC >lucreate.${TRC}
rm $TRC; mv $DBG lucreate.${DBG}; mv $OUT lucreate.${OUT}; mv $ERR lucreate.${ERR}

$DTRACE "lumount -l $ERR -o $OUT $NBE /mnt" |& tee $DBG
$GAWK $TRC >lumount.${TRC}
rm $TRC; mv $DBG lumount.${DBG}; mv $OUT lumount.${OUT}; mv $ERR lumount.${ERR}

$DTRACE "luumount -l $ERR -o $OUT $NBE" |& tee $DBG
$GAWK $TRC >luumount.${TRC}
rm $TRC; mv $DBG luumount.${DBG}; mv $OUT luumount.${OUT}; mv $ERR luumount.${ERR}

$DTRACE "luupgrade -u -n $NBE -s $CD -j /var/tmp/profile.$SNVR -l $ERR -o $OUT" |& tee $DBG
$GAWK $TRC >luupgrade.${TRC}
rm -f $TRC
mv $DBG luupgrade.${DBG}; mv $OUT luupgrade.${OUT}; mv $ERR luupgrade.${ERR}

$DTRACE "luactivate -l $ERR -o $OUT $NBE" |& tee $DBG
$GAWK $TRC >luactivate.${TRC}
rm $TRC; mv $DBG luactivate.${DBG}; mv $OUT luactivate.${OUT}; mv $ERR luactivate.${ERR}

$DTRACE "ludelete -l $ERR -o $OUT $NBE" |& tee $DBG
$GAWK $TRC >ludelete.${TRC}
rm $TRC; mv $DBG ludelete.${DBG}; mv $OUT ludelete.${OUT}; mv $ERR ludelete.${ERR}

Rule of thumb: When luactivate or ludelete fails, usually it is sufficient to look for problems wrt. lumount. If lumount fails, all mentioned LU commands will fail as well OR the machine will not be able to boot into the new BE OR will boot, but go into single user mode because of problems mounting one or more slices/ZFSs!

LU packages are not uptodate

Always make sure, that the currently installed LU packages SUNWluu SUNWlur SUNWlucfg have at least the version of the target boot environment. E.g. if you are running snv_b98 and wanna upgrade to snv_b103, make sure, that you have installed the LU packages from snv_b103 in the currently running snv_b98.

pkgrm SUNWluu SUNWlur SUNWlucfg
pkgadd -d $CD/Solaris_11/Product SUNWlucfg SUNWlur SUNWluu
# Solaris
gpatch -p0 -d / -b -z .orig < /local/misc/etc/lu-5.10.patch
# Nevada
gpatch -p0 -d / -b -z .orig < /local/misc/etc/lu-5.11.patch

Also check, whether all required patches are installed. Especially 121430-36 (sparc) / 121431-37 (x86) and not earlier are highly recommended: allmost all problems especially wrt. zones should vanish with these patches. However, don't forget to check Solaris™ Live Upgrade Software: Minimum Patch Requirements!

checkpatches.sh -p 119081-25 124628-05 ...

Wrong zonepath

One common problem is, that lucreate properly clones a zone by cloning its zonepath ZFS, however it doesn't set the zonepath of the cloned zone to the cloned ZFS.

# zfs list | grep zones
rpool/zones                        285M   219G    21K  /rpool/zones
rpool/zones/sdev                   284M   219G   283M  /rpool/zones/sdev
rpool/zones/sdev@snv_b103          394K      -   283M  -
rpool/zones/sdev-snv_b103          754K   219G   283M  /rpool/zones/sdev-snv_b103

# zfs set mountpoint=/mnt rpool/ROOT/snv_b103
# zfs mount rpool/ROOT/snv_b103
# zonecfg -R /mnt -z sdev info zonepath
zonepath: /mnt/rpool/zones/sdev

The error you will probably see in this case using 'lumount snv_b103 /mnt' is:

ERROR: unable to mount zones:
cannot mount '/rpool/zones/sdev': directory is not empty
...
zone 'sdev': zone root /rpool/zones/sdev/root already in use by zone sdev
zoneadm: zone 'sdev': call to zoneadmd failed
ERROR: unable to mount zone <sdev> in </.alt.snv_b103>
...

To fix that problem permanently, you can apply the lu patch mentioned above.

Otherwise, fix it manually. E.g.

zfs set mountpoint=/mnt rpool/ROOT/snv_b103
zfs mount rpool/ROOT/snv_b103
zfs mount rpool/ROOT/snv_b103/var
zonecfg -R /mnt -z sdev set -F zonepath=/mnt/rpool/zones/sdev-snv_b103
umount /mnt/var
umount /mnt

Wrong mount order in /etc/lu/ICF.*

When lucreate creates a BE, it stores the none-zone filesystems in a file called /etc/lu/ICF.$NUM, whereby $NUM is the ID of the coresponding BE (see /etc/lutab). This file will be used by luumount, to mount all those filesystems before the filesystems of the zones get mounted.

Unfortunately, when a BE gets created for the first time (initial BE), existing filesystems are recorded in the wrong order, which leads to hidden mountpoints, when lumount is called.

snv_101:-:/dev/zvol/dsk/rpool/swap:swap:4192256
snv_101:/:rpool/ROOT/snv_101:zfs:0
snv_101:/export/home:rpool/export/home:zfs:0
snv_101:/export:rpool/export:zfs:0
snv_101:/rpool/zones:rpool/zones:zfs:0
snv_101:/rpool:rpool:zfs:0
snv_101:/var:rpool/ROOT/snv_101/var:zfs:0

So in this example lumount mounts rpool/zones to /rpool/zones first (which contains the directory aka mountpoint sdev for the zone sdev). After that, it mounts rpool on /rpool, which contains the empty directory zones (mountpoint for rpool/zones). Finally it tries to mount the zonepathes, e.g. rpool/zones/sdev on /rpool/zones/sdev, but this obviously fails, since this mountpoint is hidden by /rpool.

ERROR: unable to mount zones:
zoneadm: /mnt/rpool/zones/sdev: No such file or directory
could not verify zonepath /mnt/rpool/zones/sdev because of the above errors.
zoneadm: zone sdev failed to verify
ERROR: unable to mount zone <sdev> in </mnt>
...

To fix the problem, just edit the /etc/lu/ICF.$NUM file and bring the entries into the correct order.

snv_101:-:/dev/zvol/dsk/rpool/swap:swap:4192256
snv_101:/:rpool/ROOT/snv_101:zfs:0
snv_101:/export:rpool/export:zfs:0
snv_101:/export/home:rpool/export/home:zfs:0
snv_101:/rpool:rpool:zfs:0
snv_101:/rpool/zones:rpool/zones:zfs:0
snv_101:/var:rpool/ROOT/snv_101/var:zfs:0

Unfortunately luupgrade recreates ICF when it thinks, it is necessary and thus it may fail to upgrade zones. That means the script in charge needs to be fixed permanently by applying lu patch mentioned above.

If you got caught by this bug, remember to clean up the ZFS mountpoints! Otherwise the system will not come up when booting in the BE, because 'zfs mount -a' will fail dueto none-empty directories.

lucreate fails with ERROR: cannot mount '/.alt.tmp.b-3F.mnt/var': directory is not empty

If you have split the /var from the / zfs, lucreate may fail with an error message like this

ERROR: cannot mount '/.alt.tmp.b-3F.mnt/var': directory is not empty
ERROR: cannot mount mount point </.alt.tmp.b-3F.mnt/var> device <rpool/ROOT/test/var>
ERROR: failed to mount file system <rpool/ROOT/test/var> on </.alt.tmp.b-3F.mnt/var>
ERROR: unmounting partially mounted boot environment file systems
ERROR: cannot mount boot environment by icf file </etc/lu/ICF.3>
ERROR: Unable to mount ABE <test>
ERROR: Unable to clone the existing file systems from boot environment <s10u8_20100821> to create boot environment <test>
ERROR: Cannot make file systems for boot environment .

This happens, if the current / filesystem contains a /var directory, which is not empty. Usually it contains a tmp/ subdirectory or other stuff, however one can not see this, since the /var is mounted over it.

Unfortunately we can't simply mount -F lofs / /mnt, since Solaris "mounts" /var to /mnt/var as well (unlike Linux mount --bind ...). So the easiest way is to luactivate a working BE, boot into it and fix the bogus root filesystem of the BE you came from. E.g.:

zfs set mountpoint=/mnt rpool/ROOT/buggyBE
zfs mount rpool/ROOT/buggyBE
rm -rf /mnt/var/*
ls -al /mnt/var
zfs umount /mnt
zfs set mountpoint=/  rpool/ROOT/buggyBE

Finally luactivate the buggyBE, boot into it and delete the incomplete BE and destroy all ZFS left over from the previously failed lucreate. E.g.:

ludelete test
# delete the remaining BE ZFS, e.g.
zfs list -t all |grep test
zfs destroy rpool/ROOT/test/var
zfs destroy rpool/ROOT/test
zfs destroy rpool/ROOT/`lucurr`/var@test
zfs destroy rpool/ROOT/`lucurr`@test
# and do not forget the cloned zone filesystems/snapshots

lumount_zones doesn't lofs mount already mounted zonepath ZFS

If one calls e.g. 'lumount snv_101 /mnt' (current BE is e.g. snv_b103), lumount mounts first the none-zone ZFSs and than the zonepath ZFSs using /usr/lib/lu/lumount_zones. Unfortunately lumount_zones checks only, whether the corresponding ZFS is already mounted, but NOT its current mountpoint. So if rpool/zones/sdev is already mounted (the default since usually canmount property of rpool/zones is on as well) e.g. to /rpool/zones/sdev, it does not get mounted on /mnt/rpool/zones/sdev as a loopback filesystem and you'll get usually the follwoing error:

ERROR: unable to mount zones:
/mnt/rpool/zones/sdev must not be group readable.
/mnt/rpool/zones/sdev must not be group executable.
/mnt/rpool/zones/sdev must not be world readable.
/mnt/rpool/zones/sdev must not be world executable.
could not verify zonepath /mnt/rpool/zones/sdev because of the above errors.
zoneadm: zone sdev failed to verify
ERROR: unable to mount zone <sdev> in </mnt>
...

NOTE: The "not ... readable|executable" error message is a little bit misleading. This is because the mountpoints for the zones have 0755 permission.

zfs mount rpool/ROOT/snv_101
mount -o ro,nosub,nodevices -F lofs /rpool /mnt/rpool
mount -o ro,nosub,nodevices -F lofs /rpool/zones /mnt/rpool/zones
ls -al /mnt/rpool/zones
total 12
drwxr-xr-x   4 root     root           4 Dec 13 21:19 .
drwxr-xr-x   5 root     root           5 Dec 13 19:07 ..
drwxr-xr-x   2 root     root           2 Dec 13 21:19 sdev
drwxr-xr-x   2 root     root           2 Dec 13 20:59 sdev-snv_b103

or a little bit shorter

umount /rpool/zones/sdev
ls -al /rpool/zones/
total 12
drwxr-xr-x   4 root     root           4 Dec 13 21:19 .
drwxr-xr-x   5 root     root           5 Dec 13 19:07 ..
drwxr-xr-x   2 root     root           2 Dec 13 21:19 sdev
drwx------   5 root     root           5 Dec 13 20:59 sdev-snv_b103

So if one 'chmod 0700 /rpool/zones/sdev' and mounts rpool/zones/sdev again, one gets a slightly more descriptive error message, which indicates, that the ZFS for the zonepath is not mounted on the required mountpoint:

ERROR: unable to mount zones:
zone 'sdev': can't stat /mnt/rpool/zones/sdev/root: No such file or directory
zoneadm: zone 'sdev': call to zoneadmd failed
ERROR: unable to mount zone <sdev> in </mnt>
...

To fix the problem, simply unmount the zonepath in question.

umount /rpool/zones/sdev
# OR
ls -1d /$RPOOL/zones/* | xargs -L 1 umount

luupgrade: Installing failsafe fails

This usually happens on luupgrade of x86 machines and is an aftereffect of the lumount_zones bug described above. The error message looks like this:

luupgrade: The Solaris upgrade of the boot environment <snv_b103> is partially complete.
luupgrade: Installing failsafe
luupgrade: ERROR: Unable to mount boot environment <snv_b103>
...

Since this is the last more or less important step in luupgrade, one can "ignore" this message and fix the problem manually. E.g.:

zfs set mountpoint=/mnt rpool/ROOT/snv_b103
zfs mount rpool/ROOT/snv_b103
# if `isainfo -k` = "amd64" AND `uname -r` = "5.11"
cp $CD/boot/amd64/x86.miniroot /mnt/boot/x86.miniroot-safe
# else
cp $CD/boot/x86.miniroot /mnt/boot/x86.miniroot-safe
umount /mnt

lucreate: no zone clones

On x86 we encountered the situation, where lucreate was able to create a new BE, however it did not clone the zonepath ZFSs. The reason for this misbehavior was, that the current BE wasn't setup properly - luactivate and friends did not set the mountpoint for its root path to / but kept the temporary mountpoint instead.

# zfs list -r rpool
rpool                             20.5G   113G  29.5K  /rpool
rpool/ROOT                        4.47G   113G    18K  legacy
rpool/ROOT/zfs1008BE              4.47G   113G  3.17G  /.alt.zfs1008BE
rpool/ROOT/zfs1008BE/var          1.30G   113G  1.30G  /.alt.zfs1008BE/var
rpool/dump                        8.02G   113G  8.02G  -
rpool/swap                        8.01G   121G    16K  -
# df -h /var
Filesystem             size   used  avail capacity  Mounted on
rpool/ROOT/zfs1008BE   134G   3.2G   113G     3%    /

So GRUB managed to find the right root ZFS and managed to mount it on / ignoring the ZFS mountpoint property. However, lucreate uses the mountpoint property value of the current BE's root ZFS to determine all none-global zones in it and their corresponding zonepath. And since there is no zone index file (e.g. /.alt.zfs1008BE/etc/zones/index) lucreate wrongly assumes, that there are no zones to clone.

Thus the missing zone clones are the reason, why ludelete of the created zone fails: The new BE aka / clone has the unmodified copy of the /etc/zones/index for the zones in the current BE and thus tries to recursively the zonepath ZFSs of the current BE (e.g. zfs destroy -r pool1/zones/edub-zfs1008BE). Hopefully, all zones are running, otherwise the zonepath ZFSs will be lost! Hint number 1:

Never delete a BE with uncloned zones without making sure, that all zones in the current BE are up and running, i.e. the zonepath ZFSs are busy. Otherwise you will loose them!

To fix the problem, boot into the current BE's failsafe archive and fix its mountpoint property.

SunOS Release 5.10 Version Generic_137138-09 32-bit                             
Copyright 1983-2008 Sun Microsystems, Inc.  All rights reserved.                
Use is subject to license terms.                                                
Booting to milestone "milestone/single-user:default".                           
Configuring devices.                                                           
Searching for installed OS instances...
fdisk: Cannot stat device /dev/rdsk/c0t600C0FF000000000099C790E.
mount: I/O error
mount: Cannot mount /dev/dsk/c2t0d0s2
Failed to mount /dev/dsk/c2t0d0s2 read-only: skipping.
mount: I/O error
mount: Cannot mount /dev/dsk/c2t1d0s2
Failed to mount /dev/dsk/c2t1d0s2 read-only: skipping.

ROOT/zfs1008BE was found on rpool.
Do you wish to have it mounted read-write on /a? [y,n,?] y
mounting rpool on /a
cannot mount '/a/.alt.zfs1008BE': failed to create mountpoint
Unable to mount rpool/ROOT/zfs1008BE as root
#
# zfs set mountpoint=/ rpool/ROOT/zfs1008BE
# init 6

LU commands awefully slow

On some servers lu commands like lumount, luumount, lucreate, luactivate, etc. seem to hang/never gets finished. Usually this happens on servers with a lot of filesystems and/or zones. Against the latter we can't do anything right now, however one should let lu* commands ignore all filesystems, which are not required for the purpose of live upgrade/patching, so that the lu commands do not try to [un]mount per loopback aka lofs into the appropriate BE/zones. E.g. excluding ~2200 ZFS on a X4600 M2 (4xDualCore Opteron 8222 3GHz) saves about 40 min per lucreate, lumount, luactivate, etc. (or about 1s per ignored filesystem) ...

To accomplish that, one needs to apply the lu patch mentioned above, create the file /etc/lu/fs2ignore.regex and add the regular expressions (one per line) which match those filesystems, which should be ignored by lu* commands.

E.g. to exclude all user home directories or better ZFSs, whomes mountpoint is below /export/home, the following command is sufficient:

echo '/export/home' > /etc/lu/fs2ignore.regex
# check whether this is, what you want
pfexec /sbin/sh /usr/lib/lu/ludefine -v /etc/vfstab -n tmpBE
# and make sure, no pathes inherited to zones are hidden - if the following
# command lists anything on stdout, chances for getting into trouble are very high
/usr/bin/egrep -f /etc/lu/fs2ignore.regex /etc/zones/*

For more information about valid regular expressions see the man page for /usr/bin/egrep, which is the command used with the option -v to filter out the filesystems from mount -p and zfs list.

Always make sure, that /etc/lu/fs2ignore.regex matches the filesystems you wanna have ignored, and nothing else. Otherwise LU commands may fail or even destroy valueable data!

luactivate: /etc/lu/DelayUpdate/: cannot create

The latest bug introduced with 121430-36/121431-37. This happens, because the appropriate script uses the environment variable BOOT_MENU_FILE very often, but is unset. So the simple workaround is to set this variable to its intended value, before invoking luactivate:

setenv BOOT_MENU_FILE menu.lst

patchadd: Not enough space in /var/run

It may happen, that patchadd moans about not having enough space in /var/run to copy overlay objects (e.g. kernel patch 139555-08). On recent Solaris versions /var/run is a tmpfs. So if you have not enough RAM or e.g. a line like the following one in your /etc/vfstab, patchadd can fail:

swap    -   /tmp    tmpfs   -   yes size=512M

Since Solaris seems to allocated per default the half of the given size parameter per default, patchadd sees even on a almost clean /tmp only ~ 256M or even less, depending on what your system is currently doing. E.g.:

swap                   262M   136K       262M     1%    /tmp
swap                   262M    48K       262M     1%    /var/run
swap                   264M   1.3M       262M     1%    /etc/svc/volatile
# bootenvironment to be patched
rpool0/ROOT/s10u6_20090517    33G   4.7G        18G    22%    /mnt
swap                   262M     8K       262M     1%    /mnt/var/run
swap                   262M     0K       262M     0%    /mnt/tmp

Obviously all tmpfs filesystems try to share the same "memory partition".

So to fix the problem, one may change the size parameter for /tmp at least to 2x the size patchadd needs and reboot (in contrast to other OSs remounting it is not supported on Solaris). However, rebooting is often not an option for production systems, so one may try to force the OS to allocate the max. tmpfs size by creating an appropriate sized file and removing it right before starting patchadd. Note: In contrast what one may expect, Solaris does not satisfy immediately your "more space request" and thus your used "create sized file" procedure may fail several times 'til /tmp gets its max size as specified in /etc/vfstab (IMHO that's a bug). Also note, that the OS tries to resize it down, as soon as possible. So you need to be fast, when starting patchadd after you got an appriopriate sized /tmp aka /var/run .

cd /var/tmp
unzip 139555-08.zip

# repeat until you got, what you want 
dd if=/dev/zero of=/tmp/test.dd bs=1024k count=512
df -h /tmp

# than hurry up with patching, e.g.
rm /tmp/test.dd ; /usr/sbin/patchadd -R /mnt /var/tmp/139555-08

ERROR: Failure reading non-global zone module

If you have packages installed, which don't obey the restrictions of pkginfo(4), e.g. having a description with more than 1023 characters, luupgrade may fail with the error message ERROR: Failure reading non-global zone module: zonename. The only way to fix it is to uninstall the given package and re-install it after the zone has been upgraded. To find the problematic package, one may use something like this:

nawk '/DESC=/ { print length($0)-5 , FILENAME }' \
     `find /var/sadm/pkg -name pkginfo | fgrep -v /save/` | sort -nr

Copyright (C) 2008 Jens Elkner (jel+lu@cs.uni-magdeburg.de)