yast/yast-storage-ng

View on GitHub
doc/upgrade.md

Summary

Maintainability
Test Coverage
# Upgrade process

This document summarizes some potential problems with storage-ng when trying to upgrade a system.

During the product upgrade, that is, when selecting "Upgrade" option in the Linuxrc menu, all filesystems are mounted to discover the current installed Operating Systems. Then, the user selects what OS should be upgraded from the list of available Operating Systems.

Once an OS is selected, the filesystem is mounted again and its /etc/fstab is parsed. Each entry in the fstab is also mounted, except the entry associated to the root mount point because root is already mounted.

This process can lead to some potential problems in storage-ng when the device to mount is an encryption device. First of all, we need to understand how fstab file is generated by storage-ng.

Storage-ng generates each entry in the fstab by taking into account the `mount_by` option of the filesystem mount point:

```

UUID=111-222-333                    /home   ext4    defaults 0 0  # mount_by = uuid
/dev/sda2                           /home   ext4    defaults 0 0  # mount_by = device name
LABEL=home_enc                      /home   ext4    defaults 0 0  # mount_by = volume label
/dev/disk/by-id/scsi-11212-part2    /home   ext4    defaults 0 0  # mount_by = device id
/dev/disk/by-path/pci-0002-part2    /home   ext4    defaults 0 0  # mount_by = device path

```

In case that the filesystem is directly over an encryption device, the fstab entries might be something like:

```
UUID=111-222-333                            /home   ext4    defaults 0 0  # mount_by = uuid
/dev/mapper/cr_ata-111-part2                /home   ext4    defaults 0 0  # mount_by = device name
LABEL=home_enc                              /home   ext4    defaults 0 0  # mount_by = volume label
/dev/disk/by-id/dm-name-cr_ata-111-part2    /home   ext4    defaults 0 0
/dev/disk/by-uuid/111-222-333               /home   ext4    defaults 0 0
/dev/disk/by-label/home_enc                 /home   ext4    defaults 0 0
```

Note that storage-ng generates fstab entries for encryption devices only by using "uuid", "device name" or "volume label" format, although the user always could edit a fstab entry and add another possible udev name, for example, by-id, by-uuid or by-label. Option by-path does not apply for encryption devices because they are not real physical devices attached to a port.

The problems come when the fstab entry contains the encryption device name as part of the device spec ("cr_ata-111-part2" in the example above):

```
/dev/mapper/cr_ata-111-part2                /home   ext4    defaults 0 0  # mount_by = device name
/dev/disk/by-id/dm-name-cr_ata-111-part2    /home   ext4    defaults 0 0
```

In that cases, there are two potential problems when trying to mount the device indicated in that fstab entry. On one hand, the device could not be found in the probed devicegraph. And, on the other hand, that device name could not exist in the inst-sys. Let's see each case.

## Problem 1: device not found in devicegraph

As mentioned above, the device name of an encryption device could not be found in the probed devicegraph. The reason is because storage-ng probes the encryption devices with an auto-generated name (e.g., "cr-auto-1"), and in general, that auto-generated name does not match with the name from the fstab entry.

So, if the fstab has an entry like the following:

```
/dev/mapper/cr_ata-111-part2    /home   ext4    defaults 0 0
```

that "/dev/mapper/cr_ata-111-part2" will not be found in the devicegraph because there is nothing probed with that name. To avoid this problem, the crypttab file of the Operating System to upgrade is parsed in addition to its fstab file.

Storage-ng generates the crypttab entries taking into account the default `mount_by` option. So, the crypttab file could have entries like:

```
cr_home     UUID=000-111-222                            # default mount_by = uuid
cr_home     /dev/sda2                                   # default mount_by = device name
cr_home     /dev/sda2                                   # default mount_by = volume label
cr_home     /dev/disk/by-id/scsi-11212-part2            # default mount_by = device id
cr_home     /dev/disk/by-path/pci-0002-part2            # default mount_by = device path
cr_home     /dev/disk/by-uuid/000-111-222
```

