Trim both internal and adopted private storage.

Refactor fstrim code to be encapsulated in unique task object, and
give it option of benchmarking when finished.  Trimming now includes
both storage from fstab and adopted private volumes.  Cleaner timing
stats are logged for each unique volume.

Add wakelock during ongoing async move tasks.  Push disk sysfs path
to framework so it can parse any SD card registers as desired.

Bug: 21831325
Change-Id: I76577685f5cae4929c251ad314ffdaeb5eb1c8bf
This commit is contained in:
Jeff Sharkey 2015-06-26 14:02:09 -07:00
parent c7b5b570bd
commit c86ab6f538
17 changed files with 326 additions and 296 deletions

View file

@ -17,7 +17,6 @@ common_src_files := \
CheckBattery.cpp \
Ext4Crypt.cpp \
VoldUtil.c \
fstrim.c \
cryptfs.c \
Disk.cpp \
VolumeBase.cpp \
@ -27,6 +26,7 @@ common_src_files := \
Utils.cpp \
MoveTask.cpp \
Benchmark.cpp \
TrimTask.cpp \
common_c_includes := \
system/extras/ext4_utils \

View file

@ -22,6 +22,7 @@
#include <base/file.h>
#include <base/logging.h>
#include <cutils/iosched_policy.h>
#include <private/android_filesystem_config.h>
#include <sys/time.h>
#include <sys/resource.h>
@ -33,14 +34,19 @@ using android::base::WriteStringToFile;
namespace android {
namespace vold {
static std::string simpleRead(const std::string& path) {
std::string tmp;
ReadFileToString(path, &tmp);
tmp.erase(tmp.find_last_not_of(" \n\r") + 1);
return tmp;
static void notifyResult(const std::string& path, int64_t create_d,
int64_t drop_d, int64_t run_d, int64_t destroy_d) {
std::string res(path +
+ " " + BenchmarkIdent()
+ " " + std::to_string(create_d)
+ " " + std::to_string(drop_d)
+ " " + std::to_string(run_d)
+ " " + std::to_string(destroy_d));
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::BenchmarkResult, res.c_str(), false);
}
nsecs_t Benchmark(const std::string& path, const std::string& sysPath) {
static nsecs_t benchmark(const std::string& path) {
errno = 0;
int orig_prio = getpriority(PRIO_PROCESS, 0);
if (errno != 0) {
@ -82,9 +88,11 @@ nsecs_t Benchmark(const std::string& path, const std::string& sysPath) {
sync();
nsecs_t create = systemTime(SYSTEM_TIME_BOOTTIME);
LOG(VERBOSE) << "Before drop_caches";
if (!WriteStringToFile("3", "/proc/sys/vm/drop_caches")) {
PLOG(ERROR) << "Failed to drop_caches";
}
LOG(VERBOSE) << "After drop_caches";
nsecs_t drop = systemTime(SYSTEM_TIME_BOOTTIME);
BenchmarkRun();
@ -95,6 +103,16 @@ nsecs_t Benchmark(const std::string& path, const std::string& sysPath) {
sync();
nsecs_t destroy = systemTime(SYSTEM_TIME_BOOTTIME);
if (chdir(orig_cwd) != 0) {
PLOG(ERROR) << "Failed to chdir";
}
if (android_set_ioprio(0, orig_clazz, orig_ioprio)) {
PLOG(ERROR) << "Failed to android_set_ioprio";
}
if (setpriority(PRIO_PROCESS, 0, orig_prio) != 0) {
PLOG(ERROR) << "Failed to setpriority";
}
nsecs_t create_d = create - start;
nsecs_t drop_d = drop - create;
nsecs_t run_d = run - drop;
@ -105,39 +123,27 @@ nsecs_t Benchmark(const std::string& path, const std::string& sysPath) {
LOG(INFO) << "run took " << nanoseconds_to_milliseconds(run_d) << "ms";
LOG(INFO) << "destroy took " << nanoseconds_to_milliseconds(destroy_d) << "ms";
std::string detail;
detail += "id=" + BenchmarkIdent()
+ ",cr=" + std::to_string(create_d)
+ ",dr=" + std::to_string(drop_d)
+ ",ru=" + std::to_string(run_d)
+ ",de=" + std::to_string(destroy_d)
+ ",si=" + simpleRead(sysPath + "/size")
+ ",ve=" + simpleRead(sysPath + "/device/vendor")
+ ",mo=" + simpleRead(sysPath + "/device/model")
+ ",csd=" + simpleRead(sysPath + "/device/csd");
notifyResult(path, create_d, drop_d, run_d, destroy_d);
// Scrub CRC and serial number out of CID
std::string cid = simpleRead(sysPath + "/device/cid");
if (cid.length() == 32) {
cid.erase(32, 1);
cid.erase(18, 8);
detail += ",cid=" + cid;
}
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::BenchmarkResult, detail.c_str(), false);
if (chdir(orig_cwd) != 0) {
PLOG(ERROR) << "Failed to chdir";
}
if (android_set_ioprio(0, orig_clazz, orig_ioprio)) {
PLOG(ERROR) << "Failed to android_set_ioprio";
}
if (setpriority(PRIO_PROCESS, 0, orig_prio) != 0) {
PLOG(ERROR) << "Failed to setpriority";
}
return run_d;
}
nsecs_t BenchmarkPrivate(const std::string& path) {
std::string benchPath(path);
benchPath += "/misc";
if (android::vold::PrepareDir(benchPath, 01771, AID_SYSTEM, AID_MISC)) {
return -1;
}
benchPath += "/vold";
if (android::vold::PrepareDir(benchPath, 0700, AID_ROOT, AID_ROOT)) {
return -1;
}
benchPath += "/bench";
if (android::vold::PrepareDir(benchPath, 0700, AID_ROOT, AID_ROOT)) {
return -1;
}
return benchmark(benchPath);
}
} // namespace vold
} // namespace android

View file

@ -25,7 +25,8 @@
namespace android {
namespace vold {
nsecs_t Benchmark(const std::string& path, const std::string& sysPath);
/* Benchmark a private volume mounted at the given path */
nsecs_t BenchmarkPrivate(const std::string& path);
} // namespace vold
} // namespace android

View file

@ -45,8 +45,8 @@
#include "Loop.h"
#include "Devmapper.h"
#include "cryptfs.h"
#include "fstrim.h"
#include "MoveTask.h"
#include "TrimTask.h"
#define DUMP_ARGS 0
@ -255,7 +255,7 @@ int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
} else if (cmd == "benchmark" && argc > 2) {
// benchmark [volId]
std::string id(argv[2]);
nsecs_t res = vm->benchmarkVolume(id);
nsecs_t res = vm->benchmarkPrivate(id);
return cli->sendMsg(ResponseCode::CommandOkay,
android::base::StringPrintf("%" PRId64, res).c_str(), false);
@ -600,32 +600,23 @@ int CommandListener::FstrimCmd::runCommand(SocketClient *cli,
return 0;
}
int rc = 0;
VolumeManager *vm = VolumeManager::Instance();
std::lock_guard<std::mutex> lock(vm->getLock());
if (!strcmp(argv[1], "dotrim")) {
if (argc != 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dotrim", false);
return 0;
}
dumpArgs(argc, argv, -1);
rc = fstrim_filesystems(0);
} else if (!strcmp(argv[1], "dodtrim")) {
if (argc != 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dodtrim", false);
return 0;
}
dumpArgs(argc, argv, -1);
rc = fstrim_filesystems(1); /* Do Deep Discard trim */
} else {
dumpArgs(argc, argv, -1);
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fstrim cmd", false);
int flags = 0;
std::string cmd(argv[1]);
if (cmd == "dotrim") {
flags = 0;
} else if (cmd == "dotrimbench") {
flags = android::vold::TrimTask::Flags::kBenchmarkAfter;
} else if (cmd == "dodtrim") {
flags = android::vold::TrimTask::Flags::kDeepTrim;
} else if (cmd == "dodtrimbench") {
flags = android::vold::TrimTask::Flags::kDeepTrim
| android::vold::TrimTask::Flags::kBenchmarkAfter;
}
// Always report that the command succeeded and return the error code.
// The caller will check the return value to see what the error was.
char msg[255];
snprintf(msg, sizeof(msg), "%d", rc);
cli->sendMsg(ResponseCode::CommandOkay, msg, false);
return 0;
(new android::vold::TrimTask(flags))->start();
return sendGenericOkFail(cli, 0);
}

View file

@ -105,6 +105,15 @@ std::shared_ptr<VolumeBase> Disk::findVolume(const std::string& id) {
return nullptr;
}
void Disk::listVolumes(VolumeBase::Type type, std::list<std::string>& list) {
for (auto vol : mVolumes) {
if (vol->getType() == type) {
list.push_back(vol->getId());
}
// TODO: consider looking at stacked volumes
}
}
status_t Disk::create() {
CHECK(!mCreated);
mCreated = true;
@ -229,6 +238,7 @@ status_t Disk::readMetadata() {
notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRId64, mSize));
notifyEvent(ResponseCode::DiskLabelChanged, mLabel);
notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath);
return OK;
}

3
Disk.h
View file

@ -18,6 +18,7 @@
#define ANDROID_VOLD_DISK_H
#include "Utils.h"
#include "VolumeBase.h"
#include <utils/Errors.h>
@ -64,6 +65,8 @@ public:
std::shared_ptr<VolumeBase> findVolume(const std::string& id);
void listVolumes(VolumeBase::Type type, std::list<std::string>& list);
status_t create();
status_t destroy();

View file

@ -22,6 +22,7 @@
#include <base/stringprintf.h>
#include <base/logging.h>
#include <private/android_filesystem_config.h>
#include <hardware_legacy/power.h>
#include <dirent.h>
#include <sys/wait.h>
@ -40,6 +41,8 @@ static const int kMoveFailedInternalError = -6;
static const char* kCpPath = "/system/bin/cp";
static const char* kRmPath = "/system/bin/rm";
static const char* kWakeLock = "MoveTask";
MoveTask::MoveTask(const std::shared_ptr<VolumeBase>& from,
const std::shared_ptr<VolumeBase>& to) :
mFrom(from), mTo(to) {
@ -168,6 +171,8 @@ static void bringOnline(const std::shared_ptr<VolumeBase>& vol) {
}
void MoveTask::run() {
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
std::string fromPath;
std::string toPath;
@ -205,11 +210,13 @@ void MoveTask::run() {
}
notifyProgress(kMoveSucceeded);
release_wake_lock(kWakeLock);
return;
fail:
bringOnline(mFrom);
bringOnline(mTo);
notifyProgress(kMoveFailedInternalError);
release_wake_lock(kWakeLock);
return;
}

View file

@ -70,6 +70,7 @@ public:
static const int DiskSizeChanged = 641;
static const int DiskLabelChanged = 642;
static const int DiskScanned = 643;
static const int DiskSysPathChanged = 644;
static const int DiskDestroyed = 649;
static const int VolumeCreated = 650;
@ -83,6 +84,7 @@ public:
static const int MoveStatus = 660;
static const int BenchmarkResult = 661;
static const int TrimResult = 662;
static int convertFromErrno();
};

155
TrimTask.cpp Normal file
View file

@ -0,0 +1,155 @@
/*
* Copyright (C) 2015 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 "TrimTask.h"
#include "Benchmark.h"
#include "Utils.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include <base/stringprintf.h>
#include <base/logging.h>
#include <cutils/properties.h>
#include <fs_mgr.h>
#include <private/android_filesystem_config.h>
#include <hardware_legacy/power.h>
#include <dirent.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
/* From a would-be kernel header */
#define FIDTRIM _IOWR('f', 128, struct fstrim_range) /* Deep discard trim */
#define BENCHMARK_ENABLED 0
using android::base::StringPrintf;
namespace android {
namespace vold {
static const char* kWakeLock = "TrimTask";
TrimTask::TrimTask(int flags) : mFlags(flags) {
// Collect both fstab and vold volumes
addFromFstab();
VolumeManager* vm = VolumeManager::Instance();
std::list<std::string> privateIds;
vm->listVolumes(VolumeBase::Type::kPrivate, privateIds);
for (auto id : privateIds) {
auto vol = vm->findVolume(id);
if (vol != nullptr && vol->getState() == VolumeBase::State::kMounted) {
mPaths.push_back(vol->getPath());
}
}
}
TrimTask::~TrimTask() {
}
void TrimTask::addFromFstab() {
struct fstab *fstab;
struct fstab_rec *prev_rec = NULL;
fstab = fs_mgr_read_fstab(android::vold::DefaultFstabPath().c_str());
for (int i = 0; i < fstab->num_entries; i++) {
/* Skip raw partitions */
if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
!strcmp(fstab->recs[i].fs_type, "mtd")) {
continue;
}
/* Skip read-only filesystems */
if (fstab->recs[i].flags & MS_RDONLY) {
continue;
}
if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
continue; /* Should we trim fat32 filesystems? */
}
if (fs_mgr_is_notrim(&fstab->recs[i])) {
continue;
}
/* Skip the multi-type partitions, which are required to be following each other.
* See fs_mgr.c's mount_with_alternatives().
*/
if (prev_rec && !strcmp(prev_rec->mount_point, fstab->recs[i].mount_point)) {
continue;
}
mPaths.push_back(fstab->recs[i].mount_point);
prev_rec = &fstab->recs[i];
}
fs_mgr_free_fstab(fstab);
}
void TrimTask::start() {
mThread = std::thread(&TrimTask::run, this);
}
static void notifyResult(const std::string& path, int64_t bytes, int64_t delta) {
std::string res(path
+ " " + std::to_string(bytes)
+ " " + std::to_string(delta));
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::TrimResult, res.c_str(), false);
}
void TrimTask::run() {
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
for (auto path : mPaths) {
LOG(DEBUG) << "Starting trim of " << path;
int fd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
if (fd < 0) {
PLOG(WARNING) << "Failed to open " << path;
continue;
}
struct fstrim_range range;
memset(&range, 0, sizeof(range));
range.len = ULLONG_MAX;
nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
if (ioctl(fd, (mFlags & Flags::kDeepTrim) ? FIDTRIM : FITRIM, &range)) {
PLOG(WARNING) << "Trim failed on " << path;
notifyResult(path, -1, -1);
} else {
nsecs_t delta = systemTime(SYSTEM_TIME_BOOTTIME) - start;
LOG(INFO) << "Trimmed " << range.len << " bytes on " << path
<< " in " << nanoseconds_to_milliseconds(delta) << "ms";
notifyResult(path, range.len, delta);
}
close(fd);
if (mFlags & Flags::kBenchmarkAfter) {
#if BENCHMARK_ENABLED
BenchmarkPrivate(path);
#else
LOG(DEBUG) << "Benchmark disabled";
#endif
}
}
release_wake_lock(kWakeLock);
}
} // namespace vold
} // namespace android

