Snap for 8564071 from 63199a4c44c372d70a78c3a24badecde54344b4c to mainline-tethering-release

Change-Id: I794b54f2085795633d30dbeb4d525438dcaffb58
diff --git a/AUTHORS b/AUTHORS
index 2bee369..050d953 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -17,18 +17,26 @@
 following people have contributed patches (autogenerated list):
 
 1c7718e7 <shirokovMartin@gmail.com>
+a1346054 <36859588+a1346054@users.noreply.github.com>
 admorgan <admorgan@morgancomputers.net>
 Ahmed Masud <ahmed.masud@trustifier.com>
+AKowshik <AKowshik@users.noreply.github.com>
 Alan Somers <asomers@gmail.com>
+Albert Chen <58009229+hselin-kalista-io@users.noreply.github.com>
 Albert Chen <hselin.chen@gmail.com>
 Alexander <aleksandr.rvachev@eltex-co.ru>
 alex <devkral@web.de>
 Alex Richman <alex@richman.io>
+Amir Goldstein <amir73il@gmail.com>
 amosonn <amosonn@gmail.com>
 Anatol Pomozov <anatol.pomozov@gmail.com>
+Andrew Gaul <andrew@gaul.org>
+Andrew Gaul <gaul@google.com>
 Angelo G. Del Regno <kholk11@gmail.com>
+Anthony Rebello <rebello.anthony@gmail.com>
 Antonio SJ Musumeci <trapexit@spawn.link>
 Arunav Sanyal <Khalian@users.noreply.github.com>
+asafkahlon <35964924+asafkahlon@users.noreply.github.com>
 Ashley Pittman <ashleypittman@users.noreply.github.com>
 AsumFace <asumface@gmail.com>
 Banglang <banglang.huang@foxmail.com>
@@ -41,8 +49,11 @@
 Carl Edquist <edquist@cs.wisc.edu>
 Carlos Maiolino <cmaiolino-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
 Chad Austin <chad@chadaustin.me>
+Changli Gao <xiaosuo@gmail.com>
+Christian Menges <christian.menges@tum.de>
 Christopher Harrison <ch12@sanger.ac.uk>
 Consus <consus@gmx.com>
+Craig Chi <craig08@users.noreply.github.com>
 Csaba Henk <csaba.henk@creo.hu>
 Csaba Henk <csaba@lowlife.hu>
 cvs2git <>
@@ -59,36 +70,58 @@
 Enke Chen <enkechen@yahoo.com>
 Eric Engestrom <eric@engestrom.ch>
 Eric Wong <normalperson@yhbt.net>
+Etienne Dublé <etienne.duble@imag.fr>
+Fabian Vogt <fabian@ritter-vogt.de>
 Fabrice Bauzac <fbauzac@amadeus.com>
+Fabrice Fontaine <fontaine.fabrice@gmail.com>
 Fedor Korotkov <fedor.korotkov@gmail.com>
 Feng Shuo <steve.shuo.feng@gmail.com>
+ferivoz <72023087+ferivoz@users.noreply.github.com>
+Feverfew <Feverfew@users.noreply.github.com>
+Florian Weimer <fw@deneb.enyo.de>
 Forty-Bot <Forty-Bot@users.noreply.github.com>
+Giulio Benetti <giulio.benetti@benettiengineering.com>
 Giuseppe Scrivano <giuseppe@scrivano.org>
 guraga <rulumasi@dodsi.com>
 HazelFZ <xfzfygz@gmail.com>
 Heiko Becker <heirecka@exherbo.org>
 Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+Hookey <Hookey@users.noreply.github.com>
+human <human@neet.fi>
 Ikey Doherty <michael.i.doherty@intel.com>
 itsdeepak <deepak.sn@samsung.com>
 Jan Blumschein <jan@jan-blumschein.de>
 Jann Horn <jannh@google.com>
 Jay Hankins <jay-hankins@users.noreply.github.com>
 Jean-Pierre André <jpandre@users.noreply.github.com>
+Jean-Yves VET <jyvet@users.noreply.github.com>
+Jérémie Galarneau <jeremie.galarneau@gmail.com>
 Joachim Schiele <joachim.schiele@daimler.com>
 Joachim Schiele <js@lastlog.de>
 Joerg Thalheim <joerg@thalheim.io>
+John Baber-Lucero <github@frundle.com>
 John Muir <john@jmuir.com>
 Joseph Dodge <joseph.dodge@veritas.com>
 Josh Soref <jsoref@users.noreply.github.com>
+Junichi Uekawa <dancer@debian.org>
+Junichi Uekawa <dancerj@gmail.com>
+Junichi Uekawa <dancer@netfort.gr.jp>
+Kangjing "Chaser" Huang <huangkangjing@gmail.com>
 Kevin Vigor <kvigor@fb.com>
 Kirill Smelkov <kirr@nexedi.com>
 Laszlo Boszormenyi (GCS) <gcs@debian.org>
 Laszlo Papp <ext-laszlo.papp@nokia.com>
+Laurent Bigonville <bigon@users.noreply.github.com>
+Lilo Huang <lilohuang@users.noreply.github.com>
 Liu Bo <liub.liubo@gmail.com>
+Li-Wen Hsu <lwhsu.github@lwhsu.org>
+lixiaokeng <lixiaokeng@huawei.com>
 Madan Valluri <mvalluri@cumulus-systems.com>
+Manuel Jacob <me@manueljacob.de>
 Marcin Sulikowski <marcin.sulikowski@editshare.com>
 Mark Glines <mark@glines.org>
 Martin Blanchard <tchaik@gmx.com>
+Martin Pärtel <martin.partel@gmail.com>
 Mateusz Urbańczyk <murbanczyk@qed.ai>
 Mattias Nissler <mnissler@chromium.org>
 maxice8 <30738253+maxice8@users.noreply.github.com>
@@ -100,6 +133,7 @@
 Miklos Szeredi <mszeredi@redhat.com>
 Miklos Szeredi <mszeredi@suse.cz>
 Miklos Szeredi <szmi@users.noreply.github.com>
+Misono Tomohiro <misono.tm@gmail.com>
 mkmm@gmx-topmail.de <mkmm@gmx-topmail.de>
 Natanael Copa <ncopa@alpinelinux.org>
 Niels de Vos <ndevos@redhat.com>
@@ -108,33 +142,50 @@
 Olivier Blin <olivier.blin@softathome.com>
 pablomh <pablomh@gmail.com>
 Peter Lemenkov <lemenkov@gmail.com>
+philmd <philmd@users.noreply.github.com>
 Przemyslaw Pawelczyk <przemoc@gmail.com>
 Przemysław Pawełczyk <przemoc@gmail.com>
 Ratna_Bolla@dell.com <Ratna_Bolla@dell.com>
