summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTreehugger Robot2018-06-25 16:24:07 -0500
committerGerrit Code Review2018-06-25 16:24:07 -0500
commit516ec4c2570411039975e0fcdba9b5f8d9b31b3b (patch)
tree025e31900ceed198c12d461bbc197271fa2620b2
parentfc1cf90741e59d5615a7dcea1813f38bfa3a2eec (diff)
parent1f428ea0547203924926d685495859e879ac63ce (diff)
downloadplatform-system-core-516ec4c2570411039975e0fcdba9b5f8d9b31b3b.tar.gz
platform-system-core-516ec4c2570411039975e0fcdba9b5f8d9b31b3b.tar.xz
platform-system-core-516ec4c2570411039975e0fcdba9b5f8d9b31b3b.zip
Merge "libdm: Add helper classes for loop control."
-rw-r--r--fs_mgr/libdm/Android.bp4
-rw-r--r--fs_mgr/libdm/include/libdm/loop_control.h82
-rw-r--r--fs_mgr/libdm/loop_control.cpp121
-rw-r--r--fs_mgr/libdm/loop_control_test.cpp65
4 files changed, 271 insertions, 1 deletions
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index f1b18ddaf..21a4cb5bd 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -28,7 +28,8 @@ cc_library_static {
28 srcs: [ 28 srcs: [
29 "dm_table.cpp", 29 "dm_table.cpp",
30 "dm_target.cpp", 30 "dm_target.cpp",
31 "dm.cpp" 31 "dm.cpp",
32 "loop_control.cpp",
32 ], 33 ],
33 34
34 header_libs: [ 35 header_libs: [
@@ -47,5 +48,6 @@ cc_test {
47 ], 48 ],
48 srcs: [ 49 srcs: [
49 "dm_test.cpp", 50 "dm_test.cpp",
51 "loop_control_test.cpp",
50 ] 52 ]
51} 53}
diff --git a/fs_mgr/libdm/include/libdm/loop_control.h b/fs_mgr/libdm/include/libdm/loop_control.h
new file mode 100644
index 000000000..e6e83f40e
--- /dev/null
+++ b/fs_mgr/libdm/include/libdm/loop_control.h
@@ -0,0 +1,82 @@
1/*
2 * Copyright 2018 Google, Inc
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#ifndef _LIBDM_LOOP_CONTROL_H_
18#define _LIBDM_LOOP_CONTROL_H_
19
20#include <string>
21
22#include <android-base/unique_fd.h>
23
24namespace android {
25namespace dm {
26
27class LoopControl final {
28 public:
29 LoopControl();
30
31 // Attaches the file specified by 'file_fd' to the loop device specified
32 // by 'loopdev'
33 bool Attach(int file_fd, std::string* loopdev) const;
34
35 // Detach the loop device given by 'loopdev' from the attached backing file.
36 bool Detach(const std::string& loopdev) const;
37
38 LoopControl(const LoopControl&) = delete;
39 LoopControl& operator=(const LoopControl&) = delete;
40 LoopControl& operator=(LoopControl&&) = default;
41 LoopControl(LoopControl&&) = default;
42
43 private:
44 bool FindFreeLoopDevice(std::string* loopdev) const;
45
46 static constexpr const char* kLoopControlDevice = "/dev/loop-control";
47
48 android::base::unique_fd control_fd_;
49};
50
51// Create a temporary loop device around a file descriptor or path.
52class LoopDevice {
53 public:
54 // Create a loop device for the given file descriptor. It is closed when
55 // LoopDevice is destroyed only if auto_close is true.
56 LoopDevice(int fd, bool auto_close = false);
57 // Create a loop device for the given file path. It will be opened for
58 // reading and writing and closed when the loop device is detached.
59 explicit LoopDevice(const std::string& path);
60 ~LoopDevice();
61
62 bool valid() const { return fd_ != -1 && !device_.empty(); }
63 const std::string& device() const { return device_; }
64
65 LoopDevice(const LoopDevice&) = delete;
66 LoopDevice& operator=(const LoopDevice&) = delete;
67 LoopDevice& operator=(LoopDevice&&) = default;
68 LoopDevice(LoopDevice&&) = default;
69
70 private:
71 void Init();
72
73 android::base::unique_fd fd_;
74 bool owns_fd_;
75 std::string device_;
76 LoopControl control_;
77};
78
79} // namespace dm
80} // namespace android
81
82#endif /* _LIBDM_LOOP_CONTROL_H_ */
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
diff --git a/fs_mgr/libdm/loop_control_test.cpp b/fs_mgr/libdm/loop_control_test.cpp
new file mode 100644
index 000000000..cd1d015ff
--- /dev/null
+++ b/fs_mgr/libdm/loop_control_test.cpp
@@ -0,0 +1,65 @@
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/memfd.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <sys/stat.h>
24#include <sys/syscall.h>
25#include <sys/types.h>
26#include <unistd.h>
27
28#include <android-base/file.h>
29#include <android-base/unique_fd.h>
30#include <gtest/gtest.h>
31
32using namespace std;
33using namespace android::dm;
34using unique_fd = android::base::unique_fd;
35
36static unique_fd TempFile() {
37 // A loop device needs to be at least one sector to actually work, so fill
38 // up the file with a message.
39 unique_fd fd(syscall(__NR_memfd_create, "fake_disk", 0));
40 if (fd < 0) {
41 return {};
42 }
43 char buffer[] = "Hello";
44 for (size_t i = 0; i < 1000; i++) {
45 if (!android::base::WriteFully(fd, buffer, sizeof(buffer))) {
46 perror("write");
47 return {};
48 }
49 }
50 return fd;
51}
52
53TEST(libdm, LoopControl) {
54 unique_fd fd = TempFile();
55 ASSERT_GE(fd, 0);
56
57 LoopDevice loop(fd);
58 ASSERT_TRUE(loop.valid());
59
60 char buffer[6];
61 unique_fd loop_fd(open(loop.device().c_str(), O_RDWR));
62 ASSERT_GE(loop_fd, 0);
63 ASSERT_TRUE(android::base::ReadFully(loop_fd, buffer, sizeof(buffer)));
64 ASSERT_EQ(memcmp(buffer, "Hello", 6), 0);
65}