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: I76577685f5cae4929c251ad314ffdaeb5eb1c8bfgugelfrei
parent
c7b5b570bd
commit
c86ab6f538
@ -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
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in new issue