| /* | |
| * Copyright (C) 2013 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "VoldUtil.h" | |
| #include "Utils.h" | |
| #include <libdm/dm.h> | |
| #include <android-base/file.h> | |
| #include <android-base/logging.h> | |
| #include <android-base/stringprintf.h> | |
| #include <android-base/strings.h> | |
| using android::base::Basename; | |
| using android::base::Realpath; | |
| using namespace android::dm; | |
| android::fs_mgr::Fstab fstab_default; | |
| static std::string GetUfsHostControllerSysfsPathOnce() { | |
| android::fs_mgr::FstabEntry* entry = | |
| android::fs_mgr::GetEntryForMountPoint(&fstab_default, DATA_MNT_POINT); | |
| if (entry == nullptr) { | |
| LOG(ERROR) << "No mount point entry for " << DATA_MNT_POINT; | |
| return ""; | |
| } | |
| // Handle symlinks. | |
| std::string real_path; | |
| if (!Realpath(entry->blk_device, &real_path)) { | |
| real_path = entry->blk_device; | |
| } | |
| // Handle logical volumes. | |
| android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance(); | |
| for (;;) { | |
| std::optional<std::string> parent = dm.GetParentBlockDeviceByPath(real_path); | |
| if (!parent.has_value()) break; | |
| real_path = *parent; | |
| } | |
| std::string path = "/sys/class/block/" + Basename(real_path); | |
| // Walk up the sysfs directory tree from the partition (e.g, /sys/class/block/sda34) | |
| // or from the disk (e.g., /sys/class/block/sda) to reach the UFS host controller's directory | |
| // (e.g., /sys/class/block/sda34/../device/../../.. --> /sys/devices/platform/00000000.ufs). | |
| if (android::vold::pathExists(path + "/../device")) { | |
| path += "/../device/../../.."; | |
| } else if (android::vold::pathExists(path + "/device")) { | |
| path += "/device/../../.."; | |
| } else { | |
| LOG(WARNING) << "Failed to get sysfs_path for user data partition"; | |
| return ""; | |
| } | |
| // Verify the block device is UFS by checking for the presence of "uic_link_state", | |
| // which is UFS interconnect layer link state. | |
| // If not UFS, return an empty path. | |
| if (!android::vold::pathExists(path + "/uic_link_state")) { | |
| LOG(ERROR) << "The block device (" << Basename(real_path) << ") of " << DATA_MNT_POINT | |
| << " is not UFS."; | |
| return ""; | |
| } | |
| LOG(DEBUG) << "The sysfs directory for the ufs host controller is found at " << path; | |
| return path; | |
| } | |
| // get sysfs directory for the ufs host controller containing userdata | |
| // returns an empty string on failures. | |
| std::string GetUfsHostControllerSysfsPath() { | |
| static std::string ufshc_sysfs_path = GetUfsHostControllerSysfsPathOnce(); | |
| return ufshc_sysfs_path; | |
| } |