1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
16 #include <sys/types.h>
28 #include "common/errno.h"
29 #include "common/safe_io.h"
30 #include "include/types.h"
34 #include "common/config.h"
35 #include "include/ceph_assert.h"
36 #include "include/cephfs/ceph_ll_client.h"
37 #include "include/ceph_fuse.h"
40 #include <fuse_lowlevel.h>
42 #define dout_context g_ceph_context
44 #define FINO_INO(x) ((x) & ((1ull<<48)-1ull))
45 #define FINO_STAG(x) ((x) >> 48)
46 #define MAKE_FINO(i,s) ((i) | ((int64_t)(s) << 48))
47 #define STAG_MASK 0xffff
50 #define MINORMASK ((1U << MINORBITS) - 1)
52 #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
53 #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
54 #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
56 static uint32_t new_encode_dev(dev_t dev
)
58 unsigned major
= MAJOR(dev
);
59 unsigned minor
= MINOR(dev
);
60 return (minor
& 0xff) | (major
<< 8) | ((minor
& ~0xff) << 12);
63 static dev_t
new_decode_dev(uint32_t dev
)
65 unsigned major
= (dev
& 0xfff00) >> 8;
66 unsigned minor
= (dev
& 0xff) | ((dev
>> 12) & 0xfff00);
67 return MKDEV(major
, minor
);
70 class CephFuse::Handle
{
72 Handle(Client
*c
, int fd
);
75 int init(int argc
, const char *argv
[]);
80 uint64_t fino_snap(uint64_t fino
);
81 uint64_t make_fake_ino(inodeno_t ino
, snapid_t snapid
);
82 Inode
* iget(fuse_ino_t fino
);
88 struct fuse_session
*se
;
89 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
90 struct fuse_cmdline_opts opts
;
96 ceph::mutex stag_lock
= ceph::make_mutex("fuse_ll.cc stag_lock");
99 ceph::unordered_map
<uint64_t,int> snap_stag_map
;
100 ceph::unordered_map
<int,uint64_t> stag_snap_map
;
102 pthread_key_t fuse_req_key
= 0;
103 void set_fuse_req(fuse_req_t
);
104 fuse_req_t
get_fuse_req();
106 struct fuse_args args
;
109 static int getgroups(fuse_req_t req
, gid_t
**sgids
)
111 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
113 int c
= fuse_req_getgroups(req
, 0, NULL
);
121 gid_t
*gids
= new (std::nothrow
) gid_t
[c
];
125 c
= fuse_req_getgroups(req
, c
, gids
);
136 static void get_fuse_groups(UserPerm
& perms
, fuse_req_t req
)
138 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)fuse_req_userdata(req
);
139 if (cfuse
->client
->cct
->_conf
.get_val
<bool>("fuse_set_user_groups")) {
141 int count
= getgroups(req
, &gids
);
144 perms
.init_gids(gids
, count
);
145 } else if (count
< 0) {
146 derr
<< __func__
<< ": getgroups failed: " << cpp_strerror(-count
)
153 static CephFuse::Handle
*fuse_ll_req_prepare(fuse_req_t req
)
155 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)fuse_req_userdata(req
);
156 cfuse
->set_fuse_req(req
);
160 static void fuse_ll_lookup(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
162 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
163 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
164 struct fuse_entry_param fe
;
165 Inode
*i2
, *i1
= cfuse
->iget(parent
); // see below
167 UserPerm
perms(ctx
->uid
, ctx
->gid
);
168 get_fuse_groups(perms
, req
);
172 r
= cfuse
->client
->lookup_ino(parent
, perms
, &i1
);
174 fuse_reply_err(req
, -r
);
179 memset(&fe
, 0, sizeof(fe
));
180 r
= cfuse
->client
->ll_lookup(i1
, name
, &fe
.attr
, &i2
, perms
);
182 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
183 fe
.attr
.st_rdev
= new_encode_dev(fe
.attr
.st_rdev
);
184 fuse_reply_entry(req
, &fe
);
186 fuse_reply_err(req
, -r
);
189 // XXX NB, we dont iput(i2) because FUSE will do so in a matching
194 static void fuse_ll_forget(fuse_req_t req
, fuse_ino_t ino
,
195 long unsigned nlookup
)
197 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
198 cfuse
->client
->ll_forget(cfuse
->iget(ino
), nlookup
+1);
199 fuse_reply_none(req
);
202 static void fuse_ll_getattr(fuse_req_t req
, fuse_ino_t ino
,
203 struct fuse_file_info
*fi
)
205 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
206 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
207 Inode
*in
= cfuse
->iget(ino
);
209 UserPerm
perms(ctx
->uid
, ctx
->gid
);
210 get_fuse_groups(perms
, req
);
214 if (cfuse
->client
->ll_getattr(in
, &stbuf
, perms
)
216 stbuf
.st_ino
= cfuse
->make_fake_ino(stbuf
.st_ino
, stbuf
.st_dev
);
217 stbuf
.st_rdev
= new_encode_dev(stbuf
.st_rdev
);
218 fuse_reply_attr(req
, &stbuf
, 0);
220 fuse_reply_err(req
, ENOENT
);
222 cfuse
->iput(in
); // iput required
225 static void fuse_ll_setattr(fuse_req_t req
, fuse_ino_t ino
, struct stat
*attr
,
226 int to_set
, struct fuse_file_info
*fi
)
228 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
229 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
230 Inode
*in
= cfuse
->iget(ino
);
231 UserPerm
perms(ctx
->uid
, ctx
->gid
);
232 get_fuse_groups(perms
, req
);
235 if (to_set
& FUSE_SET_ATTR_MODE
) mask
|= CEPH_SETATTR_MODE
;
236 if (to_set
& FUSE_SET_ATTR_UID
) mask
|= CEPH_SETATTR_UID
;
237 if (to_set
& FUSE_SET_ATTR_GID
) mask
|= CEPH_SETATTR_GID
;
238 if (to_set
& FUSE_SET_ATTR_MTIME
) mask
|= CEPH_SETATTR_MTIME
;
239 if (to_set
& FUSE_SET_ATTR_ATIME
) mask
|= CEPH_SETATTR_ATIME
;
240 if (to_set
& FUSE_SET_ATTR_SIZE
) mask
|= CEPH_SETATTR_SIZE
;
241 #if !defined(__APPLE__)
242 if (to_set
& FUSE_SET_ATTR_MTIME_NOW
) mask
|= CEPH_SETATTR_MTIME_NOW
;
243 if (to_set
& FUSE_SET_ATTR_ATIME_NOW
) mask
|= CEPH_SETATTR_ATIME_NOW
;
246 int r
= cfuse
->client
->ll_setattr(in
, attr
, mask
, perms
);
248 fuse_reply_attr(req
, attr
, 0);
250 fuse_reply_err(req
, -r
);
252 cfuse
->iput(in
); // iput required
257 static void fuse_ll_setxattr(fuse_req_t req
, fuse_ino_t ino
, const char *name
,
258 const char *value
, size_t size
,
260 #if defined(__APPLE__)
265 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
266 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
267 Inode
*in
= cfuse
->iget(ino
);
268 UserPerm
perms(ctx
->uid
, ctx
->gid
);
269 get_fuse_groups(perms
, req
);
271 int r
= cfuse
->client
->ll_setxattr(in
, name
, value
, size
, flags
, perms
);
272 fuse_reply_err(req
, -r
);
274 cfuse
->iput(in
); // iput required
277 static void fuse_ll_listxattr(fuse_req_t req
, fuse_ino_t ino
, size_t size
)
279 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
280 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
281 Inode
*in
= cfuse
->iget(ino
);
283 UserPerm
perms(ctx
->uid
, ctx
->gid
);
284 get_fuse_groups(perms
, req
);
286 int r
= cfuse
->client
->ll_listxattr(in
, buf
, size
, perms
);
287 if (size
== 0 && r
>= 0)
288 fuse_reply_xattr(req
, r
);
290 fuse_reply_buf(req
, buf
, r
);
292 fuse_reply_err(req
, -r
);
294 cfuse
->iput(in
); // iput required
297 static void fuse_ll_getxattr(fuse_req_t req
, fuse_ino_t ino
, const char *name
,
299 #if defined(__APPLE__)
304 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
305 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
306 Inode
*in
= cfuse
->iget(ino
);
308 UserPerm
perms(ctx
->uid
, ctx
->gid
);
309 get_fuse_groups(perms
, req
);
311 int r
= cfuse
->client
->ll_getxattr(in
, name
, buf
, size
, perms
);
312 if (size
== 0 && r
>= 0)
313 fuse_reply_xattr(req
, r
);
315 fuse_reply_buf(req
, buf
, r
);
317 fuse_reply_err(req
, -r
);
319 cfuse
->iput(in
); // iput required
322 static void fuse_ll_removexattr(fuse_req_t req
, fuse_ino_t ino
,
325 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
326 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
327 Inode
*in
= cfuse
->iget(ino
);
328 UserPerm
perms(ctx
->uid
, ctx
->gid
);
329 get_fuse_groups(perms
, req
);
331 int r
= cfuse
->client
->ll_removexattr(in
, name
, perms
);
332 fuse_reply_err(req
, -r
);
334 cfuse
->iput(in
); // iput required
337 static void fuse_ll_opendir(fuse_req_t req
, fuse_ino_t ino
,
338 struct fuse_file_info
*fi
)
340 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
341 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
342 Inode
*in
= cfuse
->iget(ino
);
345 UserPerm
perms(ctx
->uid
, ctx
->gid
);
346 get_fuse_groups(perms
, req
);
348 int r
= cfuse
->client
->ll_opendir(in
, fi
->flags
, (dir_result_t
**)&dirp
,
351 fi
->fh
= (uint64_t)dirp
;
352 fuse_reply_open(req
, fi
);
354 fuse_reply_err(req
, -r
);
357 cfuse
->iput(in
); // iput required
360 static void fuse_ll_readlink(fuse_req_t req
, fuse_ino_t ino
)
362 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
363 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
364 Inode
*in
= cfuse
->iget(ino
);
365 char buf
[PATH_MAX
+ 1]; // leave room for a null terminator
366 UserPerm
perms(ctx
->uid
, ctx
->gid
);
367 get_fuse_groups(perms
, req
);
369 int r
= cfuse
->client
->ll_readlink(in
, buf
, sizeof(buf
) - 1, perms
);
372 fuse_reply_readlink(req
, buf
);
374 fuse_reply_err(req
, -r
);
377 cfuse
->iput(in
); // iput required
380 static void fuse_ll_mknod(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
381 mode_t mode
, dev_t rdev
)
383 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
384 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
385 Inode
*i2
, *i1
= cfuse
->iget(parent
);
386 struct fuse_entry_param fe
;
387 UserPerm
perms(ctx
->uid
, ctx
->gid
);
388 get_fuse_groups(perms
, req
);
390 memset(&fe
, 0, sizeof(fe
));
392 int r
= cfuse
->client
->ll_mknod(i1
, name
, mode
, new_decode_dev(rdev
),
393 &fe
.attr
, &i2
, perms
);
395 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
396 fe
.attr
.st_rdev
= new_encode_dev(fe
.attr
.st_rdev
);
397 fuse_reply_entry(req
, &fe
);
399 fuse_reply_err(req
, -r
);
402 // XXX NB, we dont iput(i2) because FUSE will do so in a matching
404 cfuse
->iput(i1
); // iput required
407 static void fuse_ll_mkdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
410 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
411 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
413 struct fuse_entry_param fe
;
415 memset(&fe
, 0, sizeof(fe
));
416 UserPerm
perm(ctx
->uid
, ctx
->gid
);
417 get_fuse_groups(perm
, req
);
418 #ifdef HAVE_SYS_SYNCFS
419 auto fuse_multithreaded
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
420 "fuse_multithreaded");
421 auto fuse_syncfs_on_mksnap
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
422 "fuse_syncfs_on_mksnap");
423 if (cfuse
->fino_snap(parent
) == CEPH_SNAPDIR
&&
424 fuse_multithreaded
&& fuse_syncfs_on_mksnap
) {
426 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
427 int fd
= ::open(cfuse
->opts
.mountpoint
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
429 int fd
= ::open(cfuse
->mountpoint
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
434 int r
= ::syncfs(fd
);
440 fuse_reply_err(req
, err
);
446 i1
= cfuse
->iget(parent
);
447 int r
= cfuse
->client
->ll_mkdir(i1
, name
, mode
, &fe
.attr
, &i2
, perm
);
449 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
450 fe
.attr
.st_rdev
= new_encode_dev(fe
.attr
.st_rdev
);
451 fuse_reply_entry(req
, &fe
);
453 fuse_reply_err(req
, -r
);
456 // XXX NB, we dont iput(i2) because FUSE will do so in a matching
458 cfuse
->iput(i1
); // iput required
461 static void fuse_ll_unlink(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
463 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
464 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
465 Inode
*in
= cfuse
->iget(parent
);
466 UserPerm
perm(ctx
->uid
, ctx
->gid
);
467 get_fuse_groups(perm
, req
);
469 int r
= cfuse
->client
->ll_unlink(in
, name
, perm
);
470 fuse_reply_err(req
, -r
);
472 cfuse
->iput(in
); // iput required
475 static void fuse_ll_rmdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
477 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
478 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
479 Inode
*in
= cfuse
->iget(parent
);
480 UserPerm
perms(ctx
->uid
, ctx
->gid
);
481 get_fuse_groups(perms
, req
);
483 int r
= cfuse
->client
->ll_rmdir(in
, name
, perms
);
484 fuse_reply_err(req
, -r
);
486 cfuse
->iput(in
); // iput required
489 static void fuse_ll_symlink(fuse_req_t req
, const char *existing
,
490 fuse_ino_t parent
, const char *name
)
492 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
493 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
494 Inode
*i2
, *i1
= cfuse
->iget(parent
);
495 struct fuse_entry_param fe
;
496 UserPerm
perms(ctx
->uid
, ctx
->gid
);
497 get_fuse_groups(perms
, req
);
499 memset(&fe
, 0, sizeof(fe
));
501 int r
= cfuse
->client
->ll_symlink(i1
, name
, existing
, &fe
.attr
, &i2
, perms
);
503 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
504 fe
.attr
.st_rdev
= new_encode_dev(fe
.attr
.st_rdev
);
505 fuse_reply_entry(req
, &fe
);
507 fuse_reply_err(req
, -r
);
510 // XXX NB, we dont iput(i2) because FUSE will do so in a matching
512 cfuse
->iput(i1
); // iput required
515 static void fuse_ll_rename(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
516 fuse_ino_t newparent
, const char *newname
517 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
522 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
523 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
524 Inode
*in
= cfuse
->iget(parent
);
525 Inode
*nin
= cfuse
->iget(newparent
);
526 UserPerm
perm(ctx
->uid
, ctx
->gid
);
527 get_fuse_groups(perm
, req
);
529 int r
= cfuse
->client
->ll_rename(in
, name
, nin
, newname
, perm
);
530 fuse_reply_err(req
, -r
);
532 cfuse
->iput(in
); // iputs required
536 static void fuse_ll_link(fuse_req_t req
, fuse_ino_t ino
, fuse_ino_t newparent
,
539 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
540 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
541 Inode
*in
= cfuse
->iget(ino
);
542 Inode
*nin
= cfuse
->iget(newparent
);
543 struct fuse_entry_param fe
;
545 memset(&fe
, 0, sizeof(fe
));
546 UserPerm
perm(ctx
->uid
, ctx
->gid
);
547 get_fuse_groups(perm
, req
);
550 * Note that we could successfully link, but then fail the subsequent
551 * getattr and return an error. Perhaps we should ignore getattr errors,
552 * but then how do we tell FUSE that the attrs are bogus?
554 int r
= cfuse
->client
->ll_link(in
, nin
, newname
, perm
);
556 r
= cfuse
->client
->ll_getattr(in
, &fe
.attr
, perm
);
558 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
559 fe
.attr
.st_rdev
= new_encode_dev(fe
.attr
.st_rdev
);
560 fuse_reply_entry(req
, &fe
);
566 * Many ll operations in libcephfs return an extra inode reference, but
567 * ll_link currently does not. Still, FUSE needs one for the new dentry,
568 * so we commandeer the reference taken earlier when ll_link is successful.
569 * On error however, we must put that reference.
572 fuse_reply_err(req
, -r
);
578 static void fuse_ll_open(fuse_req_t req
, fuse_ino_t ino
,
579 struct fuse_file_info
*fi
)
581 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
582 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
583 Inode
*in
= cfuse
->iget(ino
);
585 UserPerm
perms(ctx
->uid
, ctx
->gid
);
586 get_fuse_groups(perms
, req
);
588 int r
= cfuse
->client
->ll_open(in
, fi
->flags
, &fh
, perms
);
590 fi
->fh
= (uint64_t)fh
;
591 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
592 auto fuse_disable_pagecache
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
593 "fuse_disable_pagecache");
594 auto fuse_use_invalidate_cb
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
595 "fuse_use_invalidate_cb");
596 if (fuse_disable_pagecache
)
598 else if (fuse_use_invalidate_cb
)
601 fuse_reply_open(req
, fi
);
603 fuse_reply_err(req
, -r
);
606 cfuse
->iput(in
); // iput required
609 static void fuse_ll_read(fuse_req_t req
, fuse_ino_t ino
, size_t size
, off_t off
,
610 struct fuse_file_info
*fi
)
612 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
613 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
615 int r
= cfuse
->client
->ll_read(fh
, off
, size
, &bl
);
617 fuse_reply_buf(req
, bl
.c_str(), bl
.length());
619 fuse_reply_err(req
, -r
);
622 static void fuse_ll_write(fuse_req_t req
, fuse_ino_t ino
, const char *buf
,
623 size_t size
, off_t off
, struct fuse_file_info
*fi
)
625 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
626 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
627 int r
= cfuse
->client
->ll_write(fh
, off
, size
, buf
);
629 fuse_reply_write(req
, r
);
631 fuse_reply_err(req
, -r
);
634 static void fuse_ll_flush(fuse_req_t req
, fuse_ino_t ino
,
635 struct fuse_file_info
*fi
)
637 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
638 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
639 int r
= cfuse
->client
->ll_flush(fh
);
640 fuse_reply_err(req
, -r
);
643 #ifdef FUSE_IOCTL_COMPAT
644 static void fuse_ll_ioctl(fuse_req_t req
, fuse_ino_t ino
,
645 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 5)
650 void *arg
, struct fuse_file_info
*fi
,
651 unsigned flags
, const void *in_buf
, size_t in_bufsz
, size_t out_bufsz
)
653 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
655 if (flags
& FUSE_IOCTL_COMPAT
) {
656 fuse_reply_err(req
, ENOSYS
);
660 switch (static_cast<unsigned>(cmd
)) {
661 case CEPH_IOC_GET_LAYOUT
: {
662 file_layout_t layout
;
663 struct ceph_ioctl_layout l
;
664 Fh
*fh
= (Fh
*)fi
->fh
;
665 cfuse
->client
->ll_file_layout(fh
, &layout
);
666 l
.stripe_unit
= layout
.stripe_unit
;
667 l
.stripe_count
= layout
.stripe_count
;
668 l
.object_size
= layout
.object_size
;
669 l
.data_pool
= layout
.pool_id
;
670 fuse_reply_ioctl(req
, 0, &l
, sizeof(struct ceph_ioctl_layout
));
674 fuse_reply_err(req
, EINVAL
);
679 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
681 static void fuse_ll_fallocate(fuse_req_t req
, fuse_ino_t ino
, int mode
,
682 off_t offset
, off_t length
,
683 struct fuse_file_info
*fi
)
685 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
686 Fh
*fh
= (Fh
*)fi
->fh
;
687 int r
= cfuse
->client
->ll_fallocate(fh
, mode
, offset
, length
);
688 fuse_reply_err(req
, -r
);
693 static void fuse_ll_release(fuse_req_t req
, fuse_ino_t ino
,
694 struct fuse_file_info
*fi
)
696 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
697 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
698 int r
= cfuse
->client
->ll_release(fh
);
699 fuse_reply_err(req
, -r
);
702 static void fuse_ll_fsync(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
703 struct fuse_file_info
*fi
)
705 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
706 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
707 int r
= cfuse
->client
->ll_fsync(fh
, datasync
);
708 fuse_reply_err(req
, -r
);
711 struct readdir_context
{
715 size_t pos
; /* in buf */
720 * return 0 on success, -1 if out of space
722 static int fuse_ll_add_dirent(void *p
, struct dirent
*de
,
723 struct ceph_statx
*stx
, off_t next_off
,
726 struct readdir_context
*c
= (struct readdir_context
*)p
;
727 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)fuse_req_userdata(c
->req
);
730 st
.st_ino
= cfuse
->make_fake_ino(stx
->stx_ino
, c
->snap
);
731 st
.st_mode
= stx
->stx_mode
;
732 st
.st_rdev
= new_encode_dev(stx
->stx_rdev
);
734 size_t room
= c
->size
- c
->pos
;
735 size_t entrysize
= fuse_add_direntry(c
->req
, c
->buf
+ c
->pos
, room
,
736 de
->d_name
, &st
, next_off
);
737 if (entrysize
> room
)
745 static void fuse_ll_readdir(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
746 off_t off
, struct fuse_file_info
*fi
)
748 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
750 dir_result_t
*dirp
= reinterpret_cast<dir_result_t
*>(fi
->fh
);
751 cfuse
->client
->seekdir(dirp
, off
);
753 struct readdir_context rc
;
755 rc
.buf
= new char[size
];
758 rc
.snap
= cfuse
->fino_snap(ino
);
760 int r
= cfuse
->client
->readdir_r_cb(dirp
, fuse_ll_add_dirent
, &rc
);
761 if (r
== 0 || r
== -ENOSPC
) /* ignore ENOSPC from our callback */
762 fuse_reply_buf(req
, rc
.buf
, rc
.pos
);
764 fuse_reply_err(req
, -r
);
768 static void fuse_ll_releasedir(fuse_req_t req
, fuse_ino_t ino
,
769 struct fuse_file_info
*fi
)
771 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
772 dir_result_t
*dirp
= reinterpret_cast<dir_result_t
*>(fi
->fh
);
773 cfuse
->client
->ll_releasedir(dirp
);
774 fuse_reply_err(req
, 0);
777 static void fuse_ll_fsyncdir(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
778 struct fuse_file_info
*fi
)
780 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
781 dir_result_t
*dirp
= reinterpret_cast<dir_result_t
*>(fi
->fh
);
782 int r
= cfuse
->client
->ll_fsyncdir(dirp
);
783 fuse_reply_err(req
, -r
);
786 static void fuse_ll_access(fuse_req_t req
, fuse_ino_t ino
, int mask
)
788 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
789 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
790 Inode
*in
= cfuse
->iget(ino
);
791 UserPerm
perms(ctx
->uid
, ctx
->gid
);
792 get_fuse_groups(perms
, req
);
794 int r
= cfuse
->client
->inode_permission(in
, perms
, mask
);
795 fuse_reply_err(req
, -r
);
799 static void fuse_ll_create(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
800 mode_t mode
, struct fuse_file_info
*fi
)
802 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
803 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
804 Inode
*i1
= cfuse
->iget(parent
), *i2
;
805 struct fuse_entry_param fe
;
807 UserPerm
perms(ctx
->uid
, ctx
->gid
);
808 get_fuse_groups(perms
, req
);
810 memset(&fe
, 0, sizeof(fe
));
812 // pass &i2 for the created inode so that ll_create takes an initial ll_ref
813 int r
= cfuse
->client
->ll_create(i1
, name
, mode
, fi
->flags
, &fe
.attr
, &i2
,
816 fi
->fh
= (uint64_t)fh
;
817 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
818 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
819 auto fuse_disable_pagecache
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
820 "fuse_disable_pagecache");
821 auto fuse_use_invalidate_cb
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
822 "fuse_use_invalidate_cb");
823 if (fuse_disable_pagecache
)
825 else if (fuse_use_invalidate_cb
)
828 fuse_reply_create(req
, &fe
, fi
);
830 fuse_reply_err(req
, -r
);
831 // XXX NB, we dont iput(i2) because FUSE will do so in a matching
833 cfuse
->iput(i1
); // iput required
836 static void fuse_ll_statfs(fuse_req_t req
, fuse_ino_t ino
)
838 struct statvfs stbuf
;
839 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
840 Inode
*in
= cfuse
->iget(ino
);
841 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
842 UserPerm
perms(ctx
->uid
, ctx
->gid
);
843 get_fuse_groups(perms
, req
);
845 int r
= cfuse
->client
->ll_statfs(in
, &stbuf
, perms
);
847 fuse_reply_statfs(req
, &stbuf
);
849 fuse_reply_err(req
, -r
);
851 cfuse
->iput(in
); // iput required
854 static void fuse_ll_getlk(fuse_req_t req
, fuse_ino_t ino
,
855 struct fuse_file_info
*fi
, struct flock
*lock
)
857 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
858 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
860 int r
= cfuse
->client
->ll_getlk(fh
, lock
, fi
->lock_owner
);
862 fuse_reply_lock(req
, lock
);
864 fuse_reply_err(req
, -r
);
867 static void fuse_ll_setlk(fuse_req_t req
, fuse_ino_t ino
,
868 struct fuse_file_info
*fi
, struct flock
*lock
, int sleep
)
870 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
871 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
873 // must use multithread if operation may block
874 auto fuse_multithreaded
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
875 "fuse_multithreaded");
876 if (!fuse_multithreaded
&& sleep
&& lock
->l_type
!= F_UNLCK
) {
877 fuse_reply_err(req
, EDEADLK
);
881 int r
= cfuse
->client
->ll_setlk(fh
, lock
, fi
->lock_owner
, sleep
);
882 fuse_reply_err(req
, -r
);
885 static void fuse_ll_interrupt(fuse_req_t req
, void* data
)
887 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
888 cfuse
->client
->ll_interrupt(data
);
891 static void switch_interrupt_cb(void *handle
, void* data
)
893 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)handle
;
894 fuse_req_t req
= cfuse
->get_fuse_req();
897 fuse_req_interrupt_func(req
, fuse_ll_interrupt
, data
);
899 fuse_req_interrupt_func(req
, NULL
, NULL
);
902 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
903 static void fuse_ll_flock(fuse_req_t req
, fuse_ino_t ino
,
904 struct fuse_file_info
*fi
, int cmd
)
906 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
907 Fh
*fh
= (Fh
*)fi
->fh
;
909 // must use multithread if operation may block
910 auto fuse_multithreaded
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
911 "fuse_multithreaded");
912 if (!fuse_multithreaded
&& !(cmd
& (LOCK_NB
| LOCK_UN
))) {
913 fuse_reply_err(req
, EDEADLK
);
917 int r
= cfuse
->client
->ll_flock(fh
, cmd
, fi
->lock_owner
);
918 fuse_reply_err(req
, -r
);
922 #if !defined(__APPLE__)
923 static mode_t
umask_cb(void *handle
)
925 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)handle
;
926 fuse_req_t req
= cfuse
->get_fuse_req();
927 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
932 static void ino_invalidate_cb(void *handle
, vinodeno_t vino
, int64_t off
,
935 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
936 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)handle
;
937 fuse_ino_t fino
= cfuse
->make_fake_ino(vino
.ino
, vino
.snapid
);
938 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
939 fuse_lowlevel_notify_inval_inode(cfuse
->se
, fino
, off
, len
);
941 fuse_lowlevel_notify_inval_inode(cfuse
->ch
, fino
, off
, len
);
946 static void dentry_invalidate_cb(void *handle
, vinodeno_t dirino
,
947 vinodeno_t ino
, const char *name
, size_t len
)
949 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)handle
;
950 fuse_ino_t fdirino
= cfuse
->make_fake_ino(dirino
.ino
, dirino
.snapid
);
951 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
953 if (ino
.ino
!= inodeno_t())
954 fino
= cfuse
->make_fake_ino(ino
.ino
, ino
.snapid
);
955 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
956 fuse_lowlevel_notify_delete(cfuse
->se
, fdirino
, fino
, name
, len
);
958 fuse_lowlevel_notify_delete(cfuse
->ch
, fdirino
, fino
, name
, len
);
960 #elif FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
961 fuse_lowlevel_notify_inval_entry(cfuse
->ch
, fdirino
, name
, len
);
965 static int remount_cb(void *handle
)
967 // used for trimming kernel dcache. when remounting a file system, linux kernel
968 // trims all unused dentries in the file system
969 char cmd
[128+PATH_MAX
];
970 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)handle
;
971 snprintf(cmd
, sizeof(cmd
), "LIBMOUNT_FSTAB=/dev/null mount -i -o remount %s",
972 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
973 cfuse
->opts
.mountpoint
);
978 if (r
!= 0 && r
!= -1) {
985 static void do_init(void *data
, fuse_conn_info
*conn
)
987 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)data
;
988 Client
*client
= cfuse
->client
;
990 #if !defined(__APPLE__)
991 if (!client
->fuse_default_permissions
&& client
->ll_handle_umask()) {
992 // apply umask in userspace if posix acl is enabled
993 if(conn
->capable
& FUSE_CAP_DONT_MASK
)
994 conn
->want
|= FUSE_CAP_DONT_MASK
;
996 if(conn
->capable
& FUSE_CAP_EXPORT_SUPPORT
)
997 conn
->want
|= FUSE_CAP_EXPORT_SUPPORT
;
1000 if (cfuse
->fd_on_success
) {
1001 //cout << "fuse init signaling on fd " << fd_on_success << std::endl;
1002 // see Preforker::daemonize(), ceph-fuse's parent process expects a `-1`
1003 // from a daemonized child process.
1005 int err
= safe_write(cfuse
->fd_on_success
, &r
, sizeof(r
));
1007 derr
<< "fuse_ll: do_init: safe_write failed with error "
1008 << cpp_strerror(err
) << dendl
;
1011 //cout << "fuse init done signaling on fd " << fd_on_success << std::endl;
1013 // close stdout, etc.
1020 const static struct fuse_lowlevel_ops fuse_ll_oper
= {
1023 lookup
: fuse_ll_lookup
,
1024 forget
: fuse_ll_forget
,
1025 getattr
: fuse_ll_getattr
,
1026 setattr
: fuse_ll_setattr
,
1027 readlink
: fuse_ll_readlink
,
1028 mknod
: fuse_ll_mknod
,
1029 mkdir
: fuse_ll_mkdir
,
1030 unlink
: fuse_ll_unlink
,
1031 rmdir
: fuse_ll_rmdir
,
1032 symlink
: fuse_ll_symlink
,
1033 rename
: fuse_ll_rename
,
1037 write
: fuse_ll_write
,
1038 flush
: fuse_ll_flush
,
1039 release
: fuse_ll_release
,
1040 fsync
: fuse_ll_fsync
,
1041 opendir
: fuse_ll_opendir
,
1042 readdir
: fuse_ll_readdir
,
1043 releasedir
: fuse_ll_releasedir
,
1044 fsyncdir
: fuse_ll_fsyncdir
,
1045 statfs
: fuse_ll_statfs
,
1046 setxattr
: fuse_ll_setxattr
,
1047 getxattr
: fuse_ll_getxattr
,
1048 listxattr
: fuse_ll_listxattr
,
1049 removexattr
: fuse_ll_removexattr
,
1050 access
: fuse_ll_access
,
1051 create
: fuse_ll_create
,
1052 getlk
: fuse_ll_getlk
,
1053 setlk
: fuse_ll_setlk
,
1055 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
1056 #ifdef FUSE_IOCTL_COMPAT
1057 ioctl
: fuse_ll_ioctl
,
1063 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
1067 flock
: fuse_ll_flock
,
1069 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
1070 fallocate
: fuse_ll_fallocate
1075 CephFuse::Handle::Handle(Client
*c
, int fd
) :
1079 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
1085 snap_stag_map
[CEPH_NOSNAP
] = 0;
1086 stag_snap_map
[0] = CEPH_NOSNAP
;
1087 memset(&args
, 0, sizeof(args
));
1088 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1089 memset(&opts
, 0, sizeof(opts
));
1093 CephFuse::Handle::~Handle()
1095 fuse_opt_free_args(&args
);
1098 void CephFuse::Handle::finalize()
1100 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1102 fuse_remove_signal_handlers(se
);
1103 fuse_session_unmount(se
);
1104 fuse_session_destroy(se
);
1106 if (opts
.mountpoint
)
1107 free(opts
.mountpoint
);
1110 fuse_remove_signal_handlers(se
);
1112 fuse_session_remove_chan(ch
);
1114 fuse_session_destroy(se
);
1116 fuse_unmount(mountpoint
, ch
);
1119 pthread_key_delete(fuse_req_key
);
1122 int CephFuse::Handle::init(int argc
, const char *argv
[])
1125 int r
= pthread_key_create(&fuse_req_key
, NULL
);
1127 derr
<< "pthread_key_create failed." << dendl
;
1131 // set up fuse argc/argv
1133 const char **newargv
= (const char **) malloc((argc
+ 10) * sizeof(char *));
1137 newargv
[newargc
++] = argv
[0];
1138 newargv
[newargc
++] = "-f"; // stay in foreground
1140 auto fuse_allow_other
= client
->cct
->_conf
.get_val
<bool>(
1141 "fuse_allow_other");
1142 auto fuse_default_permissions
= client
->cct
->_conf
.get_val
<bool>(
1143 "fuse_default_permissions");
1144 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
1145 auto fuse_big_writes
= client
->cct
->_conf
.get_val
<bool>(
1147 auto fuse_max_write
= client
->cct
->_conf
.get_val
<Option::size_t>(
1149 auto fuse_atomic_o_trunc
= client
->cct
->_conf
.get_val
<bool>(
1150 "fuse_atomic_o_trunc");
1152 auto fuse_debug
= client
->cct
->_conf
.get_val
<bool>(
1155 if (fuse_allow_other
) {
1156 newargv
[newargc
++] = "-o";
1157 newargv
[newargc
++] = "allow_other";
1159 if (fuse_default_permissions
) {
1160 newargv
[newargc
++] = "-o";
1161 newargv
[newargc
++] = "default_permissions";
1163 #if defined(__linux__)
1164 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
1165 if (fuse_big_writes
) {
1166 newargv
[newargc
++] = "-o";
1167 newargv
[newargc
++] = "big_writes";
1169 if (fuse_max_write
> 0) {
1171 newargv
[newargc
++] = "-o";
1172 newargv
[newargc
++] = strsplice
;
1173 sprintf(strsplice
, "max_write=%zu", (size_t)fuse_max_write
);
1174 newargv
[newargc
++] = strsplice
;
1176 if (fuse_atomic_o_trunc
) {
1177 newargv
[newargc
++] = "-o";
1178 newargv
[newargc
++] = "atomic_o_trunc";
1183 newargv
[newargc
++] = "-d";
1185 for (int argctr
= 1; argctr
< argc
; argctr
++)
1186 newargv
[newargc
++] = argv
[argctr
];
1188 derr
<< "init, newargv = " << newargv
<< " newargc=" << newargc
<< dendl
;
1189 struct fuse_args a
= FUSE_ARGS_INIT(newargc
, (char**)newargv
);
1190 args
= a
; // Roundabout construction b/c FUSE_ARGS_INIT is for initialization not assignment
1192 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1193 if (fuse_parse_cmdline(&args
, &opts
) == -1) {
1195 if (fuse_parse_cmdline(&args
, &mountpoint
, NULL
, NULL
) == -1) {
1197 derr
<< "fuse_parse_cmdline failed." << dendl
;
1198 fuse_opt_free_args(&args
);
1203 ceph_assert(args
.allocated
); // Checking fuse has realloc'd args so we can free newargv
1208 int CephFuse::Handle::start()
1210 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1211 se
= fuse_session_new(&args
, &fuse_ll_oper
, sizeof(fuse_ll_oper
), this);
1213 ch
= fuse_mount(mountpoint
, &args
);
1215 derr
<< "fuse_mount(mountpoint=" << mountpoint
<< ") failed." << dendl
;
1219 se
= fuse_lowlevel_new(&args
, &fuse_ll_oper
, sizeof(fuse_ll_oper
), this);
1222 derr
<< "fuse_lowlevel_new failed" << dendl
;
1226 signal(SIGTERM
, SIG_DFL
);
1227 signal(SIGINT
, SIG_DFL
);
1228 if (fuse_set_signal_handlers(se
) == -1) {
1229 derr
<< "fuse_set_signal_handlers failed" << dendl
;
1233 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1234 if (fuse_session_mount(se
, opts
.mountpoint
) != 0) {
1235 derr
<< "fuse_session_mount failed" << dendl
;
1239 fuse_session_add_chan(se
, ch
);
1243 struct ceph_client_callback_args args
= {
1245 ino_cb
: client
->cct
->_conf
.get_val
<bool>("fuse_use_invalidate_cb") ?
1246 ino_invalidate_cb
: NULL
,
1247 dentry_cb
: dentry_invalidate_cb
,
1248 switch_intr_cb
: switch_interrupt_cb
,
1249 #if defined(__linux__)
1250 remount_cb
: remount_cb
,
1252 #if !defined(__APPLE__)
1256 client
->ll_register_callbacks(&args
);
1261 int CephFuse::Handle::loop()
1263 auto fuse_multithreaded
= client
->cct
->_conf
.get_val
<bool>(
1264 "fuse_multithreaded");
1265 if (fuse_multithreaded
) {
1266 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 1)
1268 struct fuse_loop_config conf
= { 0 };
1270 conf
.clone_fd
= opts
.clone_fd
;
1271 return fuse_session_loop_mt(se
, &conf
);
1273 #elif FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1274 return fuse_session_loop_mt(se
, opts
.clone_fd
);
1276 return fuse_session_loop_mt(se
);
1279 return fuse_session_loop(se
);
1283 uint64_t CephFuse::Handle::fino_snap(uint64_t fino
)
1285 if (fino
== FUSE_ROOT_ID
)
1288 if (client
->use_faked_inos()) {
1289 vinodeno_t vino
= client
->map_faked_ino(fino
);
1292 std::lock_guard
l(stag_lock
);
1293 uint64_t stag
= FINO_STAG(fino
);
1294 ceph_assert(stag_snap_map
.count(stag
));
1295 return stag_snap_map
[stag
];
1299 Inode
* CephFuse::Handle::iget(fuse_ino_t fino
)
1301 if (fino
== FUSE_ROOT_ID
)
1302 return client
->get_root();
1304 if (client
->use_faked_inos()) {
1305 return client
->ll_get_inode((ino_t
)fino
);
1307 vinodeno_t
vino(FINO_INO(fino
), fino_snap(fino
));
1308 return client
->ll_get_inode(vino
);
1312 void CephFuse::Handle::iput(Inode
*in
)
1317 uint64_t CephFuse::Handle::make_fake_ino(inodeno_t ino
, snapid_t snapid
)
1319 if (client
->use_faked_inos()) {
1320 // already faked by libcephfs
1321 if (ino
== client
->get_root_ino())
1322 return FUSE_ROOT_ID
;
1326 if (snapid
== CEPH_NOSNAP
&& ino
== client
->get_root_ino())
1327 return FUSE_ROOT_ID
;
1329 std::lock_guard
l(stag_lock
);
1330 auto p
= snap_stag_map
.find(snapid
);
1331 if (p
!= snap_stag_map
.end()) {
1332 inodeno_t fino
= MAKE_FINO(ino
, p
->second
);
1336 int first
= last_stag
& STAG_MASK
;
1337 int stag
= (++last_stag
) & STAG_MASK
;
1338 for (; stag
!= first
; stag
= (++last_stag
) & STAG_MASK
) {
1342 auto p
= stag_snap_map
.find(stag
);
1343 if (p
== stag_snap_map
.end()) {
1344 snap_stag_map
[snapid
] = stag
;
1345 stag_snap_map
[stag
] = snapid
;
1349 if (!client
->ll_get_snap_ref(p
->second
)) {
1350 snap_stag_map
.erase(p
->second
);
1351 snap_stag_map
[snapid
] = stag
;
1357 ceph_abort_msg("run out of stag");
1359 inodeno_t fino
= MAKE_FINO(ino
, stag
);
1360 //cout << "make_fake_ino " << ino << "." << snapid << " -> " << fino << std::endl;
1365 void CephFuse::Handle::set_fuse_req(fuse_req_t req
)
1367 pthread_setspecific(fuse_req_key
, (void*)req
);
1370 fuse_req_t
CephFuse::Handle::get_fuse_req()
1372 return (fuse_req_t
) pthread_getspecific(fuse_req_key
);
1376 CephFuse::CephFuse(Client
*c
, int fd
) : _handle(new CephFuse::Handle(c
, fd
))
1380 CephFuse::~CephFuse()
1385 int CephFuse::init(int argc
, const char *argv
[])
1387 return _handle
->init(argc
, argv
);
1390 int CephFuse::start()
1392 return _handle
->start();
1395 int CephFuse::loop()
1397 return _handle
->loop();
1400 void CephFuse::finalize()
1402 return _handle
->finalize();
1405 std::string
CephFuse::get_mount_point() const
1407 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1408 if (_handle
->opts
.mountpoint
) {
1409 return _handle
->opts
.mountpoint
;
1411 if (_handle
->mountpoint
) {
1412 return _handle
->mountpoint
;