diff --git a/Android.mk b/Android.mk index d13fa8b..669d9af 100644 --- a/Android.mk +++ b/Android.mk @@ -15,6 +15,7 @@ common_src_files := \ Devmapper.cpp \ ResponseCode.cpp \ Xwarp.cpp \ + fstrim.c \ cryptfs.c common_c_includes := \ diff --git a/CommandListener.cpp b/CommandListener.cpp index 2986cac..f8baff5 100644 --- a/CommandListener.cpp +++ b/CommandListener.cpp @@ -38,6 +38,7 @@ #include "Loop.h" #include "Devmapper.h" #include "cryptfs.h" +#include "fstrim.h" #define DUMP_ARGS 0 @@ -50,6 +51,7 @@ CommandListener::CommandListener() : registerCmd(new StorageCmd()); registerCmd(new XwarpCmd()); registerCmd(new CryptfsCmd()); + registerCmd(new FstrimCmd()); } void CommandListener::dumpArgs(int argc, char **argv, int argObscure) { @@ -609,3 +611,41 @@ int CommandListener::CryptfsCmd::runCommand(SocketClient *cli, return 0; } + +CommandListener::FstrimCmd::FstrimCmd() : + VoldCommand("fstrim") { +} +int CommandListener::FstrimCmd::runCommand(SocketClient *cli, + int argc, char **argv) { + if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) { + cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run fstrim commands", false); + return 0; + } + + if (argc < 2) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); + return 0; + } + + int rc = 0; + + 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(); + } else { + dumpArgs(argc, argv, -1); + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fstrim cmd", false); + } + + // 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; +} diff --git a/CommandListener.h b/CommandListener.h index 4ef4a0c..8cc5b09 100644 --- a/CommandListener.h +++ b/CommandListener.h @@ -78,6 +78,13 @@ private: virtual ~CryptfsCmd() {} int runCommand(SocketClient *c, int argc, char ** argv); }; + + class FstrimCmd : public VoldCommand { + public: + FstrimCmd(); + virtual ~FstrimCmd() {} + int runCommand(SocketClient *c, int argc, char ** argv); + }; }; #endif diff --git a/fstrim.c b/fstrim.c new file mode 100644 index 0000000..156446a --- /dev/null +++ b/fstrim.c @@ -0,0 +1,86 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#define LOG_TAG "fstrim" +#include "cutils/log.h" + +int fstrim_filesystems(void) +{ + int i; + int fd; + int ret = 0; + struct fstrim_range range = { 0 }; + struct stat sb; + extern struct fstab *fstab; + + SLOGI("Starting fstrim work...\n"); + + 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 (stat(fstab->recs[i].mount_point, &sb) == -1) { + SLOGE("Cannot stat mount point %s\n", fstab->recs[i].mount_point); + ret = -1; + continue; + } + if (!S_ISDIR(sb.st_mode)) { + SLOGE("%s is not a directory\n", fstab->recs[i].mount_point); + ret = -1; + continue; + } + + fd = open(fstab->recs[i].mount_point, O_RDONLY); + 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 FITRIM ioctl on %s", fstab->recs[i].mount_point); + if (ioctl(fd, FITRIM, &range)) { + SLOGE("FITRIM ioctl failed on %s", fstab->recs[i].mount_point); + ret = -1; + } + SLOGI("Trimmed %llu bytes on %s\n", range.len, fstab->recs[i].mount_point); + close(fd); + } + SLOGI("Finished fstrim work.\n"); + + return ret; +} + diff --git a/fstrim.h b/fstrim.h new file mode 100644 index 0000000..e46e804 --- /dev/null +++ b/fstrim.h @@ -0,0 +1,24 @@ +/* + * 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(void); +#ifdef __cplusplus +} +#endif +