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 if (g_conf().get_val
<bool>("fuse_set_user_groups")) {
140 int count
= getgroups(req
, &gids
);
143 perms
.init_gids(gids
, count
);
144 } else if (count
< 0) {
145 derr
<< __func__
<< ": getgroups failed: " << cpp_strerror(-count
)
152 static CephFuse::Handle
*fuse_ll_req_prepare(fuse_req_t req
)
154 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)fuse_req_userdata(req
);
155 cfuse
->set_fuse_req(req
);
159 static void fuse_ll_lookup(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
161 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
162 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
163 struct fuse_entry_param fe
;
164 Inode
*i2
, *i1
= cfuse
->iget(parent
); // see below
166 UserPerm
perms(ctx
->uid
, ctx
->gid
);
167 get_fuse_groups(perms
, req
);
171 r
= cfuse
->client
->lookup_ino(parent
, perms
, &i1
);
173 fuse_reply_err(req
, -r
);
178 memset(&fe
, 0, sizeof(fe
));
179 r
= cfuse
->client
->ll_lookup(i1
, name
, &fe
.attr
, &i2
, perms
);
181 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
182 fe
.attr
.st_rdev
= new_encode_dev(fe
.attr
.st_rdev
);
183 fuse_reply_entry(req
, &fe
);
185 fuse_reply_err(req
, -r
);
188 // XXX NB, we dont iput(i2) because FUSE will do so in a matching
193 static void fuse_ll_forget(fuse_req_t req
, fuse_ino_t ino
,
194 long unsigned nlookup
)
196 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
197 cfuse
->client
->ll_forget(cfuse
->iget(ino
), nlookup
+1);
198 fuse_reply_none(req
);
201 static void fuse_ll_getattr(fuse_req_t req
, fuse_ino_t ino
,
202 struct fuse_file_info
*fi
)
204 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
205 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
206 Inode
*in
= cfuse
->iget(ino
);
208 UserPerm
perms(ctx
->uid
, ctx
->gid
);
209 get_fuse_groups(perms
, req
);
213 if (cfuse
->client
->ll_getattr(in
, &stbuf
, perms
)
215 stbuf
.st_ino
= cfuse
->make_fake_ino(stbuf
.st_ino
, stbuf
.st_dev
);
216 stbuf
.st_rdev
= new_encode_dev(stbuf
.st_rdev
);
217 fuse_reply_attr(req
, &stbuf
, 0);
219 fuse_reply_err(req
, ENOENT
);
221 cfuse
->iput(in
); // iput required
224 static void fuse_ll_setattr(fuse_req_t req
, fuse_ino_t ino
, struct stat
*attr
,
225 int to_set
, struct fuse_file_info
*fi
)
227 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
228 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
229 Inode
*in
= cfuse
->iget(ino
);
230 UserPerm
perms(ctx
->uid
, ctx
->gid
);
231 get_fuse_groups(perms
, req
);
234 if (to_set
& FUSE_SET_ATTR_MODE
) mask
|= CEPH_SETATTR_MODE
;
235 if (to_set
& FUSE_SET_ATTR_UID
) mask
|= CEPH_SETATTR_UID
;
236 if (to_set
& FUSE_SET_ATTR_GID
) mask
|= CEPH_SETATTR_GID
;
237 if (to_set
& FUSE_SET_ATTR_MTIME
) mask
|= CEPH_SETATTR_MTIME
;
238 if (to_set
& FUSE_SET_ATTR_ATIME
) mask
|= CEPH_SETATTR_ATIME
;
239 if (to_set
& FUSE_SET_ATTR_SIZE
) mask
|= CEPH_SETATTR_SIZE
;
240 #if !defined(__APPLE__)
241 if (to_set
& FUSE_SET_ATTR_MTIME_NOW
) mask
|= CEPH_SETATTR_MTIME_NOW
;
242 if (to_set
& FUSE_SET_ATTR_ATIME_NOW
) mask
|= CEPH_SETATTR_ATIME_NOW
;
245 int r
= cfuse
->client
->ll_setattr(in
, attr
, mask
, perms
);
247 fuse_reply_attr(req
, attr
, 0);
249 fuse_reply_err(req
, -r
);
251 cfuse
->iput(in
); // iput required
256 static void fuse_ll_setxattr(fuse_req_t req
, fuse_ino_t ino
, const char *name
,
257 const char *value
, size_t size
,
259 #if defined(__APPLE__)
264 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
265 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
266 Inode
*in
= cfuse
->iget(ino
);
267 UserPerm
perms(ctx
->uid
, ctx
->gid
);
268 get_fuse_groups(perms
, req
);
270 int r
= cfuse
->client
->ll_setxattr(in
, name
, value
, size
, flags
, perms
);
271 fuse_reply_err(req
, -r
);
273 cfuse
->iput(in
); // iput required
276 static void fuse_ll_listxattr(fuse_req_t req
, fuse_ino_t ino
, size_t size
)
278 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
279 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
280 Inode
*in
= cfuse
->iget(ino
);
282 UserPerm
perms(ctx
->uid
, ctx
->gid
);
283 get_fuse_groups(perms
, req
);
285 int r
= cfuse
->client
->ll_listxattr(in
, buf
, size
, perms
);
286 if (size
== 0 && r
>= 0)
287 fuse_reply_xattr(req
, r
);
289 fuse_reply_buf(req
, buf
, r
);
291 fuse_reply_err(req
, -r
);
293 cfuse
->iput(in
); // iput required
296 static void fuse_ll_getxattr(fuse_req_t req
, fuse_ino_t ino
, const char *name
,
298 #if defined(__APPLE__)
303 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
304 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
305 Inode
*in
= cfuse
->iget(ino
);
307 UserPerm
perms(ctx
->uid
, ctx
->gid
);
308 get_fuse_groups(perms
, req
);
310 int r
= cfuse
->client
->ll_getxattr(in
, name
, buf
, size
, perms
);
311 if (size
== 0 && r
>= 0)
312 fuse_reply_xattr(req
, r
);
314 fuse_reply_buf(req
, buf
, r
);
316 fuse_reply_err(req
, -r
);
318 cfuse
->iput(in
); // iput required
321 static void fuse_ll_removexattr(fuse_req_t req
, fuse_ino_t ino
,
324 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
325 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
326 Inode
*in
= cfuse
->iget(ino
);
327 UserPerm
perms(ctx
->uid
, ctx
->gid
);
328 get_fuse_groups(perms
, req
);
330 int r
= cfuse
->client
->ll_removexattr(in
, name
, perms
);
331 fuse_reply_err(req
, -r
);
333 cfuse
->iput(in
); // iput required
336 static void fuse_ll_opendir(fuse_req_t req
, fuse_ino_t ino
,
337 struct fuse_file_info
*fi
)
339 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
340 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
341 Inode
*in
= cfuse
->iget(ino
);
344 UserPerm
perms(ctx
->uid
, ctx
->gid
);
345 get_fuse_groups(perms
, req
);
347 int r
= cfuse
->client
->ll_opendir(in
, fi
->flags
, (dir_result_t
**)&dirp
,
350 fi
->fh
= (uint64_t)dirp
;
351 fuse_reply_open(req
, fi
);
353 fuse_reply_err(req
, -r
);
356 cfuse
->iput(in
); // iput required
359 static void fuse_ll_readlink(fuse_req_t req
, fuse_ino_t ino
)
361 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
362 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
363 Inode
*in
= cfuse
->iget(ino
);
364 char buf
[PATH_MAX
+ 1]; // leave room for a null terminator
365 UserPerm
perms(ctx
->uid
, ctx
->gid
);
366 get_fuse_groups(perms
, req
);
368 int r
= cfuse
->client
->ll_readlink(in
, buf
, sizeof(buf
) - 1, perms
);
371 fuse_reply_readlink(req
, buf
);
373 fuse_reply_err(req
, -r
);
376 cfuse
->iput(in
); // iput required
379 static void fuse_ll_mknod(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
380 mode_t mode
, dev_t rdev
)
382 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
383 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
384 Inode
*i2
, *i1
= cfuse
->iget(parent
);
385 struct fuse_entry_param fe
;
386 UserPerm
perms(ctx
->uid
, ctx
->gid
);
387 get_fuse_groups(perms
, req
);
389 memset(&fe
, 0, sizeof(fe
));
391 int r
= cfuse
->client
->ll_mknod(i1
, name
, mode
, new_decode_dev(rdev
),
392 &fe
.attr
, &i2
, perms
);
394 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
395 fe
.attr
.st_rdev
= new_encode_dev(fe
.attr
.st_rdev
);
396 fuse_reply_entry(req
, &fe
);
398 fuse_reply_err(req
, -r
);
401 // XXX NB, we dont iput(i2) because FUSE will do so in a matching
403 cfuse
->iput(i1
); // iput required
406 static void fuse_ll_mkdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
409 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
410 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
412 struct fuse_entry_param fe
;
414 memset(&fe
, 0, sizeof(fe
));
415 UserPerm
perm(ctx
->uid
, ctx
->gid
);
416 get_fuse_groups(perm
, req
);
417 #ifdef HAVE_SYS_SYNCFS
418 auto fuse_multithreaded
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
419 "fuse_multithreaded");
420 auto fuse_syncfs_on_mksnap
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
421 "fuse_syncfs_on_mksnap");
422 if (cfuse
->fino_snap(parent
) == CEPH_SNAPDIR
&&
423 fuse_multithreaded
&& fuse_syncfs_on_mksnap
) {
425 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
426 int fd
= ::open(cfuse
->opts
.mountpoint
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
428 int fd
= ::open(cfuse
->mountpoint
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
433 int r
= ::syncfs(fd
);
439 fuse_reply_err(req
, err
);
445 i1
= cfuse
->iget(parent
);
446 int r
= cfuse
->client
->ll_mkdir(i1
, name
, mode
, &fe
.attr
, &i2
, perm
);
448 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
449 fe
.attr
.st_rdev
= new_encode_dev(fe
.attr
.st_rdev
);
450 fuse_reply_entry(req
, &fe
);
452 fuse_reply_err(req
, -r
);
455 // XXX NB, we dont iput(i2) because FUSE will do so in a matching
457 cfuse
->iput(i1
); // iput required
460 static void fuse_ll_unlink(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
462 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
463 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
464 Inode
*in
= cfuse
->iget(parent
);
465 UserPerm
perm(ctx
->uid
, ctx
->gid
);
466 get_fuse_groups(perm
, req
);
468 int r
= cfuse
->client
->ll_unlink(in
, name
, perm
);
469 fuse_reply_err(req
, -r
);
471 cfuse
->iput(in
); // iput required
474 static void fuse_ll_rmdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
476 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
477 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
478 Inode
*in
= cfuse
->iget(parent
);
479 UserPerm
perms(ctx
->uid
, ctx
->gid
);
480 get_fuse_groups(perms
, req
);
482 int r
= cfuse
->client
->ll_rmdir(in
, name
, perms
);
483 fuse_reply_err(req
, -r
);
485 cfuse
->iput(in
); // iput required
488 static void fuse_ll_symlink(fuse_req_t req
, const char *existing
,
489 fuse_ino_t parent
, const char *name
)
491 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
492 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
493 Inode
*i2
, *i1
= cfuse
->iget(parent
);
494 struct fuse_entry_param fe
;
495 UserPerm
perms(ctx
->uid
, ctx
->gid
);
496 get_fuse_groups(perms
, req
);
498 memset(&fe
, 0, sizeof(fe
));
500 int r
= cfuse
->client
->ll_symlink(i1
, name
, existing
, &fe
.attr
, &i2
, perms
);
502 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
503 fe
.attr
.st_rdev
= new_encode_dev(fe
.attr
.st_rdev
);
504 fuse_reply_entry(req
, &fe
);
506 fuse_reply_err(req
, -r
);
509 // XXX NB, we dont iput(i2) because FUSE will do so in a matching
511 cfuse
->iput(i1
); // iput required
514 static void fuse_ll_rename(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
515 fuse_ino_t newparent
, const char *newname
516 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
521 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
522 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
523 Inode
*in
= cfuse
->iget(parent
);
524 Inode
*nin
= cfuse
->iget(newparent
);
525 UserPerm
perm(ctx
->uid
, ctx
->gid
);
526 get_fuse_groups(perm
, req
);
528 int r
= cfuse
->client
->ll_rename(in
, name
, nin
, newname
, perm
);
529 fuse_reply_err(req
, -r
);
531 cfuse
->iput(in
); // iputs required
535 static void fuse_ll_link(fuse_req_t req
, fuse_ino_t ino
, fuse_ino_t newparent
,
538 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
539 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
540 Inode
*in
= cfuse
->iget(ino
);
541 Inode
*nin
= cfuse
->iget(newparent
);
542 struct fuse_entry_param fe
;
544 memset(&fe
, 0, sizeof(fe
));
545 UserPerm
perm(ctx
->uid
, ctx
->gid
);
546 get_fuse_groups(perm
, req
);
549 * Note that we could successfully link, but then fail the subsequent
550 * getattr and return an error. Perhaps we should ignore getattr errors,
551 * but then how do we tell FUSE that the attrs are bogus?
553 int r
= cfuse
->client
->ll_link(in
, nin
, newname
, perm
);
555 r
= cfuse
->client
->ll_getattr(in
, &fe
.attr
, perm
);
557 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
558 fe
.attr
.st_rdev
= new_encode_dev(fe
.attr
.st_rdev
);
559 fuse_reply_entry(req
, &fe
);
565 * Many ll operations in libcephfs return an extra inode reference, but
566 * ll_link currently does not. Still, FUSE needs one for the new dentry,
567 * so we commandeer the reference taken earlier when ll_link is successful.
568 * On error however, we must put that reference.
571 fuse_reply_err(req
, -r
);
577 static void fuse_ll_open(fuse_req_t req
, fuse_ino_t ino
,
578 struct fuse_file_info
*fi
)
580 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
581 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
582 Inode
*in
= cfuse
->iget(ino
);
584 UserPerm
perms(ctx
->uid
, ctx
->gid
);
585 get_fuse_groups(perms
, req
);
587 int r
= cfuse
->client
->ll_open(in
, fi
->flags
, &fh
, perms
);
589 fi
->fh
= (uint64_t)fh
;
590 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
591 auto fuse_disable_pagecache
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
592 "fuse_disable_pagecache");
593 auto fuse_use_invalidate_cb
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
594 "fuse_use_invalidate_cb");
595 if (fuse_disable_pagecache
)
597 else if (fuse_use_invalidate_cb
)
600 fuse_reply_open(req
, fi
);
602 fuse_reply_err(req
, -r
);
605 cfuse
->iput(in
); // iput required
608 static void fuse_ll_read(fuse_req_t req
, fuse_ino_t ino
, size_t size
, off_t off
,
609 struct fuse_file_info
*fi
)
611 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
612 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
614 int r
= cfuse
->client
->ll_read(fh
, off
, size
, &bl
);
616 fuse_reply_buf(req
, bl
.c_str(), bl
.length());
618 fuse_reply_err(req
, -r
);
621 static void fuse_ll_write(fuse_req_t req
, fuse_ino_t ino
, const char *buf
,
622 size_t size
, off_t off
, struct fuse_file_info
*fi
)
624 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
625 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
626 int r
= cfuse
->client
->ll_write(fh
, off
, size
, buf
);
628 fuse_reply_write(req
, r
);
630 fuse_reply_err(req
, -r
);
633 static void fuse_ll_flush(fuse_req_t req
, fuse_ino_t ino
,
634 struct fuse_file_info
*fi
)
636 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
637 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
638 int r
= cfuse
->client
->ll_flush(fh
);
639 fuse_reply_err(req
, -r
);
642 #ifdef FUSE_IOCTL_COMPAT
643 static void fuse_ll_ioctl(fuse_req_t req
, fuse_ino_t ino
,
644 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 5)
649 void *arg
, struct fuse_file_info
*fi
,
650 unsigned flags
, const void *in_buf
, size_t in_bufsz
, size_t out_bufsz
)
652 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
654 if (flags
& FUSE_IOCTL_COMPAT
) {
655 fuse_reply_err(req
, ENOSYS
);
659 switch (static_cast<unsigned>(cmd
)) {
660 case CEPH_IOC_GET_LAYOUT
: {
661 file_layout_t layout
;
662 struct ceph_ioctl_layout l
;
663 Fh
*fh
= (Fh
*)fi
->fh
;
664 cfuse
->client
->ll_file_layout(fh
, &layout
);
665 l
.stripe_unit
= layout
.stripe_unit
;
666 l
.stripe_count
= layout
.stripe_count
;
667 l
.object_size
= layout
.object_size
;
668 l
.data_pool
= layout
.pool_id
;
669 fuse_reply_ioctl(req
, 0, &l
, sizeof(struct ceph_ioctl_layout
));
673 fuse_reply_err(req
, EINVAL
);
678 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
680 static void fuse_ll_fallocate(fuse_req_t req
, fuse_ino_t ino
, int mode
,
681 off_t offset
, off_t length
,
682 struct fuse_file_info
*fi
)
684 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
685 Fh
*fh
= (Fh
*)fi
->fh
;
686 int r
= cfuse
->client
->ll_fallocate(fh
, mode
, offset
, length
);
687 fuse_reply_err(req
, -r
);
692 static void fuse_ll_release(fuse_req_t req
, fuse_ino_t ino
,
693 struct fuse_file_info
*fi
)
695 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
696 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
697 int r
= cfuse
->client
->ll_release(fh
);
698 fuse_reply_err(req
, -r
);
701 static void fuse_ll_fsync(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
702 struct fuse_file_info
*fi
)
704 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
705 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
706 int r
= cfuse
->client
->ll_fsync(fh
, datasync
);
707 fuse_reply_err(req
, -r
);
710 struct readdir_context
{
714 size_t pos
; /* in buf */
719 * return 0 on success, -1 if out of space
721 static int fuse_ll_add_dirent(void *p
, struct dirent
*de
,
722 struct ceph_statx
*stx
, off_t next_off
,
725 struct readdir_context
*c
= (struct readdir_context
*)p
;
726 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)fuse_req_userdata(c
->req
);
729 st
.st_ino
= cfuse
->make_fake_ino(stx
->stx_ino
, c
->snap
);
730 st
.st_mode
= stx
->stx_mode
;
731 st
.st_rdev
= new_encode_dev(stx
->stx_rdev
);
733 size_t room
= c
->size
- c
->pos
;
734 size_t entrysize
= fuse_add_direntry(c
->req
, c
->buf
+ c
->pos
, room
,
735 de
->d_name
, &st
, next_off
);
736 if (entrysize
> room
)
744 static void fuse_ll_readdir(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
745 off_t off
, struct fuse_file_info
*fi
)
747 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
749 dir_result_t
*dirp
= reinterpret_cast<dir_result_t
*>(fi
->fh
);
750 cfuse
->client
->seekdir(dirp
, off
);
752 struct readdir_context rc
;
754 rc
.buf
= new char[size
];
757 rc
.snap
= cfuse
->fino_snap(ino
);
759 int r
= cfuse
->client
->readdir_r_cb(dirp
, fuse_ll_add_dirent
, &rc
);
760 if (r
== 0 || r
== -ENOSPC
) /* ignore ENOSPC from our callback */
761 fuse_reply_buf(req
, rc
.buf
, rc
.pos
);
763 fuse_reply_err(req
, -r
);
767 static void fuse_ll_releasedir(fuse_req_t req
, fuse_ino_t ino
,
768 struct fuse_file_info
*fi
)
770 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
771 dir_result_t
*dirp
= reinterpret_cast<dir_result_t
*>(fi
->fh
);
772 cfuse
->client
->ll_releasedir(dirp
);
773 fuse_reply_err(req
, 0);
776 static void fuse_ll_fsyncdir(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
777 struct fuse_file_info
*fi
)
779 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
780 dir_result_t
*dirp
= reinterpret_cast<dir_result_t
*>(fi
->fh
);
781 int r
= cfuse
->client
->ll_fsyncdir(dirp
);
782 fuse_reply_err(req
, -r
);
785 static void fuse_ll_access(fuse_req_t req
, fuse_ino_t ino
, int mask
)
787 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
788 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
789 Inode
*in
= cfuse
->iget(ino
);
790 UserPerm
perms(ctx
->uid
, ctx
->gid
);
791 get_fuse_groups(perms
, req
);
793 int r
= cfuse
->client
->inode_permission(in
, perms
, mask
);
794 fuse_reply_err(req
, -r
);
798 static void fuse_ll_create(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
799 mode_t mode
, struct fuse_file_info
*fi
)
801 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
802 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
803 Inode
*i1
= cfuse
->iget(parent
), *i2
;
804 struct fuse_entry_param fe
;
806 UserPerm
perms(ctx
->uid
, ctx
->gid
);
807 get_fuse_groups(perms
, req
);
809 memset(&fe
, 0, sizeof(fe
));
811 // pass &i2 for the created inode so that ll_create takes an initial ll_ref
812 int r
= cfuse
->client
->ll_create(i1
, name
, mode
, fi
->flags
, &fe
.attr
, &i2
,
815 fi
->fh
= (uint64_t)fh
;
816 fe
.ino
= cfuse
->make_fake_ino(fe
.attr
.st_ino
, fe
.attr
.st_dev
);
817 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
818 auto fuse_disable_pagecache
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
819 "fuse_disable_pagecache");
820 auto fuse_use_invalidate_cb
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
821 "fuse_use_invalidate_cb");
822 if (fuse_disable_pagecache
)
824 else if (fuse_use_invalidate_cb
)
827 fuse_reply_create(req
, &fe
, fi
);
829 fuse_reply_err(req
, -r
);
830 // XXX NB, we dont iput(i2) because FUSE will do so in a matching
832 cfuse
->iput(i1
); // iput required
835 static void fuse_ll_statfs(fuse_req_t req
, fuse_ino_t ino
)
837 struct statvfs stbuf
;
838 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
839 Inode
*in
= cfuse
->iget(ino
);
840 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
841 UserPerm
perms(ctx
->uid
, ctx
->gid
);
842 get_fuse_groups(perms
, req
);
844 int r
= cfuse
->client
->ll_statfs(in
, &stbuf
, perms
);
846 fuse_reply_statfs(req
, &stbuf
);
848 fuse_reply_err(req
, -r
);
850 cfuse
->iput(in
); // iput required
853 static void fuse_ll_getlk(fuse_req_t req
, fuse_ino_t ino
,
854 struct fuse_file_info
*fi
, struct flock
*lock
)
856 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
857 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
859 int r
= cfuse
->client
->ll_getlk(fh
, lock
, fi
->lock_owner
);
861 fuse_reply_lock(req
, lock
);
863 fuse_reply_err(req
, -r
);
866 static void fuse_ll_setlk(fuse_req_t req
, fuse_ino_t ino
,
867 struct fuse_file_info
*fi
, struct flock
*lock
, int sleep
)
869 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
870 Fh
*fh
= reinterpret_cast<Fh
*>(fi
->fh
);
872 // must use multithread if operation may block
873 auto fuse_multithreaded
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
874 "fuse_multithreaded");
875 if (!fuse_multithreaded
&& sleep
&& lock
->l_type
!= F_UNLCK
) {
876 fuse_reply_err(req
, EDEADLK
);
880 int r
= cfuse
->client
->ll_setlk(fh
, lock
, fi
->lock_owner
, sleep
);
881 fuse_reply_err(req
, -r
);
884 static void fuse_ll_interrupt(fuse_req_t req
, void* data
)
886 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
887 cfuse
->client
->ll_interrupt(data
);
890 static void switch_interrupt_cb(void *handle
, void* data
)
892 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)handle
;
893 fuse_req_t req
= cfuse
->get_fuse_req();
896 fuse_req_interrupt_func(req
, fuse_ll_interrupt
, data
);
898 fuse_req_interrupt_func(req
, NULL
, NULL
);
901 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
902 static void fuse_ll_flock(fuse_req_t req
, fuse_ino_t ino
,
903 struct fuse_file_info
*fi
, int cmd
)
905 CephFuse::Handle
*cfuse
= fuse_ll_req_prepare(req
);
906 Fh
*fh
= (Fh
*)fi
->fh
;
908 // must use multithread if operation may block
909 auto fuse_multithreaded
= cfuse
->client
->cct
->_conf
.get_val
<bool>(
910 "fuse_multithreaded");
911 if (!fuse_multithreaded
&& !(cmd
& (LOCK_NB
| LOCK_UN
))) {
912 fuse_reply_err(req
, EDEADLK
);
916 int r
= cfuse
->client
->ll_flock(fh
, cmd
, fi
->lock_owner
);
917 fuse_reply_err(req
, -r
);
921 #if !defined(__APPLE__)
922 static mode_t
umask_cb(void *handle
)
924 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)handle
;
925 fuse_req_t req
= cfuse
->get_fuse_req();
926 const struct fuse_ctx
*ctx
= fuse_req_ctx(req
);
931 static void ino_invalidate_cb(void *handle
, vinodeno_t vino
, int64_t off
,
934 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
935 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)handle
;
936 fuse_ino_t fino
= cfuse
->make_fake_ino(vino
.ino
, vino
.snapid
);
937 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
938 fuse_lowlevel_notify_inval_inode(cfuse
->se
, fino
, off
, len
);
940 fuse_lowlevel_notify_inval_inode(cfuse
->ch
, fino
, off
, len
);
945 static void dentry_invalidate_cb(void *handle
, vinodeno_t dirino
,
946 vinodeno_t ino
, const char *name
, size_t len
)
948 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)handle
;
949 fuse_ino_t fdirino
= cfuse
->make_fake_ino(dirino
.ino
, dirino
.snapid
);
950 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
952 if (ino
.ino
!= inodeno_t())
953 fino
= cfuse
->make_fake_ino(ino
.ino
, ino
.snapid
);
954 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
955 fuse_lowlevel_notify_delete(cfuse
->se
, fdirino
, fino
, name
, len
);
957 fuse_lowlevel_notify_delete(cfuse
->ch
, fdirino
, fino
, name
, len
);
959 #elif FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
960 fuse_lowlevel_notify_inval_entry(cfuse
->ch
, fdirino
, name
, len
);
964 static int remount_cb(void *handle
)
966 // used for trimming kernel dcache. when remounting a file system, linux kernel
967 // trims all unused dentries in the file system
968 char cmd
[128+PATH_MAX
];
969 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)handle
;
970 snprintf(cmd
, sizeof(cmd
), "LIBMOUNT_FSTAB=/dev/null mount -i -o remount %s",
971 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
972 cfuse
->opts
.mountpoint
);
977 if (r
!= 0 && r
!= -1) {
984 static void do_init(void *data
, fuse_conn_info
*conn
)
986 CephFuse::Handle
*cfuse
= (CephFuse::Handle
*)data
;
987 Client
*client
= cfuse
->client
;
989 #if !defined(__APPLE__)
990 if (!client
->fuse_default_permissions
&& client
->ll_handle_umask()) {
991 // apply umask in userspace if posix acl is enabled
992 if(conn
->capable
& FUSE_CAP_DONT_MASK
)
993 conn
->want
|= FUSE_CAP_DONT_MASK
;
995 if(conn
->capable
& FUSE_CAP_EXPORT_SUPPORT
)
996 conn
->want
|= FUSE_CAP_EXPORT_SUPPORT
;
999 if (cfuse
->fd_on_success
) {
1000 //cout << "fuse init signaling on fd " << fd_on_success << std::endl;
1001 // see Preforker::daemonize(), ceph-fuse's parent process expects a `-1`
1002 // from a daemonized child process.
1004 int err
= safe_write(cfuse
->fd_on_success
, &r
, sizeof(r
));
1006 derr
<< "fuse_ll: do_init: safe_write failed with error "
1007 << cpp_strerror(err
) << dendl
;
1010 //cout << "fuse init done signaling on fd " << fd_on_success << std::endl;
1012 // close stdout, etc.
1019 const static struct fuse_lowlevel_ops fuse_ll_oper
= {
1022 lookup
: fuse_ll_lookup
,
1023 forget
: fuse_ll_forget
,
1024 getattr
: fuse_ll_getattr
,
1025 setattr
: fuse_ll_setattr
,
1026 readlink
: fuse_ll_readlink
,
1027 mknod
: fuse_ll_mknod
,
1028 mkdir
: fuse_ll_mkdir
,
1029 unlink
: fuse_ll_unlink
,
1030 rmdir
: fuse_ll_rmdir
,
1031 symlink
: fuse_ll_symlink
,
1032 rename
: fuse_ll_rename
,
1036 write
: fuse_ll_write
,
1037 flush
: fuse_ll_flush
,
1038 release
: fuse_ll_release
,
1039 fsync
: fuse_ll_fsync
,
1040 opendir
: fuse_ll_opendir
,
1041 readdir
: fuse_ll_readdir
,
1042 releasedir
: fuse_ll_releasedir
,
1043 fsyncdir
: fuse_ll_fsyncdir
,
1044 statfs
: fuse_ll_statfs
,
1045 setxattr
: fuse_ll_setxattr
,
1046 getxattr
: fuse_ll_getxattr
,
1047 listxattr
: fuse_ll_listxattr
,
1048 removexattr
: fuse_ll_removexattr
,
1049 access
: fuse_ll_access
,
1050 create
: fuse_ll_create
,
1051 getlk
: fuse_ll_getlk
,
1052 setlk
: fuse_ll_setlk
,
1054 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
1055 #ifdef FUSE_IOCTL_COMPAT
1056 ioctl
: fuse_ll_ioctl
,
1062 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
1066 flock
: fuse_ll_flock
,
1068 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
1069 fallocate
: fuse_ll_fallocate
1074 CephFuse::Handle::Handle(Client
*c
, int fd
) :
1078 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
1084 snap_stag_map
[CEPH_NOSNAP
] = 0;
1085 stag_snap_map
[0] = CEPH_NOSNAP
;
1086 memset(&args
, 0, sizeof(args
));
1087 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1088 memset(&opts
, 0, sizeof(opts
));
1092 CephFuse::Handle::~Handle()
1094 fuse_opt_free_args(&args
);
1097 void CephFuse::Handle::finalize()
1099 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1101 fuse_remove_signal_handlers(se
);
1102 fuse_session_unmount(se
);
1103 fuse_session_destroy(se
);
1105 if (opts
.mountpoint
)
1106 free(opts
.mountpoint
);
1109 fuse_remove_signal_handlers(se
);
1111 fuse_session_remove_chan(ch
);
1113 fuse_session_destroy(se
);
1115 fuse_unmount(mountpoint
, ch
);
1118 pthread_key_delete(fuse_req_key
);
1121 int CephFuse::Handle::init(int argc
, const char *argv
[])
1124 int r
= pthread_key_create(&fuse_req_key
, NULL
);
1126 derr
<< "pthread_key_create failed." << dendl
;
1130 // set up fuse argc/argv
1132 const char **newargv
= (const char **) malloc((argc
+ 10) * sizeof(char *));
1136 newargv
[newargc
++] = argv
[0];
1137 newargv
[newargc
++] = "-f"; // stay in foreground
1139 auto fuse_allow_other
= client
->cct
->_conf
.get_val
<bool>(
1140 "fuse_allow_other");
1141 auto fuse_default_permissions
= client
->cct
->_conf
.get_val
<bool>(
1142 "fuse_default_permissions");
1143 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
1144 auto fuse_big_writes
= client
->cct
->_conf
.get_val
<bool>(
1146 auto fuse_max_write
= client
->cct
->_conf
.get_val
<Option::size_t>(
1148 auto fuse_atomic_o_trunc
= client
->cct
->_conf
.get_val
<bool>(
1149 "fuse_atomic_o_trunc");
1151 auto fuse_debug
= client
->cct
->_conf
.get_val
<bool>(
1154 if (fuse_allow_other
) {
1155 newargv
[newargc
++] = "-o";
1156 newargv
[newargc
++] = "allow_other";
1158 if (fuse_default_permissions
) {
1159 newargv
[newargc
++] = "-o";
1160 newargv
[newargc
++] = "default_permissions";
1162 #if defined(__linux__)
1163 #if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
1164 if (fuse_big_writes
) {
1165 newargv
[newargc
++] = "-o";
1166 newargv
[newargc
++] = "big_writes";
1168 if (fuse_max_write
> 0) {
1170 newargv
[newargc
++] = "-o";
1171 newargv
[newargc
++] = strsplice
;
1172 sprintf(strsplice
, "max_write=%zu", (size_t)fuse_max_write
);
1173 newargv
[newargc
++] = strsplice
;
1175 if (fuse_atomic_o_trunc
) {
1176 newargv
[newargc
++] = "-o";
1177 newargv
[newargc
++] = "atomic_o_trunc";
1182 newargv
[newargc
++] = "-d";
1184 for (int argctr
= 1; argctr
< argc
; argctr
++)
1185 newargv
[newargc
++] = argv
[argctr
];
1187 derr
<< "init, newargv = " << newargv
<< " newargc=" << newargc
<< dendl
;
1188 struct fuse_args a
= FUSE_ARGS_INIT(newargc
, (char**)newargv
);
1189 args
= a
; // Roundabout construction b/c FUSE_ARGS_INIT is for initialization not assignment
1191 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1192 if (fuse_parse_cmdline(&args
, &opts
) == -1) {
1194 if (fuse_parse_cmdline(&args
, &mountpoint
, NULL
, NULL
) == -1) {
1196 derr
<< "fuse_parse_cmdline failed." << dendl
;
1197 fuse_opt_free_args(&args
);
1202 ceph_assert(args
.allocated
); // Checking fuse has realloc'd args so we can free newargv
1207 int CephFuse::Handle::start()
1209 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1210 se
= fuse_session_new(&args
, &fuse_ll_oper
, sizeof(fuse_ll_oper
), this);
1212 ch
= fuse_mount(mountpoint
, &args
);
1214 derr
<< "fuse_mount(mountpoint=" << mountpoint
<< ") failed." << dendl
;
1218 se
= fuse_lowlevel_new(&args
, &fuse_ll_oper
, sizeof(fuse_ll_oper
), this);
1221 derr
<< "fuse_lowlevel_new failed" << dendl
;
1225 signal(SIGTERM
, SIG_DFL
);
1226 signal(SIGINT
, SIG_DFL
);
1227 if (fuse_set_signal_handlers(se
) == -1) {
1228 derr
<< "fuse_set_signal_handlers failed" << dendl
;
1232 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1233 if (fuse_session_mount(se
, opts
.mountpoint
) != 0) {
1234 derr
<< "fuse_session_mount failed" << dendl
;
1238 fuse_session_add_chan(se
, ch
);
1242 struct ceph_client_callback_args args
= {
1244 ino_cb
: client
->cct
->_conf
.get_val
<bool>("fuse_use_invalidate_cb") ?
1245 ino_invalidate_cb
: NULL
,
1246 dentry_cb
: dentry_invalidate_cb
,
1247 switch_intr_cb
: switch_interrupt_cb
,
1248 #if defined(__linux__)
1249 remount_cb
: remount_cb
,
1251 #if !defined(__APPLE__)
1255 client
->ll_register_callbacks(&args
);
1260 int CephFuse::Handle::loop()
1262 auto fuse_multithreaded
= client
->cct
->_conf
.get_val
<bool>(
1263 "fuse_multithreaded");
1264 if (fuse_multithreaded
) {
1265 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 1)
1267 struct fuse_loop_config conf
= { 0 };
1269 conf
.clone_fd
= opts
.clone_fd
;
1270 return fuse_session_loop_mt(se
, &conf
);
1272 #elif FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1273 return fuse_session_loop_mt(se
, opts
.clone_fd
);
1275 return fuse_session_loop_mt(se
);
1278 return fuse_session_loop(se
);
1282 uint64_t CephFuse::Handle::fino_snap(uint64_t fino
)
1284 if (fino
== FUSE_ROOT_ID
)
1287 if (client
->use_faked_inos()) {
1288 vinodeno_t vino
= client
->map_faked_ino(fino
);
1291 std::lock_guard
l(stag_lock
);
1292 uint64_t stag
= FINO_STAG(fino
);
1293 ceph_assert(stag_snap_map
.count(stag
));
1294 return stag_snap_map
[stag
];
1298 Inode
* CephFuse::Handle::iget(fuse_ino_t fino
)
1300 if (fino
== FUSE_ROOT_ID
)
1301 return client
->get_root();
1303 if (client
->use_faked_inos()) {
1304 return client
->ll_get_inode((ino_t
)fino
);
1306 vinodeno_t
vino(FINO_INO(fino
), fino_snap(fino
));
1307 return client
->ll_get_inode(vino
);
1311 void CephFuse::Handle::iput(Inode
*in
)
1316 uint64_t CephFuse::Handle::make_fake_ino(inodeno_t ino
, snapid_t snapid
)
1318 if (client
->use_faked_inos()) {
1319 // already faked by libcephfs
1320 if (ino
== client
->get_root_ino())
1321 return FUSE_ROOT_ID
;
1325 if (snapid
== CEPH_NOSNAP
&& ino
== client
->get_root_ino())
1326 return FUSE_ROOT_ID
;
1328 std::lock_guard
l(stag_lock
);
1329 auto p
= snap_stag_map
.find(snapid
);
1330 if (p
!= snap_stag_map
.end()) {
1331 inodeno_t fino
= MAKE_FINO(ino
, p
->second
);
1335 int first
= last_stag
& STAG_MASK
;
1336 int stag
= (++last_stag
) & STAG_MASK
;
1337 for (; stag
!= first
; stag
= (++last_stag
) & STAG_MASK
) {
1341 auto p
= stag_snap_map
.find(stag
);
1342 if (p
== stag_snap_map
.end()) {
1343 snap_stag_map
[snapid
] = stag
;
1344 stag_snap_map
[stag
] = snapid
;
1348 if (!client
->ll_get_snap_ref(p
->second
)) {
1349 snap_stag_map
.erase(p
->second
);
1350 snap_stag_map
[snapid
] = stag
;
1356 ceph_abort_msg("run out of stag");
1358 inodeno_t fino
= MAKE_FINO(ino
, stag
);
1359 //cout << "make_fake_ino " << ino << "." << snapid << " -> " << fino << std::endl;
1364 void CephFuse::Handle::set_fuse_req(fuse_req_t req
)
1366 pthread_setspecific(fuse_req_key
, (void*)req
);
1369 fuse_req_t
CephFuse::Handle::get_fuse_req()
1371 return (fuse_req_t
) pthread_getspecific(fuse_req_key
);
1375 CephFuse::CephFuse(Client
*c
, int fd
) : _handle(new CephFuse::Handle(c
, fd
))
1379 CephFuse::~CephFuse()
1384 int CephFuse::init(int argc
, const char *argv
[])
1386 return _handle
->init(argc
, argv
);
1389 int CephFuse::start()
1391 return _handle
->start();
1394 int CephFuse::loop()
1396 return _handle
->loop();
1399 void CephFuse::finalize()
1401 return _handle
->finalize();
1404 std::string
CephFuse::get_mount_point() const
1406 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1407 if (_handle
->opts
.mountpoint
) {
1408 return _handle
->opts
.mountpoint
;
1410 if (_handle
->mountpoint
) {
1411 return _handle
->mountpoint
;