Ext4.cpp revision 46bb69f49a8630cc97e84976d0327495b7dd5708
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <fcntl.h>
20#include <unistd.h>
21#include <errno.h>
22#include <string.h>
23#include <dirent.h>
24#include <errno.h>
25#include <fcntl.h>
26#include <vector>
27#include <string>
28
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <sys/types.h>
32#include <sys/mman.h>
33#include <sys/mount.h>
34#include <sys/wait.h>
35
36#include <linux/kdev_t.h>
37
38#define LOG_TAG "Vold"
39
40#include <android-base/logging.h>
41#include <android-base/stringprintf.h>
42#include <cutils/log.h>
43#include <cutils/properties.h>
44#include <logwrap/logwrap.h>
45#include <selinux/selinux.h>
46
47#include "Ext4.h"
48#include "Ext4Crypt.h"
49#include "Utils.h"
50#include "VoldUtil.h"
51
52using android::base::StringPrintf;
53
54namespace android {
55namespace vold {
56namespace ext4 {
57
58static const char* kResizefsPath = "/system/bin/resize2fs";
59#ifdef TARGET_USES_MKE2FS
60static const char* kMkfsPath = "/system/bin/mke2fs";
61#else
62static const char* kMkfsPath = "/system/bin/make_ext4fs";
63#endif
64static const char* kFsckPath = "/system/bin/e2fsck";
65
66bool IsSupported() {
67    return access(kMkfsPath, X_OK) == 0
68            && access(kFsckPath, X_OK) == 0
69            && IsFilesystemSupported("ext4");
70}
71
72status_t Check(const std::string& source, const std::string& target) {
73    // The following is shamelessly borrowed from fs_mgr.c, so it should be
74    // kept in sync with any changes over there.
75
76    const char* c_source = source.c_str();
77    const char* c_target = target.c_str();
78
79    int status;
80    int ret;
81    long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
82    char *tmpmnt_opts = (char*) "nomblk_io_submit,errors=remount-ro";
83
84    /*
85     * First try to mount and unmount the filesystem.  We do this because
86     * the kernel is more efficient than e2fsck in running the journal and
87     * processing orphaned inodes, and on at least one device with a
88     * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
89     * to do what the kernel does in about a second.
90     *
91     * After mounting and unmounting the filesystem, run e2fsck, and if an
92     * error is recorded in the filesystem superblock, e2fsck will do a full
93     * check.  Otherwise, it does nothing.  If the kernel cannot mount the
94     * filesytsem due to an error, e2fsck is still run to do a full check
95     * fix the filesystem.
96     */
97    ret = mount(c_source, c_target, "ext4", tmpmnt_flags, tmpmnt_opts);
98    if (!ret) {
99        int i;
100        for (i = 0; i < 5; i++) {
101            // Try to umount 5 times before continuing on.
102            // Should we try rebooting if all attempts fail?
103            int result = umount(c_target);
104            if (result == 0) {
105                break;
106            }
107            ALOGW("%s(): umount(%s)=%d: %s\n", __func__, c_target, result, strerror(errno));
108            sleep(1);
109        }
110    }
111
112    /*
113     * Some system images do not have e2fsck for licensing reasons
114     * (e.g. recent SDK system images). Detect these and skip the check.
115     */
116    if (access(kFsckPath, X_OK)) {
117        ALOGD("Not running %s on %s (executable not in system image)\n",
118                kFsckPath, c_source);
119    } else {
120        ALOGD("Running %s on %s\n", kFsckPath, c_source);
121
122        std::vector<std::string> cmd;
123        cmd.push_back(kFsckPath);
124        cmd.push_back("-y");
125        cmd.push_back(c_source);
126
127        // ext4 devices are currently always trusted
128        return ForkExecvp(cmd, sFsckContext);
129    }
130
131    return 0;
132}
133
134status_t Mount(const std::string& source, const std::string& target, bool ro,
135        bool remount, bool executable) {
136    int rc;
137    unsigned long flags;
138
139    const char* c_source = source.c_str();
140    const char* c_target = target.c_str();
141
142    flags = MS_NOATIME | MS_NODEV | MS_NOSUID | MS_DIRSYNC;
143
144    flags |= (executable ? 0 : MS_NOEXEC);
145    flags |= (ro ? MS_RDONLY : 0);
146    flags |= (remount ? MS_REMOUNT : 0);
147
148    rc = mount(c_source, c_target, "ext4", flags, NULL);
149
150    if (rc && errno == EROFS) {
151        SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source);
152        flags |= MS_RDONLY;
153        rc = mount(c_source, c_target, "ext4", flags, NULL);
154    }
155
156    return rc;
157}
158
159status_t Resize(const std::string& source, unsigned long numSectors) {
160    std::vector<std::string> cmd;
161    cmd.push_back(kResizefsPath);
162    cmd.push_back("-f");
163    cmd.push_back(source);
164    cmd.push_back(StringPrintf("%lu", numSectors));
165
166    return ForkExecvp(cmd);
167}
168
169status_t Format(const std::string& source, unsigned long numSectors,
170        const std::string& target) {
171    std::vector<std::string> cmd;
172    cmd.push_back(kMkfsPath);
173
174#ifdef TARGET_USES_MKE2FS
175    cmd.push_back("-b");
176    cmd.push_back("4096");
177
178    cmd.push_back("-t");
179    cmd.push_back("ext4");
180
181    cmd.push_back("-M");
182    cmd.push_back(target);
183
184    std::string options("has_journal,quota");
185    if (e4crypt_is_native()) {
186        options += ",encrypt";
187    }
188
189    cmd.push_back("-O");
190    cmd.push_back(options);
191
192    cmd.push_back(source);
193
194    if (numSectors)
195        cmd.push_back(StringPrintf("%lu", numSectors * (4096 / 512)));
196#else
197    cmd.push_back("-J");
198
199    cmd.push_back("-a");
200    cmd.push_back(target);
201
202    if (numSectors) {
203        cmd.push_back("-l");
204        cmd.push_back(StringPrintf("%lu", numSectors * 512));
205    }
206
207    // Always generate a real UUID
208    cmd.push_back("-u");
209    cmd.push_back(source);
210#endif
211
212    return ForkExecvp(cmd);
213}
214
215}  // namespace ext4
216}  // namespace vold
217}  // namespace android
218