+Rethan <359062468@qq.con>
 Reuben Hawkins <reubenhwk@gmail.com>
+rfjakob <jakobunt@gmail.com>
+richardweinberger <richard@nod.at>
 Richard W.M. Jones <rjones@redhat.com>
 Riku Voipio <riku.voipio@linaro.org>
 Robo Shimmer <roboshim@users.noreply.github.com>
 Roland Bauerschmidt <rb@debian.org>
 Roman Bogorodskiy <bogorodskiy@gmail.com>
+Rosen Penev <rosenp@gmail.com>
 Rostislav <rostislav@users.noreply.github.com>
 Rostislav Skudnov <rostislav@tuxera.com>
 Sam Huffman <40582525+samh-sifive@users.noreply.github.com>
+Sam James <sam@gentoo.org>
 Sam Stuewe <halosghost@archlinux.info>
 Sangwoo Moon <swmoon00@gmail.com>
+Sargun Dhillon <sargun@sargun.me>
 scosu <mpargmann@allfex.org>
 Scott Worley <scottworley@scottworley.com>
 Sebastian Pipping <sebastian@pipping.org>
+Sergey Fedoseev <fedoseev.sergey@gmail.com>
+Seunghoon Yeon <yeonsh@gmail.com>
 Sławek Rudnicki <slawek.rudnicki@editshare.com>
 Stefan Hajnoczi <stefanha@gmail.com>
 Stefan Hajnoczi <stefanha@redhat.com>
+Stephen Kitt <steve@sk2.org>
 Tej Chajed <tchajed@mit.edu>
 tenzap <46226844+tenzap@users.noreply.github.com>
 therealneworld@gmail.com <therealneworld@gmail.com>
+Tobias Nießen <tniessen@users.noreply.github.com>
+Tomasz Kulasek <34129113+tkulasek@users.noreply.github.com>
+Tom Callaway <spot@fedoraproject.org>
+Tom Callaway <spotrh@gmail.com>
 Tomohiro Kusumi <kusumi.tomohiro@gmail.com>
 userwithuid <userwithuid@gmail.com>
 Valentin Plugaru <valentin.plugaru@uni.lu>
 Vivek Goyal <vgoyal@redhat.com>
 William Woodruff <william@yossarian.net>
 Winfried Koehler <w_scan@gmx-topmail.de>
+winndows <winndows@163.com>
 Yuri Per <yuri@acronis.com>
