blob: c732cb6ce90927062e6338ebce48ad97515cc400 [file] [log] [blame]
Sergei Datsenko3cf72cb2019-04-01 11:27:50 +11001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cros-disks/mount_point.h"
6
Ben Chan4cc7a012019-04-10 16:32:56 -07007#include <utility>
8
Qijiang Fan713061e2021-03-08 15:45:12 +09009#include <base/check.h>
Anand K Mistryf1bd0862019-12-20 11:54:55 +110010#include <base/logging.h>
11
François Degrosbf7bb592019-07-12 09:49:52 +100012#include "cros-disks/error_logger.h"
Sergei Datsenko3cf72cb2019-04-01 11:27:50 +110013#include "cros-disks/mounter.h"
François Degros8b4e31e2019-07-29 11:39:19 +100014#include "cros-disks/quote.h"
Sergei Datsenko3cf72cb2019-04-01 11:27:50 +110015
16namespace cros_disks {
17
Anand K Mistryf1bd0862019-12-20 11:54:55 +110018// static
19std::unique_ptr<MountPoint> MountPoint::CreateLeaking(
20 const base::FilePath& path) {
Sergei Datsenko0ba12032021-01-07 08:51:14 +110021 auto mount_point =
22 std::make_unique<MountPoint>(MountPointData{path}, nullptr);
23 mount_point->Release();
24 return mount_point;
Anand K Mistryf1bd0862019-12-20 11:54:55 +110025}
26
Sergei Datsenko0ba12032021-01-07 08:51:14 +110027// static
28std::unique_ptr<MountPoint> MountPoint::Mount(MountPointData data,
29 const Platform* platform,
30 MountErrorType* error) {
31 *error = platform->Mount(data.source, data.mount_path.value(),
32 data.filesystem_type, data.flags, data.data);
33 if (*error != MOUNT_ERROR_NONE) {
34 return nullptr;
35 }
36 return std::make_unique<MountPoint>(std::move(data), platform);
37}
38
39MountPoint::MountPoint(MountPointData data, const Platform* platform)
40 : data_(std::move(data)), platform_(platform) {
Sergei Datsenko2d9c7a32021-01-05 23:13:13 +110041 DCHECK(!path().empty());
Anand K Mistryf1bd0862019-12-20 11:54:55 +110042}
Sergei Datsenko3cf72cb2019-04-01 11:27:50 +110043
44MountPoint::~MountPoint() {
Sergei Datsenko0ba12032021-01-07 08:51:14 +110045 if (!released_) {
46 MountErrorType error = Unmount();
47 if (error != MOUNT_ERROR_NONE && error != MOUNT_ERROR_PATH_NOT_MOUNTED) {
48 LOG(WARNING) << "Unmount error while destroying MountPoint("
49 << quote(path()) << "): " << error;
50 }
51 }
Sergei Datsenko3cf72cb2019-04-01 11:27:50 +110052}
53
54void MountPoint::Release() {
Anand K Mistryf1bd0862019-12-20 11:54:55 +110055 released_ = true;
Sergei Datsenko3cf72cb2019-04-01 11:27:50 +110056}
57
58MountErrorType MountPoint::Unmount() {
Anand K Mistryf1bd0862019-12-20 11:54:55 +110059 if (released_) {
60 // TODO(amistry): "not mounted" and "already unmounted" are logically
61 // different and should be treated differently. Introduce a new error code
62 // to represent this distinction.
François Degros3a796902019-07-12 14:49:58 +100063 return MOUNT_ERROR_PATH_NOT_MOUNTED;
Sergei Datsenko3cf72cb2019-04-01 11:27:50 +110064 }
Anand K Mistryf1bd0862019-12-20 11:54:55 +110065 MountErrorType error = UnmountImpl();
Sergei Datsenko0ba12032021-01-07 08:51:14 +110066 if (error == MOUNT_ERROR_NONE || error == MOUNT_ERROR_PATH_NOT_MOUNTED) {
Anand K Mistryf1bd0862019-12-20 11:54:55 +110067 released_ = true;
Sergei Datsenko3cf72cb2019-04-01 11:27:50 +110068 }
69 return error;
70}
71
Sergei Datsenko0ba12032021-01-07 08:51:14 +110072MountErrorType MountPoint::Remount(bool read_only) {
73 if (released_) {
74 return MOUNT_ERROR_PATH_NOT_MOUNTED;
Anand K Mistryf1bd0862019-12-20 11:54:55 +110075 }
Sergei Datsenko0ba12032021-01-07 08:51:14 +110076 int new_flags = (data_.flags & ~MS_RDONLY) | (read_only ? MS_RDONLY : 0);
77 MountErrorType error = RemountImpl(new_flags);
78 if (error == MOUNT_ERROR_NONE) {
79 data_.flags = new_flags;
80 }
81 return error;
82}
Anand K Mistryf1bd0862019-12-20 11:54:55 +110083
Sergei Datsenko0ba12032021-01-07 08:51:14 +110084MountErrorType MountPoint::UnmountImpl() {
85 // We take a 2-step approach to unmounting FUSE filesystems. First, try a
86 // normal unmount. This lets the VFS flush any pending data and lets the
87 // filesystem shut down cleanly. If the filesystem is busy, force unmount
88 // the filesystem. This is done because there is no good recovery path the
89 // user can take, and these filesystem are sometimes unmounted implicitly on
90 // login/logout/suspend.
91
92 MountErrorType error = platform_->Unmount(path().value(), 0 /* flags */);
93 if (error != MOUNT_ERROR_PATH_ALREADY_MOUNTED) {
94 // MOUNT_ERROR_PATH_ALREADY_MOUNTED is returned on EBUSY.
95 return error;
Anand K Mistryf1bd0862019-12-20 11:54:55 +110096 }
Sergei Datsenko0ba12032021-01-07 08:51:14 +110097
98 // For FUSE filesystems, MNT_FORCE will cause the kernel driver to
99 // immediately close the channel to the user-space driver program and cancel
100 // all outstanding requests. However, if any program is still accessing the
101 // filesystem, the umount2() will fail with EBUSY and the mountpoint will
102 // still be attached. Since the mountpoint is no longer valid, use
103 // MNT_DETACH to also force the mountpoint to be disconnected.
104 // On a non-FUSE filesystem MNT_FORCE doesn't have effect, so it only
105 // handles MNT_DETACH, but it's OK to pass MNT_FORCE too.
106 LOG(WARNING) << "Mount point " << quote(path())
107 << " is busy, using force unmount";
108 return platform_->Unmount(path().value(), MNT_FORCE | MNT_DETACH);
109}
110
111MountErrorType MountPoint::RemountImpl(int flags) {
112 return platform_->Mount(data_.source, data_.mount_path.value(),
113 data_.filesystem_type, flags | MS_REMOUNT,
114 data_.data);
Anand K Mistryf1bd0862019-12-20 11:54:55 +1100115}
116
Sergei Datsenko3cf72cb2019-04-01 11:27:50 +1100117} // namespace cros_disks