1 /*
2 Copyright 2005-2010 Jakub Kruszona-Zawadzki, Gemius SA, 2013-2014 EditShare, 2013-2015 Skytechnology sp. z o.o..
3
4 This file was part of MooseFS and is part of LizardFS
5
6 LizardFS is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, version 3.
9
10 LizardFS is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with LizardFS If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "common/platform.h"
20 #include "mount/fuse/mfs_fuse.h"
21
22 #include <memory>
23 #include <string>
24 #include <type_traits>
25 #include <vector>
26
27 #include "common/massert.h"
28 #include "common/small_vector.h"
29 #include "common/special_inode_defs.h"
30 #include "mount/fuse/lock_conversion.h"
31 #include "mount/lizard_client.h"
32 #include "mount/lizard_client_context.h"
33 #include "mount/thread_safe_map.h"
34 #include "protocol/MFSCommunication.h"
35
36 #if SPECIAL_INODE_ROOT != FUSE_ROOT_ID
37 #error FUSE_ROOT_ID is not equal to SPECIAL_INODE_ROOT
38 #endif
39
40 #define READDIR_BUFFSIZE 50000
41
42 /**
43 * Function checking if types are equal, ignoring constness
44 */
45 template <class A, class B>
checkTypesEqual(const A & a,const B & b)46 void checkTypesEqual(const A& a, const B& b) {
47 static_assert(std::is_same<decltype(a), decltype(b)>::value,
48 "Types don't match");
49 }
50
51 #if defined(__FreeBSD__) || defined(__DragonFly__)
52 #include <sys/user.h>
53 #endif
54
55 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
56 #include <sys/sysctl.h>
57
getBsdGroups(LizardClient::Context & ctx)58 void getBsdGroups(LizardClient::Context &ctx) {
59 int mib_path[4];
60 struct kinfo_proc kinfo;
61 size_t len;
62
63 len = 4;
64 sysctlnametomib("kern.proc.pid", mib_path, &len);
65 mib_path[3] = ctx.pid;
66
67 len = sizeof(kinfo);
68 memset(&kinfo, 0, sizeof(kinfo));
69 if (sysctl(mib_path, 4, &kinfo, &len, nullptr, 0) == 0) {
70 #if defined(__APPLE__)
71 ctx.gids.resize(kinfo.kp_eproc.e_ucred.cr_ngroups + 1);
72 ctx.gids[0] = ctx.gid;
73 for (int i = 0; i < kinfo.kp_eproc.e_ucred.cr_ngroups; ++i) {
74 ctx.gids[i + 1] = kinfo.kp_eproc.e_ucred.cr_groups[i];
75 }
76 #elif defined(__DragonFly__)
77 ctx.gids.resize(kinfo.kp_ngroups + 1);
78 ctx.gids[0] = ctx.gid;
79 for (int i = 0; i < kinfo.kp_ngroups; ++i) {
80 ctx.gids[i + 1] = kinfo.kp_groups[i];
81 }
82 #else
83 ctx.gids.resize(kinfo.ki_ngroups + 1);
84 ctx.gids[0] = ctx.gid;
85 for (int i = 0; i < kinfo.ki_ngroups; ++i) {
86 ctx.gids[i + 1] = kinfo.ki_groups[i];
87 }
88 #endif
89 }
90 }
91 #endif
92
updateGroupsForContext(fuse_req_t & req,LizardClient::Context & ctx)93 static void updateGroupsForContext(fuse_req_t &req, LizardClient::Context &ctx) {
94 static_assert(sizeof(gid_t) == sizeof(LizardClient::Context::IdType),
95 "Invalid IdType to call fuse_req_getgroups");
96
97 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
98 (void)req;
99 getBsdGroups(ctx);
100 LizardClient::updateGroups(ctx);
101 #elif (FUSE_VERSION < 28)
102 (void)req, (void)ctx;
103 #else
104 static const int kMaxGroups = GroupCache::kDefaultGroupsSize - 1;
105
106 assert(ctx.gids.size() == 1);
107 ctx.gids.resize(kMaxGroups + 1);
108
109 int getgroups_ret = fuse_req_getgroups(req, kMaxGroups, ctx.gids.data() + 1);
110 ctx.gids.resize(std::max(1, getgroups_ret + 1));
111 if (getgroups_ret > kMaxGroups) {
112 getgroups_ret = fuse_req_getgroups(req, ctx.gids.size() - 1, ctx.gids.data() + 1);
113
114 // we include check for case when number of groups has been changed between
115 // calls to fuse_req_getgroups
116 ctx.gids.resize(std::max(1, std::min<int>(getgroups_ret + 1, ctx.gids.size())));
117 }
118 LizardClient::updateGroups(ctx);
119 #endif
120 }
121
122 /**
123 * A function converting fuse_ctx to LizardClient::Context
124 */
get_context(fuse_req_t & req)125 LizardClient::Context get_context(fuse_req_t& req) {
126 auto fuse_ctx = fuse_req_ctx(req);
127 #if (FUSE_VERSION >= 28)
128 mode_t umask = fuse_ctx->umask;
129 #else
130 mode_t umask = 0000;
131 #endif
132 auto ret = LizardClient::Context(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid, umask);
133 if (fuse_ctx->pid > 0) {
134 updateGroupsForContext(req, ret);
135 }
136 return ret;
137 }
138
139 /**
140 * A wrapper that allows one to use fuse_file_info as if it was LizardClient::FileInfo object.
141 * During construction, LizardClient::FileInfo object is initialized with information from the
142 * provided fuse_file_info.
143 * During destruction, the fuse_file_info is updated to reflect any changes made to the
144 * LizardClient::FileInfo object.
145 */
146 class fuse_file_info_wrapper {
147 public:
fuse_file_info_wrapper(fuse_file_info * fi)148 fuse_file_info_wrapper(fuse_file_info* fi)
149 : fuse_fi_(fi), fs_fi_(fuse_fi_
150 ? new LizardClient::FileInfo(fi->flags, fi->direct_io, fi->keep_cache, fi->fh,
151 fi->lock_owner)
152 : nullptr) {
153 if (fs_fi_) {
154 assert(fuse_fi_);
155 } else {
156 assert(!fuse_fi_);
157 }
158 }
operator LizardClient::FileInfo*()159 operator LizardClient::FileInfo*() {
160 return fs_fi_.get();
161 }
~fuse_file_info_wrapper()162 ~fuse_file_info_wrapper() {
163 if (fs_fi_) {
164 fuse_fi_->direct_io = fs_fi_->direct_io;
165 fuse_fi_->fh = fs_fi_->fh;
166 fuse_fi_->flags = fs_fi_->flags;
167 fuse_fi_->keep_cache = fs_fi_->keep_cache;
168 checkTypesEqual(fuse_fi_->direct_io , fs_fi_->direct_io);
169 checkTypesEqual(fuse_fi_->fh , fs_fi_->fh);
170 checkTypesEqual(fuse_fi_->flags , fs_fi_->flags);
171 checkTypesEqual(fuse_fi_->keep_cache, fs_fi_->keep_cache);
172 }
173 }
174
175 private:
176 fuse_file_info* fuse_fi_;
177 std::unique_ptr<LizardClient::FileInfo> fs_fi_;
178 };
179
180 /**
181 * A function converting LizardFS::EntryParam to fuse_entry_param
182 */
make_fuse_entry_param(const LizardClient::EntryParam & e)183 fuse_entry_param make_fuse_entry_param(const LizardClient::EntryParam& e) {
184 fuse_entry_param ret;
185 memset(&ret, 0, sizeof(ret));
186 checkTypesEqual(ret.generation, e.generation);
187 checkTypesEqual(ret.attr, e.attr);
188 checkTypesEqual(ret.attr_timeout, e.attr_timeout);
189 checkTypesEqual(ret.entry_timeout, e.entry_timeout);
190 ret.ino = e.ino;
191 ret.generation = e.generation;
192 ret.attr = e.attr;
193 ret.attr_timeout = e.attr_timeout;
194 ret.entry_timeout = e.entry_timeout;
195 return ret;
196 }
197
198 #ifndef EDQUOT
199 # define EDQUOT ENOSPC
200 #endif
201 #ifndef ENOATTR
202 # ifdef ENODATA
203 # define ENOATTR ENODATA
204 # else
205 # define ENOATTR ENOENT
206 # endif
207 #endif
208
209 ThreadSafeMap<std::uintptr_t, lzfs_locks::InterruptData> gLockInterruptData;
210
211 #if FUSE_USE_VERSION >= 26
mfs_statfs(fuse_req_t req,fuse_ino_t ino)212 void mfs_statfs(fuse_req_t req,fuse_ino_t ino) {
213 #else
214 void mfs_statfs(fuse_req_t req) {
215 fuse_ino_t ino = 0;
216 #endif
217 try {
218 auto a = LizardClient::statfs(get_context(req), ino);
219 fuse_reply_statfs(req, &a);
220 } catch (LizardClient::RequestException& e) {
221 fuse_reply_err(req, e.system_error_code);
222 }
223 }
224
225 void mfs_access(fuse_req_t req, fuse_ino_t ino, int mask) {
226 try {
227 LizardClient::access(get_context(req), ino, mask);
228 fuse_reply_err(req, 0);
229 } catch (LizardClient::RequestException& e) {
230 fuse_reply_err(req, e.system_error_code);
231 }
232 }
233
234 void mfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) {
235 try {
236 auto fuseEntryParam = make_fuse_entry_param(
237 LizardClient::lookup(get_context(req), parent, name));
238 fuse_reply_entry(req, &fuseEntryParam);
239 } catch (LizardClient::RequestException& e) {
240 fuse_reply_err(req, e.system_error_code);
241 }
242 }
243
244 void mfs_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *) {
245 try {
246 // FileInfo not needed, not conducive to optimization
247 auto a = LizardClient::getattr(get_context(req), ino);
248 fuse_reply_attr(req, &a.attr, a.attrTimeout);
249 } catch (LizardClient::RequestException& e) {
250 fuse_reply_err(req, e.system_error_code);
251 }
252 }
253
254 void mfs_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *stbuf, int to_set,
255 struct fuse_file_info *) {
256 try {
257 static_assert(LIZARDFS_SET_ATTR_MODE == FUSE_SET_ATTR_MODE, "incompatible");
258 static_assert(LIZARDFS_SET_ATTR_UID == FUSE_SET_ATTR_UID, "incompatible");
259 static_assert(LIZARDFS_SET_ATTR_GID == FUSE_SET_ATTR_GID, "incompatible");
260 static_assert(LIZARDFS_SET_ATTR_SIZE == FUSE_SET_ATTR_SIZE, "incompatible");
261 static_assert(LIZARDFS_SET_ATTR_ATIME == FUSE_SET_ATTR_ATIME, "incompatible");
262 static_assert(LIZARDFS_SET_ATTR_MTIME == FUSE_SET_ATTR_MTIME, "incompatible");
263 #if (FUSE_VERSION >= 28)
264 static_assert(LIZARDFS_SET_ATTR_ATIME_NOW == FUSE_SET_ATTR_ATIME_NOW, "incompatible");
265 static_assert(LIZARDFS_SET_ATTR_MTIME_NOW == FUSE_SET_ATTR_MTIME_NOW, "incompatible");
266 #endif
267
268 auto a = LizardClient::setattr(get_context(req), ino, stbuf, to_set);
269 fuse_reply_attr(req, &a.attr, a.attrTimeout);
270 } catch (LizardClient::RequestException& e) {
271 fuse_reply_err(req, e.system_error_code);
272 }
273 }
274
275 void mfs_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev) {
276 try {
277 auto fuseEntryParam = make_fuse_entry_param(
278 LizardClient::mknod(get_context(req), parent, name, mode, rdev));
279 fuse_reply_entry(req, &fuseEntryParam);
280 } catch (LizardClient::RequestException& e) {
281 fuse_reply_err(req, e.system_error_code);
282 }
283 }
284
285 void mfs_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) {
286 try {
287 LizardClient::unlink(get_context(req), parent, name);
288 fuse_reply_err(req, 0);
289 } catch (LizardClient::RequestException& e) {
290 fuse_reply_err(req, e.system_error_code);
291 }
292 }
293
294 void mfs_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) {
295 try {
296 auto fuseEntryParam = make_fuse_entry_param(
297 LizardClient::mkdir(get_context(req), parent, name, mode));
298 fuse_reply_entry(req, &fuseEntryParam);
299 } catch (LizardClient::RequestException& e) {
300 fuse_reply_err(req, e.system_error_code);
301 }
302 }
303
304 void mfs_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) {
305 try {
306 LizardClient::rmdir(get_context(req), parent, name);
307 fuse_reply_err(req, 0);
308 } catch (LizardClient::RequestException& e) {
309 fuse_reply_err(req, e.system_error_code);
310 }
311 }
312
313 void mfs_symlink(fuse_req_t req, const char *path, fuse_ino_t parent, const char *name) {
314 try {
315 auto fuseEntryParam = make_fuse_entry_param(
316 LizardClient::symlink(get_context(req), path, parent, name));
317 fuse_reply_entry(req, &fuseEntryParam);
318 } catch (LizardClient::RequestException& e) {
319 fuse_reply_err(req, e.system_error_code);
320 }
321 }
322
323 void mfs_readlink(fuse_req_t req, fuse_ino_t ino) {
324 try {
325 fuse_reply_readlink(req,
326 LizardClient::readlink(get_context(req), ino).c_str());
327 } catch (LizardClient::RequestException& e) {
328 fuse_reply_err(req, e.system_error_code);
329 }
330 }
331
332 void mfs_rename(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent,
333 const char *newname) {
334 try {
335 LizardClient::rename(get_context(req), parent, name, newparent, newname);
336 fuse_reply_err(req, 0);
337 } catch (LizardClient::RequestException& e) {
338 fuse_reply_err(req, e.system_error_code);
339 }
340 }
341
342 void mfs_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname) {
343 try {
344 auto fuseEntryParam = make_fuse_entry_param(
345 LizardClient::link(get_context(req), ino, newparent, newname));
346 fuse_reply_entry(req, &fuseEntryParam);
347 } catch (LizardClient::RequestException& e) {
348 fuse_reply_err(req, e.system_error_code);
349 }
350 }
351
352 void mfs_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
353 try {
354 LizardClient::opendir(get_context(req), ino);
355 fuse_reply_open(req, fi);
356 } catch (LizardClient::RequestException& e) {
357 fuse_reply_err(req, e.system_error_code);
358 }
359 }
360
361 void mfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
362 struct fuse_file_info */*fi*/) {
363 try {
364 char buffer[READDIR_BUFFSIZE];
365 if (size > READDIR_BUFFSIZE) {
366 size = READDIR_BUFFSIZE;
367 }
368 size_t bytesInBuffer = 0;
369 bool end = false;
370 while (!end) {
371 // Calculate approximated number of entries which will fit in the buffer. If this
372 // number is smaller than the actual value, LizardClient::readdir will be called more
373 // than once for a single mfs_readdir (this will eg. generate more oplog entries than
374 // one might expect). If it's bigger, the code will be slightly less optimal because
375 // superfluous entries will be extracted by LizardClient::readdir and then discarded by
376 // us. Using maxEntries=+inf makes the complexity of the getdents syscall O(n^2).
377 // The expression below generates some upper bound of the actual number of entries
378 // to be returned (because fuse adds 24 bytes of metadata to each file name in
379 // fuse_add_direntry and aligns size up to 8 bytes), so LizardClient::readdir
380 // should be called only once.
381 size_t maxEntries = 1 + size / 32;
382 // Now extract some entries and rewrite them into the buffer.
383 auto fsDirEntries = LizardClient::readdir(get_context(req), ino, off, maxEntries);
384 if (fsDirEntries.empty()) {
385 break; // no more entries (we don't need to set 'end = true' here to end the loop)
386 }
387 for (const auto& e : fsDirEntries) {
388 size_t entrySize = fuse_add_direntry(req,
389 buffer + bytesInBuffer, size,
390 e.name.c_str(), &(e.attr), e.nextEntryOffset);
391 if (entrySize > size) {
392 end = true; // buffer is full
393 break;
394 }
395 off = e.nextEntryOffset; // update offset of the next call to LizardClient::readdir
396 bytesInBuffer += entrySize;
397 size -= entrySize; // decrease remaining buffer size
398 }
399 }
400 fuse_reply_buf(req, buffer, bytesInBuffer);
401 } catch (LizardClient::RequestException& e) {
402 fuse_reply_err(req, e.system_error_code);
403 }
404 }
405
406 void mfs_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info */*fi*/) {
407 try {
408 LizardClient::releasedir(ino);
409 fuse_reply_err(req, 0);
410 } catch (LizardClient::RequestException& e) {
411 fuse_reply_err(req, e.system_error_code);
412 }
413 }
414
415 void mfs_create(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode,
416 struct fuse_file_info *fi) {
417 try {
418 auto e = make_fuse_entry_param(LizardClient::create(
419 get_context(req), parent, name, mode, fuse_file_info_wrapper(fi)));
420 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
421 LizardClient::remove_file_info(fuse_file_info_wrapper(fi));
422 }
423 } catch (LizardClient::RequestException& e) {
424 fuse_reply_err(req, e.system_error_code);
425 }
426 }
427
428 void mfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
429 try {
430 LizardClient::open(get_context(req), ino, fuse_file_info_wrapper(fi));
431 if (fuse_reply_open(req, fi) == -ENOENT) {
432 LizardClient::remove_file_info(fuse_file_info_wrapper(fi));
433 }
434 } catch (LizardClient::RequestException& e) {
435 fuse_reply_err(req, e.system_error_code);
436 }
437 }
438
439 void mfs_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
440 try {
441 LizardClient::release(ino, fuse_file_info_wrapper(fi));
442 fuse_reply_err(req, 0);
443 } catch (LizardClient::RequestException& e) {
444 fuse_reply_err(req, e.system_error_code);
445 }
446 }
447
448 void mfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
449 try {
450 if (LizardClient::isSpecialInode(ino)) {
451 auto ret = LizardClient::read_special_inode(
452 get_context(req), ino, size, off, fuse_file_info_wrapper(fi));
453 fuse_reply_buf(req, (char*) ret.data(), ret.size());
454 } else {
455 ReadCache::Result ret = LizardClient::read(
456 get_context(req), ino, size, off, fuse_file_info_wrapper(fi));
457
458 small_vector<struct iovec, 8> reply;
459 ret.toIoVec(reply, off, size);
460 fuse_reply_iov(req, reply.data(), reply.size());
461 }
462 } catch (LizardClient::RequestException& e) {
463 fuse_reply_err(req, e.system_error_code);
464 }
465 }
466
467 void mfs_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off,
468 struct fuse_file_info *fi) {
469 try {
470 fuse_reply_write(req, LizardClient::write(
471 get_context(req), ino, buf, size, off, fuse_file_info_wrapper(fi)));
472 } catch (LizardClient::RequestException& e) {
473 fuse_reply_err(req, e.system_error_code);
474 }
475 }
476
477 void mfs_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
478 try {
479 LizardClient::flush(get_context(req), ino, fuse_file_info_wrapper(fi));
480 fuse_reply_err(req, 0);
481 } catch (LizardClient::RequestException& e) {
482 fuse_reply_err(req, e.system_error_code);
483 }
484 }
485
486 void mfs_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) {
487 try {
488 LizardClient::fsync(get_context(req), ino, datasync, fuse_file_info_wrapper(fi));
489 fuse_reply_err(req, 0);
490 } catch (LizardClient::RequestException& e) {
491 fuse_reply_err(req, e.system_error_code);
492 }
493 }
494
495 #if defined(__APPLE__)
496 void mfs_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name, const char *value,
497 size_t size, int flags, uint32_t position) {
498 #else
499 void mfs_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name, const char *value,
500 size_t size, int flags) {
501 uint32_t position=0;
502 #endif
503 try {
504 LizardClient::setxattr(get_context(req), ino, name, value, size, flags, position);
505 fuse_reply_err(req, 0);
506 } catch (LizardClient::RequestException& e) {
507 fuse_reply_err(req, e.system_error_code);
508 }
509 }
510
511 #if defined(__APPLE__)
512 void mfs_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size,
513 uint32_t position) {
514 #else
515 void mfs_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) {
516 uint32_t position=0;
517 #endif /* __APPLE__ */
518 try {
519 auto a = LizardClient::getxattr(get_context(req), ino, name, size, position);
520 if (size == 0) {
521 fuse_reply_xattr(req, a.valueLength);
522 } else {
523 fuse_reply_buf(req,(const char*)a.valueBuffer.data(), a.valueLength);
524 }
525 } catch (LizardClient::RequestException& e) {
526 fuse_reply_err(req, e.system_error_code);
527 }
528 }
529
530 void mfs_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size) {
531 try {
532 auto a = LizardClient::listxattr(get_context(req), ino, size);
533 if (size == 0) {
534 fuse_reply_xattr(req, a.valueLength);
535 } else {
536 fuse_reply_buf(req,(const char*)a.valueBuffer.data(), a.valueLength);
537 }
538 } catch (LizardClient::RequestException& e) {
539 fuse_reply_err(req, e.system_error_code);
540 }
541 }
542
543 void mfs_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name) {
544 try {
545 LizardClient::removexattr(get_context(req), ino, name);
546 fuse_reply_err(req, 0);
547 } catch (LizardClient::RequestException& e) {
548 fuse_reply_err(req, e.system_error_code);
549 }
550 }
551
552 #if FUSE_VERSION >= 26
553 void lzfs_flock_interrupt(fuse_req_t req, void *data) {
554 auto interrupt_data = gLockInterruptData.take(reinterpret_cast<std::uintptr_t>(data));
555
556 // if there was any data
557 if (interrupt_data.first) {
558 // handle interrupt
559 LizardClient::flock_interrupt(interrupt_data.second);
560 fuse_reply_err(req, EINTR);
561 }
562 }
563
564 void lzfs_setlk_interrupt(fuse_req_t req, void *data) {
565 auto interrupt_data = gLockInterruptData.take(reinterpret_cast<std::uintptr_t>(data));
566
567 // if there was any data
568 if (interrupt_data.first) {
569 // handle interrupt
570 LizardClient::setlk_interrupt(interrupt_data.second);
571 fuse_reply_err(req, EINTR);
572 }
573 }
574
575 void lzfs_getlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock) {
576 try {
577 if (!lzfs_locks::posixOpValid(lock->l_type)) {
578 fuse_reply_err(req, EINVAL);
579 return;
580 }
581
582 lzfs_locks::FlockWrapper lzfslock = lzfs_locks::convertPLock(*lock, 1);
583 LizardClient::getlk(get_context(req), ino, fuse_file_info_wrapper(fi), lzfslock);
584 struct flock retlock = lzfs_locks::convertToFlock(lzfslock);
585 fuse_reply_lock(req, &retlock);
586 } catch (LizardClient::RequestException& e) {
587 fuse_reply_err(req, e.system_error_code);
588 }
589 }
590
591 void lzfs_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep) {
592 std::uintptr_t interrupt_data_key = gLockInterruptData.generateKey();
593 try {
594 if (fuse_req_interrupted(req)) {
595 fuse_reply_err(req, EINTR);
596 return;
597 }
598
599 if (!lzfs_locks::posixOpValid(lock->l_type)) {
600 fuse_reply_err(req, EINVAL);
601 return;
602 }
603
604 lzfs_locks::FlockWrapper lzfslock = lzfs_locks::convertPLock(*lock, sleep);
605 uint32_t reqid = LizardClient::setlk_send(get_context(req), ino, fuse_file_info_wrapper(fi),
606 lzfslock);
607
608 // save interrupt data in static structure
609 gLockInterruptData.put(interrupt_data_key,
610 lzfs_locks::InterruptData(fi->lock_owner, ino, reqid));
611
612 // register interrupt handle
613 if (lzfslock.l_type == lzfs_locks::kShared || lzfslock.l_type == lzfs_locks::kExclusive) {
614 fuse_req_interrupt_func(req, lzfs_setlk_interrupt,
615 reinterpret_cast<void*>(interrupt_data_key));
616 }
617
618 // WARNING: csetlk_recv() won't work with polonaise server,
619 // since actual code requires setlk_send()
620 // to be executed by the same thread.
621 LizardClient::setlk_recv();
622
623 // release the memory
624 auto interrupt_data = gLockInterruptData.take(interrupt_data_key);
625 if (interrupt_data.first) {
626 fuse_reply_err(req, 0);
627 }
628 } catch (LizardClient::RequestException& e) {
629 // release the memory
630 auto interrupt_data = gLockInterruptData.take(interrupt_data_key);
631 if (interrupt_data.first) {
632 fuse_reply_err(req, e.system_error_code);
633 }
634 }
635 }
636 #endif
637 #if FUSE_VERSION >= 29
638
639 void lzfs_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op) {
640 std::uintptr_t interrupt_data_key = gLockInterruptData.generateKey();
641 try {
642 if (fuse_req_interrupted(req)) {
643 fuse_reply_err(req, EINTR);
644 return;
645 }
646
647 if (!lzfs_locks::flockOpValid(op)) {
648 fuse_reply_err(req, EINVAL);
649 return;
650 }
651
652 uint32_t lzfs_op = lzfs_locks::flockOpConv(op);
653 uint32_t reqid = LizardClient::flock_send(get_context(req), ino,
654 fuse_file_info_wrapper(fi), lzfs_op);
655
656 // save interrupt data in static structure
657 gLockInterruptData.put(interrupt_data_key,
658 lzfs_locks::InterruptData(fi->lock_owner, ino, reqid));
659 // register interrupt handle
660 if (lzfs_op == lzfs_locks::kShared || lzfs_op == lzfs_locks::kExclusive) {
661 fuse_req_interrupt_func(req, lzfs_flock_interrupt,
662 reinterpret_cast<void*>(interrupt_data_key));
663 }
664
665 LizardClient::flock_recv();
666
667 // release the memory
668 auto interrupt_data = gLockInterruptData.take(interrupt_data_key);
669 if (interrupt_data.first) {
670 fuse_reply_err(req, 0);
671 }
672 } catch (LizardClient::RequestException& e) {
673 // release the memory
674 auto interrupt_data = gLockInterruptData.take(interrupt_data_key);
675 if (interrupt_data.first) {
676 fuse_reply_err(req, e.system_error_code);
677 }
678 }
679 }
680 #endif
681