Merge "liblog: use default tag for loggability checks if no tag is provided"
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 3463a68..9180a06 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -101,6 +101,7 @@
 using android::base::unique_fd;
 using android::dm::DeviceMapper;
 using android::dm::DmDeviceState;
+using android::dm::DmTargetLinear;
 
 // Realistically, this file should be part of the android::fs_mgr namespace;
 using namespace android::fs_mgr;
@@ -1114,6 +1115,83 @@
     }
 }
 
+static constexpr const char* kUserdataWrapperName = "userdata-wrapper";
+
+static void WrapUserdata(FstabEntry* entry, dev_t dev, const std::string& block_device) {
+    DeviceMapper& dm = DeviceMapper::Instance();
+    if (dm.GetState(kUserdataWrapperName) != DmDeviceState::INVALID) {
+        // This will report failure for us. If we do fail to get the path,
+        // we leave the device unwrapped.
+        dm.GetDmDevicePathByName(kUserdataWrapperName, &entry->blk_device);
+        return;
+    }
+
+    unique_fd fd(open(block_device.c_str(), O_RDONLY | O_CLOEXEC));
+    if (fd < 0) {
+        PLOG(ERROR) << "open failed: " << entry->blk_device;
+        return;
+    }
+
+    auto dev_str = android::base::StringPrintf("%u:%u", major(dev), minor(dev));
+    uint64_t sectors = get_block_device_size(fd) / 512;
+
+    android::dm::DmTable table;
+    table.Emplace<DmTargetLinear>(0, sectors, dev_str, 0);
+
+    std::string dm_path;
+    if (!dm.CreateDevice(kUserdataWrapperName, table, &dm_path, 20s)) {
+        LOG(ERROR) << "Failed to create userdata wrapper device";
+        return;
+    }
+    entry->blk_device = dm_path;
+}
+
+// When using Virtual A/B, partitions can be backed by /data and mapped with
+// device-mapper in first-stage init. This can happen when merging an OTA or
+// when using adb remount to house "scratch". In this case, /data cannot be
+// mounted directly off the userdata block device, and e2fsck will refuse to
+// scan it, because the kernel reports the block device as in-use.
+//
+// As a workaround, when mounting /data, we create a trivial dm-linear wrapper
+// if the underlying block device already has dependencies. Note that we make
+// an exception for metadata-encrypted devices, since dm-default-key is already
+// a wrapper.
+static void WrapUserdataIfNeeded(FstabEntry* entry, const std::string& actual_block_device = {}) {
+    const auto& block_device =
+            actual_block_device.empty() ? entry->blk_device : actual_block_device;
+    if (entry->mount_point != "/data" || !entry->key_dir.empty() ||
+        android::base::StartsWith(block_device, "/dev/block/dm-")) {
+        return;
+    }
+
+    struct stat st;
+    if (stat(block_device.c_str(), &st) < 0) {
+        PLOG(ERROR) << "stat failed: " << block_device;
+        return;
+    }
+
+    std::string path = android::base::StringPrintf("/sys/dev/block/%u:%u/holders",
+                                                   major(st.st_rdev), minor(st.st_rdev));
+    std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
+    if (!dir) {
+        PLOG(ERROR) << "opendir failed: " << path;
+        return;
+    }
+
+    struct dirent* d;
+    bool has_holders = false;
+    while ((d = readdir(dir.get())) != nullptr) {
+        if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
+            has_holders = true;
+            break;
+        }
+    }
+
+    if (has_holders) {
+        WrapUserdata(entry, st.st_rdev, block_device);
+    }
+}
+
 static bool IsMountPointMounted(const std::string& mount_point) {
     // Check if this is already mounted.
     Fstab fstab;
@@ -1193,6 +1271,8 @@
             }
         }
 
+        WrapUserdataIfNeeded(&current_entry);
+
         if (!checkpoint_manager.Update(&current_entry)) {
             continue;
         }
@@ -1463,6 +1543,9 @@
     }
     std::string block_device;
     if (auto entry = GetEntryForMountPoint(&proc_mounts, "/data"); entry != nullptr) {
+        // Note: we don't care about a userdata wrapper here, since it's safe
+        // to remount on top of the bow device instead, there will be no
+        // conflicts.
         block_device = entry->blk_device;
     } else {
         LERROR << "/data is not mounted";
@@ -1581,6 +1664,8 @@
             }
         }
 
+        WrapUserdataIfNeeded(&fstab_entry, n_blk_device);
+
         if (!checkpoint_manager.Update(&fstab_entry, n_blk_device)) {
             LERROR << "Could not set up checkpoint partition, skipping!";
             continue;
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index 16339d3..698e74d 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -138,8 +138,17 @@
     return enabled;
 }
 
+static bool schedtune_enabled() {
+    return (CgroupMap::GetInstance().FindController("schedtune").IsUsable());
+}
+
+static bool cpuctl_enabled() {
+    return (CgroupMap::GetInstance().FindController("cpu").IsUsable());
+}
+
 bool schedboost_enabled() {
-    static bool enabled = (CgroupMap::GetInstance().FindController("schedtune").IsUsable());
+    static bool enabled = schedtune_enabled() || cpuctl_enabled();
+
     return enabled;
 }
 
@@ -162,7 +171,9 @@
 
     std::string group;
     if (schedboost_enabled()) {
-        if (getCGroupSubsys(tid, "schedtune", group) < 0) return -1;
+        if ((getCGroupSubsys(tid, "schedtune", group) < 0) &&
+            (getCGroupSubsys(tid, "cpu", group) < 0))
+		return -1;
     }
     if (group.empty() && cpusets_enabled()) {
         if (getCGroupSubsys(tid, "cpuset", group) < 0) return -1;