1c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey/*
2c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey * Copyright (C) 2015 The Android Open Source Project
3c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey *
4c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey * you may not use this file except in compliance with the License.
6c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey * You may obtain a copy of the License at
7c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey *
8c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey *
10c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey * Unless required by applicable law or agreed to in writing, software
11c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey * See the License for the specific language governing permissions and
14c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey * limitations under the License.
15c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey */
16c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
17c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include "TrimTask.h"
18c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include "Benchmark.h"
19c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include "Utils.h"
20c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include "VolumeManager.h"
21c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include "ResponseCode.h"
22c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
237e128fbe212c64492afa98bfd6d7fab6f1956831Elliott Hughes#include <android-base/stringprintf.h>
247e128fbe212c64492afa98bfd6d7fab6f1956831Elliott Hughes#include <android-base/logging.h>
25c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include <cutils/properties.h>
26c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include <fs_mgr.h>
27c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include <private/android_filesystem_config.h>
28c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include <hardware_legacy/power.h>
29c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
30c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include <dirent.h>
31c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include <sys/mount.h>
32c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include <sys/stat.h>
33c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include <sys/types.h>
34c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include <sys/wait.h>
35c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include <fcntl.h>
36c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
37c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey/* From a would-be kernel header */
38c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#define FIDTRIM         _IOWR('f', 128, struct fstrim_range)    /* Deep discard trim */
39c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
401a20a6487faad2869eaec962e4373402aa7461b3Jeff Sharkey#define BENCHMARK_ENABLED 1
41c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
42c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkeyusing android::base::StringPrintf;
43c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
44c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkeynamespace android {
45c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkeynamespace vold {
46c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
47c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkeystatic const char* kWakeLock = "TrimTask";
48c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
49c86ab6f538bec63638c168d6c843fe7cf73add3bJeff SharkeyTrimTask::TrimTask(int flags) : mFlags(flags) {
50c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    // Collect both fstab and vold volumes
51c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    addFromFstab();
52c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
53c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    VolumeManager* vm = VolumeManager::Instance();
54c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    std::list<std::string> privateIds;
55c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    vm->listVolumes(VolumeBase::Type::kPrivate, privateIds);
56c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    for (auto id : privateIds) {
57c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        auto vol = vm->findVolume(id);
58c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        if (vol != nullptr && vol->getState() == VolumeBase::State::kMounted) {
59c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            mPaths.push_back(vol->getPath());
60c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        }
61c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    }
62c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey}
63c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
64c86ab6f538bec63638c168d6c843fe7cf73add3bJeff SharkeyTrimTask::~TrimTask() {
65c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey}
66c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
67c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkeyvoid TrimTask::addFromFstab() {
68c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    struct fstab *fstab;
69c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    struct fstab_rec *prev_rec = NULL;
70c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
71c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    fstab = fs_mgr_read_fstab(android::vold::DefaultFstabPath().c_str());
72c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    for (int i = 0; i < fstab->num_entries; i++) {
73c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        /* Skip raw partitions */
74c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
75c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            !strcmp(fstab->recs[i].fs_type, "mtd")) {
76c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            continue;
77c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        }
78c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        /* Skip read-only filesystems */
79c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        if (fstab->recs[i].flags & MS_RDONLY) {
80c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            continue;
81c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        }
82c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
83c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            continue; /* Should we trim fat32 filesystems? */
84c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        }
85c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        if (fs_mgr_is_notrim(&fstab->recs[i])) {
86c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            continue;
87c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        }
88c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
89c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        /* Skip the multi-type partitions, which are required to be following each other.
90c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey         * See fs_mgr.c's mount_with_alternatives().
91c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey         */
92c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        if (prev_rec && !strcmp(prev_rec->mount_point, fstab->recs[i].mount_point)) {
93c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            continue;
94c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        }
95c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
96c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        mPaths.push_back(fstab->recs[i].mount_point);
97c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        prev_rec = &fstab->recs[i];
98c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    }
99c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    fs_mgr_free_fstab(fstab);
100c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey}
101c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
102c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkeyvoid TrimTask::start() {
103c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    mThread = std::thread(&TrimTask::run, this);
104c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey}
105c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
106c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkeystatic void notifyResult(const std::string& path, int64_t bytes, int64_t delta) {
107c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    std::string res(path
108c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            + " " + std::to_string(bytes)
109c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            + " " + std::to_string(delta));
110c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
111c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            ResponseCode::TrimResult, res.c_str(), false);
112c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey}
113c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
114c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkeyvoid TrimTask::run() {
115c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
116c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
117c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    for (auto path : mPaths) {
118c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        LOG(DEBUG) << "Starting trim of " << path;
119c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
120c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        int fd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
121c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        if (fd < 0) {
122c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            PLOG(WARNING) << "Failed to open " << path;
123c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            continue;
124c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        }
125c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
126c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        struct fstrim_range range;
127c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        memset(&range, 0, sizeof(range));
128c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        range.len = ULLONG_MAX;
129c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
130c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
131c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        if (ioctl(fd, (mFlags & Flags::kDeepTrim) ? FIDTRIM : FITRIM, &range)) {
132c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            PLOG(WARNING) << "Trim failed on " << path;
133c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            notifyResult(path, -1, -1);
134c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        } else {
135c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            nsecs_t delta = systemTime(SYSTEM_TIME_BOOTTIME) - start;
136c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            LOG(INFO) << "Trimmed " << range.len << " bytes on " << path
137c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey                    << " in " << nanoseconds_to_milliseconds(delta) << "ms";
138c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            notifyResult(path, range.len, delta);
139c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        }
140c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        close(fd);
141c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
142c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        if (mFlags & Flags::kBenchmarkAfter) {
143c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#if BENCHMARK_ENABLED
144c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            BenchmarkPrivate(path);
145c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#else
146c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey            LOG(DEBUG) << "Benchmark disabled";
147c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#endif
148c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        }
149c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    }
150c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
151c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    release_wake_lock(kWakeLock);
152c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey}
153c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey
154c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey}  // namespace vold
155c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey}  // namespace android
156