+Zhiqiang Liu <liuzhiqiang26@huawei.com>
+zsugabubus <zsugabubus@users.noreply.github.com>
diff --git a/Android.bp b/Android.bp
index e43cdf7..c862300 100644
--- a/Android.bp
+++ b/Android.bp
@@ -45,7 +45,7 @@
     cflags: [
         "-D_FILE_OFFSET_BITS=64",
         "-DFUSERMOUNT_DIR=\"/system/bin\"",
-        "-DFUSE_USE_VERSION=34",
+        "-DFUSE_USE_VERSION=35",
         "-Wall",
         "-Werror",
         "-Wextra",
diff --git a/README.md b/README.md
index f0f48c4..052effc 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@
 beyond addressing high-impact issues. When reporting bugs, please
 understand that unless you are including a pull request or are
 reporting a critical issue, you will probably not get a response. If
-you are using libfuse, please consider to contribute to the project.
+you are using libfuse, please consider contributing to the project.
 
 
 Supported Platforms
@@ -50,8 +50,8 @@
 ------------
 
 You can download libfuse from
-https://github.com/libfuse/libfuse/releases. To build and install, we
-recommend to use [Meson](http://mesonbuild.com/) and
+https://github.com/libfuse/libfuse/releases. To build and install, you
+must use [Meson](http://mesonbuild.com/) and
 [Ninja](https://ninja-build.org).  After extracting the libfuse
 tarball, create a (temporary) build directory and run Meson:
 
@@ -59,13 +59,13 @@
     $ meson ..
 
 Normally, the default build options will work fine. If you
-nevertheless want to adjust them, you can do so with the *mesonconf*
-command:
+nevertheless want to adjust them, you can do so with the
+*meson configure* command:
 
-    $ mesonconf # list options
-    $ mesonconf  -D disable-mtab=true # set an option
+    $ meson configure # list options
+    $ meson configure -D disable-mtab=true # set an option
 
-To build, test and install libfuse, you then use Ninja:
+To build, test, and install libfuse, you then use Ninja:
 
     $ ninja
     $ sudo python3 -m pytest test/
@@ -126,7 +126,7 @@
 Building your own filesystem
 ------------------------------
 
-FUSE comes with several example file systems in the `examples`
+FUSE comes with several example file systems in the `example`
 directory. For example, the *passthrough* examples mirror the contents
 of the root directory under the mountpoint. Start from there and adapt
 the code!
@@ -147,10 +147,3 @@
 
 Please report any bugs on the GitHub issue tracker at
 https://github.com/libfuse/libfuse/issues.
-
-
-Professional Support
---------------------
-
-Professional support is offered via [Rath
-Consulting](http://www.rath-consulting.biz).
diff --git a/include/fuse.h b/include/fuse.h
index 883f6e5..9e6c633 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -48,9 +48,12 @@
 	 * FUSE_FILL_DIR_FLAGS for the filler function.  The filesystem may also
 	 * just ignore this flag completely.
 	 */
-	FUSE_READDIR_PLUS = (1 << 0),
+	FUSE_READDIR_PLUS = (1 << 0)
 };
 
+/**
+ * Readdir flags, passed to fuse_fill_dir_t callback.
+ */
 enum fuse_fill_dir_flags {
 	/**
 	 * "Plus" mode: all file attributes are valid
@@ -61,7 +64,7 @@
 	 * It is okay to set FUSE_FILL_DIR_PLUS if FUSE_READDIR_PLUS is not set
 	 * and vice versa.
 	 */
-	FUSE_FILL_DIR_PLUS = (1 << 1),
+	FUSE_FILL_DIR_PLUS = (1 << 1)
 };
 
 /** Function to add an entry in a readdir() operation
@@ -74,7 +77,7 @@
  * 
  * @param buf the buffer passed to the readdir() operation
  * @param name the file name of the directory entry
- * @param stat file attributes, can be NULL
+ * @param stbuf file attributes, can be NULL
  * @param off offset of the next entry or zero
  * @param flags fill flags
  * @return 1 if buffer is full, zero otherwise
@@ -121,7 +124,7 @@
 	/**
 	 * The timeout in seconds for which a negative lookup will be
 	 * cached. This means, that if file did not exist (lookup
-	 * retuned ENOENT), the lookup will only be redone after the
+	 * returned ENOENT), the lookup will only be redone after the
 	 * timeout, and the file/directory will be assumed to not
 	 * exist until then. A value of zero means that negative
 	 * lookups are not cached.
@@ -255,8 +258,8 @@
 	/**
 	 * If this option is given the file-system handlers for the
 	 * following operations will not receive path information:
-	 * read, write, flush, release, fsync, readdir, releasedir,
-	 * fsyncdir, lock, ioctl and poll.
+	 * read, write, flush, release, fallocate, fsync, readdir,
+	 * releasedir, fsyncdir, lock, ioctl and poll.
 	 *
 	 * For the truncate, getattr, chmod, chown and utimens
 	 * operations the path will be provided only if the struct
@@ -361,14 +364,14 @@
 
 	/** Change the permission bits of a file
 	 *
-	 * `fi` will always be NULL if the file is not currenlty open, but
+	 * `fi` will always be NULL if the file is not currently open, but
 	 * may also be NULL if the file is open.
 	 */
 	int (*chmod) (const char *, mode_t, struct fuse_file_info *fi);
 
 	/** Change the owner and group of a file
 	 *
-	 * `fi` will always be NULL if the file is not currenlty open, but
+	 * `fi` will always be NULL if the file is not currently open, but
 	 * may also be NULL if the file is open.
 	 *
 	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
@@ -378,7 +381,7 @@
 
 	/** Change the size of a file
 	 *
-	 * `fi` will always be NULL if the file is not currenlty open, but
+	 * `fi` will always be NULL if the file is not currently open, but
 	 * may also be NULL if the file is open.
 	 *
 	 * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is
@@ -407,8 +410,8 @@
 	 *  - When writeback caching is disabled, the filesystem is
 	 *    expected to properly handle the O_APPEND flag and ensure
 	 *    that each write is appending to the end of the file.
-	 * 
-         *  - When writeback caching is enabled, the kernel will
+	 *
+	 *  - When writeback caching is enabled, the kernel will
 	 *    handle O_APPEND. However, unless all changes to the file
 	 *    come through the kernel this will not work reliably. The
 	 *    filesystem should thus either ignore the O_APPEND flag
@@ -648,7 +651,7 @@
 	 * This supersedes the old utime() interface.  New applications
 	 * should use this.
 	 *
-	 * `fi` will always be NULL if the file is not currenlty open, but
+	 * `fi` will always be NULL if the file is not currently open, but
 	 * may also be NULL if the file is open.
 	 *
 	 * See the utimensat(2) man page for details.
@@ -664,6 +667,10 @@
 	 */
 	int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
 
+#if FUSE_USE_VERSION < 35
+	int (*ioctl) (const char *, int cmd, void *arg,
+		      struct fuse_file_info *, unsigned int flags, void *data);
+#else
 	/**
 	 * Ioctl
 	 *
@@ -682,6 +689,7 @@
 	 */
 	int (*ioctl) (const char *, unsigned int cmd, void *arg,
 		      struct fuse_file_info *, unsigned int flags, void *data);
+#endif
 
 	/**
 	 * Poll for IO readiness events
@@ -767,9 +775,10 @@
 	 * additional cost of transferring data through the FUSE kernel module
 	 * to user space (glibc) and then back into the FUSE filesystem again.
 	 *
-	 * In case this method is not implemented, glibc falls back to reading
-	 * data from the source and writing to the destination. Effectively
-	 * doing an inefficient copy of the data.
+	 * In case this method is not implemented, applications are expected to
+	 * fall back to a regular file copy.   (Some glibc versions did this
+	 * emulation automatically, but the emulation has been removed from all
+	 * glibc release branches.)
 	 */
 	ssize_t (*copy_file_range) (const char *path_in,
 				    struct fuse_file_info *fi_in,
@@ -850,7 +859,7 @@
  *   4: Mounting failed
  *   5: Failed to daemonize (detach from session)
  *   6: Failed to set up signal handlers
- *   7: An error occured during the life of the file system
+ *   7: An error occurred during the life of the file system
  *
  * @param argc the argument counter passed to the main() function
  * @param argv the argument vector passed to the main() function
@@ -978,6 +987,10 @@
  */
 void fuse_exit(struct fuse *f);
 
+#if FUSE_USE_VERSION < 32
+int fuse_loop_mt_31(struct fuse *f, int clone_fd);
+#define fuse_loop_mt(f, clone_fd) fuse_loop_mt_31(f, clone_fd)
+#else
 /**
  * FUSE event loop with multiple threads
  *
@@ -1009,10 +1022,6 @@
  *
  * See also: fuse_loop()
  */
-#if FUSE_USE_VERSION < 32
-int fuse_loop_mt_31(struct fuse *f, int clone_fd);
-#define fuse_loop_mt(f, clone_fd) fuse_loop_mt_31(f, clone_fd)
-#else
 int fuse_loop_mt(struct fuse *f, struct fuse_loop_config *config);
 #endif
 
@@ -1189,9 +1198,15 @@
 			const char *name);
 int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
 		 uint64_t *idx);
+#if FUSE_USE_VERSION < 35
+int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd,
+		  void *arg, struct fuse_file_info *fi, unsigned int flags,
+		  void *data);
+#else
 int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, unsigned int cmd,
 		  void *arg, struct fuse_file_info *fi, unsigned int flags,
 		  void *data);
+#endif
 int fuse_fs_poll(struct fuse_fs *fs, const char *path,
 		 struct fuse_file_info *fi, struct fuse_pollhandle *ph,
 		 unsigned *reventsp);
diff --git a/include/fuse_common.h b/include/fuse_common.h
index 7ac28d7..3f836d7 100644
--- a/include/fuse_common.h
+++ b/include/fuse_common.h
@@ -23,9 +23,9 @@
 #define FUSE_MAJOR_VERSION 3
 
 /** Minor version of FUSE library interface */
-#define FUSE_MINOR_VERSION 2
+#define FUSE_MINOR_VERSION 10
 
-#define FUSE_MAKE_VERSION(maj, min)  ((maj) * 10 + (min))
+#define FUSE_MAKE_VERSION(maj, min)  ((maj) * 100 + (min))
 #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
 
 #ifdef __cplusplus
@@ -352,6 +352,19 @@
 #define FUSE_CAP_HANDLE_KILLPRIV         (1 << 20)
 
 /**
+ * Indicates that the kernel supports caching symlinks in its page cache.
+ *
+ * When this feature is enabled, symlink targets are saved in the page cache.
+ * You can invalidate a cached link by calling:
+ * `fuse_lowlevel_notify_inval_inode(se, ino, 0, 0);`
+ *
+ * This feature is disabled by default.
+ * If the kernel supports it (>= 4.20), you can enable this feature by
+ * setting this flag in the `want` field of the `fuse_conn_info` structure.
+ */
+#define FUSE_CAP_CACHE_SYMLINKS        (1 << 23)
+
+/**
  * Indicates support for zero-message opendirs. If this flag is set in
  * the `capable` field of the `fuse_conn_info` structure, then the filesystem
  * may return `ENOSYS` from the opendir() handler to indicate success. Further
@@ -364,6 +377,29 @@
 #define FUSE_CAP_NO_OPENDIR_SUPPORT    (1 << 24)
 
 /**
+ * Indicates support for invalidating cached pages only on explicit request.
+ *
+ * If this flag is set in the `capable` field of the `fuse_conn_info` structure,
+ * then the FUSE kernel module supports invalidating cached pages only on
+ * explicit request by the filesystem through fuse_lowlevel_notify_inval_inode()
+ * or fuse_invalidate_path().
+ *
+ * By setting this flag in the `want` field of the `fuse_conn_info` structure,
+ * the filesystem is responsible for invalidating cached pages through explicit
+ * requests to the kernel.
+ *
+ * Note that setting this flag does not prevent the cached pages from being
+ * flushed by OS itself and/or through user actions.
+ *
+ * Note that if both FUSE_CAP_EXPLICIT_INVAL_DATA and FUSE_CAP_AUTO_INVAL_DATA
+ * are set in the `capable` field of the `fuse_conn_info` structure then
+ * FUSE_CAP_AUTO_INVAL_DATA takes precedence.
+ *
+ * This feature is disabled by default.
+ */
+#define FUSE_CAP_EXPLICIT_INVAL_DATA    (1 << 25)
+
+/**
  * Indicates support for passthrough mode access for read/write operations.
  *
  * If this flag is set in the `capable` field of the `fuse_conn_info`
@@ -629,7 +665,7 @@
 	 * until .size bytes have been copied or an error or EOF is
 	 * detected.
 	 */
-	FUSE_BUF_FD_RETRY	= (1 << 3),
+	FUSE_BUF_FD_RETRY	= (1 << 3)
 };
 
 /**
@@ -671,7 +707,7 @@
 	 * is full or empty).  See SPLICE_F_NONBLOCK in the splice(2)
 	 * man page.
 	 */