Several things to take into account here. When the UUID= format is used, that UUID refers to the LUKS device instead of the underlying device. When the default mount_by is "volume label", the kernel name of the underlying device is used. When using "device id" or "device path" as default mount_by, the proper udev name of the underlying device is used. And finally, the user could indicate a device by using uuid udev name.

Once the crypttab file is parsed, the information about encryption names is stored in the devicegraph to be able to find an encryption device when it was probed with another name. For example, if we have a fstab entry like:

```
/dev/mapper/cr_home     /home   ext4    defaults 0 0
```

and a crypttab entry like:

```
cr_home     /dev/sda2
```

the device "/dev/sda2" is searched in the devicegraph and the crypttab name "cr_home" is stored in its associated encryption device. So, in case that there is an encryption device over "/dev/sda2", for example "/dev/mapper/cr-auto-1", that encryption device will save "cr_home" as alternative name.

Once this information is saved in the encryption devices, when an encryption name is searched in the devicegraph, we can check if the searched named is the alternative name of any encryption device. So, for this example, when we search in the devicegraph the device by "/dev/mapper/cr_home", we can return "/dev/mapper/cr-auto-1".

This problem was fixed for SLE-15, see pull requests for [libstorage-ng](https://github.com/openSUSE/libstorage-ng/pull/535), [yast2-storage-ng](https://github.com/yast/yast-storage-ng/pull/659) and [yast2-update](https://github.com/yast/yast-update/pull/101) packages. And here the related bug [bsc#1094963](https://bugzilla.suse.com/show_bug.cgi?id=1094963).


## Problem 2: device not found in inst-sys

The second problem comes when the mounting action is peformed by using the encryption name read from the fstab file. As mentioned above, the fstab entry for an encryption device could be one of the following:

```
UUID=111-222-333                            /home   ext4    defaults 0 0  # mount_by = uuid
/dev/mapper/cr_ata-111-part2                /home   ext4    defaults 0 0  # mount_by = device name
LABEL=home_enc                              /home   ext4    defaults 0 0  # mount_by = volume label
/dev/disk/by-id/dm-name-cr_ata-111-part2    /home   ext4    defaults 0 0
/dev/disk/by-uuid/111-222-333               /home   ext4    defaults 0 0
/dev/disk/by-label/home_enc                 /home   ext4    defaults 0 0
```

The fstab spec could be problematic when it includes the encryption device name as part of the device spec, that is:

```
/dev/mapper/cr_ata-111-part2                /home   ext4    defaults 0 0
/dev/disk/by-id/dm-name-cr_ata-111-part2    /home   ext4    defaults 0 0
```

In such cases, the mount command would fail if the encryption device was probed with another name. For example, if the encryption device was probed with "cr-auto-1" name, the inst-sys will contain the following device names:

```
/dev/mapper/cr-auto-1
/dev/disk/by-id/dm-name-cr-auto-1
```

So, when the fstab device tryied to be mounted, it will fail:

```
mount /dev/mapper/cr_ata-111-part2 /home  => fail device /dev/mapper/cr_ata-111-part2 does not exist
```

The solution here is to avoid to use the fstab spec when that device name is not safe enough. So, instead of using the fstab spec, the udev uuid name of the encryption device will be used due to that name exists in the inst-sys:

```
mount /dev/disk/by-uuid/111-222-333 /home
```

Note that the old storage was creating fstab entries with the option "nofail" for some mount points, for example "/" or "/home". Therefore, a system generated with old storage could silently fail when trying to mount the filesystem, and the upgrade process could finish without that volume being mounted.

```
/dev/mapper/cr_ata-111-part2                /home   ext4    nofail 0 0
```

This could make the upgrade useless when some important mount point is not properly mounted, for example, when mounting an encrypted /usr silently fails.

Those problems are now fixed for SLE-15-SP1, see pull requests for [libstorage-ng](https://github.com/openSUSE/libstorage-ng/pull/589), [yast2-storage-ng](https://github.com/yast/yast-storage-ng/pull/790) and [yast2-update](https://github.com/yast/yast-update/pull/115).