Commit graph

13 commits

Author SHA1 Message Date
David Anderson
91c9f56d30 libsnapshot: Pass the correct source device to snapuserd.
When a partition shrinks, it is not correct to use the base device as
the "source" device for the new COW format, because we may need to read
blocks that do not exist in the new partition.

To resolve this, we store a copy of the old partition layout in /metadata,
and use it to create a "source" view of the old partition. The new
stacking looks as follows:

  partition_b (dm-snapshot):
   - partition_b-base (partition_b dm-linear)
   - partition_b-cow-user (dm-user + snapuserd):
      - partition_b-cow (COW image)
      - partition_b-src (partition_a dm-linear)

Bug: 177935716
Test: vts_libsnapshot_test
Change-Id: I872f271cc1f25cc796b94188fdde247cdc4050b4
2021-01-20 18:17:08 -08:00
David Anderson
eb7eb4bef6 libsnapshot: Use the COW size from the update manifest.
When Virtual A/B Compression is enabled, the manifest contains the
predicted COW size. Use this instead of the algorithm based on the
kernel COW format.

Bug: 168554689
Test: vts_libsnapshot_test
Change-Id: I545679b4834957ff80a930d91cb44afbadebb66c
2020-11-02 13:24:16 -08:00
David Anderson
f57fd97df3 libsnapshot: Add support for first-to-second-stage transitions of snapuserd.
This patch introduces the fundamentals needed to support booting off
dm-user. First, a method has been added to start snapuserd in
first-stage init. It simply forks and execs, creates a specially named
first-stage socket, then waits for requests.

Next, a new method has been added to SnapshotManager to perform a
second-stage handoff. This works by first launching a second copy of
snapuserd using init's normal service management functionality. The new
snapuserd runs alongside the original, but has correct privileges and a
correct selinux context. Next, we inspect each COW device, and if its
table uses dm-user, we replace the table with a renamed control
device. The new control device is bound to the new snapuserd.

device-mapper guarantees that such a table swap is safe. It flushes I/O
to the old table and then replaces it with the new table. Once the new
table is in place, the old dm-user control devices are automatically
destroyed. Thus, once all dm-user devices has been transitioned, the
first-stage daemon is idle and can gracefully exit.

This patch does not modify init. A few changes will be needed on top of
this patch:

(1) CreateLogicalAndSnapshotPartitions will need further changes to
start the first-stage daemon and track its pid. Additionally, it will
need to ensure the named socket file is deleted, so there is no further
IPC allowed after partitions are completed.
(2) init will need to propagate the pid to second-stage init so the
process can be killed (or signalled).
(3) first-stage snapuserd will need to gracefully exit once it has no
active handler threads.
(4) second-stage init will need to invoke the transition helper on
SnapshotMaanager, ideally as soon as feasible.

Bug: 168259959
Test: manual test
Change-Id: I54dec2edf85ed95f11ab4518eb3d7dbaf0bdcbfd
2020-11-02 13:24:05 -08:00
Yifan Hong
dee5225b6c Add OptimizeSourceCopyOperation
... so that an operation can be skipped partially. For example, if
an operation contains blocks:
    563412 -> 123456
... then optimized operation is:
    5612 -> 1256

Test: update_engine_unittests
Test: apply incremental OTA
Bug: 148623880

In an experiment, this reduces CoW size of an incremental update
package by 200MB (out of 700MB).

Change-Id: I86ca23fd589ddbc84c81318283b5f4e71782a759
2020-03-11 12:10:32 -07:00
Yifan Hong
12fe03d470 Make snapshotctl logging better.
snapshotctl merge --logcat --log-to-file
- If --logcat, log to logcat
- If --log-to-file, log to /data/misc/snapshotctl_log/
- If both, log to both
- If none, log to stdout

Test: manually test these 4 cases
Bug: 148818798
Change-Id: I44b52936c0d095867acc6ee781c6bec04f6ebd6b
2020-02-04 14:01:24 -08:00
Yifan Hong
b37311d4dd SnapshotManager::Return -> Return
Now that the class becomes more complicated, move it out
of SnapshotManager.

Also, make it independent of FiemapStatus. libsnapshot and
libfiemap has different return classes.

Test: libsnapshot_test
Change-Id: If340959ba60bcd51c36e2b48f4d11c149ead907a
2020-01-17 14:43:27 -08:00
Yifan Hong
cd232f9734 SnapshotManager expose no space error
When there is not enough space on /userdata, CreateUpdateSnapshot
returns SnapshotManager::Return with ErrorCode::NO_SPACE.