-	FUSE_BUF_SPLICE_NONBLOCK= (1 << 4),
+	FUSE_BUF_SPLICE_NONBLOCK= (1 << 4)
 };
 
 /**
diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h
index bd8794e..70278fa 100644
--- a/include/fuse_kernel.h
+++ b/include/fuse_kernel.h
@@ -424,11 +424,11 @@
 	FUSE_LSEEK		= 46,
 	FUSE_COPY_FILE_RANGE	= 47,
 
-	/* CUSE specific operations */
-	CUSE_INIT		= 4096,
+	/* Android specific operations */
+	FUSE_CANONICAL_PATH     = 2016,
 
-        /* Android specific operations */
-        FUSE_CANONICAL_PATH     = 2016,
+	/* CUSE specific operations */
+	CUSE_INIT		= 4096
 };
 
 enum fuse_notify_code {
@@ -438,7 +438,7 @@
 	FUSE_NOTIFY_STORE = 4,
 	FUSE_NOTIFY_RETRIEVE = 5,
 	FUSE_NOTIFY_DELETE = 6,
-	FUSE_NOTIFY_CODE_MAX,
+	FUSE_NOTIFY_CODE_MAX
 };
 
 /* The read buffer is required to be at least 8k, but may be much larger */
@@ -457,6 +457,17 @@
 	struct fuse_attr attr;
 };
 
+#define FUSE_ACTION_KEEP        0
+#define FUSE_ACTION_REMOVE      1
+#define FUSE_ACTION_REPLACE     2
+
+struct fuse_entry_bpf_out {
+        uint64_t        backing_action;
+        uint64_t        backing_fd;
+        uint64_t        bpf_action;
+        uint64_t        bpf_fd;
+};
+
 struct fuse_forget_in {
 	uint64_t	nlookup;
 };
@@ -859,4 +870,51 @@
 	uint64_t	flags;
 };
 
+/** Export fuse_args only for bpf */
+#ifdef __KERNEL__
+struct fuse_mount;
+
+/** One input argument of a request */
+struct fuse_in_arg {
+  unsigned size;
+  const void *value;
+};
+
+/** One output argument of a request */
+struct fuse_arg {
+  unsigned size;
+  void *value;
+};
+
+struct fuse_args {
+  uint64_t nodeid;
+  uint32_t opcode;
+  unsigned short in_numargs;
+  unsigned short out_numargs;
+  int force:1;
+  int noreply:1;
+  int nocreds:1;
+  int in_pages:1;
+  int out_pages:1;
+  int out_argvar:1;
+  int page_zeroing:1;
+  int page_replace:1;
+  int may_block:1;
+  struct fuse_in_arg in_args[5];
+  struct fuse_arg out_args[3];
+  void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error);
+
+  /* Path used for completing d_canonical_path */
+  struct path *canonical_path;
+};
+#endif
+
+#define FUSE_BPF_USER_FILTER    1
+#define FUSE_BPF_BACKING        2
+#define FUSE_BPF_POST_FILTER    4
+
+#define FUSE_OPCODE_FILTER      0x0ffff
+#define FUSE_PREFILTER          0x10000
+#define FUSE_POSTFILTER         0x20000
+
 #endif /* _LINUX_FUSE_H */
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index e916112..c591f71 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -14,7 +14,7 @@
  * Low level API
  *
  * IMPORTANT: you should define FUSE_USE_VERSION before including this
- * header.  To use the newest API define it to 31 (recommended for any
+ * header.  To use the newest API define it to 35 (recommended for any
  * new application).
  */
 
@@ -98,6 +98,10 @@
 	    that come through the kernel, this should be set to a very
 	    large value. */
 	double entry_timeout;
+        uint64_t        backing_action;
+        uint64_t        backing_fd;
+        uint64_t        bpf_action;
+        uint64_t        bpf_fd;
 };
 
 /**
@@ -709,7 +713,7 @@
 	 * values that was previously returned by readdir() for the same
 	 * directory handle. In this case, readdir() should skip over entries
 	 * coming before the position defined by the off_t value. If entries
-	 * are added or removed while the directory handle is open, they filesystem
+	 * are added or removed while the directory handle is open, the filesystem
 	 * may still include the entries that have been removed, and may not
 	 * report the entries that have been created. However, addition or
 	 * removal of entries must never cause readdir() to skip over unrelated
@@ -1002,6 +1006,11 @@
 	void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize,
 		      uint64_t idx);
 
+#if FUSE_USE_VERSION < 35
+	void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd,
+		       void *arg, struct fuse_file_info *fi, unsigned flags,
+		       const void *in_buf, size_t in_bufsz, size_t out_bufsz);
+#else
 	/**
 	 * Ioctl
 	 *
@@ -1033,6 +1042,7 @@
 	void (*ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned int cmd,
 		       void *arg, struct fuse_file_info *fi, unsigned flags,
 		       const void *in_buf, size_t in_bufsz, size_t out_bufsz);
+#endif
 
 	/**
 	 * Poll for IO readiness
@@ -1257,9 +1267,9 @@
  * Reply with an error code or success.
  *
  * Possible requests:
- *   all except forget
+ *   all except forget, forget_multi, retrieve_reply
  *
- * Whereever possible, error codes should be chosen from the list of
+ * Wherever possible, error codes should be chosen from the list of
  * documented error conditions in the corresponding system calls
  * manpage.
  *
@@ -1987,6 +1997,11 @@
  */
 int fuse_session_loop(struct fuse_session *se);
 
