summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaichi Hirono2017-03-06 00:23:16 -0600
committerDaichi Hirono2017-03-28 19:13:58 -0500
commit8e16ceecb770df194ed7fb6ba70c01505a52a609 (patch)
tree32fac895d893e97e279fbf6998604904fd31df31 /libappfuse/FuseAppLoop.cc
parentdf937b8255d86d97c97fd8d9ca7ea5352e2d8975 (diff)
downloadplatform-system-core-8e16ceecb770df194ed7fb6ba70c01505a52a609.tar.gz
platform-system-core-8e16ceecb770df194ed7fb6ba70c01505a52a609.tar.xz
platform-system-core-8e16ceecb770df194ed7fb6ba70c01505a52a609.zip
Change FuseAppLoop so that it can process messages asynchronously.
Previously FuseAppLoopCallback needs to return values in a synchrnous manner. The CL changes it to asynchronous mannger so that apps can process FUSE message asynchrnously. Bug: 35229514 Test: FuseAppLoopTest Change-Id: I8edcfdb003a25cfd5e9c490ec871140220b21e35 (cherry picked from commit f5d15f9fc4b8bd7a866660fe208bf857dea839ba)
Diffstat (limited to 'libappfuse/FuseAppLoop.cc')
-rw-r--r--libappfuse/FuseAppLoop.cc345
1 files changed, 186 insertions, 159 deletions
diff --git a/libappfuse/FuseAppLoop.cc b/libappfuse/FuseAppLoop.cc
index a31880e41..b6bc191b7 100644
--- a/libappfuse/FuseAppLoop.cc
+++ b/libappfuse/FuseAppLoop.cc
@@ -16,205 +16,232 @@
16 16
17#include "libappfuse/FuseAppLoop.h" 17#include "libappfuse/FuseAppLoop.h"
18 18
19#include <sys/eventfd.h>
19#include <sys/stat.h> 20#include <sys/stat.h>
20 21
21#include <android-base/logging.h> 22#include <android-base/logging.h>
22#include <android-base/unique_fd.h> 23#include <android-base/unique_fd.h>
23 24
25#include "libappfuse/EpollController.h"
26
24namespace android { 27namespace android {
25namespace fuse { 28namespace fuse {
26 29
27namespace { 30namespace {
28 31
29void HandleLookUp(FuseBuffer* buffer, FuseAppLoopCallback* callback) { 32bool HandleLookUp(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) {
30 // AppFuse does not support directory structure now. 33 // AppFuse does not support directory structure now.
31 // It can lookup only files under the mount point. 34 // It can lookup only files under the mount point.
32 if (buffer->request.header.nodeid != FUSE_ROOT_ID) { 35 if (buffer->request.header.nodeid != FUSE_ROOT_ID) {
33 LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID."; 36 LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID.";
34 buffer->response.Reset(0, -ENOENT, buffer->request.header.unique); 37 return loop->ReplySimple(buffer->request.header.unique, -ENOENT);
35 return; 38 }
36 }
37
38 // Ensure that the filename ends with 0.
39 const size_t filename_length =
40 buffer->request.header.len - sizeof(fuse_in_header);
41 if (buffer->request.lookup_name[filename_length - 1] != 0) {
42 LOG(ERROR) << "File name does not end with 0.";
43 buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
44 return;
45 }
46
47 const uint64_t inode =
48 static_cast<uint64_t>(atol(buffer->request.lookup_name));
49 if (inode == 0 || inode == LONG_MAX) {
50 LOG(ERROR) << "Invalid filename";
51 buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
52 return;
53 }
54
55 const int64_t size = callback->OnGetSize(inode);
56 if (size < 0) {
57 buffer->response.Reset(0, size, buffer->request.header.unique);
58 return;
59 }
60
61 buffer->response.Reset(sizeof(fuse_entry_out), 0,
62 buffer->request.header.unique);
63 buffer->response.entry_out.nodeid = inode;
64 buffer->response.entry_out.attr_valid = 10;
65 buffer->response.entry_out.entry_valid = 10;
66 buffer->response.entry_out.attr.ino = inode;
67 buffer->response.entry_out.attr.mode = S_IFREG | 0777;
68 buffer->response.entry_out.attr.size = size;
69}
70 39
71void HandleGetAttr(FuseBuffer* buffer, FuseAppLoopCallback* callback) { 40 // Ensure that the filename ends with 0.
72 const uint64_t nodeid = buffer->request.header.nodeid; 41 const size_t filename_length = buffer->request.header.len - sizeof(fuse_in_header);
73 int64_t size; 42 if (buffer->request.lookup_name[filename_length - 1] != 0) {
74 uint32_t mode; 43 LOG(ERROR) << "File name does not end with 0.";
75 if (nodeid == FUSE_ROOT_ID) { 44 return loop->ReplySimple(buffer->request.header.unique, -ENOENT);
76 size = 0; 45 }
77 mode = S_IFDIR | 0777; 46
78 } else { 47 const uint64_t inode = static_cast<uint64_t>(atol(buffer->request.lookup_name));
79 size = callback->OnGetSize(buffer->request.header.nodeid); 48 if (inode == 0 || inode == LONG_MAX) {
80 if (size < 0) { 49 LOG(ERROR) << "Invalid filename";
81 buffer->response.Reset(0, size, buffer->request.header.unique); 50 return loop->ReplySimple(buffer->request.header.unique, -ENOENT);
82 return;
83 } 51 }
84 mode = S_IFREG | 0777;
85 }
86
87 buffer->response.Reset(sizeof(fuse_attr_out), 0,
88 buffer->request.header.unique);
89 buffer->response.attr_out.attr_valid = 10;
90 buffer->response.attr_out.attr.ino = nodeid;
91 buffer->response.attr_out.attr.mode = mode;
92 buffer->response.attr_out.attr.size = size;
93}
94 52
95void HandleOpen(FuseBuffer* buffer, FuseAppLoopCallback* callback) { 53 callback->OnLookup(buffer->request.header.unique, inode);
96 const int32_t file_handle = callback->OnOpen(buffer->request.header.nodeid); 54 return true;
97 if (file_handle < 0) {
98 buffer->response.Reset(0, file_handle, buffer->request.header.unique);
99 return;
100 }
101 buffer->response.Reset(sizeof(fuse_open_out), kFuseSuccess,
102 buffer->request.header.unique);
103 buffer->response.open_out.fh = file_handle;
104} 55}
105 56
106void HandleFsync(FuseBuffer* buffer, FuseAppLoopCallback* callback) { 57bool HandleGetAttr(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) {
107 buffer->response.Reset(0, callback->OnFsync(buffer->request.header.nodeid), 58 if (buffer->request.header.nodeid == FUSE_ROOT_ID) {
108 buffer->request.header.unique); 59 return loop->ReplyGetAttr(buffer->request.header.unique, buffer->request.header.nodeid, 0,
60 S_IFDIR | 0777);
61 } else {
62 callback->OnGetAttr(buffer->request.header.unique, buffer->request.header.nodeid);
63 return true;
64 }
109} 65}
110 66
111void HandleRelease(FuseBuffer* buffer, FuseAppLoopCallback* callback) { 67bool HandleRead(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) {
112 buffer->response.Reset(0, callback->OnRelease(buffer->request.header.nodeid), 68 if (buffer->request.read_in.size > kFuseMaxRead) {
113 buffer->request.header.unique); 69 return loop->ReplySimple(buffer->request.header.unique, -EINVAL);
70 }
71
72 callback->OnRead(buffer->request.header.unique, buffer->request.header.nodeid,
73 buffer->request.read_in.offset, buffer->request.read_in.size);
74 return true;
114} 75}
115 76
116void HandleRead(FuseBuffer* buffer, FuseAppLoopCallback* callback) { 77bool HandleWrite(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) {
117 const uint64_t unique = buffer->request.header.unique; 78 if (buffer->request.write_in.size > kFuseMaxWrite) {
118 const uint64_t nodeid = buffer->request.header.nodeid; 79 return loop->ReplySimple(buffer->request.header.unique, -EINVAL);
119 const uint64_t offset = buffer->request.read_in.offset; 80 }
120 const uint32_t size = buffer->request.read_in.size; 81
121 82 callback->OnWrite(buffer->request.header.unique, buffer->request.header.nodeid,
122 if (size > kFuseMaxRead) { 83 buffer->request.write_in.offset, buffer->request.write_in.size,
123 buffer->response.Reset(0, -EINVAL, buffer->request.header.unique); 84 buffer->request.write_data);
124 return; 85 return true;
125 }
126
127 const int32_t read_size = callback->OnRead(nodeid, offset, size,
128 buffer->response.read_data);
129 if (read_size < 0) {
130 buffer->response.Reset(0, read_size, buffer->request.header.unique);
131 return;
132 }
133
134 buffer->response.ResetHeader(read_size, kFuseSuccess, unique);
135} 86}
136 87
137void HandleWrite(FuseBuffer* buffer, FuseAppLoopCallback* callback) { 88bool HandleMessage(FuseAppLoop* loop, FuseBuffer* buffer, int fd, FuseAppLoopCallback* callback) {
138 const uint64_t unique = buffer->request.header.unique; 89 if (!buffer->request.Read(fd)) {
139 const uint64_t nodeid = buffer->request.header.nodeid; 90 return false;
140 const uint64_t offset = buffer->request.write_in.offset; 91 }
141 const uint32_t size = buffer->request.write_in.size; 92
142 93 const uint32_t opcode = buffer->request.header.opcode;
143 if (size > kFuseMaxWrite) { 94 LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
144 buffer->response.Reset(0, -EINVAL, buffer->request.header.unique); 95 switch (opcode) {
145 return; 96 case FUSE_FORGET:
146 } 97 // Do not reply to FUSE_FORGET.
147 98 return true;
148 const int32_t write_size = callback->OnWrite(nodeid, offset, size, 99
149 buffer->request.write_data); 100 case FUSE_LOOKUP:
150 if (write_size < 0) { 101 return HandleLookUp(loop, buffer, callback);
151 buffer->response.Reset(0, write_size, buffer->request.header.unique); 102
152 return; 103 case FUSE_GETATTR:
153 } 104 return HandleGetAttr(loop, buffer, callback);
154 105
155 buffer->response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique); 106 case FUSE_OPEN:
156 buffer->response.write_out.size = write_size; 107 callback->OnOpen(buffer->request.header.unique, buffer->request.header.nodeid);
108 return true;
109
110 case FUSE_READ:
111 return HandleRead(loop, buffer, callback);
112
113 case FUSE_WRITE:
114 return HandleWrite(loop, buffer, callback);
115
116 case FUSE_RELEASE:
117 callback->OnRelease(buffer->request.header.unique, buffer->request.header.nodeid);
118 return true;
119
120 case FUSE_FSYNC:
121 callback->OnFsync(buffer->request.header.unique, buffer->request.header.nodeid);
122 return true;
123
124 default:
125 buffer->HandleNotImpl();
126 return buffer->response.Write(fd);
127 }
157} 128}
158 129
159} // namespace 130} // namespace
160 131
161bool StartFuseAppLoop(int raw_fd, FuseAppLoopCallback* callback) { 132FuseAppLoopCallback::~FuseAppLoopCallback() = default;
162 base::unique_fd fd(raw_fd); 133
163 FuseBuffer buffer; 134FuseAppLoop::FuseAppLoop(base::unique_fd&& fd) : fd_(std::move(fd)) {}
164 135
165 LOG(DEBUG) << "Start fuse loop."; 136void FuseAppLoop::Break() {
166 while (callback->IsActive()) { 137 const int64_t value = 1;
167 if (!buffer.request.Read(fd)) { 138 if (write(break_fd_, &value, sizeof(value)) == -1) {
168 return false; 139 PLOG(ERROR) << "Failed to send a break event";
169 } 140 }
141}
170 142
171 const uint32_t opcode = buffer.request.header.opcode; 143bool FuseAppLoop::ReplySimple(uint64_t unique, int32_t result) {
172 LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode; 144 if (result == -ENOSYS) {
173 switch (opcode) { 145 // We should not return -ENOSYS because the kernel stops delivering FUSE
174 case FUSE_FORGET: 146 // command after receiving -ENOSYS as a result for the command.
175 // Do not reply to FUSE_FORGET. 147 result = -EBADF;
176 continue; 148 }
149 FuseSimpleResponse response;
150 response.Reset(0, result, unique);
151 return response.Write(fd_);
152}
177 153
178 case FUSE_LOOKUP: 154bool FuseAppLoop::ReplyLookup(uint64_t unique, uint64_t inode, int64_t size) {
179 HandleLookUp(&buffer, callback); 155 FuseSimpleResponse response;
180 break; 156 response.Reset(sizeof(fuse_entry_out), 0, unique);
157 response.entry_out.nodeid = inode;
158 response.entry_out.attr_valid = 10;
159 response.entry_out.entry_valid = 10;
160 response.entry_out.attr.ino = inode;
161 response.entry_out.attr.mode = S_IFREG | 0777;
162 response.entry_out.attr.size = size;
163 return response.Write(fd_);
164}
181 165
182 case FUSE_GETATTR: 166bool FuseAppLoop::ReplyGetAttr(uint64_t unique, uint64_t inode, int64_t size, int mode) {
183 HandleGetAttr(&buffer, callback); 167 CHECK(mode == (S_IFREG | 0777) || mode == (S_IFDIR | 0777));
184 break; 168 FuseSimpleResponse response;
169 response.Reset(sizeof(fuse_attr_out), 0, unique);
170 response.attr_out.attr_valid = 10;
171 response.attr_out.attr.ino = inode;
172 response.attr_out.attr.mode = mode;
173 response.attr_out.attr.size = size;
174 return response.Write(fd_);
175}
185 176
186 case FUSE_OPEN: 177bool FuseAppLoop::ReplyOpen(uint64_t unique, uint64_t fh) {
187 HandleOpen(&buffer, callback); 178 FuseSimpleResponse response;
188 break; 179 response.Reset(sizeof(fuse_open_out), kFuseSuccess, unique);
180 response.open_out.fh = fh;
181 return response.Write(fd_);
182}
189 183
190 case FUSE_READ: 184bool FuseAppLoop::ReplyWrite(uint64_t unique, uint32_t size) {
191 HandleRead(&buffer, callback); 185 CHECK(size <= kFuseMaxWrite);
192 break; 186 FuseSimpleResponse response;
187 response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique);
188 response.write_out.size = size;
189 return response.Write(fd_);
190}
193 191
194 case FUSE_WRITE: 192bool FuseAppLoop::ReplyRead(uint64_t unique, uint32_t size, const void* data) {
195 HandleWrite(&buffer, callback); 193 CHECK(size <= kFuseMaxRead);
196 break; 194 FuseSimpleResponse response;
195 response.ResetHeader(size, kFuseSuccess, unique);
196 return response.WriteWithBody(fd_, sizeof(FuseResponse), data);
197}
197 198
198 case FUSE_RELEASE: 199void FuseAppLoop::Start(FuseAppLoopCallback* callback) {
199 HandleRelease(&buffer, callback); 200 break_fd_.reset(eventfd(/* initval */ 0, EFD_CLOEXEC));
200 break; 201 if (break_fd_.get() == -1) {
202 PLOG(ERROR) << "Failed to open FD for break event";
203 return;
204 }
205
206 base::unique_fd epoll_fd(epoll_create1(EPOLL_CLOEXEC));
207 if (epoll_fd.get() == -1) {
208 PLOG(ERROR) << "Failed to open FD for epoll";
209 return;
210 }
201 211
202 case FUSE_FSYNC: 212 int last_event;
203 HandleFsync(&buffer, callback); 213 int break_event;
204 break;
205 214
206 default: 215 std::unique_ptr<EpollController> epoll_controller(new EpollController(std::move(epoll_fd)));
207 buffer.HandleNotImpl(); 216 if (!epoll_controller->AddFd(fd_, EPOLLIN, &last_event)) {
208 break; 217 return;
218 }
219 if (!epoll_controller->AddFd(break_fd_, EPOLLIN, &break_event)) {
220 return;
209 } 221 }
210 222
211 if (!buffer.response.Write(fd)) { 223 last_event = 0;
212 LOG(ERROR) << "Failed to write a response to the device."; 224 break_event = 0;
213 return false; 225
226 FuseBuffer buffer;
227 while (true) {
228 if (!epoll_controller->Wait(1)) {
229 break;
230 }
231 last_event = 0;
232 *reinterpret_cast<int*>(epoll_controller->events()[0].data.ptr) =
233 epoll_controller->events()[0].events;
234
235 if (break_event != 0 || (last_event & ~EPOLLIN) != 0) {
236 break;
237 }
238
239 if (!HandleMessage(this, &buffer, fd_, callback)) {
240 break;
241 }
214 } 242 }
215 }
216 243
217 return true; 244 LOG(VERBOSE) << "FuseAppLoop exit";
218} 245}
219 246
220} // namespace fuse 247} // namespace fuse