54
TrimTask.h Normal file
View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef ANDROID_VOLD_TRIM_TASK_H
#define ANDROID_VOLD_TRIM_TASK_H
#include "Utils.h"
#include <thread>
#include <list>
namespace android {
namespace vold {
class TrimTask {
public:
TrimTask(int flags);
virtual ~TrimTask();
enum Flags {
kDeepTrim = 1 << 0,
kBenchmarkAfter = 1 << 1,
};
void start();
private:
int mFlags;
std::list<std::string> mPaths;
std::thread mThread;
void addFromFstab();
void run();
DISALLOW_COPY_AND_ASSIGN(TrimTask);
};
} // namespace vold
} // namespace android
#endif

View file

@ -22,6 +22,7 @@
#include <base/logging.h>
#include <base/stringprintf.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <private/android_filesystem_config.h>
#include <logwrap/logwrap.h>
@ -532,5 +533,11 @@ dev_t GetDevice(const std::string& path) {
}
}
std::string DefaultFstabPath() {
char hardware[PROPERTY_VALUE_MAX];
property_get("ro.hardware", hardware, "");
return StringPrintf("/fstab.%s", hardware);
}
} // namespace vold
} // namespace android

View file

@ -92,6 +92,8 @@ std::string BuildKeyPath(const std::string& partGuid);
dev_t GetDevice(const std::string& path);
std::string DefaultFstabPath();
} // namespace vold
} // namespace android