Test: libsnapshot_test
Bug: 138808058

Change-Id: If2effe63f6a4324eff8d05d4db4ce98be8190262
2020-01-07 14:20:44 -08:00
Yifan Hong
55974f1425 libsnapshot: write files atomically
... by writing to a temporary file then rename()'ing it
back.

Test: libsnapshot_test
Bug: 144549076
Change-Id: Ide400aff8d67d56d422d0adea3a4f1673ebc9994
2019-12-04 14:49:47 -08:00
Alessio Balsini
3ab9f1f85b COW device initialized by zeroing the whole first chunk
To be compliant with lvm, instead of just zeroing the first 32 bit of
the COW device, force to zero the whole first chunk.
Also switch to std::vector to store the zeroes, reducing the stack
growth.

Test: libsnapshot_test
Bug: 139202197
Change-Id: I2d98549528a222d6c27bb566c68477b5ec3add20
Signed-off-by: Alessio Balsini <balsini@google.com>
2019-10-30 17:50:59 +00:00
Yifan Hong
d2a0247538 libsnapshot: Add EnsureMetadataMounted
In recovery, client is responsible for calling
EnsureMetadataMounted before doing (almost) all
operations on SnapshotManager, e.g.

- CancelUpdate() before sideloading
- BeginUpdate() on retrofit Virtual A/B before sideloading
- Finishing merge before flashing

Test: libsnapshot_test
Test: recovery sideload
Bug: 140749209
Change-Id: I1034a7fa74e31b6850896e61e86341239dbf2699
2019-10-25 15:37:11 -07:00
Yifan Hong
20a23bb41c libsnapshot: Also use empty space in super for COW
The super partition usually has some empty space even after
the target partitions are created, especially for retrofit
Virtual A/B devices. Use that empty space for COW before taking
up userdata space.

- PartitionCowCreator computes free regions in super partition metadata
  and use that space until it is used up. It returns a pair of numbers
  (cow_partition_size, cow_file_size) and let SnapshotManager to create
  the partition / images with proper sizes.
  - A region is considered free iff it is used by NEITHER target NOR
    source partitions
  - The list is in PartitionCowCreator's return value so that
    SnapshotManager can use it as a guide when creating partitions.
  - These partitions are created under the group named "cow".
    - Avoid mapping COW partitions directly during init first stage
      mount. Init only maps them when they are needed by the top-level
      device.
- CreateCowImage no longer zero-fills the first 4 bytes of the image.
  (See below)
- CreateUpdatePartitions: after creating the snapshot, also maps the COW
  devices (via MapCowDevices()) and zero-fills the first 4 bytes of the
  top-level COW device.
- Add a new SnapshotManager::MapCowDevices() function, which maps both
  the COW partition (in super) and the COW image (through
  IImageManager) (if necessary). Then, create a dm-linear target that
  concatenates them (if necessary).
- Add a new SnapshotManager::UnmapCowDevices() functions that does the
  reverse MapCowDevices().
- DeleteSnapshot also unmaps the top-level COW device and COW partition
  before unmapping the COW images (before deleting them).

Test: libsnapshot_test

Change-Id: I0098b7e842ab48b0b4dd2a59142098b098d23d34
2019-09-11 18:32:57 -07:00
Yifan Hong
c69029f2a8 libsnapshot: APIs for all partitions
Add CreateCowForUpdate / MapSnapshotDevicesForUpdate
that update_engine and init can call them directly.

Bug: 134536978
Test: libsnapshot_test

Change-Id: If53c48855931db27454fd2893745915c77fd37f8
2019-09-11 18:32:57 -07:00
Yifan Hong
f35687df6e libsnapshot: MapPartitionWithSnapshot cleanup itself if failed
When we run MapPartitionWithSnapshot, intermediate devices aren't
cleaned up if the call fails. Hence, record these intermediate devices
we have created along the way using the new AutoDevices class. Upon
failure, the AutoDevices object will be destroyed, and all the
intermediate devices will be deleted from device mapper or image
manager. Upon success, AutoDevices::Release() makes sure the
intermediate devices aren't deleted.

Test: libsnapshot_test

Change-Id: Iff4c1297528288a27765c0224b67254b68c89776
2019-09-05 15:14:34 -07:00