xref: /aosp_15_r20/system/apex/apexd/apexd_dm.cpp (revision 33f3758387333dbd2962d7edbd98681940d895da)
1*33f37583SAndroid Build Coastguard Worker /*
2*33f37583SAndroid Build Coastguard Worker  * Copyright (C) 2024 The Android Open Source Project
3*33f37583SAndroid Build Coastguard Worker  *
4*33f37583SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*33f37583SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*33f37583SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*33f37583SAndroid Build Coastguard Worker  *
8*33f37583SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*33f37583SAndroid Build Coastguard Worker  *
10*33f37583SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*33f37583SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*33f37583SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*33f37583SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*33f37583SAndroid Build Coastguard Worker  * limitations under the License.
15*33f37583SAndroid Build Coastguard Worker  */
16*33f37583SAndroid Build Coastguard Worker 
17*33f37583SAndroid Build Coastguard Worker #include "apexd_dm.h"
18*33f37583SAndroid Build Coastguard Worker 
19*33f37583SAndroid Build Coastguard Worker #include <ApexProperties.sysprop.h>
20*33f37583SAndroid Build Coastguard Worker #include <android-base/logging.h>
21*33f37583SAndroid Build Coastguard Worker #include <utils/Trace.h>
22*33f37583SAndroid Build Coastguard Worker 
23*33f37583SAndroid Build Coastguard Worker using android::base::ErrnoError;
24*33f37583SAndroid Build Coastguard Worker using android::base::Error;
25*33f37583SAndroid Build Coastguard Worker using android::base::Result;
26*33f37583SAndroid Build Coastguard Worker using android::dm::DeviceMapper;
27*33f37583SAndroid Build Coastguard Worker using android::dm::DmDeviceState;
28*33f37583SAndroid Build Coastguard Worker using android::dm::DmTable;
29*33f37583SAndroid Build Coastguard Worker 
30*33f37583SAndroid Build Coastguard Worker namespace android::apex {
31*33f37583SAndroid Build Coastguard Worker 
~DmDevice()32*33f37583SAndroid Build Coastguard Worker DmDevice::~DmDevice() {
33*33f37583SAndroid Build Coastguard Worker   if (!cleared_) {
34*33f37583SAndroid Build Coastguard Worker     Result<void> ret = DeleteDmDevice(name_, /* deferred= */ false);
35*33f37583SAndroid Build Coastguard Worker     if (!ret.ok()) {
36*33f37583SAndroid Build Coastguard Worker       LOG(ERROR) << ret.error();
37*33f37583SAndroid Build Coastguard Worker     }
38*33f37583SAndroid Build Coastguard Worker   }
39*33f37583SAndroid Build Coastguard Worker }
40*33f37583SAndroid Build Coastguard Worker 
CreateDmDeviceInternal(DeviceMapper & dm,const std::string & name,const DmTable & table,const std::chrono::milliseconds & timeout)41*33f37583SAndroid Build Coastguard Worker static Result<DmDevice> CreateDmDeviceInternal(
42*33f37583SAndroid Build Coastguard Worker     DeviceMapper& dm, const std::string& name, const DmTable& table,
43*33f37583SAndroid Build Coastguard Worker     const std::chrono::milliseconds& timeout) {
44*33f37583SAndroid Build Coastguard Worker   std::string dev_path;
45*33f37583SAndroid Build Coastguard Worker   if (!dm.CreateDevice(name, table, &dev_path, timeout)) {
46*33f37583SAndroid Build Coastguard Worker     return Error() << "Couldn't create dm-device.";
47*33f37583SAndroid Build Coastguard Worker   }
48*33f37583SAndroid Build Coastguard Worker   return DmDevice(name, dev_path);
49*33f37583SAndroid Build Coastguard Worker }
50*33f37583SAndroid Build Coastguard Worker 
CreateDmDevice(const std::string & name,const DmTable & table,bool reuse_device)51*33f37583SAndroid Build Coastguard Worker Result<DmDevice> CreateDmDevice(const std::string& name, const DmTable& table,
52*33f37583SAndroid Build Coastguard Worker                                 bool reuse_device) {
53*33f37583SAndroid Build Coastguard Worker   ATRACE_NAME("CreateDmDevice");
54*33f37583SAndroid Build Coastguard Worker   LOG(VERBOSE) << "Creating dm-device " << name;
55*33f37583SAndroid Build Coastguard Worker 
56*33f37583SAndroid Build Coastguard Worker   auto timeout = std::chrono::milliseconds(
57*33f37583SAndroid Build Coastguard Worker       android::sysprop::ApexProperties::dm_create_timeout().value_or(1000));
58*33f37583SAndroid Build Coastguard Worker 
59*33f37583SAndroid Build Coastguard Worker   DeviceMapper& dm = DeviceMapper::Instance();
60*33f37583SAndroid Build Coastguard Worker 
61*33f37583SAndroid Build Coastguard Worker   auto state = dm.GetState(name);
62*33f37583SAndroid Build Coastguard Worker   if (state == DmDeviceState::INVALID) {
63*33f37583SAndroid Build Coastguard Worker     return CreateDmDeviceInternal(dm, name, table, timeout);
64*33f37583SAndroid Build Coastguard Worker   }
65*33f37583SAndroid Build Coastguard Worker 
66*33f37583SAndroid Build Coastguard Worker   if (reuse_device) {
67*33f37583SAndroid Build Coastguard Worker     if (state == DmDeviceState::ACTIVE) {
68*33f37583SAndroid Build Coastguard Worker       LOG(WARNING) << "Deleting existing active dm-device " << name;
69*33f37583SAndroid Build Coastguard Worker       OR_RETURN(DeleteDmDevice(name, /* deferred= */ false));
70*33f37583SAndroid Build Coastguard Worker       return CreateDmDeviceInternal(dm, name, table, timeout);
71*33f37583SAndroid Build Coastguard Worker     }
72*33f37583SAndroid Build Coastguard Worker     if (!dm.LoadTableAndActivate(name, table)) {
73*33f37583SAndroid Build Coastguard Worker       dm.DeleteDevice(name);
74*33f37583SAndroid Build Coastguard Worker       return Error() << "Failed to activate dm-device " << name;
75*33f37583SAndroid Build Coastguard Worker     }
76*33f37583SAndroid Build Coastguard Worker     std::string path;
77*33f37583SAndroid Build Coastguard Worker     if (!dm.WaitForDevice(name, timeout, &path)) {
78*33f37583SAndroid Build Coastguard Worker       dm.DeleteDevice(name);
79*33f37583SAndroid Build Coastguard Worker       return Error() << "Failed waiting for dm-device " << name;
80*33f37583SAndroid Build Coastguard Worker     }
81*33f37583SAndroid Build Coastguard Worker     return DmDevice(name, path);
82*33f37583SAndroid Build Coastguard Worker   } else {
83*33f37583SAndroid Build Coastguard Worker     // Delete dangling dm-device. This can happen if apexd fails to delete it
84*33f37583SAndroid Build Coastguard Worker     // while unmounting an apex.
85*33f37583SAndroid Build Coastguard Worker     LOG(WARNING) << "Deleting existing dm-device " << name;
86*33f37583SAndroid Build Coastguard Worker     OR_RETURN(DeleteDmDevice(name, /* deferred= */ false));
87*33f37583SAndroid Build Coastguard Worker     return CreateDmDeviceInternal(dm, name, table, timeout);
88*33f37583SAndroid Build Coastguard Worker   }
89*33f37583SAndroid Build Coastguard Worker }
90*33f37583SAndroid Build Coastguard Worker 
91*33f37583SAndroid Build Coastguard Worker // Deletes a device-mapper device with a given name and path
92*33f37583SAndroid Build Coastguard Worker // Synchronizes on the device actually being deleted from userspace.
DeleteDmDevice(const std::string & name,bool deferred)93*33f37583SAndroid Build Coastguard Worker Result<void> DeleteDmDevice(const std::string& name, bool deferred) {
94*33f37583SAndroid Build Coastguard Worker   DeviceMapper& dm = DeviceMapper::Instance();
95*33f37583SAndroid Build Coastguard Worker   if (deferred) {
96*33f37583SAndroid Build Coastguard Worker     if (!dm.DeleteDeviceDeferred(name)) {
97*33f37583SAndroid Build Coastguard Worker       return ErrnoError() << "Failed to issue deferred delete of dm-device "
98*33f37583SAndroid Build Coastguard Worker                           << name;
99*33f37583SAndroid Build Coastguard Worker     }
100*33f37583SAndroid Build Coastguard Worker     return {};
101*33f37583SAndroid Build Coastguard Worker   }
102*33f37583SAndroid Build Coastguard Worker   auto timeout = std::chrono::milliseconds(
103*33f37583SAndroid Build Coastguard Worker       android::sysprop::ApexProperties::dm_delete_timeout().value_or(750));
104*33f37583SAndroid Build Coastguard Worker   if (!dm.DeleteDevice(name, timeout)) {
105*33f37583SAndroid Build Coastguard Worker     return Error() << "Failed to delete dm-device " << name;
106*33f37583SAndroid Build Coastguard Worker   }
107*33f37583SAndroid Build Coastguard Worker   return {};
108*33f37583SAndroid Build Coastguard Worker }
109*33f37583SAndroid Build Coastguard Worker 
110*33f37583SAndroid Build Coastguard Worker }  // namespace android::apex