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 <chrono>
21 #include <string>
22 
23 #include <android-base/unique_fd.h>
24 
25 namespace android {
26 namespace dm {
27 
28 class LoopControl final {
29   public:
30     LoopControl();
31 
32     // Attaches the file specified by 'file_fd' to the loop device specified
33     // by 'loopdev'. It is possible that in between allocating and attaching
34     // a loop device, another process attaches to the chosen loop device. If
35     // this happens, Attach() will retry for up to |timeout_ms|. The timeout
36     // should not be zero.
37     //
38     // The caller does not have to call WaitForFile(); it is implicitly called.
39     // The given |timeout_ms| covers both potential sources of timeout.
40     bool Attach(int file_fd, const std::chrono::milliseconds& timeout_ms,
41                 std::string* loopdev) const;
42 
43     // Detach the loop device given by 'loopdev' from the attached backing file.
44     bool Detach(const std::string& loopdev) const;
45 
46     // Enable Direct I/O on a loop device. This requires kernel 4.9+.
47     static bool EnableDirectIo(int fd);
48 
49     LoopControl(const LoopControl&) = delete;
50     LoopControl& operator=(const LoopControl&) = delete;
51     LoopControl& operator=(LoopControl&&) = default;
52     LoopControl(LoopControl&&) = default;
53 
54   private:
55     bool FindFreeLoopDevice(std::string* loopdev) const;
56 
57     static constexpr const char* kLoopControlDevice = "/dev/loop-control";
58 
59     android::base::unique_fd control_fd_;
60 };
61 
62 // Create a temporary loop device around a file descriptor or path.
63 class LoopDevice {
64   public:
65     // Create a loop device for the given file descriptor. It is closed when
66     // LoopDevice is destroyed only if auto_close is true.
67     LoopDevice(android::base::borrowed_fd fd, const std::chrono::milliseconds& timeout_ms,
68                bool auto_close = false);
69     // Create a loop device for the given file path. It will be opened for
70     // reading and writing and closed when the loop device is detached.
71     LoopDevice(const std::string& path, const std::chrono::milliseconds& timeout_ms);
72     ~LoopDevice();
73 
valid()74     bool valid() const { return valid_; }
device()75     const std::string& device() const { return device_; }
76 
77     LoopDevice(const LoopDevice&) = delete;
78     LoopDevice& operator=(const LoopDevice&) = delete;
79     LoopDevice& operator=(LoopDevice&&) = default;
80     LoopDevice(LoopDevice&&) = default;
81 
82   private:
83     void Init(const std::chrono::milliseconds& timeout_ms);
84 
85     android::base::borrowed_fd fd_;
86     android::base::unique_fd owned_fd_;
87     std::string device_;
88     LoopControl control_;
89     bool valid_ = false;
90 };
91 
92 }  // namespace dm
93 }  // namespace android
94 
95 #endif /* _LIBDM_LOOP_CONTROL_H_ */
96