Sergei Datsenko | 3cf72cb | 2019-04-01 11:27:50 +1100 | [diff] [blame] | 1 | // 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 Chan | 4cc7a01 | 2019-04-10 16:32:56 -0700 | [diff] [blame] | 7 | #include <utility> |
| 8 | |
Qijiang Fan | 713061e | 2021-03-08 15:45:12 +0900 | [diff] [blame] | 9 | #include <base/check.h> |
Anand K Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 10 | #include <base/logging.h> |
| 11 | |
François Degros | bf7bb59 | 2019-07-12 09:49:52 +1000 | [diff] [blame] | 12 | #include "cros-disks/error_logger.h" |
Sergei Datsenko | 3cf72cb | 2019-04-01 11:27:50 +1100 | [diff] [blame] | 13 | #include "cros-disks/mounter.h" |
François Degros | 8b4e31e | 2019-07-29 11:39:19 +1000 | [diff] [blame] | 14 | #include "cros-disks/quote.h" |
Sergei Datsenko | 3cf72cb | 2019-04-01 11:27:50 +1100 | [diff] [blame] | 15 | |
| 16 | namespace cros_disks { |
| 17 | |
Anand K Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 18 | // static |
| 19 | std::unique_ptr<MountPoint> MountPoint::CreateLeaking( |
| 20 | const base::FilePath& path) { |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 21 | auto mount_point = |
| 22 | std::make_unique<MountPoint>(MountPointData{path}, nullptr); |
| 23 | mount_point->Release(); |
| 24 | return mount_point; |
Anand K Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 25 | } |
| 26 | |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 27 | // static |
| 28 | std::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 | |
| 39 | MountPoint::MountPoint(MountPointData data, const Platform* platform) |
| 40 | : data_(std::move(data)), platform_(platform) { |
Sergei Datsenko | 2d9c7a3 | 2021-01-05 23:13:13 +1100 | [diff] [blame] | 41 | DCHECK(!path().empty()); |
Anand K Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 42 | } |
Sergei Datsenko | 3cf72cb | 2019-04-01 11:27:50 +1100 | [diff] [blame] | 43 | |
| 44 | MountPoint::~MountPoint() { |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 45 | 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 Datsenko | 3cf72cb | 2019-04-01 11:27:50 +1100 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | void MountPoint::Release() { |
Anand K Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 55 | released_ = true; |
Sergei Datsenko | 3cf72cb | 2019-04-01 11:27:50 +1100 | [diff] [blame] | 56 | } |
| 57 | |
| 58 | MountErrorType MountPoint::Unmount() { |
Anand K Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 59 | 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 Degros | 3a79690 | 2019-07-12 14:49:58 +1000 | [diff] [blame] | 63 | return MOUNT_ERROR_PATH_NOT_MOUNTED; |
Sergei Datsenko | 3cf72cb | 2019-04-01 11:27:50 +1100 | [diff] [blame] | 64 | } |
Anand K Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 65 | MountErrorType error = UnmountImpl(); |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 66 | if (error == MOUNT_ERROR_NONE || error == MOUNT_ERROR_PATH_NOT_MOUNTED) { |
Anand K Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 67 | released_ = true; |
Sergei Datsenko | 3cf72cb | 2019-04-01 11:27:50 +1100 | [diff] [blame] | 68 | } |
| 69 | return error; |
| 70 | } |
| 71 | |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 72 | MountErrorType MountPoint::Remount(bool read_only) { |
| 73 | if (released_) { |
| 74 | return MOUNT_ERROR_PATH_NOT_MOUNTED; |
Anand K Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 75 | } |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 76 | 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 Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 83 | |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 84 | MountErrorType 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 Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 96 | } |
Sergei Datsenko | 0ba1203 | 2021-01-07 08:51:14 +1100 | [diff] [blame] | 97 | |
| 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 | |
| 111 | MountErrorType 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 Mistry | f1bd086 | 2019-12-20 11:54:55 +1100 | [diff] [blame] | 115 | } |
| 116 | |
Sergei Datsenko | 3cf72cb | 2019-04-01 11:27:50 +1100 | [diff] [blame] | 117 | } // namespace cros_disks |