OSDN Git Service

vold: Honor mount options for ext4/f2fs partitions
[android-x86/system-vold.git] / model / PublicVolume.cpp
1 /*
2  * Copyright (C) 2015 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 "PublicVolume.h"
18
19 #include "AppFuseUtil.h"
20 #include "Utils.h"
21 #include "VolumeManager.h"
22 #include "fs/Exfat.h"
23 #include "fs/Ext4.h"
24 #include "fs/F2fs.h"
25 #include "fs/Ntfs.h"
26 #include "fs/Vfat.h"
27
28 #include <android-base/logging.h>
29 #include <android-base/properties.h>
30 #include <android-base/stringprintf.h>
31 #include <cutils/fs.h>
32 #include <private/android_filesystem_config.h>
33 #include <utils/Timers.h>
34
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include <sys/mount.h>
38 #include <sys/stat.h>
39 #include <sys/sysmacros.h>
40 #include <sys/types.h>
41 #include <sys/wait.h>
42
43 using android::base::GetBoolProperty;
44 using android::base::StringPrintf;
45
46 namespace android {
47 namespace vold {
48
49 static const char* kSdcardFsPath = "/system/bin/sdcard";
50
51 static const char* kAsecPath = "/mnt/secure/asec";
52
53 PublicVolume::PublicVolume(dev_t device, const std::string& fstype /* = "" */,
54                            const std::string& mntopts /* = "" */) :
55         VolumeBase(Type::kPublic), mDevice(device),
56         mFsType(fstype), mMntOpts(mntopts)  {
57     setId(StringPrintf("public:%u,%u", major(device), minor(device)));
58     mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
59     mFuseMounted = false;
60     mUseSdcardFs = IsSdcardfsUsed();
61 }
62
63 PublicVolume::~PublicVolume() {}
64
65 status_t PublicVolume::readMetadata() {
66     status_t res = ReadMetadataUntrusted(mDevPath, &mFsType, &mFsUuid, &mFsLabel);
67
68     auto listener = getListener();
69     if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
70
71     return res;
72 }
73
74 status_t PublicVolume::initAsecStage() {
75     std::string legacyPath(mRawPath + "/android_secure");
76     std::string securePath(mRawPath + "/.android_secure");
77
78     // Recover legacy secure path
79     if (!access(legacyPath.c_str(), R_OK | X_OK) && access(securePath.c_str(), R_OK | X_OK)) {
80         if (rename(legacyPath.c_str(), securePath.c_str())) {
81             PLOG(WARNING) << getId() << " failed to rename legacy ASEC dir";
82         }
83     }
84
85     if (TEMP_FAILURE_RETRY(mkdir(securePath.c_str(), 0700))) {
86         if (errno != EEXIST) {
87             PLOG(WARNING) << getId() << " creating ASEC stage failed";
88             return -errno;
89         }
90     }
91
92     BindMount(securePath, kAsecPath);
93
94     return OK;
95 }
96
97 status_t PublicVolume::doCreate() {
98     return CreateDeviceNode(mDevPath, mDevice);
99 }
100
101 status_t PublicVolume::doDestroy() {
102     return DestroyDeviceNode(mDevPath);
103 }
104
105 status_t PublicVolume::doMount() {
106     bool isVisible = getMountFlags() & MountFlags::kVisible;
107     readMetadata();
108
109     if (!IsFilesystemSupported(mFsType)) {
110         LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
111         return -EIO;
112     }
113
114     // Use UUID as stable name, if available
115     std::string stableName = getId();
116     if (!mFsUuid.empty()) {
117         stableName = mFsUuid;
118     }
119
120     mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());
121
122     mSdcardFsDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());
123     mSdcardFsRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());
124     mSdcardFsWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());
125     mSdcardFsFull = StringPrintf("/mnt/runtime/full/%s", stableName.c_str());
126
127     setInternalPath(mRawPath);
128     if (isVisible) {
129         setPath(StringPrintf("/storage/%s", stableName.c_str()));
130     } else {
131         setPath(mRawPath);
132     }
133
134     if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
135         PLOG(ERROR) << getId() << " failed to create mount points";
136         return -errno;
137     }
138
139     int ret = 0;
140     if (mFsType == "exfat") {
141         ret = exfat::Check(mDevPath);
142     } else if (mFsType == "ext4") {
143         ret = ext4::Check(mDevPath, mRawPath);
144     } else if (mFsType == "f2fs") {
145         ret = f2fs::Check(mDevPath);
146     } else if (mFsType == "ntfs") {
147         ret = ntfs::Check(mDevPath);
148     } else if (mFsType == "vfat") {
149         ret = vfat::Check(mDevPath);
150     } else {
151         LOG(WARNING) << getId() << " unsupported filesystem check, skipping";
152     }
153     if (ret) {
154         LOG(ERROR) << getId() << " failed filesystem check";
155         return -EIO;
156     }
157
158     if (mFsType == "exfat") {
159         ret = exfat::Mount(mDevPath, mRawPath, AID_ROOT,
160                            (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007);
161     } else if (mFsType == "ext4") {
162         ret = ext4::Mount(mDevPath, mRawPath, false, false, true, mMntOpts);
163     } else if (mFsType == "f2fs") {
164         ret = f2fs::Mount(mDevPath, mRawPath, mMntOpts);
165     } else if (mFsType == "ntfs") {
166         ret = ntfs::Mount(mDevPath, mRawPath, AID_ROOT,
167                           (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007);
168     } else if (mFsType == "vfat") {
169         ret = vfat::Mount(mDevPath, mRawPath, false, false, false, AID_ROOT,
170                           (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007, true);
171     } else {
172         ret = ::mount(mDevPath.c_str(), mRawPath.c_str(), mFsType.c_str(), 0, NULL);
173     }
174     if (ret) {
175         PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
176         return -EIO;
177     }
178
179     if (getMountFlags() & MountFlags::kPrimary) {
180         initAsecStage();
181     }
182
183     if (!isVisible) {
184         // Not visible to apps, so no need to spin up sdcardfs or FUSE
185         return OK;
186     }
187
188     if (mUseSdcardFs) {
189         if (fs_prepare_dir(mSdcardFsDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
190             fs_prepare_dir(mSdcardFsRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
191             fs_prepare_dir(mSdcardFsWrite.c_str(), 0700, AID_ROOT, AID_ROOT) ||
192             fs_prepare_dir(mSdcardFsFull.c_str(), 0700, AID_ROOT, AID_ROOT)) {
193             PLOG(ERROR) << getId() << " failed to create sdcardfs mount points";
194             return -errno;
195         }
196
197         dev_t before = GetDevice(mSdcardFsFull);
198
199         int sdcardFsPid;
200         if (!(sdcardFsPid = fork())) {
201             if (getMountFlags() & MountFlags::kPrimary) {
202                 // clang-format off
203                 if (execl(kSdcardFsPath, kSdcardFsPath,
204                         "-u", "1023", // AID_MEDIA_RW
205                         "-g", "1023", // AID_MEDIA_RW
206                         "-U", std::to_string(getMountUserId()).c_str(),
207                         "-w",
208                         mRawPath.c_str(),
209                         stableName.c_str(),
210                         NULL)) {
211                     // clang-format on
212                     PLOG(ERROR) << "Failed to exec";
213                 }
214             } else {
215                 // clang-format off
216                 if (execl(kSdcardFsPath, kSdcardFsPath,
217                         "-u", "1023", // AID_MEDIA_RW
218                         "-g", "1023", // AID_MEDIA_RW
219                         "-U", std::to_string(getMountUserId()).c_str(),
220                         mRawPath.c_str(),
221                         stableName.c_str(),
222                         NULL)) {
223                     // clang-format on
224                     PLOG(ERROR) << "Failed to exec";
225                 }
226             }
227
228             LOG(ERROR) << "sdcardfs exiting";
229             _exit(1);
230         }
231
232         if (sdcardFsPid == -1) {
233             PLOG(ERROR) << getId() << " failed to fork";
234             return -errno;
235         }
236
237         nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
238         while (before == GetDevice(mSdcardFsFull)) {
239             LOG(DEBUG) << "Waiting for sdcardfs to spin up...";
240             usleep(50000);  // 50ms
241
242             nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
243             if (nanoseconds_to_milliseconds(now - start) > 5000) {
244                 LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up";
245                 return -ETIMEDOUT;
246             }
247         }
248         /* sdcardfs will have exited already. The filesystem will still be running */
249         TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0));
250     }
251
252     // We need to mount FUSE *after* sdcardfs, since the FUSE daemon may depend
253     // on sdcardfs being up.
254     LOG(INFO) << "Mounting public fuse volume";
255     android::base::unique_fd fd;
256     int user_id = getMountUserId();
257     int result = MountUserFuse(user_id, getInternalPath(), stableName, &fd);
258
259     if (result != 0) {
260         LOG(ERROR) << "Failed to mount public fuse volume";
261         doUnmount();
262         return -result;
263     }
264
265     mFuseMounted = true;
266     auto callback = getMountCallback();
267     if (callback) {
268         bool is_ready = false;
269         callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready);
270         if (!is_ready) {
271             LOG(ERROR) << "Failed to complete public volume mount";
272             doUnmount();
273             return -EIO;
274         }
275     }
276
277     ConfigureReadAheadForFuse(GetFuseMountPathForUser(user_id, stableName), 256u);
278
279     // See comment in model/EmulatedVolume.cpp
280     ConfigureMaxDirtyRatioForFuse(GetFuseMountPathForUser(user_id, stableName), 40u);
281
282     return OK;
283 }
284
285 status_t PublicVolume::doUnmount() {
286     // Unmount the storage before we kill the FUSE process. If we kill
287     // the FUSE process first, most file system operations will return
288     // ENOTCONN until the unmount completes. This is an exotic and unusual
289     // error code and might cause broken behaviour in applications.
290     KillProcessesUsingPath(getPath());
291
292     if (mFuseMounted) {
293         // Use UUID as stable name, if available
294         std::string stableName = getId();
295         if (!mFsUuid.empty()) {
296             stableName = mFsUuid;
297         }
298
299         if (UnmountUserFuse(getMountUserId(), getInternalPath(), stableName) != OK) {
300             PLOG(INFO) << "UnmountUserFuse failed on public fuse volume";
301             return -errno;
302         }
303
304         mFuseMounted = false;
305     }
306
307     ForceUnmount(kAsecPath);
308
309     if (mUseSdcardFs) {
310         ForceUnmount(mSdcardFsDefault);
311         ForceUnmount(mSdcardFsRead);
312         ForceUnmount(mSdcardFsWrite);
313         ForceUnmount(mSdcardFsFull);
314
315         rmdir(mSdcardFsDefault.c_str());
316         rmdir(mSdcardFsRead.c_str());
317         rmdir(mSdcardFsWrite.c_str());
318         rmdir(mSdcardFsFull.c_str());
319
320         mSdcardFsDefault.clear();
321         mSdcardFsRead.clear();
322         mSdcardFsWrite.clear();
323         mSdcardFsFull.clear();
324     }
325     ForceUnmount(mRawPath);
326     rmdir(mRawPath.c_str());
327     mRawPath.clear();
328
329     return OK;
330 }
331
332 status_t PublicVolume::doFormat(const std::string& fsType) {
333     bool useVfat = vfat::IsSupported();
334     bool useExfat = exfat::IsSupported();
335     status_t res = UNKNOWN_ERROR;
336
337     // Resolve the target filesystem type
338     if (fsType == "auto" && useVfat && useExfat) {
339         uint64_t size = 0;
340
341         res = GetBlockDevSize(mDevPath, &size);
342         if (res != OK) {
343             LOG(ERROR) << "Couldn't get device size " << mDevPath;
344             return res;
345         }
346
347         // If both vfat & exfat are supported use exfat for SDXC (>~32GiB) cards
348         if (size > 32896LL * 1024 * 1024) {
349             useVfat = false;
350         } else {
351             useExfat = false;
352         }
353     } else if (fsType == "vfat") {
354         useExfat = false;
355     } else if (fsType == "exfat") {
356         useVfat = false;
357     }
358
359     if (!useVfat && !useExfat && !IsFilesystemSupported(fsType)) {
360         LOG(ERROR) << "Unsupported filesystem " << fsType;
361         return -EINVAL;
362     }
363
364     if (WipeBlockDevice(mDevPath) != OK) {
365         LOG(WARNING) << getId() << " failed to wipe";
366     }
367
368     if (useVfat) {
369         res = vfat::Format(mDevPath, 0);
370     } else if (useExfat) {
371         res = exfat::Format(mDevPath);
372     } else if (fsType == "ext4") {
373         res = ext4::Format(mDevPath, 0, mRawPath);
374     } else if (fsType == "f2fs") {
375         res = f2fs::Format(mDevPath);
376     } else if (fsType == "ntfs") {
377         res = ntfs::Format(mDevPath);
378     } else {
379         LOG(ERROR) << getId() << " unrecognized filesystem " << fsType;
380         errno = EIO;
381     }
382
383     if (res != OK) {
384         LOG(ERROR) << getId() << " failed to format";
385         res = -errno;
386     }
387
388     return res;
389 }
390
391 }  // namespace vold
392 }  // namespace android