1 /*
2 * Copyright (C) 2016 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 specic language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "libappfuse/FuseBridgeLoop.h"
18
19 #include <sys/epoll.h>
20 #include <sys/socket.h>
21
22 #include <unordered_map>
23
24 #include <android-base/logging.h>
25 #include <android-base/unique_fd.h>
26
27 #include "libappfuse/EpollController.h"
28
29 namespace android {
30 namespace fuse {
31 namespace {
32
33 enum class FuseBridgeState { kWaitToReadEither, kWaitToReadProxy, kWaitToWriteProxy, kClosing };
34
35 struct FuseBridgeEntryEvent {
36 FuseBridgeEntry* entry;
37 int events;
38 };
39
GetObservedEvents(FuseBridgeState state,int * device_events,int * proxy_events)40 void GetObservedEvents(FuseBridgeState state, int* device_events, int* proxy_events) {
41 switch (state) {
42 case FuseBridgeState::kWaitToReadEither:
43 *device_events = EPOLLIN;
44 *proxy_events = EPOLLIN;
45 return;
46 case FuseBridgeState::kWaitToReadProxy:
47 *device_events = 0;
48 *proxy_events = EPOLLIN;
49 return;
50 case FuseBridgeState::kWaitToWriteProxy:
51 *device_events = 0;
52 *proxy_events = EPOLLOUT;
53 return;
54 case FuseBridgeState::kClosing:
55 *device_events = 0;
56 *proxy_events = 0;
57 return;
58 }
59 }
60 }
61
62 class FuseBridgeEntry {
63 public:
FuseBridgeEntry(int mount_id,base::unique_fd && dev_fd,base::unique_fd && proxy_fd)64 FuseBridgeEntry(int mount_id, base::unique_fd&& dev_fd, base::unique_fd&& proxy_fd)
65 : mount_id_(mount_id),
66 device_fd_(std::move(dev_fd)),
67 proxy_fd_(std::move(proxy_fd)),
68 state_(FuseBridgeState::kWaitToReadEither),
69 last_state_(FuseBridgeState::kWaitToReadEither),
70 last_device_events_({this, 0}),
71 last_proxy_events_({this, 0}),
72 open_count_(0) {}
73
74 // Transfer bytes depends on availability of FDs and the internal |state_|.
Transfer(FuseBridgeLoopCallback * callback)75 void Transfer(FuseBridgeLoopCallback* callback) {
76 constexpr int kUnexpectedEventMask = ~(EPOLLIN | EPOLLOUT);
77 const bool unexpected_event = (last_device_events_.events & kUnexpectedEventMask) ||
78 (last_proxy_events_.events & kUnexpectedEventMask);
79 const bool device_read_ready = last_device_events_.events & EPOLLIN;
80 const bool proxy_read_ready = last_proxy_events_.events & EPOLLIN;
81 const bool proxy_write_ready = last_proxy_events_.events & EPOLLOUT;
82
83 last_device_events_.events = 0;
84 last_proxy_events_.events = 0;
85
86 LOG(VERBOSE) << "Transfer device_read_ready=" << device_read_ready
87 << " proxy_read_ready=" << proxy_read_ready
88 << " proxy_write_ready=" << proxy_write_ready;
89
90 if (unexpected_event) {
91 LOG(ERROR) << "Invalid epoll event is observed";
92 state_ = FuseBridgeState::kClosing;
93 return;
94 }
95
96 switch (state_) {
97 case FuseBridgeState::kWaitToReadEither:
98 if (proxy_read_ready) {
99 state_ = ReadFromProxy();
100 } else if (device_read_ready) {
101 state_ = ReadFromDevice(callback);
102 }
103 return;
104
105 case FuseBridgeState::kWaitToReadProxy:
106 CHECK(proxy_read_ready);
107 state_ = ReadFromProxy();
108 return;
109
110 case FuseBridgeState::kWaitToWriteProxy:
111 CHECK(proxy_write_ready);
112 state_ = WriteToProxy();
113 return;
114
115 case FuseBridgeState::kClosing:
116 return;
117 }
118 }
119
IsClosing() const120 bool IsClosing() const { return state_ == FuseBridgeState::kClosing; }
121
mount_id() const122 int mount_id() const { return mount_id_; }
123
124 private:
125 friend class BridgeEpollController;
126
ReadFromProxy()127 FuseBridgeState ReadFromProxy() {
128 switch (buffer_.response.ReadOrAgain(proxy_fd_)) {
129 case ResultOrAgain::kSuccess:
130 break;
131 case ResultOrAgain::kFailure:
132 return FuseBridgeState::kClosing;
133 case ResultOrAgain::kAgain:
134 return FuseBridgeState::kWaitToReadProxy;
135 }
136
137 if (!buffer_.response.Write(device_fd_)) {
138 return FuseBridgeState::kClosing;
139 }
140
141 auto it = opcode_map_.find(buffer_.response.header.unique);
142 if (it != opcode_map_.end()) {
143 switch (it->second) {
144 case FUSE_OPEN:
145 if (buffer_.response.header.error == fuse::kFuseSuccess) {
146 open_count_++;
147 }
148 break;
149
150 case FUSE_RELEASE:
151 if (open_count_ > 0) {
152 open_count_--;
153 } else {
154 LOG(WARNING) << "Unexpected FUSE_RELEASE before opening a file.";
155 break;
156 }
157 if (open_count_ == 0) {
158 return FuseBridgeState::kClosing;
159 }
160 break;
161 }
162 opcode_map_.erase(it);
163 }
164
165 return FuseBridgeState::kWaitToReadEither;
166 }
167
ReadFromDevice(FuseBridgeLoopCallback * callback)168 FuseBridgeState ReadFromDevice(FuseBridgeLoopCallback* callback) {
169 LOG(VERBOSE) << "ReadFromDevice";
170 if (!buffer_.request.Read(device_fd_)) {
171 return FuseBridgeState::kClosing;
172 }
173
174 const uint32_t opcode = buffer_.request.header.opcode;
175 LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
176 switch (opcode) {
177 case FUSE_FORGET:
178 // Do not reply to FUSE_FORGET.
179 return FuseBridgeState::kWaitToReadEither;
180
181 case FUSE_LOOKUP:
182 case FUSE_GETATTR:
183 case FUSE_OPEN:
184 case FUSE_READ:
185 case FUSE_WRITE:
186 case FUSE_RELEASE:
187 case FUSE_FSYNC:
188 if (opcode == FUSE_OPEN || opcode == FUSE_RELEASE) {
189 opcode_map_.emplace(buffer_.request.header.unique, opcode);
190 }
191 return WriteToProxy();
192
193 case FUSE_INIT:
194 buffer_.HandleInit();
195 break;
196
197 default:
198 buffer_.HandleNotImpl();
199 break;
200 }
201
202 if (!buffer_.response.Write(device_fd_)) {
203 return FuseBridgeState::kClosing;
204 }
205
206 if (opcode == FUSE_INIT) {
207 callback->OnMount(mount_id_);
208 }
209
210 return FuseBridgeState::kWaitToReadEither;
211 }
212
WriteToProxy()213 FuseBridgeState WriteToProxy() {
214 switch (buffer_.request.WriteOrAgain(proxy_fd_)) {
215 case ResultOrAgain::kSuccess:
216 return FuseBridgeState::kWaitToReadEither;
217 case ResultOrAgain::kFailure:
218 return FuseBridgeState::kClosing;
219 case ResultOrAgain::kAgain:
220 return FuseBridgeState::kWaitToWriteProxy;
221 }
222 }
223
224 const int mount_id_;
225 base::unique_fd device_fd_;
226 base::unique_fd proxy_fd_;
227 FuseBuffer buffer_;
228 FuseBridgeState state_;
229 FuseBridgeState last_state_;
230 FuseBridgeEntryEvent last_device_events_;
231 FuseBridgeEntryEvent last_proxy_events_;
232
233 // Remember map between unique and opcode in fuse_in_header so that we can
234 // refer the opcode later.
235 std::unordered_map<uint64_t, uint32_t> opcode_map_;
236
237 int open_count_;
238
239 DISALLOW_COPY_AND_ASSIGN(FuseBridgeEntry);
240 };
241
242 class BridgeEpollController : private EpollController {
243 public:
BridgeEpollController(base::unique_fd && poll_fd)244 BridgeEpollController(base::unique_fd&& poll_fd) : EpollController(std::move(poll_fd)) {}
245
AddBridgePoll(FuseBridgeEntry * bridge) const246 bool AddBridgePoll(FuseBridgeEntry* bridge) const {
247 return InvokeControl(EPOLL_CTL_ADD, bridge);
248 }
249
UpdateOrDeleteBridgePoll(FuseBridgeEntry * bridge) const250 bool UpdateOrDeleteBridgePoll(FuseBridgeEntry* bridge) const {
251 return InvokeControl(
252 bridge->state_ != FuseBridgeState::kClosing ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, bridge);
253 }
254
Wait(size_t bridge_count,std::unordered_set<FuseBridgeEntry * > * entries_out)255 bool Wait(size_t bridge_count, std::unordered_set<FuseBridgeEntry*>* entries_out) {
256 CHECK(entries_out);
257 const size_t event_count = std::max<size_t>(bridge_count * 2, 1);
258 if (!EpollController::Wait(event_count)) {
259 return false;
260 }
261 entries_out->clear();
262 for (const auto& event : events()) {
263 FuseBridgeEntryEvent* const entry_event =
264 reinterpret_cast<FuseBridgeEntryEvent*>(event.data.ptr);
265 entry_event->events = event.events;
266 entries_out->insert(entry_event->entry);
267 }
268 return true;
269 }
270
271 private:
InvokeControl(int op,FuseBridgeEntry * bridge) const272 bool InvokeControl(int op, FuseBridgeEntry* bridge) const {
273 LOG(VERBOSE) << "InvokeControl op=" << op << " bridge=" << bridge->mount_id_
274 << " state=" << static_cast<int>(bridge->state_)
275 << " last_state=" << static_cast<int>(bridge->last_state_);
276
277 int last_device_events;
278 int last_proxy_events;
279 int device_events;
280 int proxy_events;
281 GetObservedEvents(bridge->last_state_, &last_device_events, &last_proxy_events);
282 GetObservedEvents(bridge->state_, &device_events, &proxy_events);
283 bool result = true;
284 if (op != EPOLL_CTL_MOD || last_device_events != device_events) {
285 result &= EpollController::InvokeControl(op, bridge->device_fd_, device_events,
286 &bridge->last_device_events_);
287 }
288 if (op != EPOLL_CTL_MOD || last_proxy_events != proxy_events) {
289 result &= EpollController::InvokeControl(op, bridge->proxy_fd_, proxy_events,
290 &bridge->last_proxy_events_);
291 }
292 return result;
293 }
294 };
295
FuseBridgeLoop()296 FuseBridgeLoop::FuseBridgeLoop() : opened_(true) {
297 base::unique_fd epoll_fd(epoll_create1(/* no flag */ 0));
298 if (epoll_fd.get() == -1) {
299 PLOG(ERROR) << "Failed to open FD for epoll";
300 opened_ = false;
301 return;
302 }
303 epoll_controller_.reset(new BridgeEpollController(std::move(epoll_fd)));
304 }
305
~FuseBridgeLoop()306 FuseBridgeLoop::~FuseBridgeLoop() { CHECK(bridges_.empty()); }
307
AddBridge(int mount_id,base::unique_fd dev_fd,base::unique_fd proxy_fd)308 bool FuseBridgeLoop::AddBridge(int mount_id, base::unique_fd dev_fd, base::unique_fd proxy_fd) {
309 LOG(VERBOSE) << "Adding bridge " << mount_id;
310
311 std::unique_ptr<FuseBridgeEntry> bridge(
312 new FuseBridgeEntry(mount_id, std::move(dev_fd), std::move(proxy_fd)));
313 std::lock_guard<std::mutex> lock(mutex_);
314 if (!opened_) {
315 LOG(ERROR) << "Tried to add a mount to a closed bridge";
316 return false;
317 }
318 if (bridges_.count(mount_id)) {
319 LOG(ERROR) << "Tried to add a mount point that has already been added";
320 return false;
321 }
322 if (!epoll_controller_->AddBridgePoll(bridge.get())) {
323 return false;
324 }
325
326 bridges_.emplace(mount_id, std::move(bridge));
327 return true;
328 }
329
ProcessEventLocked(const std::unordered_set<FuseBridgeEntry * > & entries,FuseBridgeLoopCallback * callback)330 bool FuseBridgeLoop::ProcessEventLocked(const std::unordered_set<FuseBridgeEntry*>& entries,
331 FuseBridgeLoopCallback* callback) {
332 for (auto entry : entries) {
333 entry->Transfer(callback);
334 if (!epoll_controller_->UpdateOrDeleteBridgePoll(entry)) {
335 return false;
336 }
337 if (entry->IsClosing()) {
338 const int mount_id = entry->mount_id();
339 callback->OnClosed(mount_id);
340 bridges_.erase(mount_id);
341 if (bridges_.size() == 0) {
342 // All bridges are now closed.
343 return false;
344 }
345 }
346 }
347 return true;
348 }
349
Start(FuseBridgeLoopCallback * callback)350 void FuseBridgeLoop::Start(FuseBridgeLoopCallback* callback) {
351 LOG(DEBUG) << "Start fuse bridge loop";
352 std::unordered_set<FuseBridgeEntry*> entries;
353 while (true) {
354 const bool wait_result = epoll_controller_->Wait(bridges_.size(), &entries);
355 LOG(VERBOSE) << "Receive epoll events";
356 {
357 std::lock_guard<std::mutex> lock(mutex_);
358 if (!(wait_result && ProcessEventLocked(entries, callback))) {
359 for (auto it = bridges_.begin(); it != bridges_.end();) {
360 callback->OnClosed(it->second->mount_id());
361 it = bridges_.erase(it);
362 }
363 opened_ = false;
364 return;
365 }
366 }
367 }
368 }
369
370 } // namespace fuse
371 } // namespace android
372