View file

@ -60,7 +60,6 @@
#include "Asec.h"
#include "VoldUtil.h"
#include "cryptfs.h"
#include "fstrim.h"
#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file"
@ -370,20 +369,23 @@ std::shared_ptr<android::vold::VolumeBase> VolumeManager::findVolume(const std::
return nullptr;
}
nsecs_t VolumeManager::benchmarkVolume(const std::string& id) {
void VolumeManager::listVolumes(android::vold::VolumeBase::Type type,
std::list<std::string>& list) {
list.clear();
for (auto disk : mDisks) {
disk->listVolumes(type, list);
}
}
nsecs_t VolumeManager::benchmarkPrivate(const std::string& id) {
std::string path;
std::string sysPath;
auto vol = findVolume(id);
if (vol != nullptr) {
if (vol->getState() == android::vold::VolumeBase::State::kMounted) {
path = vol->getPath();
auto disk = findDisk(vol->getDiskId());
if (disk != nullptr) {
sysPath = disk->getSysPath();
}
}
} else {
if (id == "private" || id == "null") {
path = "/data";
} else {
auto vol = findVolume(id);
if (vol != nullptr && vol->getState() == android::vold::VolumeBase::State::kMounted) {
path = vol->getPath();
}
}
if (path.empty()) {
@ -391,20 +393,7 @@ nsecs_t VolumeManager::benchmarkVolume(const std::string& id) {
return -1;
}
path += "/misc";
if (android::vold::PrepareDir(path, 01771, AID_SYSTEM, AID_MISC)) {
return -1;
}
path += "/vold";
if (android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT)) {
return -1;
}
path += "/bench";
if (android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT)) {
return -1;
}
return android::vold::Benchmark(path, sysPath);
return android::vold::BenchmarkPrivate(path);
}
int VolumeManager::forgetPartition(const std::string& partGuid) {

View file

@ -118,7 +118,9 @@ public:
std::shared_ptr<android::vold::Disk> findDisk(const std::string& id);
std::shared_ptr<android::vold::VolumeBase> findVolume(const std::string& id);
nsecs_t benchmarkVolume(const std::string& id);
void listVolumes(android::vold::VolumeBase::Type type, std::list<std::string>& list);
nsecs_t benchmarkPrivate(const std::string& id);
int forgetPartition(const std::string& partGuid);

165
fstrim.c
View file

@ -1,165 +0,0 @@
/*
* 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 <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <limits.h>
#include <linux/fs.h>
#include <time.h>
#include <fs_mgr.h>
#include <pthread.h>
#define LOG_TAG "fstrim"
#include "cutils/log.h"
#include "hardware_legacy/power.h"
/* These numbers must match what the MountService specified in
* frameworks/base/services/java/com/android/server/EventLogTags.logtags
*/
#define LOG_FSTRIM_START 2755
#define LOG_FSTRIM_FINISH 2756
#define FSTRIM_WAKELOCK "dofstrim"
#define UNUSED __attribute__((unused))
/* From a would-be kernel header */
#define FIDTRIM _IOWR('f', 128, struct fstrim_range) /* Deep discard trim */
static unsigned long long get_boot_time_ms(void)
{
struct timespec t;
unsigned long long time_ms;
t.tv_sec = 0;
t.tv_nsec = 0;
clock_gettime(CLOCK_BOOTTIME, &t);
time_ms = (t.tv_sec * 1000LL) + (t.tv_nsec / 1000000);
return time_ms;
}
static void *do_fstrim_filesystems(void *thread_arg)
{
int i;
int fd;
int ret = 0;
struct fstrim_range range = { 0 };
extern struct fstab *fstab;
int deep_trim = !!thread_arg;
struct fstab_rec *prev_rec = NULL;
SLOGI("Starting fstrim work...\n");
/* Get a wakelock as this may take a while, and we don't want the
* device to sleep on us.
*/
acquire_wake_lock(PARTIAL_WAKE_LOCK, FSTRIM_WAKELOCK);
/* Log the start time in the event log */
LOG_EVENT_LONG(LOG_FSTRIM_START, get_boot_time_ms());
for (i = 0; i < fstab->num_entries; i++) {
/* Skip raw partitions */
if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
!strcmp(fstab->recs[i].fs_type, "mtd")) {
continue;
}
/* Skip read-only filesystems */
if (fstab->recs[i].flags & MS_RDONLY) {
continue;
}
if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
continue; /* Should we trim fat32 filesystems? */
}
if (fs_mgr_is_notrim(&fstab->recs[i])) {
continue;
}
/* Skip the multi-type partitions, which are required to be following each other.
* See fs_mgr.c's mount_with_alternatives().
*/
if (prev_rec && !strcmp(prev_rec->mount_point, fstab->recs[i].mount_point)) {
continue;
}
fd = open(fstab->recs[i].mount_point, O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
if (fd < 0) {
SLOGE("Cannot open %s for FITRIM\n", fstab->recs[i].mount_point);
ret = -1;
continue;
}
memset(&range, 0, sizeof(range));
range.len = ULLONG_MAX;
SLOGI("Invoking %s ioctl on %s", deep_trim ? "FIDTRIM" : "FITRIM", fstab->recs[i].mount_point);
ret = ioctl(fd, deep_trim ? FIDTRIM : FITRIM, &range);
if (ret) {
SLOGE("%s ioctl failed on %s (error %d/%s)", deep_trim ? "FIDTRIM" : "FITRIM", fstab->recs[i].mount_point, errno, strerror(errno));
ret = -1;
} else {
SLOGI("Trimmed %llu bytes on %s\n", range.len, fstab->recs[i].mount_point);
}
close(fd);
prev_rec = &fstab->recs[i];
}
/* Log the finish time in the event log */
LOG_EVENT_LONG(LOG_FSTRIM_FINISH, get_boot_time_ms());
SLOGI("Finished fstrim work.\n");
/* Release the wakelock that let us work */
release_wake_lock(FSTRIM_WAKELOCK);
return (void *)(uintptr_t)ret;
}
int fstrim_filesystems(int deep_trim)
{
pthread_t t;
int ret;
/* Depending on the emmc chip and size, this can take upwards
* of a few minutes. If done in the same thread as the caller
* of this function, that would block vold from accepting any
* commands until the trim is finished. So start another thread
* to do the work, and return immediately.
*
* This function should not be called more than once per day, but
* even if it is called a second time before the first one finishes,
* the kernel will "do the right thing" and split the work between
* the two ioctls invoked in separate threads.
*/
ret = pthread_create(&t, NULL, do_fstrim_filesystems, (void *)(intptr_t)deep_trim);
if (ret) {
SLOGE("Cannot create thread to do fstrim");
return ret;
}
ret = pthread_detach(t);
if (ret) {
SLOGE("Cannot detach thread doing fstrim");
return ret;
}
return 0;
}

View file

@ -1,24 +0,0 @@
/*
* 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.
*/
#ifdef __cplusplus
extern "C" {
#endif
int fstrim_filesystems(int deep_trim);
#ifdef __cplusplus
}
#endif

View file

@ -208,25 +208,15 @@ static void coldboot(const char *path) {
}
static int process_config(VolumeManager *vm) {
bool has_adoptable = false;
char hardware[PROPERTY_VALUE_MAX];
property_get("ro.hardware", hardware, "");
std::string fstab_filename(StringPrintf("/fstab.%s", hardware));
#ifdef DEBUG_FSTAB
if (access(DEBUG_FSTAB, R_OK) == 0) {
LOG(DEBUG) << "Found debug fstab; switching!";
fstab_filename = DEBUG_FSTAB;
}
#endif
fstab = fs_mgr_read_fstab(fstab_filename.c_str());
std::string path(android::vold::DefaultFstabPath());
fstab = fs_mgr_read_fstab(path.c_str());
if (!fstab) {
PLOG(ERROR) << "Failed to open " << fstab_filename;
PLOG(ERROR) << "Failed to open default fstab " << path;
return -1;
}
/* Loop through entries looking for ones that vold manages */
bool has_adoptable = false;
for (int i = 0; i < fstab->num_entries; i++) {
if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
if (fs_mgr_is_nonremovable(&fstab->recs[i])) {