summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'fs_mgr/libdm/loop_control.cpp')
-rw-r--r--fs_mgr/libdm/loop_control.cpp121
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
30namespace android {
31namespace dm {
32
33LoopControl::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
40bool 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
60bool 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
80bool 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
94LoopDevice::LoopDevice(int fd, bool auto_close) : fd_(fd), owns_fd_(auto_close) {
95 Init();
96}
97
98LoopDevice::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
107LoopDevice::~LoopDevice() {
108 if (valid()) {
109 control_.Detach(device_);
110 }
111 if (!owns_fd_) {
112 (void)fd_.release();
113 }
114}
115
116void LoopDevice::Init() {
117 control_.Attach(fd_, &device_);
118}
119
120} // namespace dm
121} // namespace android