+#if FUSE_USE_VERSION < 32
+int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd);
+#define fuse_session_loop_mt(se, clone_fd) fuse_session_loop_mt_31(se, clone_fd)
+#else
+#if (!defined(__UCLIBC__) && !defined(__APPLE__))
 /**
  * Enter a multi-threaded event loop.
  *
@@ -1998,11 +2013,11 @@
  * @param config session loop configuration 
  * @return see fuse_session_loop()
  */
-#if FUSE_USE_VERSION < 32
-int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd);
-#define fuse_session_loop_mt(se, clone_fd) fuse_session_loop_mt_31(se, clone_fd)
-#else
 int fuse_session_loop_mt(struct fuse_session *se, struct fuse_loop_config *config);
+#else
+int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config);
+#define fuse_session_loop_mt(se, config) fuse_session_loop_mt_32(se, config)
+#endif
 #endif
 
 /**
diff --git a/lib/buffer.c b/lib/buffer.c
index 5ab9b87..757807a 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -266,6 +266,9 @@
 {
 	const struct fuse_buf *buf = fuse_bufvec_current(bufv);
 
+	if (!buf)
+		return 0;
+
 	bufv->off += len;
 	assert(bufv->off <= buf->size);
 	if (bufv->off == buf->size) {
diff --git a/lib/cuse_lowlevel.c b/lib/cuse_lowlevel.c
index 9917b64..b70947e 100644
--- a/lib/cuse_lowlevel.c
+++ b/lib/cuse_lowlevel.c
@@ -319,6 +319,7 @@
 	if (res == -1)
 		goto err_sig;
 
+	fuse_opt_free_args(&args);
 	return se;
 
 err_sig:
diff --git a/lib/fuse.c b/lib/fuse.c
old mode 100755
new mode 100644
index b0f5b30..a95d7c1
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -3390,7 +3390,7 @@
 	dh->len = 0;
 	dh->filled = 0;
 	dh->nodeid = ino;
-	fuse_mutex_init(&dh->lock);
+	pthread_mutex_init(&dh->lock, NULL);
 
 	llfi->fh = (uintptr_t) dh;
 
@@ -3566,7 +3566,7 @@
 		return 1;
 	}
 
-	if (off && statp && (flags & FUSE_FILL_DIR_PLUS)) {
+	if (statp && (flags & FUSE_FILL_DIR_PLUS)) {
 		e.attr = *statp;
 
 		if (!is_dot_or_dotdot(name)) {
@@ -3578,6 +3578,11 @@
 		}
 	} else {
 		e.attr.st_ino = FUSE_UNKNOWN_INO;
+		if (statp) {
+			e.attr.st_mode = statp->st_mode;
+			if (f->conf.use_ino)
+				e.attr.st_ino = statp->st_ino;
+		}
 		if (!f->conf.use_ino && f->conf.readdir_ino) {
 			e.attr.st_ino = (ino_t)
 				lookup_nodeid(f, dh->nodeid, name);
@@ -4533,7 +4538,7 @@
 
 		res = poll(&fds, 1, timeout * 1000);
 		if (res == -1) {
-			if (errno == -EINTR)
+			if (errno == EINTR)
 				continue;
 			else
 				break;
@@ -4569,7 +4574,7 @@
 	return fuse_session_loop(f->se);
 }
 
-FUSE_SYMVER(".symver fuse_loop_mt_32,fuse_loop_mt@@FUSE_3.2");
+FUSE_SYMVER("fuse_loop_mt_32", "fuse_loop_mt@@FUSE_3.2")
 int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config)
 {
 	if (f == NULL)
@@ -4585,7 +4590,7 @@
 }
 
 int fuse_loop_mt_31(struct fuse *f, int clone_fd);
-FUSE_SYMVER(".symver fuse_loop_mt_31,fuse_loop_mt@FUSE_3.0");
+FUSE_SYMVER("fuse_loop_mt_31", "fuse_loop_mt@FUSE_3.0")
 int fuse_loop_mt_31(struct fuse *f, int clone_fd)
 {
 	struct fuse_loop_config config;
@@ -4870,7 +4875,7 @@
 }
 
 
-FUSE_SYMVER(".symver fuse_new_31,fuse_new@@FUSE_3.1");
+FUSE_SYMVER("fuse_new_31", "fuse_new@@FUSE_3.1")
 struct fuse *fuse_new_31(struct fuse_args *args,
 		      const struct fuse_operations *op,
 		      size_t op_size, void *user_data)
@@ -4973,7 +4978,7 @@
 	if (node_table_init(&f->id_table) == -1)
 		goto out_free_name_table;
 
-	fuse_mutex_init(&f->lock);
+	pthread_mutex_init(&f->lock, NULL);
 
 	root = alloc_node(f);
 	if (root == NULL) {
@@ -5024,7 +5029,7 @@
 /* Emulates 3.0-style fuse_new(), which processes --help */
 struct fuse *fuse_new_30(struct fuse_args *args, const struct fuse_operations *op,
 			 size_t op_size, void *private_data);
-FUSE_SYMVER(".symver fuse_new_30,fuse_new@FUSE_3.0");
+FUSE_SYMVER("fuse_new_30", "fuse_new@FUSE_3.0")
 struct fuse *fuse_new_30(struct fuse_args *args,
 			 const struct fuse_operations *op,
 			 size_t op_size, void *user_data)
diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c
index 445e9a0..8fcc46c 100644
--- a/lib/fuse_loop_mt.c
+++ b/lib/fuse_loop_mt.c
@@ -32,7 +32,6 @@
 	struct fuse_worker *prev;
 	struct fuse_worker *next;
 	pthread_t thread_id;
-	size_t bufsize;
 
 	// We need to include fuse_buf so that we can properly free
 	// it when a thread is terminated by pthread_cancel().
