]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph-fuse: link to libfuse3 if fuse3 is installed 34531/head
authorXiubo Li <xiubli@redhat.com>
Wed, 15 Apr 2020 06:21:44 +0000 (02:21 -0400)
committerXiubo Li <xiubli@redhat.com>
Sat, 18 Apr 2020 09:57:29 +0000 (05:57 -0400)
Fixes: https://tracker.ceph.com/issues/44891
Signed-off-by: Xiubo Li <xiubli@redhat.com>
src/ceph_fuse.cc
src/client/fuse_ll.cc
src/include/ceph_fuse.h [new file with mode: 0644]
src/os/FuseStore.cc
src/rbd_fuse/rbd-fuse.cc

index 5ac18116f12cddbc0157076745937e1850bea0e6..9d6141c1eaa4c5434b4d0174bbaffc53c100a6e0 100644 (file)
@@ -41,6 +41,7 @@
 #include <fcntl.h>
 
 #include <fuse.h>
+#include <fuse_lowlevel.h>
 
 #define dout_context g_ceph_context
 
@@ -51,7 +52,12 @@ static void fuse_usage()
     "-h",
   };
   struct fuse_args args = FUSE_ARGS_INIT(2, (char**)argv);
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  struct fuse_cmdline_opts opts = {};
+  if (fuse_parse_cmdline(&args, &opts) == -1) {
+#else
   if (fuse_parse_cmdline(&args, nullptr, nullptr, nullptr) == -1) {
+#endif
     derr << "fuse_parse_cmdline failed." << dendl;
   }
   ceph_assert(args.allocated);
@@ -105,7 +111,12 @@ int main(int argc, const char **argv, const char *envp[]) {
       };
 
       struct fuse_args fargs = FUSE_ARGS_INIT(2, (char**)tmpargv);
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+      struct fuse_cmdline_opts opts = {};
+      if (fuse_parse_cmdline(&fargs, &opts) == -1) {
+#else
       if (fuse_parse_cmdline(&fargs, nullptr, nullptr, nullptr) == -1) {
+#endif
        derr << "fuse_parse_cmdline failed." << dendl;
       }
       ceph_assert(fargs.allocated);
index e1f2a10d701dabfa8c94a5da099538310c3d74f0..06af444f1b2f5fecf7b8c33543758e21be8f6f60 100644 (file)
@@ -85,9 +85,13 @@ public:
   int fd_on_success;
   Client *client;
 
-  struct fuse_chan *ch;
   struct fuse_session *se;
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  struct fuse_cmdline_opts opts;
+#else
+  struct fuse_chan *ch;
   char *mountpoint;
+#endif
 
   ceph::mutex stag_lock = ceph::make_mutex("fuse_ll.cc stag_lock");
   int last_stag;
@@ -418,7 +422,11 @@ static void fuse_ll_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
   if (cfuse->fino_snap(parent) == CEPH_SNAPDIR &&
       fuse_multithreaded && fuse_syncfs_on_mksnap) {
     int err = 0;
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+    int fd = ::open(cfuse->opts.mountpoint, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+#else
     int fd = ::open(cfuse->mountpoint, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+#endif
     if (fd < 0) {
       err = errno;
     } else {
@@ -504,7 +512,11 @@ static void fuse_ll_symlink(fuse_req_t req, const char *existing,
 }
 
 static void fuse_ll_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
-                          fuse_ino_t newparent, const char *newname)
+                          fuse_ino_t newparent, const char *newname
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                           , unsigned int flags
+#endif
+                           )
 {
   CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
   const struct fuse_ctx *ctx = fuse_req_ctx(req);
@@ -916,8 +928,12 @@ static void ino_invalidate_cb(void *handle, vinodeno_t vino, int64_t off,
 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
   CephFuse::Handle *cfuse = (CephFuse::Handle *)handle;
   fuse_ino_t fino = cfuse->make_fake_ino(vino.ino, vino.snapid);
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  fuse_lowlevel_notify_inval_inode(cfuse->se, fino, off, len);
+#else
   fuse_lowlevel_notify_inval_inode(cfuse->ch, fino, off, len);
 #endif
+#endif
 }
 
 static void dentry_invalidate_cb(void *handle, vinodeno_t dirino,
@@ -929,7 +945,11 @@ static void dentry_invalidate_cb(void *handle, vinodeno_t dirino,
   fuse_ino_t fino = 0;
   if (ino.ino != inodeno_t())
     fino = cfuse->make_fake_ino(ino.ino, ino.snapid);
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  fuse_lowlevel_notify_delete(cfuse->se, fdirino, fino, name.c_str(), name.length());
+#else
   fuse_lowlevel_notify_delete(cfuse->ch, fdirino, fino, name.c_str(), name.length());
+#endif
 #elif FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
   fuse_lowlevel_notify_inval_entry(cfuse->ch, fdirino, name.c_str(), name.length());
 #endif
@@ -941,7 +961,12 @@ static int remount_cb(void *handle)
   // trims all unused dentries in the file system
   char cmd[128+PATH_MAX];
   CephFuse::Handle *cfuse = (CephFuse::Handle *)handle;
-  snprintf(cmd, sizeof(cmd), "LIBMOUNT_FSTAB=/dev/null mount -i -o remount %s", cfuse->mountpoint);
+  snprintf(cmd, sizeof(cmd), "LIBMOUNT_FSTAB=/dev/null mount -i -o remount %s",
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                  cfuse->opts.mountpoint);
+#else
+                  cfuse->mountpoint);
+#endif
   int r = system(cmd);
   if (r != 0 && r != -1) {
     r = WEXITSTATUS(r);
@@ -1043,14 +1068,19 @@ const static struct fuse_lowlevel_ops fuse_ll_oper = {
 CephFuse::Handle::Handle(Client *c, int fd) :
   fd_on_success(fd),
   client(c),
-  ch(NULL),
   se(NULL),
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
+  ch(NULL),
   mountpoint(NULL),
+#endif
   last_stag(0)
 {
   snap_stag_map[CEPH_NOSNAP] = 0;
   stag_snap_map[0] = CEPH_NOSNAP;
   memset(&args, 0, sizeof(args));
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  memset(&opts, 0, sizeof(opts));
+#endif
 }
 
 CephFuse::Handle::~Handle()
@@ -1060,6 +1090,15 @@ CephFuse::Handle::~Handle()
 
 void CephFuse::Handle::finalize()
 {
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  if (se) {
+    fuse_remove_signal_handlers(se);
+    fuse_session_unmount(se);
+    fuse_session_destroy(se);
+  }
+  if (opts.mountpoint)
+    free(opts.mountpoint);
+#else
   if (se)
     fuse_remove_signal_handlers(se);
   if (ch)
@@ -1068,6 +1107,7 @@ void CephFuse::Handle::finalize()
     fuse_session_destroy(se);
   if (ch)
     fuse_unmount(mountpoint, ch);
+#endif
 
   pthread_key_delete(fuse_req_key);
 }
@@ -1094,14 +1134,16 @@ int CephFuse::Handle::init(int argc, const char *argv[])
     "fuse_allow_other");
   auto fuse_default_permissions = client->cct->_conf.get_val<bool>(
     "fuse_default_permissions");
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
   auto fuse_big_writes = client->cct->_conf.get_val<bool>(
     "fuse_big_writes");
+  auto fuse_max_write = client->cct->_conf.get_val<Option::size_t>(
+    "fuse_max_write");
   auto fuse_atomic_o_trunc = client->cct->_conf.get_val<bool>(
     "fuse_atomic_o_trunc");
+#endif
   auto fuse_debug = client->cct->_conf.get_val<bool>(
     "fuse_debug");
-  auto fuse_max_write = client->cct->_conf.get_val<Option::size_t>(
-    "fuse_max_write");
 
   if (fuse_allow_other) {
     newargv[newargc++] = "-o";
@@ -1112,6 +1154,7 @@ int CephFuse::Handle::init(int argc, const char *argv[])
     newargv[newargc++] = "default_permissions";
   }
 #if defined(__linux__)
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
   if (fuse_big_writes) {
     newargv[newargc++] = "-o";
     newargv[newargc++] = "big_writes";
@@ -1126,6 +1169,7 @@ int CephFuse::Handle::init(int argc, const char *argv[])
     newargv[newargc++] = "-o";
     newargv[newargc++] = "atomic_o_trunc";
   }
+#endif
 #endif
   if (fuse_debug)
     newargv[newargc++] = "-d";
@@ -1137,7 +1181,11 @@ int CephFuse::Handle::init(int argc, const char *argv[])
   struct fuse_args a = FUSE_ARGS_INIT(newargc, (char**)newargv);
   args = a;  // Roundabout construction b/c FUSE_ARGS_INIT is for initialization not assignment
 
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  if (fuse_parse_cmdline(&args, &opts) == -1) {
+#else
   if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) == -1) {
+#endif
     derr << "fuse_parse_cmdline failed." << dendl;
     fuse_opt_free_args(&args);
     free(newargv);
@@ -1151,6 +1199,9 @@ int CephFuse::Handle::init(int argc, const char *argv[])
 
 int CephFuse::Handle::start()
 {
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  se = fuse_session_new(&args, &fuse_ll_oper, sizeof(fuse_ll_oper), this);
+#else
   ch = fuse_mount(mountpoint, &args);
   if (!ch) {
     derr << "fuse_mount(mountpoint=" << mountpoint << ") failed." << dendl;
@@ -1158,6 +1209,7 @@ int CephFuse::Handle::start()
   }
 
   se = fuse_lowlevel_new(&args, &fuse_ll_oper, sizeof(fuse_ll_oper), this);
+#endif
   if (!se) {
     derr << "fuse_lowlevel_new failed" << dendl;
     return EDOM;
@@ -1170,7 +1222,14 @@ int CephFuse::Handle::start()
     return ENOSYS;
   }
 
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  if (fuse_session_mount(se, opts.mountpoint) != 0) {
+    derr << "fuse_session_mount failed" << dendl;
+    return ENOSYS;
+  }
+#else
   fuse_session_add_chan(se, ch);
+#endif
 
 
   struct client_callback_args args = {
@@ -1196,7 +1255,11 @@ int CephFuse::Handle::loop()
   auto fuse_multithreaded = client->cct->_conf.get_val<bool>(
     "fuse_multithreaded");
   if (fuse_multithreaded) {
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+    return fuse_session_loop_mt(se, opts.clone_fd);
+#else
     return fuse_session_loop_mt(se);
+#endif
   } else {
     return fuse_session_loop(se);
   }
@@ -1326,8 +1389,13 @@ void CephFuse::finalize()
 
 std::string CephFuse::get_mount_point() const
 {
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  if (_handle->opts.mountpoint) {
+    return _handle->opts.mountpoint;
+#else
   if (_handle->mountpoint) {
     return _handle->mountpoint;
+#endif
   } else {
     return "";
   }
diff --git a/src/include/ceph_fuse.h b/src/include/ceph_fuse.h
new file mode 100644 (file)
index 0000000..4588193
--- /dev/null
@@ -0,0 +1,32 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2012 Inktank Storage, Inc.
+ * Copyright (C) 2014 Red Hat <contact@redhat.com>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software 
+ * Foundation.  See file COPYING.
+ */
+#ifndef CEPH_FUSE_H
+#define CEPH_FUSE_H
+
+#define FUSE_USE_VERSION 30
+#include "acconfig.h"
+#include <fuse.h>
+
+static inline int filler_compat(fuse_fill_dir_t filler,
+                                void *buf, const char *name,
+                                const struct stat *stbuf,
+                                off_t off)
+{
+  return filler(buf, name, stbuf, off
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                , static_cast<enum fuse_fill_dir_flags>(0)
+#endif
+        );
+}
+#endif /* CEPH_FUSE_H */
index 98d4b12d3286a578fa7cf6f22a00b33675f35e08..35755f737f17d2f7d3ba1dca6d88e40de7ab45fb 100644 (file)
@@ -9,6 +9,8 @@
 
 #define FUSE_USE_VERSION 30
 #include <fuse.h>
+#include <fuse_lowlevel.h>
+#include "include/ceph_fuse.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -40,7 +42,9 @@ using ceph::bufferptr;
 struct fs_info {
   struct fuse_args args;
   struct fuse *f;
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
   struct fuse_chan *ch;
+#endif
   char *mountpoint;
 };
 
@@ -238,7 +242,11 @@ static int parse_fn(CephContext* cct, const char *path, coll_t *cid,
 }
 
 
-static int os_getattr(const char *path, struct stat *stbuf)
+static int os_getattr(const char *path, struct stat *stbuf
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                      , struct fuse_file_info *fi
+#endif
+                      )
 {
   fuse_context *fc = fuse_get_context();
   FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
@@ -395,7 +403,11 @@ static int os_readdir(const char *path,
                      void *buf,
                      fuse_fill_dir_t filler,
                      off_t offset,
-                     struct fuse_file_info *fi)
+                     struct fuse_file_info *fi
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                      , enum fuse_readdir_flags
+#endif
+                      )
 {
   fuse_context *fc = fuse_get_context();
   FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
@@ -420,11 +432,11 @@ static int os_readdir(const char *path,
   switch (t) {
   case FN_ROOT:
     {
-      filler(buf, "type", NULL, 0);
+      filler_compat(filler, buf, "type", NULL, 0);
       vector<coll_t> cls;
       fs->store->list_collections(cls);
       for (auto c : cls) {
-       int r = filler(buf, stringify(c).c_str(), NULL, 0);
+       int r = filler_compat(filler, buf, stringify(c).c_str(), NULL, 0);
        if (r > 0)
          break;
       }
@@ -436,28 +448,28 @@ static int os_readdir(const char *path,
       if (!ch) {
        return -ENOENT;
       }
-      filler(buf, "bitwise_hash_start", NULL, 0);
+      filler_compat(filler, buf, "bitwise_hash_start", NULL, 0);
       if (fs->store->collection_bits(ch) >= 0) {
-       filler(buf, "bitwise_hash_end", NULL, 0);
-       filler(buf, "bitwise_hash_bits", NULL, 0);
+       filler_compat(filler, buf, "bitwise_hash_end", NULL, 0);
+       filler_compat(filler, buf, "bitwise_hash_bits", NULL, 0);
       }
-      filler(buf, "all", NULL, 0);
-      filler(buf, "by_bitwise_hash", NULL, 0);
+      filler_compat(filler, buf, "all", NULL, 0);
+      filler_compat(filler, buf, "by_bitwise_hash", NULL, 0);
       spg_t pgid;
       if (cid.is_pg(&pgid) &&
          fs->store->exists(ch, pgid.make_pgmeta_oid())) {
-       filler(buf, "pgmeta", NULL, 0);
+       filler_compat(filler, buf, "pgmeta", NULL, 0);
       }
     }
     break;
 
   case FN_OBJECT:
     {
-      filler(buf, "bitwise_hash", NULL, 0);
-      filler(buf, "data", NULL, 0);
-      filler(buf, "omap", NULL, 0);
-      filler(buf, "attr", NULL, 0);
-      filler(buf, "omap_header", NULL, 0);
+      filler_compat(filler, buf, "bitwise_hash", NULL, 0);
+      filler_compat(filler, buf, "data", NULL, 0);
+      filler_compat(filler, buf, "omap", NULL, 0);
+      filler_compat(filler, buf, "attr", NULL, 0);
+      filler_compat(filler, buf, "omap_header", NULL, 0);
     }
     break;
 
@@ -512,7 +524,7 @@ static int os_readdir(const char *path,
          uint64_t cur_off = ((uint64_t)bitwise_hash << hash_shift) |
            (uint64_t)hashoff;
          string s = stringify(p);
-         r = filler(buf, s.c_str(), NULL, cur_off);
+         r = filler_compat(filler, buf, s.c_str(), NULL, cur_off);
          if (r)
            break;
        }
@@ -535,7 +547,7 @@ static int os_readdir(const char *path,
          continue;
        }
        ++offset;
-       int r = filler(buf, k.c_str(), NULL, offset);
+       int r = filler_compat(filler, buf, k.c_str(), NULL, offset);
        if (r)
          break;
       }
@@ -553,7 +565,7 @@ static int os_readdir(const char *path,
          continue;
        }
        ++offset;
-       int r = filler(buf, a.first.c_str(), NULL, offset);
+       int r = filler_compat(filler, buf, a.first.c_str(), NULL, offset);
        if (r)
          break;
       }
@@ -790,7 +802,11 @@ static int os_mkdir(const char *path, mode_t mode)
   return 0;
 }
 
-static int os_chmod(const char *path, mode_t mode)
+static int os_chmod(const char *path, mode_t mode
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                    , struct fuse_file_info *fi
+#endif
+                    )
 {
   fuse_context *fc = fuse_get_context();
   FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
@@ -1061,7 +1077,11 @@ static int os_unlink(const char *path)
   return 0;
 }
 
-static int os_truncate(const char *path, off_t size)
+static int os_truncate(const char *path, off_t size
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                       , struct fuse_file_info *fi
+#endif
+                       )
 {
   fuse_context *fc = fuse_get_context();
   FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
@@ -1127,7 +1147,9 @@ static int os_statfs(const char *path, struct statvfs *stbuf)
 static struct fuse_operations fs_oper = {
   getattr: os_getattr,
   readlink: 0,
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
   getdir: 0,
+#endif
   mknod: 0,
   mkdir: os_mkdir,
   unlink: os_unlink,
@@ -1138,7 +1160,9 @@ static struct fuse_operations fs_oper = {
   chmod: os_chmod,
   chown: 0,
   truncate: os_truncate,
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
   utime: 0,
+#endif
   open: os_open,
   read: os_read,
   write: os_write,
@@ -1187,16 +1211,38 @@ int FuseStore::start()
     "-d", // debug
   };
   int c = 3;
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  int rc;
+  struct fuse_cmdline_opts opts = {};
+#endif
   auto fuse_debug = store->cct->_conf.get_val<bool>("fuse_debug");
   if (fuse_debug)
     ++c;
   fuse_args a = FUSE_ARGS_INIT(c, (char**)v);
   info->args = a;
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  if (fuse_parse_cmdline(&info->args, &opts) == -1) {
+#else
   if (fuse_parse_cmdline(&info->args, &info->mountpoint, NULL, NULL) == -1) {
+#endif
     derr << __func__ << " failed to parse args" << dendl;
     return -EINVAL;
   }
 
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  info->mountpoint = opts.mountpoint;
+  info->f = fuse_new(&info->args, &fs_oper, sizeof(fs_oper), (void*)this);
+  if (!info->f) {
+    derr << __func__ << " fuse_new failed" << dendl;
+    return -EIO;
+  }
+
+  rc = fuse_mount(info->f, info->mountpoint);
+  if (rc != 0) {
+    derr << __func__ << " fuse_mount failed" << dendl;
+    return -EIO;
+  }
+#else
   info->ch = fuse_mount(info->mountpoint, &info->args);
   if (!info->ch) {
     derr << __func__ << " fuse_mount failed" << dendl;
@@ -1210,6 +1256,7 @@ int FuseStore::start()
     derr << __func__ << " fuse_new failed" << dendl;
     return -EIO;
   }
+#endif
 
   fuse_thread.create("fusestore");
   dout(10) << __func__ << " done" << dendl;
@@ -1229,7 +1276,11 @@ int FuseStore::loop()
 int FuseStore::stop()
 {
   dout(10) << __func__ << " enter" << dendl;
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+  fuse_unmount(info->f);
+#else
   fuse_unmount(info->mountpoint, info->ch);
+#endif
   fuse_thread.join();
   fuse_destroy(info->f);
   dout(10) << __func__ << " exit" << dendl;
index b7feea7bfd0bcabc2e3379d58c4d311cfc2f3b44..e7c8166542a7dd849711c17f7ee959c4ac6ec0b2 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "common/ceph_argparse.h"
 #include "common/ceph_context.h"
+#include "include/ceph_fuse.h"
 
 #include "global/global_init.h"
 #include "global/global_context.h"
@@ -244,7 +245,11 @@ static int count_images(void)
 
 extern "C" {
 
-static int rbdfs_getattr(const char *path, struct stat *stbuf)
+static int rbdfs_getattr(const char *path, struct stat *stbuf
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                         , struct fuse_file_info *fi
+#endif
+                        )
 {
        int fd;
        time_t now;
@@ -456,11 +461,15 @@ static void rbdfs_readdir_cb(void *_info, const char *name)
 {
        struct rbdfs_readdir_info *info = (struct rbdfs_readdir_info*) _info;
 
-       info->filler(info->buf, name, NULL, 0);
+        filler_compat(info->filler, info->buf, name, NULL, 0);
 }
 
 static int rbdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
-                          off_t offset, struct fuse_file_info *fi)
+                        off_t offset, struct fuse_file_info *fi
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+                         , enum fuse_readdir_flags
+#endif
+                         )
 {
        struct rbdfs_readdir_info info = { buf, filler };
 
@@ -472,8 +481,8 @@ static int rbdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
        if (strcmp(path, "/") != 0)
                return -ENOENT;
 
-       filler(buf, ".", NULL, 0);
-       filler(buf, "..", NULL, 0);
+       filler_compat(filler, buf, ".", NULL, 0);
+       filler_compat(filler, buf, "..", NULL, 0);
        iter_images(&info, rbdfs_readdir_cb);
 
        return 0;
@@ -488,7 +497,11 @@ static int rbdfs_releasedir(const char *path, struct fuse_file_info *fi)
 }
 
 void *
-rbdfs_init(struct fuse_conn_info *conn)
+rbdfs_init(struct fuse_conn_info *conn
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+           , struct fuse_config *cfg
+#endif
+          )
 {
        int ret;
 
@@ -570,7 +583,11 @@ rbdfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
 }
 
 int
-rbdfs_rename(const char *path, const char *destname)
+rbdfs_rename(const char *path, const char *destname
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+             , unsigned int flags
+#endif
+            )
 {
     int r;
 
@@ -587,7 +604,11 @@ rbdfs_rename(const char *path, const char *destname)
 }
 
 int
-rbdfs_utimens(const char *path, const struct timespec tv[2])
+rbdfs_utimens(const char *path, const struct timespec tv[2]
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+              , struct fuse_file_info *fi
+#endif
+             )
 {
        // called on create; not relevant
        return 0;
@@ -609,7 +630,11 @@ rbdfs_unlink(const char *path)
 
 
 int
-rbdfs_truncate(const char *path, off_t size)
+rbdfs_truncate(const char *path, off_t size
+#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
+               , struct fuse_file_info *fi
+#endif
+              )
 {
        int fd;
        int r;
@@ -724,7 +749,9 @@ rbdfs_listxattr(const char *path, char *list, size_t len)
 const static struct fuse_operations rbdfs_oper = {
   getattr:    rbdfs_getattr,
   readlink:   0,
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
   getdir:     0,
+#endif
   mknod:      0,
   mkdir:      0,
   unlink:     rbdfs_unlink,
@@ -757,8 +784,10 @@ const static struct fuse_operations rbdfs_oper = {
   destroy:    rbdfs_destroy,
   access:     0,
   create:     rbdfs_create,
+#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
   ftruncate:  0,
   fgetattr:   0,
+#endif
   lock:       0,
   utimens:    rbdfs_utimens,
   /* skip unimplemented */