platform_system_core/fs_mgr/libfiemap
David Anderson 0aabcbc973 remount: Remove errno interaction from fs_mgr_overlayfs_teardown.
This patch eliminates errno as part of the return contract for
fs_mgr_overlayfs_teardown().

The non-standard use of implicit errno makes it extremely difficult to
reason about how these functions can fail. As it turns out,
fs_mgr_overlayfs_teardown has been consistently failing for a long time,
but in a place where errno isn't set, which meant "enable-verity" never
saw the failure.

The failure was originating from umount2(MNT_DETACH) which guaranteed
that DeleteBackingImage would fail with EBUSY, and DeleteBackingImage is
a binder call that doesn't set errno.

This patch switches to umount() and returns a "busy" status if the
unmount fails with EBUSY. In this case it will also disable the scratch
partition. There is a long-standing existing bug where, for non-VAB
devices, it will delete the underlying scratch partition off super. This
is pretty risky with MNT_DETACH, but that path is left unchanged here.

Some duplicated code in set-verity-state was refactored as well, since
the return value of fs_mgr_overlayfs_teardown is now more complex.

Bug: 241179247
Test: adb-remount-test.sh
Change-Id: I2ca75332b75a302622ba9b86d122a6f2accdda3e
2022-09-19 22:30:05 -07:00
..
include/libfiemap remount: Remove errno interaction from fs_mgr_overlayfs_teardown. 2022-09-19 22:30:05 -07:00
testdata fs_mgr: Move libfiemap back to fs_mgr from system/gsid. 2019-12-16 20:10:26 -08:00
Android.bp Replace test_min_api_level with test_options.min_shipping_api_level 2021-09-28 20:35:09 +09:00
binder.cpp remount: Remove errno interaction from fs_mgr_overlayfs_teardown. 2022-09-19 22:30:05 -07:00
fiemap_status.cpp libfiemap: Create/Open returns FiemapStatus 2020-01-07 13:01:58 -08:00
fiemap_writer.cpp libfiemap: array boundary check for fiemap.fm_extents[] 2021-11-02 11:38:31 +08:00
fiemap_writer_test.cpp libfiemap: array boundary check for fiemap.fm_extents[] 2021-11-02 11:38:31 +08:00
image_manager.cpp fs_mgr: Fix __ANDROID_RECOVERY__ usage in libfiemap. 2022-02-17 13:06:13 -08:00
image_test.cpp libfiemap: Add a test case for larger block size filesystems. 2022-07-22 17:44:12 -07:00
metadata.cpp Extra logging for metadata errors 2020-02-04 20:49:59 +00:00
metadata.h libfiemap: Add a helper to verify image fiemaps. 2022-01-10 03:19:22 +00:00
passthrough.cpp libfiemap: Add some dependency injection. 2021-02-26 17:28:17 -08:00
README.md fs_mgr: Move libfiemap back to fs_mgr from system/gsid. 2019-12-16 20:10:26 -08:00
split_fiemap_writer.cpp libfiemap: Fix removal of corrupted split fiemaps. 2021-07-19 14:02:56 -07:00
utility.cpp Merge "Fix allowlist for unreliable pinning." 2020-08-07 17:57:13 +00:00
utility.h Fix allowlist for unreliable pinning. 2020-08-06 15:02:56 -07:00

libfiemap

libfiemap is a library for creating block-devices that are backed by storage in read-write partitions. It exists primary for gsid. Generally, the library works by using libfiemap_writer to allocate large files within filesystem, and then tracks their extents.

There are three main uses for libfiemap:

  • Creating images that will act as block devices. For example, gsid needs to create a system_gsi image to store Dynamic System Updates.
  • Mapping the image as a block device while /data is mounted. This is fairly tricky and is described in more detail below.
  • Mapping the image as a block device during first-stage init. This is simple because it uses the same logic from dynamic partitions.

Image creation is done through SplitFiemap. Depending on the file system, a large image may have to be split into multiple files. On Ext4 the limit is 16GiB and on FAT32 it's 4GiB. Images are saved into /data/gsi/<name>/ where <name> is chosen by the process requesting the image.

At the same time, a file called /metadata/gsi/<name>/lp_metadata is created. This is a super partition header that allows first-stage init to create dynamic partitions from the image files. It also tracks the canonical size of the image, since the file size may be larger due to alignment.

Mapping

It is easy to make block devices out of blocks on /data when it is not mounted, so first-stage init has no issues mapping dynamic partitions from images. After /data is mounted however, there are two problems:

  • /data is encrypted.
  • /dev/block/by-name/data may be marked as in-use.

We break the problem down into three scenarios.

FDE and Metadata Encrypted Devices

When FDE or metadata encryption is used, /data is not mounted from /dev/block/by-name/data. Instead, it is mounted from an intermediate dm-crypt or dm-default-key device. This means the underlying device is not marked in use, and we can create new dm-linear devices on top of it.

On these devices, a block device for an image will consist of a single device-mapper device with a dm-linear table entry for each extent in the backing file.

Unencrypted and FBE-encrypted Devices

When a device is unencrypted, or is encrypted with FBE but not metadata encryption, we instead use a loop device with LOOP_SET_DIRECT_IO enabled. Since /data/gsi has encryption disabled, this means the raw blocks will be unencrypted as well.

Split Images

If an image was too large to store a single file on the underlying filesystem, on an FBE/unencrypted device we will have multiple loop devices. In this case, we create a device-mapper device as well. For each loop device it will have one dm-linear table entry spanning the length of the device.

State Tracking

It's important that we know whether or not an image is currently in-use by a block device. It could be catastrophic to write to a dm-linear device if the underlying blocks are no longer owned by the original file. Thus, when mapping an image, we create a property called gsid.mapped_image.<name> and set it to the path of the block device.

Additionally, we create a /metadata/gsi/<subdir>/<name>.status file. Each line in this file denotes a dependency on either a device-mapper node or a loop device. When deleting a block device, this file is used to release all resources.