@@ -65,7 +64,7 @@
 	memset(ch, 0, sizeof(*ch));
 	ch->fd = fd;
 	ch->ctr = 1;
-	fuse_mutex_init(&ch->lock);
+	pthread_mutex_init(&ch->lock, NULL);
 
 	return ch;
 }
@@ -304,7 +303,7 @@
 	free(w);
 }
 
-FUSE_SYMVER(".symver fuse_session_loop_mt_32,fuse_session_loop_mt@@FUSE_3.2");
+FUSE_SYMVER("fuse_session_loop_mt_32", "fuse_session_loop_mt@@FUSE_3.2")
 int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config)
 {
 	int err;
@@ -321,7 +320,7 @@
 	mt.main.thread_id = pthread_self();
 	mt.main.prev = mt.main.next = &mt.main;
 	sem_init(&mt.finish, 0, 0);
-	fuse_mutex_init(&mt.lock);
+	pthread_mutex_init(&mt.lock, NULL);
 
 	pthread_mutex_lock(&mt.lock);
 	err = fuse_loop_start_thread(&mt);
@@ -352,7 +351,7 @@
 }
 
 int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd);
-FUSE_SYMVER(".symver fuse_session_loop_mt_31,fuse_session_loop_mt@FUSE_3.0");
+FUSE_SYMVER("fuse_session_loop_mt_31", "fuse_session_loop_mt@FUSE_3.0")
 int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd)
 {
 	struct fuse_loop_config config;
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index a4a4df0..aee22b4 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -156,7 +156,7 @@
 		req->se = se;
 		req->ctr = 1;
 		list_init_req(req);
-		fuse_mutex_init(&req->lock);
+		pthread_mutex_init(&req->lock, NULL);
 	}
 
 	return req;
