diff options
Diffstat (limited to 'fs_mgr/libdm/loop_control.cpp')
-rw-r--r-- | fs_mgr/libdm/loop_control.cpp | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/fs_mgr/libdm/loop_control.cpp b/fs_mgr/libdm/loop_control.cpp new file mode 100644 index 000000000..0beb1a63e --- /dev/null +++ b/fs_mgr/libdm/loop_control.cpp | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2018 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 "libdm/loop_control.h" | ||
18 | |||
19 | #include <fcntl.h> | ||
20 | #include <linux/loop.h> | ||
21 | #include <stdint.h> | ||
22 | #include <sys/ioctl.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #include <android-base/logging.h> | ||
27 | #include <android-base/stringprintf.h> | ||
28 | #include <android-base/unique_fd.h> | ||
29 | |||
30 | namespace android { | ||
31 | namespace dm { | ||
32 | |||
33 | LoopControl::LoopControl() : control_fd_(-1) { | ||
34 | control_fd_.reset(TEMP_FAILURE_RETRY(open(kLoopControlDevice, O_RDWR | O_CLOEXEC))); | ||
35 | if (control_fd_ < 0) { | ||
36 | PLOG(ERROR) << "Failed to open loop-control"; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | bool LoopControl::Attach(int file_fd, std::string* loopdev) const { | ||
41 | if (!FindFreeLoopDevice(loopdev)) { | ||
42 | LOG(ERROR) << "Failed to attach, no free loop devices"; | ||
43 | return false; | ||
44 | } | ||
45 | |||
46 | android::base::unique_fd loop_fd(TEMP_FAILURE_RETRY(open(loopdev->c_str(), O_RDWR | O_CLOEXEC))); | ||
47 | if (loop_fd < 0) { | ||
48 | PLOG(ERROR) << "Failed to open: " << *loopdev; | ||
49 | return false; | ||
50 | } | ||
51 | |||
52 | int rc = ioctl(loop_fd, LOOP_SET_FD, file_fd); | ||
53 | if (rc < 0) { | ||
54 | PLOG(ERROR) << "Failed LOOP_SET_FD"; | ||
55 | return false; | ||
56 | } | ||
57 | return true; | ||
58 | } | ||
59 | |||
60 | bool LoopControl::Detach(const std::string& loopdev) const { | ||
61 | if (loopdev.empty()) { | ||
62 | LOG(ERROR) << "Must provide a loop device"; | ||
63 | return false; | ||
64 | } | ||
65 | |||
66 | android::base::unique_fd loop_fd(TEMP_FAILURE_RETRY(open(loopdev.c_str(), O_RDWR | O_CLOEXEC))); | ||
67 | if (loop_fd < 0) { | ||
68 | PLOG(ERROR) << "Failed to open: " << loopdev; | ||
69 | return false; | ||
70 | } | ||
71 | |||
72 | int rc = ioctl(loop_fd, LOOP_CLR_FD, 0); | ||
73 | if (rc) { | ||
74 | PLOG(ERROR) << "Failed LOOP_CLR_FD for '" << loopdev << "'"; | ||
75 | return false; | ||
76 | } | ||
77 | return true; | ||
78 | } | ||
79 | |||
80 | bool LoopControl::FindFreeLoopDevice(std::string* loopdev) const { | ||
81 | int rc = ioctl(control_fd_, LOOP_CTL_GET_FREE); | ||
82 | if (rc < 0) { | ||
83 | PLOG(ERROR) << "Failed to get free loop device"; | ||
84 | return false; | ||
85 | } | ||
86 | |||
87 | // Ueventd on android creates all loop devices as /dev/block/loopX | ||
88 | // The total number of available devices is determined by 'loop.max_part' | ||
89 | // kernel command line argument. | ||
90 | *loopdev = ::android::base::StringPrintf("/dev/block/loop%d", rc); | ||
91 | return true; | ||
92 | } | ||
93 | |||
94 | LoopDevice::LoopDevice(int fd, bool auto_close) : fd_(fd), owns_fd_(auto_close) { | ||
95 | Init(); | ||
96 | } | ||
97 | |||
98 | LoopDevice::LoopDevice(const std::string& path) : fd_(-1), owns_fd_(true) { | ||
99 | fd_.reset(open(path.c_str(), O_RDWR | O_CLOEXEC)); | ||
100 | if (fd_ < -1) { | ||
101 | PLOG(ERROR) << "open failed for " << path; | ||
102 | return; | ||
103 | } | ||
104 | Init(); | ||
105 | } | ||
106 | |||
107 | LoopDevice::~LoopDevice() { | ||
108 | if (valid()) { | ||
109 | control_.Detach(device_); | ||
110 | } | ||
111 | if (!owns_fd_) { | ||
112 | (void)fd_.release(); | ||
113 | } | ||
114 | } | ||
115 | |||
116 | void LoopDevice::Init() { | ||
117 | control_.Attach(fd_, &device_); | ||
118 | } | ||
119 | |||
120 | } // namespace dm | ||
121 | } // namespace android | ||