am f99dfdb5: Merge "vold: fix potential socket leak"
* commit 'f99dfdb5044ed6b120a8f2a86ddf2dd92a5bb9a2':
vold: fix potential socket leak
diff --git a/Android.mk b/Android.mk
index b7a4905..098c3d0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -8,7 +8,6 @@
NetlinkHandler.cpp \
Volume.cpp \
DirectVolume.cpp \
- logwrapper.c \
Process.cpp \
Ext4.cpp \
Fat.cpp \
@@ -16,6 +15,7 @@
Devmapper.cpp \
ResponseCode.cpp \
Xwarp.cpp \
+ fstrim.c \
cryptfs.c
common_c_includes := \
@@ -26,8 +26,10 @@
common_shared_libraries := \
libsysutils \
libcutils \
+ liblog \
libdiskconfig \
libhardware_legacy \
+ liblogwrap \
libcrypto
include $(CLEAR_VARS)
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 @@
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 @@
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 @@
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/Ext4.cpp b/Ext4.cpp
index 613d623..b82b4c5 100644
--- a/Ext4.cpp
+++ b/Ext4.cpp
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/mount.h>
+#include <sys/wait.h>
#include <linux/kdev_t.h>
@@ -37,13 +38,13 @@
#include <cutils/log.h>
#include <cutils/properties.h>
+#include <logwrap/logwrap.h>
+
#include "Ext4.h"
+#include "VoldUtil.h"
#define MKEXT4FS_PATH "/system/bin/make_ext4fs";
-extern "C" int logwrap(int argc, const char **argv, int background);
-
-
int Ext4::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount,
bool executable) {
int rc;
@@ -68,22 +69,36 @@
int Ext4::format(const char *fsPath, const char *mountpoint) {
int fd;
- const char *args[6];
+ const char *args[5];
int rc;
+ int status;
args[0] = MKEXT4FS_PATH;
args[1] = "-J";
args[2] = "-a";
args[3] = mountpoint;
args[4] = fsPath;
- args[5] = NULL;
- rc = logwrap(5, args, 1);
+ rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false,
+ true);
+ if (rc != 0) {
+ SLOGE("Filesystem (ext4) format failed due to logwrap error");
+ errno = EIO;
+ return -1;
+ }
- if (rc == 0) {
+ if (!WIFEXITED(status)) {
+ SLOGE("Filesystem (ext4) format did not exit properly");
+ errno = EIO;
+ return -1;
+ }
+
+ status = WEXITSTATUS(status);
+
+ if (status == 0) {
SLOGI("Filesystem (ext4) formatted OK");
return 0;
} else {
- SLOGE("Format (ext4) failed (unknown exit code %d)", rc);
+ SLOGE("Format (ext4) failed (unknown exit code %d)", status);
errno = EIO;
return -1;
}
diff --git a/Fat.cpp b/Fat.cpp
index a7fcc28..807f440 100644
--- a/Fat.cpp
+++ b/Fat.cpp
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/mount.h>
+#include <sys/wait.h>
#include <linux/kdev_t.h>
@@ -37,11 +38,13 @@
#include <cutils/log.h>
#include <cutils/properties.h>
+#include <logwrap/logwrap.h>
+
#include "Fat.h"
+#include "VoldUtil.h"
static char FSCK_MSDOS_PATH[] = "/system/bin/fsck_msdos";
static char MKDOSFS_PATH[] = "/system/bin/newfs_msdos";
-extern "C" int logwrap(int argc, const char **argv, int background);
extern "C" int mount(const char *, const char *, const char *, unsigned long, const void *);
int Fat::check(const char *fsPath) {
@@ -54,16 +57,30 @@
int pass = 1;
int rc = 0;
do {
- const char *args[5];
+ const char *args[4];
+ int status;
args[0] = FSCK_MSDOS_PATH;
args[1] = "-p";
args[2] = "-f";
args[3] = fsPath;
- args[4] = NULL;
- rc = logwrap(4, args, 1);
+ rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status,
+ false, true);
+ if (rc != 0) {
+ SLOGE("Filesystem check failed due to logwrap error");
+ errno = EIO;
+ return -1;
+ }
- switch(rc) {
+ if (!WIFEXITED(status)) {
+ SLOGE("Filesystem check did not exit properly");
+ errno = EIO;
+ return -1;
+ }
+
+ status = WEXITSTATUS(status);
+
+ switch(status) {
case 0:
SLOGI("Filesystem check completed OK");
return 0;
@@ -84,7 +101,7 @@
return -1;
default:
- SLOGE("Filesystem check failed (unknown exit code %d)", rc);
+ SLOGE("Filesystem check failed (unknown exit code %d)", status);
errno = EIO;
return -1;
}
@@ -152,8 +169,9 @@
int Fat::format(const char *fsPath, unsigned int numSectors) {
int fd;
- const char *args[11];
+ const char *args[10];
int rc;
+ int status;
args[0] = MKDOSFS_PATH;
args[1] = "-F";
@@ -170,19 +188,33 @@
args[7] = "-s";
args[8] = size;
args[9] = fsPath;
- args[10] = NULL;
- rc = logwrap(11, args, 1);
+ rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status,
+ false, true);
} else {
args[7] = fsPath;
- args[8] = NULL;
- rc = logwrap(9, args, 1);
+ rc = android_fork_execvp(8, (char **)args, &status, false,
+ true);
}
- if (rc == 0) {
+ if (rc != 0) {
+ SLOGE("Filesystem format failed due to logwrap error");
+ errno = EIO;
+ return -1;
+ }
+
+ if (!WIFEXITED(status)) {
+ SLOGE("Filesystem format did not exit properly");
+ errno = EIO;
+ return -1;
+ }
+
+ status = WEXITSTATUS(status);
+
+ if (status == 0) {
SLOGI("Filesystem formatted OK");
return 0;
} else {
- SLOGE("Format failed (unknown exit code %d)", rc);
+ SLOGE("Format failed (unknown exit code %d)", status);
errno = EIO;
return -1;
}
diff --git a/VoldUtil.h b/VoldUtil.h
new file mode 100644
index 0000000..30a3add
--- /dev/null
+++ b/VoldUtil.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 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 _VOLDUTIL_H
+#define _VOLDUTIL_H
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
+#endif
diff --git a/cryptfs.c b/cryptfs.c
index bcacc39..3af7a5e 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -67,8 +67,8 @@
static char *saved_data_blkdev;
static char *saved_mount_point;
static int master_key_saved = 0;
-#define FSTAB_PREFIX "/fstab."
-static char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+
+extern struct fstab *fstab;
static void ioctl_init(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
{
@@ -126,19 +126,6 @@
return nr_sec;
}
-/* Get and cache the name of the fstab file so we don't
- * keep talking over the socket to the property service.
- */
-static char *get_fstab_filename(void)
-{
- if (fstab_filename[0] == 0) {
- strcpy(fstab_filename, FSTAB_PREFIX);
- property_get("ro.hardware", fstab_filename + sizeof(FSTAB_PREFIX) - 1, "");
- }
-
- return fstab_filename;
-}
-
/* key or salt can be NULL, in which case just skip writing that value. Useful to
* update the failed mount count but not change the key.
*/
@@ -153,7 +140,7 @@
char key_loc[PROPERTY_VALUE_MAX];
struct stat statbuf;
- fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+ fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
if (!strcmp(key_loc, KEY_IN_FOOTER)) {
fname = real_blk_name;
@@ -252,7 +239,7 @@
char *fname;
struct stat statbuf;
- fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+ fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
if (!strcmp(key_loc, KEY_IN_FOOTER)) {
fname = real_blk_name;
@@ -377,6 +364,86 @@
}
+static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
+ char *real_blk_name, const char *name, int fd,
+ char *extra_params)
+{
+ char buffer[DM_CRYPT_BUF_SIZE];
+ struct dm_ioctl *io;
+ struct dm_target_spec *tgt;
+ char *crypt_params;
+ char master_key_ascii[129]; /* Large enough to hold 512 bit key and null */
+ int i;
+
+ io = (struct dm_ioctl *) buffer;
+
+ /* Load the mapping table for this device */
+ tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
+
+ ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
+ io->target_count = 1;
+ tgt->status = 0;
+ tgt->sector_start = 0;
+ tgt->length = crypt_ftr->fs_size;
+ strcpy(tgt->target_type, "crypt");
+
+ crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+ convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
+ sprintf(crypt_params, "%s %s 0 %s 0 %s", crypt_ftr->crypto_type_name,
+ master_key_ascii, real_blk_name, extra_params);
+ crypt_params += strlen(crypt_params) + 1;
+ crypt_params = (char *) (((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */
+ tgt->next = crypt_params - buffer;
+
+ for (i = 0; i < TABLE_LOAD_RETRIES; i++) {
+ if (! ioctl(fd, DM_TABLE_LOAD, io)) {
+ break;
+ }
+ usleep(500000);
+ }
+
+ if (i == TABLE_LOAD_RETRIES) {
+ /* We failed to load the table, return an error */
+ return -1;
+ } else {
+ return i + 1;
+ }
+}
+
+
+static int get_dm_crypt_version(int fd, const char *name, int *version)
+{
+ char buffer[DM_CRYPT_BUF_SIZE];
+ struct dm_ioctl *io;
+ struct dm_target_versions *v;
+ int i;
+
+ io = (struct dm_ioctl *) buffer;
+
+ ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
+
+ if (ioctl(fd, DM_LIST_VERSIONS, io)) {
+ return -1;
+ }
+
+ /* Iterate over the returned versions, looking for name of "crypt".
+ * When found, get and return the version.
+ */
+ v = (struct dm_target_versions *) &buffer[sizeof(struct dm_ioctl)];
+ while (v->next) {
+ if (! strcmp(v->name, "crypt")) {
+ /* We found the crypt driver, return the version, and get out */
+ version[0] = v->version[0];
+ version[1] = v->version[1];
+ version[2] = v->version[2];
+ return 0;
+ }
+ v = (struct dm_target_versions *)(((char *)v) + v->next);
+ }
+
+ return -1;
+}
+
static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char *master_key,
char *real_blk_name, char *crypto_blk_name, const char *name)
{
@@ -389,6 +456,9 @@
int fd;
int i;
int retval = -1;
+ int version[3];
+ char *extra_params;
+ int load_count;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0 ) {
SLOGE("Cannot open device-mapper\n");
@@ -412,40 +482,27 @@
minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
snprintf(crypto_blk_name, MAXPATHLEN, "/dev/block/dm-%u", minor);
- /* Load the mapping table for this device */
- tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
-
- ioctl_init(io, 4096, name, 0);
- io->target_count = 1;
- tgt->status = 0;
- tgt->sector_start = 0;
- tgt->length = crypt_ftr->fs_size;
- strcpy(tgt->target_type, "crypt");
-
- crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
- convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
- sprintf(crypt_params, "%s %s 0 %s 0", crypt_ftr->crypto_type_name,
- master_key_ascii, real_blk_name);
- crypt_params += strlen(crypt_params) + 1;
- crypt_params = (char *) (((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */
- tgt->next = crypt_params - buffer;
-
- for (i = 0; i < TABLE_LOAD_RETRIES; i++) {
- if (! ioctl(fd, DM_TABLE_LOAD, io)) {
- break;
- }
- usleep(500000);
+ extra_params = "";
+ if (! get_dm_crypt_version(fd, name, version)) {
+ /* Support for allow_discards was added in version 1.11.0 */
+ if ((version[0] >= 2) ||
+ ((version[0] == 1) && (version[1] >= 11))) {
+ extra_params = "1 allow_discards";
+ SLOGI("Enabling support for allow_discards in dmcrypt.\n");
+ }
}
- if (i == TABLE_LOAD_RETRIES) {
+ load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name,
+ fd, extra_params);
+ if (load_count < 0) {
SLOGE("Cannot load dm-crypt mapping table.\n");
goto errout;
- } else if (i) {
- SLOGI("Took %d tries to load dmcrypt table.\n", i + 1);
+ } else if (load_count > 1) {
+ SLOGI("Took %d tries to load dmcrypt table.\n", load_count);
}
/* Resume this device to activate it */
- ioctl_init(io, 4096, name, 0);
+ ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
if (ioctl(fd, DM_DEV_SUSPEND, io)) {
SLOGE("Cannot resume the dm-crypt device\n");
@@ -616,7 +673,7 @@
return rc;
}
-#define DATA_PREP_TIMEOUT 100
+#define DATA_PREP_TIMEOUT 200
static int prep_data_fs(void)
{
int i;
@@ -626,7 +683,7 @@
property_set("vold.decrypt", "trigger_post_fs_data");
SLOGD("Just triggered post_fs_data\n");
- /* Wait a max of 25 seconds, hopefully it takes much less */
+ /* Wait a max of 50 seconds, hopefully it takes much less */
for (i=0; i<DATA_PREP_TIMEOUT; i++) {
char p[PROPERTY_VALUE_MAX];
@@ -639,6 +696,7 @@
}
if (i == DATA_PREP_TIMEOUT) {
/* Ugh, we failed to prep /data in time. Bail. */
+ SLOGE("post_fs_data timed out!\n");
return -1;
} else {
SLOGD("post_fs_data done\n");
@@ -707,7 +765,7 @@
if (! (rc = wait_and_unmount(DATA_MNT_POINT)) ) {
/* If that succeeded, then mount the decrypted filesystem */
- fs_mgr_do_mount(get_fstab_filename(), DATA_MNT_POINT, crypto_blkdev, 0);
+ fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, 0);
property_set("vold.decrypt", "trigger_load_persist_props");
/* Create necessary paths on /data */
@@ -745,10 +803,10 @@
return 1;
}
- fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
+ fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
- fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+ fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
/*
* Only report this error if key_loc is a file and it exists.
@@ -795,7 +853,7 @@
return -1;
}
- fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
+ fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
SLOGE("Error getting crypt footer and key\n");
@@ -824,7 +882,7 @@
*/
sprintf(tmp_mount_point, "%s/tmp_mnt", mount_point);
mkdir(tmp_mount_point, 0755);
- if (fs_mgr_do_mount(get_fstab_filename(), DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) {
+ if (fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, tmp_mount_point)) {
SLOGE("Error temp mounting decrypted block device\n");
delete_crypto_blk_dev(label);
crypt_ftr.failed_decrypt_count++;
@@ -955,7 +1013,7 @@
return -1;
}
- fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
+ fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
if (get_crypt_ftr_and_key(real_blkdev, &crypt_ftr, encrypted_master_key, salt)) {
SLOGE("Error getting crypt footer and key\n");
@@ -1157,7 +1215,7 @@
goto error_unencrypted;
}
- fs_mgr_get_crypt_info(get_fstab_filename(), key_loc, 0, sizeof(key_loc));
+ fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
if (!strcmp(howarg, "wipe")) {
how = CRYPTO_ENABLE_WIPE;
@@ -1168,7 +1226,7 @@
goto error_unencrypted;
}
- fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
+ fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
/* Get the size of the real block device */
fd = open(real_blkdev, O_RDONLY);
@@ -1461,7 +1519,7 @@
return -1;
}
- fs_mgr_get_crypt_info(get_fstab_filename(), 0, real_blkdev, sizeof(real_blkdev));
+ fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
if (strlen(real_blkdev) == 0) {
SLOGE("Can't find real blkdev");
return -1;
diff --git a/fstrim.c b/fstrim.c
new file mode 100644
index 0000000..4911778
--- /dev/null
+++ b/fstrim.c
@@ -0,0 +1,155 @@
+/*
+ * 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 <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"
+
+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 *ignored)
+{
+ int i;
+ int fd;
+ int ret = 0;
+ struct fstrim_range range = { 0 };
+ struct stat sb;
+ extern struct fstab *fstab;
+
+ SLOGI("Starting fstrim work...\n");
+
+ /* 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 (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);
+ }
+
+ /* 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 *)ret;
+}
+
+int fstrim_filesystems(void)
+{
+ pthread_t t;
+ int ret;
+
+ /* 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);
+
+ /* 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, NULL);
+ 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;
+}
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
+
diff --git a/logwrapper.c b/logwrapper.c
deleted file mode 100644
index 34a1e5a..0000000
--- a/logwrapper.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2008 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 <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include "private/android_filesystem_config.h"
-#include "cutils/log.h"
-#include "cutils/sched_policy.h"
-
-int parent(const char *tag, int parent_read) {
- int status;
- char buffer[4096];
-
- int a = 0; // start index of unprocessed data
- int b = 0; // end index of unprocessed data
- int sz;
- while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
-
- sz += b;
- // Log one line at a time
- for (b = 0; b < sz; b++) {
- if (buffer[b] == '\r') {
- buffer[b] = '\0';
- } else if (buffer[b] == '\n') {
- buffer[b] = '\0';
-
- ALOG(LOG_INFO, tag, "%s", &buffer[a]);
- a = b + 1;
- }
- }
-
- if (a == 0 && b == sizeof(buffer) - 1) {
- // buffer is full, flush
- buffer[b] = '\0';
- ALOG(LOG_INFO, tag, "%s", &buffer[a]);
- b = 0;
- } else if (a != b) {
- // Keep left-overs
- b -= a;
- memmove(buffer, &buffer[a], b);
- a = 0;
- } else {
- a = 0;
- b = 0;
- }
-
- }
- // Flush remaining data
- if (a != b) {
- buffer[b] = '\0';
- ALOG(LOG_INFO, tag, "%s", &buffer[a]);
- }
- status = 0xAAAA;
- if (wait(&status) != -1) { // Wait for child
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) != 0) {
- ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
- WEXITSTATUS(status));
- }
- return WEXITSTATUS(status);
- } else if (WIFSIGNALED(status))
- ALOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
- WTERMSIG(status));
- else if (WIFSTOPPED(status))
- ALOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
- WSTOPSIG(status));
- } else
- ALOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
- strerror(errno), errno);
- return -EAGAIN;
-}
-
-void child(int argc, const char**argv) {
- // create null terminated argv_child array
- char* argv_child[argc + 1];
- memcpy(argv_child, argv, argc * sizeof(char *));
- argv_child[argc] = NULL;
-
- // XXX: PROTECT FROM VIKING KILLER
- if (execv(argv_child[0], argv_child)) {
- ALOG(LOG_ERROR, "logwrapper",
- "executing %s failed: %s", argv_child[0], strerror(errno));
- exit(-1);
- }
-}
-
-int logwrap(int argc, const char* argv[], int background)
-{
- pid_t pid;
-
- int parent_ptty;
- int child_ptty;
- char *child_devname = NULL;
-
- /* Use ptty instead of socketpair so that STDOUT is not buffered */
- parent_ptty = open("/dev/ptmx", O_RDWR);
- if (parent_ptty < 0) {
- ALOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
- return -errno;
- }
-
- if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
- ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
- close(parent_ptty);
- ALOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
- return -1;
- }
-
- pid = fork();
- if (pid < 0) {
- close(parent_ptty);
- ALOG(LOG_ERROR, "logwrapper", "Failed to fork");
- return -errno;
- } else if (pid == 0) {
- /*
- * Child
- */
- child_ptty = open(child_devname, O_RDWR);
- if (child_ptty < 0) {
- close(parent_ptty);
- ALOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
- return -errno;
- }
-
- // redirect stdout and stderr
- close(parent_ptty);
- dup2(child_ptty, 1);
- dup2(child_ptty, 2);
- close(child_ptty);
-
- if (background) {
- int err = set_sched_policy(getpid(), SP_BACKGROUND);
- if (err < 0) {
- ALOG(LOG_WARN, "logwrapper",
- "Unable to background process (%s)", strerror(-err));
- }
- }
-
- child(argc, argv);
- } else {
- /*
- * Parent
- */
- int rc = parent(argv[0], parent_ptty);
- close(parent_ptty);
- return rc;
- }
-
- return 0;
-}
diff --git a/main.cpp b/main.cpp
index 5924fe4..02506e7 100644
--- a/main.cpp
+++ b/main.cpp
@@ -23,10 +23,13 @@
#include <fcntl.h>
#include <dirent.h>
+#include <fs_mgr.h>
#define LOG_TAG "Vold"
+#include "cutils/klog.h"
#include "cutils/log.h"
+#include "cutils/properties.h"
#include "VolumeManager.h"
#include "CommandListener.h"
@@ -37,6 +40,9 @@
static int process_config(VolumeManager *vm);
static void coldboot(const char *path);
+#define FSTAB_PREFIX "/fstab."
+struct fstab *fstab;
+
int main() {
VolumeManager *vm;
@@ -47,6 +53,9 @@
mkdir("/dev/block/vold", 0755);
+ /* For when cryptfs checks and mounts an encrypted filesystem */
+ klog_set_level(6);
+
/* Create our singleton managers */
if (!(vm = VolumeManager::Instance())) {
SLOGE("Unable to create VolumeManager");
@@ -142,111 +151,54 @@
}
}
-static int parse_mount_flags(char *mount_flags)
+static int process_config(VolumeManager *vm)
{
- char *save_ptr;
- int flags = 0;
+ char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+ char propbuf[PROPERTY_VALUE_MAX];
+ int i;
+ int ret = -1;
+ int flags;
- if (strcasestr(mount_flags, "encryptable")) {
- flags |= VOL_ENCRYPTABLE;
- }
+ property_get("ro.hardware", propbuf, "");
+ snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
- if (strcasestr(mount_flags, "nonremovable")) {
- flags |= VOL_NONREMOVABLE;
- }
-
- return flags;
-}
-
-static int process_config(VolumeManager *vm) {
- FILE *fp;
- int n = 0;
- char line[255];
-
- if (!(fp = fopen("/etc/vold.fstab", "r"))) {
+ fstab = fs_mgr_read_fstab(fstab_filename);
+ if (!fstab) {
+ SLOGE("failed to open %s\n", fstab_filename);
return -1;
}
- while(fgets(line, sizeof(line), fp)) {
- const char *delim = " \t";
- char *save_ptr;
- char *type, *label, *mount_point, *mount_flags, *sysfs_path;
- int flags;
-
- n++;
- line[strlen(line)-1] = '\0';
-
- if (line[0] == '#' || line[0] == '\0')
- continue;
-
- if (!(type = strtok_r(line, delim, &save_ptr))) {
- SLOGE("Error parsing type");
- goto out_syntax;
- }
- if (!(label = strtok_r(NULL, delim, &save_ptr))) {
- SLOGE("Error parsing label");
- goto out_syntax;
- }
- if (!(mount_point = strtok_r(NULL, delim, &save_ptr))) {
- SLOGE("Error parsing mount point");
- goto out_syntax;
- }
-
- if (!strcmp(type, "dev_mount")) {
+ /* Loop through entries looking for ones that vold manages */
+ for (i = 0; i < fstab->num_entries; i++) {
+ if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
DirectVolume *dv = NULL;
- char *part;
+ flags = 0;
- if (!(part = strtok_r(NULL, delim, &save_ptr))) {
- SLOGE("Error parsing partition");
- goto out_syntax;
- }
- if (strcmp(part, "auto") && atoi(part) == 0) {
- SLOGE("Partition must either be 'auto' or 1 based index instead of '%s'", part);
- goto out_syntax;
+ dv = new DirectVolume(vm, fstab->recs[i].label,
+ fstab->recs[i].mount_point,
+ fstab->recs[i].partnum);
+
+ if (dv->addPath(fstab->recs[i].blk_device)) {
+ SLOGE("Failed to add devpath %s to volume %s",
+ fstab->recs[i].blk_device, fstab->recs[i].label);
+ goto out_fail;
}
- if (!strcmp(part, "auto")) {
- dv = new DirectVolume(vm, label, mount_point, -1);
- } else {
- dv = new DirectVolume(vm, label, mount_point, atoi(part));
+ /* Set any flags that might be set for this volume */
+ if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
+ flags |= VOL_NONREMOVABLE;
}
-
- while ((sysfs_path = strtok_r(NULL, delim, &save_ptr))) {
- if (*sysfs_path != '/') {
- /* If the first character is not a '/', it must be flags */
- break;
- }
- if (dv->addPath(sysfs_path)) {
- SLOGE("Failed to add devpath %s to volume %s", sysfs_path,
- label);
- goto out_fail;
- }
+ if (fs_mgr_is_encryptable(&fstab->recs[i])) {
+ flags |= VOL_ENCRYPTABLE;
}
-
- /* If sysfs_path is non-null at this point, then it contains
- * the optional flags for this volume
- */
- if (sysfs_path)
- flags = parse_mount_flags(sysfs_path);
- else
- flags = 0;
dv->setFlags(flags);
vm->addVolume(dv);
- } else if (!strcmp(type, "map_mount")) {
- } else {
- SLOGE("Unknown type '%s'", type);
- goto out_syntax;
}
}
- fclose(fp);
- return 0;
+ ret = 0;
-out_syntax:
- SLOGE("Syntax error on config line %d", n);
- errno = -EINVAL;
out_fail:
- fclose(fp);
- return -1;
+ return ret;
}