@@ -168,6 +168,7 @@
 {
 	struct fuse_out_header *out = iov[0].iov_base;
 
+	assert(se != NULL);
 	out->len = iov_length(iov, count);
 	if (se->debug) {
 		if (out->unique == 0) {
@@ -190,8 +191,6 @@
 	int err = errno;
 
 	if (res == -1) {
-		assert(se != NULL);
-
 		/* ENOENT means the operation was interrupted */
 		if (!fuse_session_exited(se) && err != ENOENT)
 			perror("fuse: writing device");
@@ -400,20 +399,45 @@
 		arg->open_flags |= FOPEN_NONSEEKABLE;
 }
 
-int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
-{
-	struct fuse_entry_out arg;
-	size_t size = req->se->conn.proto_minor < 9 ?
-		FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
+int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param* e) {
+    struct {
+        struct fuse_entry_out arg;
+        struct fuse_entry_bpf_out bpf_arg;
+    } __attribute__((packed)) arg_ext = {0};
 
-	/* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
-	   negative entry */
-	if (!e->ino && req->se->conn.proto_minor < 4)
-		return fuse_reply_err(req, ENOENT);
+    struct fuse_entry_out arg;
+    struct fuse_entry_bpf_out bpf_arg;
+    size_t size;
+    int extended_args = e->bpf_action || bpf_arg.bpf_fd || e->backing_action || e->backing_fd;
 
-	memset(&arg, 0, sizeof(arg));
-	fill_entry(&arg, e);
-	return send_reply_ok(req, &arg, size);
+    if (extended_args) {
+        size = req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg_ext);
+    } else {
+        size = req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
+    }
+
+    /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
+       negative entry */
+    if (!e->ino && req->se->conn.proto_minor < 4) return fuse_reply_err(req, ENOENT);
+
+    memset(&arg, 0, sizeof(arg));
+
+    if (extended_args) {
+        memset(&bpf_arg, 0, sizeof(bpf_arg));
+
+        bpf_arg.bpf_action = e->bpf_action;
+        bpf_arg.bpf_fd = e->bpf_fd;
+        bpf_arg.backing_action = e->backing_action;
+        bpf_arg.backing_fd = e->backing_fd;
+
+        arg_ext.arg = arg;
+        arg_ext.bpf_arg = bpf_arg;
+
+        return send_reply_ok(req, &arg_ext, size);
+    } else {
+        fill_entry(&arg, e);
+        return send_reply_ok(req, &arg, size);
+    }
 }
 
 int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
@@ -730,7 +754,7 @@
 	struct fuse_ll_pipe *llp;
 	int splice_flags;
 	size_t pipesize;
-	size_t total_fd_size;
+	size_t total_buf_size;
 	size_t idx;
 	size_t headerlen;
 	struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
@@ -741,15 +765,13 @@
 	if (flags & FUSE_BUF_NO_SPLICE)
 		goto fallback;
 
-	total_fd_size = 0;
+	total_buf_size = 0;
 	for (idx = buf->idx; idx < buf->count; idx++) {
-		if (buf->buf[idx].flags & FUSE_BUF_IS_FD) {
-			total_fd_size = buf->buf[idx].size;
-			if (idx == buf->idx)
-				total_fd_size -= buf->off;
-		}
+		total_buf_size += buf->buf[idx].size;
+		if (idx == buf->idx)
+			total_buf_size -= buf->off;
 	}
-	if (total_fd_size < 2 * pagesize)
+	if (total_buf_size < 2 * pagesize)
 		goto fallback;
 
 	if (se->conn.proto_minor < 14 ||
@@ -1981,7 +2003,10 @@
 		fuse_reply_err(req, ENOSYS);
 }
 
-static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+/* Prevent bogus data races (bogus since "init" is called before
+ * multi-threading becomes relevant */
+static __attribute__((no_sanitize("thread")))
+void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 {
 	struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
 	struct fuse_init_out outarg;
@@ -2053,8 +2078,12 @@
 			se->conn.capable |= FUSE_CAP_POSIX_ACL;
 		if (arg->flags & FUSE_HANDLE_KILLPRIV)
 			se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
+		if (arg->flags & FUSE_CACHE_SYMLINKS)
+			se->conn.capable |= FUSE_CAP_CACHE_SYMLINKS;
 		if (arg->flags & FUSE_NO_OPENDIR_SUPPORT)
 			se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
+		if (arg->flags & FUSE_EXPLICIT_INVAL_DATA)
+			se->conn.capable |= FUSE_CAP_EXPLICIT_INVAL_DATA;
 		if (!(arg->flags & FUSE_MAX_PAGES)) {
 			size_t max_bufsize =
 				FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
@@ -2179,6 +2208,10 @@
 		outarg.flags |= FUSE_POSIX_ACL;
 	if (se->conn.want & FUSE_CAP_PASSTHROUGH)
 		outarg.flags |= FUSE_PASSTHROUGH;
+	if (se->conn.want & FUSE_CAP_CACHE_SYMLINKS)
+		outarg.flags |= FUSE_CACHE_SYMLINKS;
+	if (se->conn.want & FUSE_CAP_EXPLICIT_INVAL_DATA)
+		outarg.flags |= FUSE_EXPLICIT_INVAL_DATA;
 	outarg.max_readahead = se->conn.max_readahead;
 	outarg.max_write = se->conn.max_write;
 	if (se->conn.proto_minor >= 13) {
@@ -2319,7 +2352,7 @@
 	if (!se)
 		return -EINVAL;
 
-	if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
+	if (se->conn.proto_minor < 12)
 		return -ENOSYS;
 	
 	outarg.ino = ino;
@@ -2341,7 +2374,7 @@
 	if (!se)
 		return -EINVAL;
 	
-	if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
+	if (se->conn.proto_minor < 12)
 		return -ENOSYS;
 
 	outarg.parent = parent;
@@ -2366,7 +2399,7 @@
 	if (!se)
 		return -EINVAL;
 
-	if (se->conn.proto_major < 6 || se->conn.proto_minor < 18)
+	if (se->conn.proto_minor < 18)
 		return -ENOSYS;
 
 	outarg.parent = parent;
@@ -2395,7 +2428,7 @@
 	if (!se)
 		return -EINVAL;
 
-	if (se->conn.proto_major < 6 || se->conn.proto_minor < 15)
+	if (se->conn.proto_minor < 15)
 		return -ENOSYS;
 
 	out.unique = 0;
@@ -2473,7 +2506,7 @@
 	if (!se)
 		return -EINVAL;
 
-	if (se->conn.proto_major < 6 || se->conn.proto_minor < 15)
+	if (se->conn.proto_minor < 15)
 		return -ENOSYS;
 
 	rreq = malloc(sizeof(*rreq));
@@ -2604,6 +2637,22 @@
 		return fuse_ll_ops[opcode].name;
 }
 
+static const char *opfiltername(int filter)
+{
+	switch (filter) {
+	case 0:
+		return "NONE";
+	case FUSE_PREFILTER:
+		return "FUSE_PREFILTER";
+	case FUSE_POSTFILTER:
+		return "FUSE_POSTFILTER";
+	case FUSE_PREFILTER | FUSE_POSTFILTER:
+		return "FUSE_PREFILTER | FUSE_POSTFILTER";
+	default:
+		return "???";
+	}
+}
+
 static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
 				  struct fuse_bufvec *src)
 {
@@ -2638,6 +2687,7 @@
 	void *mbuf = NULL;
 	int err;
 	int res;
+	int opcode_filter;
 
 	if (buf->flags & FUSE_BUF_IS_FD) {
 		if (buf->size < tmpbuf.buf[0].size)
@@ -2659,11 +2709,16 @@
 		in = buf->mem;
 	}
 
+	/* Cleanup opcode most significant bits used by FUSE BPF */
+	opcode_filter = in->opcode & ~FUSE_OPCODE_FILTER;
+	in->opcode &= FUSE_OPCODE_FILTER;
+
 	if (se->debug) {
 		fuse_log(FUSE_LOG_DEBUG,
-			"unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
+			"unique: %llu, opcode: %s (%i), opcode filter: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
 			(unsigned long long) in->unique,
 			opname((enum fuse_opcode) in->opcode), in->opcode,
+			opfiltername((enum fuse_opcode) opcode_filter), opcode_filter,
 			(unsigned long long) in->nodeid, buf->size, in->pid);
 	}
 
@@ -3045,7 +3100,7 @@
 	list_init_req(&se->interrupts);
 	list_init_nreq(&se->notify_list);
 	se->notify_ctr = 1;
-	fuse_mutex_init(&se->lock);
+	pthread_mutex_init(&se->lock, NULL);
 
 	err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor);
 	if (err) {
@@ -3066,7 +3121,8 @@
 out4:
 	fuse_opt_free_args(args);
 out3:
-	free(mo);
+	if (mo != NULL)
+		destroy_mount_opts(mo);
 out2:
 	free(se);
 out1:
@@ -3132,6 +3188,7 @@
 {
 	if (se->mountpoint != NULL) {
 		fuse_kern_unmount(se->mountpoint, se->fd);
+		se->fd = -1;
 		free(se->mountpoint);
 		se->mountpoint = NULL;
 	}
@@ -3207,17 +3264,22 @@
 }
 #endif
 
+/* Prevent spurious data race warning - we don't care
+ * about races for this flag */
+__attribute__((no_sanitize_thread))
 void fuse_session_exit(struct fuse_session *se)
 {
 	se->exited = 1;
 }
 
+__attribute__((no_sanitize_thread))
 void fuse_session_reset(struct fuse_session *se)
 {
 	se->exited = 0;
 	se->error = 0;
 }
 
+__attribute__((no_sanitize_thread))
 int fuse_session_exited(struct fuse_session *se)
 {
 	return se->exited;
diff --git a/lib/fuse_misc.h b/lib/fuse_misc.h
index 2f6663e..f956ab7 100644
--- a/lib/fuse_misc.h
+++ b/lib/fuse_misc.h
@@ -10,27 +10,16 @@
 
 /*
   Versioned symbols cannot be used in some cases because it
-    - confuse the dynamic linker in uClibc
     - not supported on MacOSX (in MachO binary format)
 */
-#if (!defined(__UCLIBC__) && !defined(__APPLE__))
-#define FUSE_SYMVER(x) __asm__(x)
+#ifndef __APPLE__
+# if HAVE_SYMVER_ATTRIBUTE
+#  define FUSE_SYMVER(sym1, sym2) __attribute__ ((symver (sym2)))
+# else
+#  define FUSE_SYMVER(sym1, sym2) __asm__("\t.symver " sym1 "," sym2);
+# endif
 #else
-#define FUSE_SYMVER(x)
-#endif
-
-#ifndef USE_UCLIBC
-#define fuse_mutex_init(mut) pthread_mutex_init(mut, NULL)
-#else
-/* Is this hack still needed? */
-static inline void fuse_mutex_init(pthread_mutex_t *mut)
-{
-	pthread_mutexattr_t attr;
-	pthread_mutexattr_init(&attr);
-	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
-	pthread_mutex_init(mut, &attr);
-	pthread_mutexattr_destroy(&attr);
-}
+#define FUSE_SYMVER(sym1, sym2)
 #endif
 
 #ifdef HAVE_STRUCT_STAT_ST_ATIM
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index b01699a..35964f3 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -145,6 +145,7 @@
 	global:
 		fuse_session_loop_mt;
 		fuse_session_loop_mt_31;
+		fuse_session_loop_mt_32;
 		fuse_loop_mt;
 		fuse_loop_mt_31;
 } FUSE_3.1;
diff --git a/lib/meson.build b/lib/meson.build
index 28f0aee..98461d8 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -37,7 +37,7 @@
                   soversion: '3', include_directories: include_dirs,
                   dependencies: deps, install: true,
                   link_depends: 'fuse_versionscript',
-                  c_args: [ '-DFUSE_USE_VERSION=34',
+                  c_args: [ '-DFUSE_USE_VERSION=35',
                             '-DFUSERMOUNT_DIR="@0@"'.format(fusermount_path) ],
                   link_args: ['-Wl,--version-script,' + meson.current_source_dir()
                               + '/fuse_versionscript' ])
diff --git a/lib/modules/iconv.c b/lib/modules/iconv.c
index eb5edd8..0ec3c2b 100644
--- a/lib/modules/iconv.c
+++ b/lib/modules/iconv.c
@@ -638,13 +638,18 @@
 
 static void iconv_help(void)
 {
-	char *old = strdup(setlocale(LC_CTYPE, ""));
-	char *charmap = strdup(nl_langinfo(CODESET));
-	setlocale(LC_CTYPE, old);
-	free(old);
+	char *charmap;
+	const char *old = setlocale(LC_CTYPE, "");
+
+	charmap = strdup(nl_langinfo(CODESET));
+	if (old)
+		setlocale(LC_CTYPE, old);
+	else
+		perror("setlocale");
+
 	printf(
 "    -o from_code=CHARSET   original encoding of file names (default: UTF-8)\n"
-"    -o to_code=CHARSET	    new encoding of the file names (default: %s)\n",
+"    -o to_code=CHARSET     new encoding of the file names (default: %s)\n",
 		charmap);
 	free(charmap);
 }
@@ -667,7 +672,7 @@
 {
 	struct fuse_fs *fs;
 	struct iconv *ic;
-	char *old = NULL;
+	const char *old = NULL;
 	const char *from;
 	const char *to;
 
@@ -689,7 +694,7 @@
 	to = ic->to_code ? ic->to_code : "";
 	/* FIXME: detect charset equivalence? */
 	if (!to[0])
-		old = strdup(setlocale(LC_CTYPE, ""));
+		old = setlocale(LC_CTYPE, "");
 	ic->tofs = iconv_open(from, to);
 	if (ic->tofs == (iconv_t) -1) {
 		fuse_log(FUSE_LOG_ERR, "fuse-iconv: cannot convert from %s to %s\n",
@@ -704,7 +709,7 @@
 	}
 	if (old) {
 		setlocale(LC_CTYPE, old);
-		free(old);
+		old = NULL;
 	}
 
 	ic->next = next[0];
@@ -724,7 +729,6 @@
 	free(ic);
 	if (old) {
 		setlocale(LC_CTYPE, old);
-		free(old);
 	}
 	return NULL;
 }
diff --git a/lib/mount_util.c b/lib/mount_util.c
index f1d2325..35e9948 100644
--- a/lib/mount_util.c
+++ b/lib/mount_util.c
@@ -30,7 +30,7 @@
 #include <sys/mount.h>
 #include <sys/param.h>
 
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
 #define umount2(mnt, flags) unmount(mnt, ((flags) == 2) ? MNT_FORCE : 0)
 #endif
 
diff --git a/meson.build b/meson.build
index 0f1a77f..8a6587b 100644
--- a/meson.build
+++ b/meson.build
@@ -1,6 +1,10 @@
-project('libfuse3', ['cpp', 'c'], version: '3.8.0',
+project('libfuse3', ['c'], version: '3.10.5',
         meson_version: '>= 0.42',
-        default_options: [ 'buildtype=debugoptimized' ])
+        default_options: [
+            'buildtype=debugoptimized',
+            'cpp_std=c++11',
+            'warning_level=2',
+        ])
 
 
 platform = host_machine.system()
@@ -63,13 +67,12 @@
 #
 # Compiler configuration
 #
-add_project_arguments('-D_REENTRANT', '-DHAVE_CONFIG_H', '-Wall', '-Wextra', '-Wno-sign-compare',
+add_project_arguments('-D_REENTRANT', '-DHAVE_CONFIG_H', '-Wno-sign-compare',
                       '-Wstrict-prototypes', '-Wmissing-declarations', '-Wwrite-strings',
                       '-fno-strict-aliasing', language: 'c')
 add_project_arguments('-D_REENTRANT', '-DHAVE_CONFIG_H', '-D_GNU_SOURCE',
-                     '-Wall', '-Wextra', '-Wno-sign-compare', '-std=c++11',
-                     '-Wmissing-declarations', '-Wwrite-strings',
-                     '-fno-strict-aliasing', language: 'cpp')
+                     '-Wno-sign-compare', '-Wmissing-declarations',
+                     '-Wwrite-strings', '-fno-strict-aliasing', language: 'cpp')
 
 # Some (stupid) GCC versions warn about unused return values even when they are
 # casted to void. This makes -Wunused-result pretty useless, since there is no
@@ -87,6 +90,30 @@
      add_project_arguments('-Wno-unused-result', language: 'c')
 endif
 
+# gcc-10 and newer support the symver attribute which we need to use if we
+# want to support LTO
+# recent clang and gcc both support __has_attribute (and if they are too old
+# to have __has_attribute, then they are too old to support symver)
+# other compilers might not have __has_attribute, but in those cases
+# it is safe for this check to fail and for us to fallback to the old _asm_
+# method for symver. Anyway the attributes not supported by __has_attribute()
+# unfortunately return true giving a false positive. So let's try to build
+# using __attribute__ ((symver )) and see the result.
+code = '''
+__attribute__ ((symver ("test@TEST")))
+void foo(void) {
+}
+
+int main(void) {
+    return 0;
+}'''
+if cc.compiles(code, args: [ '-O0', '-c', '-Werror'])
+     message('Compiler supports symver attribute')
+     add_project_arguments('-DHAVE_SYMVER_ATTRIBUTE', language: 'c')
+else
+     message('Compiler does not support symver attribute')
+endif
+
 # '.' will refer to current build directory, which contains config.h
 include_dirs = include_directories('include', 'lib', '.')
 
@@ -96,7 +123,7 @@
 #
 # Read build files from sub-directories
 #
-subdirs = [ 'lib', 'include', 'test' ]
+subdirs = [ 'lib', 'include']
 if get_option('utils') and not platform.endswith('bsd') and platform != 'dragonfly'
   subdirs += [ 'util', 'doc' ]
 endif
@@ -105,6 +132,10 @@
   subdirs += 'example'
 endif
 
+if get_option('tests')
+  subdirs += 'test'
+endif
+
 foreach n : subdirs
     subdir(n)
 endforeach