<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><br><div><div><br><blockquote type="cite"><div>2023年7月24日 18:53,Yue Hu <zbestahu@gmail.com> 写道:</div><br class="Apple-interchange-newline"><div>Hi Yiyan,<br><br>Thanks for the patch!  Some comments below...<br><br>On Mon, 24 Jul 2023 13:35:27 +0800<br>Li Yiyan <<a href="mailto:lyy0627@sjtu.edu.cn">lyy0627@sjtu.edu.cn</a>> wrote:<br><br><blockquote type="cite">Add support for fuse2/3 lowlevel API in erofsfuse,<br>pass the make check test in experimental-test branch.<br>Conduct performance evaluation, providing higher<br>performance compared to highlevel API while<br>retaining compatibility with highlevel API of fuse 2.<br><br>Signed-off-by: Li Yiyan <lyy0627@sjtu.edu.cn><br>---<br>configure.ac     |  26 ++-<br>fuse/Makefile.am |   6 +-<br>fuse/lowlevel.c  | 553 +++++++++++++++++++++++++++++++++++++++++++++++<br>fuse/main.c      |  83 ++++++-<br>4 files changed, 653 insertions(+), 15 deletions(-)<br>create mode 100644 fuse/lowlevel.c<br><br>diff --git a/configure.ac b/configure.ac<br>index a8cecd0..d8d648e 100644<br>--- a/configure.ac<br>+++ b/configure.ac<br>@@ -336,15 +336,27 @@ AS_IF([test "x$with_selinux" != "xno"], [<br><br># Configure fuse<br>AS_IF([test "x$enable_fuse" != "xno"], [<br>-  PKG_CHECK_MODULES([libfuse], [fuse >= 2.6])<br>-  # Paranoia: don't trust the result reported by pkgconfig before trying out<br>  saved_LIBS="$LIBS"<br>  saved_CPPFLAGS=${CPPFLAGS}<br>-  CPPFLAGS="${libfuse_CFLAGS} ${CPPFLAGS}"<br>-  LIBS="${libfuse_LIBS} $LIBS"<br>-  AC_CHECK_LIB(fuse, fuse_main, [<br>-    have_fuse="yes" ], [<br>-    AC_MSG_ERROR([libfuse (>= 2.6) doesn't work properly])])<br>+  PKG_CHECK_MODULES([libfuse3], [fuse3 >= 3.0], [<br>+    AC_DEFINE([FUSE_USE_VERSION], [30], [used FUSE API version])<br>+    CPPFLAGS="${libfuse3_CFLAGS} ${CPPFLAGS}"<br>+    LIBS="${libfuse3_LIBS} $LIBS"<br>+    AC_CHECK_LIB(fuse3, fuse_session_new, [ AC_DEFINE([USE_LOWLEVEL], [1], [Define to 1 if libfuse lowlevel api available]) ], [<br>+    AC_MSG_ERROR([libfuse3 (>= 3.0) doesn't work properly for lowlevel api])])<br>+    have_fuse="yes"<br>+  ], [<br>+    PKG_CHECK_MODULES([libfuse2], [fuse >= 2.6], [<br>+      AC_DEFINE([FUSE_USE_VERSION], [26], [used FUSE API version])<br>+      CPPFLAGS="${libfuse2_CFLAGS} ${CPPFLAGS}"<br>+      LIBS="${libfuse2_LIBS} $LIBS"<br>+      AC_CHECK_LIB(fuse, fuse_lowlevel_new, [ AC_DEFINE([USE_LOWLEVEL], [1], [Define to 1 if libfuse lowlevel api available]) ], [<br>+        AC_MSG_NOTICE([libfuse (>= 2.6) doesn't work properly for lowlevel api])])<br>+      AC_CHECK_LIB(fuse, fuse_main, , [<br>+        AC_MSG_ERROR([libfuse (>= 2.6) doesn't work properly for highlevel api and lowlevel api])])<br>+      have_fuse="yes"<br>+    ], [have_fuse="no"])<br>+  ])<br></blockquote><br>We may drop high level part if low level is working fine, so `USE_LOWLEVEL` is unneeded.<br></div></blockquote><div><br></div><div>Thanks.</div><br><blockquote type="cite"><br><blockquote type="cite">  LIBS="${saved_LIBS}"<br>  CPPFLAGS="${saved_CPPFLAGS}"], [have_fuse="no"])<br><br>diff --git a/fuse/Makefile.am b/fuse/Makefile.am<br>index 50be783..d54fc89 100644<br>--- a/fuse/Makefile.am<br>+++ b/fuse/Makefile.am<br>@@ -3,8 +3,8 @@<br>AUTOMAKE_OPTIONS = foreign<br>noinst_HEADERS = $(top_srcdir)/fuse/macosx.h<br>bin_PROGRAMS     = erofsfuse<br>-erofsfuse_SOURCES = main.c<br>+erofsfuse_SOURCES = main.c lowlevel.c<br>erofsfuse_CFLAGS = -Wall -I$(top_srcdir)/include<br>-erofsfuse_CFLAGS += -DFUSE_USE_VERSION=26 ${libfuse_CFLAGS} ${libselinux_CFLAGS}<br>-erofsfuse_LDADD = $(top_builddir)/lib/liberofs.la ${libfuse_LIBS} ${liblz4_LIBS} \<br>+erofsfuse_CFLAGS += ${libfuse2_CFLAGS} ${libfuse3_CFLAGS} ${libselinux_CFLAGS}<br>+erofsfuse_LDADD = $(top_builddir)/lib/liberofs.la ${libfuse2_LIBS} ${libfuse3_LIBS} ${liblz4_LIBS} \<br><span class="Apple-tab-span" style="white-space: pre;"> </span>${libselinux_LIBS} ${liblzma_LIBS} ${zlib_LIBS} ${libdeflate_LIBS}<br>diff --git a/fuse/lowlevel.c b/fuse/lowlevel.c<br>new file mode 100644<br>index 0000000..89d3077<br>--- /dev/null<br>+++ b/fuse/lowlevel.c<br>@@ -0,0 +1,553 @@<br>+// SPDX-License-Identifier: GPL-2.0+<br>+/*<br>+ * Created by Li Yiyan <lyy0627@sjtu.edu.com><br>+ */<br>+#include "erofs/config.h"<br>+#include "erofs/dir.h"<br>+#include "erofs/inode.h"<br>+#include "erofs/io.h"<br>+#include "erofs/print.h"<br>+#include "macosx.h"<br>+#include "config.h"<br>+#include <fuse_opt.h><br>+#include <libgen.h><br>+#include <signal.h><br>+#include <stdlib.h><br>+#include <string.h><br>+#include <float.h><br>+<br>+#if FUSE_USE_VERSION >= 30<br>+#include <fuse3/fuse_lowlevel.h><br>+#include <fuse3/fuse.h><br>+#else<br>+#include <fuse.h><br>+#include <fuse_lowlevel.h><br>+#endif<br>+<br>+#define TMP_BUF_SIZE 4096<br></blockquote><br>I'm not sure it's a good definition.<br></blockquote><div><br></div><span style="font-variant-ligatures: normal; orphans: 2; widows: 2; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><font face="PingFangSC-Regular"><font color="#24292f"><span style="font-size: 14px;">Because in the listxattr/getxattr interface, fuse first calls </span></font></font></span></div><div><span style="font-variant-ligatures: normal; orphans: 2; widows: 2; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><font face="PingFangSC-Regular"><font color="#24292f"><span style="font-size: 14px;">erofsfuse_ll_listxattr and sets the parameter `size` to 0. </span></font></font></span></div><div><span style="font-variant-ligatures: normal; orphans: 2; widows: 2; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><font face="PingFangSC-Regular"><font color="#24292f"><span style="font-size: 14px;">This requires the implementation to use fuse_reply_xattr </span></font></font></span></div><div><span style="font-variant-ligatures: normal; orphans: 2; widows: 2; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><font face="PingFangSC-Regular"><font color="#24292f"><span style="font-size: 14px;">to return the size of the xattr. However, there is no suitable </span></font></font></span></div><div><span style="font-variant-ligatures: normal; orphans: 2; widows: 2; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><font face="PingFangSC-Regular"><font color="#24292f"><span style="font-size: 14px;">implementation in the erofs library. Therefore, I chose to </span></font></font></span></div><div><span style="font-variant-ligatures: normal; orphans: 2; widows: 2; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><font face="PingFangSC-Regular"><font color="#24292f"><span style="font-size: 14px;">allocate a sufficient xattr buffer and call the existing </span></font></font></span></div><div><span style="font-variant-ligatures: normal; orphans: 2; widows: 2; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><font face="PingFangSC-Regular"><font color="#24292f"><span style="font-size: 14px;">erofs_listxattr interface to return the correct size.</span></font></font></span><br><blockquote type="cite"><br><blockquote type="cite">+static const double EROFS_TIMEOUT = DBL_MAX;<br>+<br>+struct erofsfuse_ll_dir_context {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct erofs_dir_context ctx;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>fuse_req_t req;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>void *buf;<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>int is_plus;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>size_t offset;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>size_t buf_size;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>size_t start_off;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>struct fuse_file_info *fi;<br>+};<br>+<br>+struct erofsfuse_ll_dir_search_context {<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>struct erofs_dir_context ctx;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>const char *target_name;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>size_t target_name_len;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>struct fuse_entry_param *ent;<br>+};<br>+<br>+static int erofsfuse_ll_fill_dentries(struct erofs_dir_context *ctx)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>size_t r = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>struct stat st = { 0 };<br>+#if FUSE_USE_VERSION >= 30<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>struct fuse_entry_param param;<br>+#endif<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>char dname[EROFS_NAME_LEN + 1];<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>struct erofsfuse_ll_dir_context *fusectx = (void *)ctx;<br></blockquote><br>Why using void pointer cast?<br></blockquote><div><br></div>Thanks.<br><blockquote type="cite"><br><blockquote type="cite">+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>if (fusectx->offset < fusectx->start_off) {<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fusectx->offset +=<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>ctx->de_namelen + sizeof(struct erofs_dirent);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>strncpy(dname, ctx->dname, ctx->de_namelen);<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>dname[ctx->de_namelen] = '\0';<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>fusectx->offset += ctx->de_namelen + sizeof(struct erofs_dirent);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>if (!fusectx->is_plus) {<br></blockquote><br>Why need `is_plus`? Could we move this part under #else branch instead?<br></blockquote><div><br></div><span style="font-family: "Noto Sans SC", "SF Pro SC", "SF Pro Text", "SF Pro Icons", "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">In fact, in fuse3, support for both readdir and readdirplus is still required. </span></div><div><span style="font-family: "Noto Sans SC", "SF Pro SC", "SF Pro Text", "SF Pro Icons", "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; font-variant-ligatures: normal; orphans: 2; widows: 2; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">We need to compile code for both branches in fuse3.</span><br><blockquote type="cite"><br><blockquote type="cite">+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>st.st_mode = erofs_ftype_to_dtype(ctx->de_ftype);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>st.st_ino = ctx->de_nid;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>r = fuse_add_direntry(fusectx->req, fusectx->buf,<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>      fusectx->buf_size, dname, &st,<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>      fusectx->offset);<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>} else {<br>+#if FUSE_USE_VERSION >= 30<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>param.ino = ctx->de_nid;<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>param.generation = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>param.attr.st_ino = ctx->de_nid;<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>param.attr.st_mode = erofs_ftype_to_dtype(ctx->de_ftype);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>param.attr_timeout = EROFS_TIMEOUT;<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>param.entry_timeout = EROFS_TIMEOUT;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span>r = fuse_add_direntry_plus(fusectx->req, fusectx->buf,<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>   fusectx->buf_size, dname, &param,<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>   fusectx->offset);<br>+#endif<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>if (r > fusectx->buf_size) {<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fusectx->offset -=<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>ctx->de_namelen + sizeof(struct erofs_dirent);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return 1;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>fusectx->buf += r;<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>fusectx->buf_size -= r;<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>return 0;<br>+}<br>+<br>+static void erofsfuse_ll_fill_stat(struct erofs_inode *vi, struct stat *stbuf)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>stbuf->st_mode = vi->i_mode;<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>stbuf->st_nlink = vi->i_nlink;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>if (!S_ISDIR(stbuf->st_mode))<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>stbuf->st_size = vi->i_size;<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>if (S_ISBLK(vi->i_mode) || S_ISCHR(vi->i_mode))<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>stbuf->st_rdev = vi->u.i_rdev;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>stbuf->st_blocks = roundup(vi->i_size, erofs_blksiz()) >> 9;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>stbuf->st_uid = vi->i_uid;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>stbuf->st_gid = vi->i_gid;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>stbuf->st_ctime = vi->i_mtime;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>stbuf->st_mtime = stbuf->st_ctime;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>stbuf->st_atime = stbuf->st_ctime;<br>+}<br>+<br>+static int erofsfuse_ll_search_dentries(struct erofs_dir_context *ctx)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>int r = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>struct erofs_inode vi;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct erofsfuse_ll_dir_search_context *search_ctx = (void *)ctx;<br></blockquote><br>Why using void pointer cast?<br></blockquote><div><br></div>Thanks.<br><blockquote type="cite"><br><blockquote type="cite">+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (search_ctx->ent->ino == 0 &&<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>    search_ctx->target_name_len == ctx->de_namelen &&<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>    strncmp(search_ctx->target_name, ctx->dname, ctx->de_namelen) ==<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>    0) {<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>search_ctx->ent->ino = ctx->de_nid;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>search_ctx->ent->attr.st_ino = ctx->de_nid;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>vi.nid = (erofs_nid_t)ctx->de_nid;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>r = erofs_read_inode_from_disk(&vi);<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (r < 0)<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return r;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>erofsfuse_ll_fill_stat(&vi, &(search_ctx->ent->attr));<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>return 0;<br>+}<br>+<br>+void erofsfuse_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>  off_t off, struct fuse_file_info *fi)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>int err = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>char *buf = malloc(size);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>struct erofsfuse_ll_dir_context ctx;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>struct erofs_inode *vi = (struct erofs_inode *)fi->fh;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>erofs_dbg("readdir, ino: %lu, req: %p, fh: %lu, size: %lu, off: %lu\n",<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>  ino, req, fi->fh, size, off);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>if (!buf) {<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOMEM);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>ctx.ctx.dir = vi;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>ctx.ctx.cb = erofsfuse_ll_fill_dentries;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>ctx.fi = fi;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>ctx.buf = buf;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>ctx.buf_size = size;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>ctx.req = req;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>ctx.offset = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>ctx.is_plus = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>ctx.start_off = off;<br>+<br>+#ifdef NDEBUG<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>err = erofs_iterate_dir(&ctx.ctx, false);<br>+#else<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>err = erofs_iterate_dir(&ctx.ctx, true);<br>+#endif<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>if (err < 0) /* if buffer insufficient, return 1 */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>else<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_buf(req, buf, size - ctx.buf_size);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>free(buf);<br>+}<br>+<br>+void erofsfuse_ll_init(void *userdata, struct fuse_conn_info *conn)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>erofs_inode_manager_init();<br>+}<br>+<br>+void erofsfuse_ll_open(fuse_req_t req, fuse_ino_t ino,<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>       struct fuse_file_info *fi)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>int ret = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>struct erofs_inode *vi;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>erofs_dbg("open, ino = %lu, req = %p\n", ino, req);<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>if (fi->flags & (O_WRONLY | O_RDWR)) {<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EROFS);<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>if (ino == FUSE_ROOT_ID) {<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EISDIR);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>vi = (struct erofs_inode *)malloc(sizeof(struct erofs_inode));<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!vi) {<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOMEM);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>vi->nid = (erofs_nid_t)ino;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>ret = erofs_read_inode_from_disk(vi);<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>if (ret < 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto out;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>if (!S_ISREG(vi->i_mode)) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EISDIR);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto out;<br></blockquote><br>goto is not needed.<br></blockquote><div><br></div>Thanks.<br><blockquote type="cite"><br><blockquote type="cite">+<span class="Apple-tab-span" style="white-space: pre;">     </span>} else {<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fi->fh = (uint64_t)vi;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fi->keep_cache = 1;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_open(req, fi);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+out:<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>free(vi);<br>+}<br>+<br>+void erofsfuse_ll_getattr(fuse_req_t req, fuse_ino_t ino,<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>  struct fuse_file_info *fi)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>int ret;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>struct stat stbuf = { 0 };<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>struct erofs_inode vi;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>erofs_dbg("getattr triggered, ino: %lu, req: %p\n", ino, req);<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>vi.nid = ino == FUSE_ROOT_ID ? sbi.root_nid : (erofs_nid_t)ino;<br></blockquote><br>We use this in a couple of places.<br></blockquote><div><br></div>I’ll replace it with an inline function:</div><div><br></div><div><div style="line-height: 18px; white-space: pre;"><div><font face="PingFangSC-Regular">static inline erofs_nid_t erofsfuse_ll_getnid(fuse_ino_t ino)</font></div><div><font face="PingFangSC-Regular">{</font></div><div><font face="PingFangSC-Regular">        return ino == FUSE_ROOT_ID ? sbi.root_nid : (erofs_nid_t)ino;</font></div><div><font face="PingFangSC-Regular">}</font></div><div><font face="PingFangSC-Regular"><br></font></div></div><blockquote type="cite"><br><blockquote type="cite">+<span class="Apple-tab-span" style="white-space: pre;">       </span>ret = erofs_read_inode_from_disk(&vi);<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>if (ret < 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>erofs_dbg("read inode from disk failed, nid = %lu\n", vi.nid);<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOENT);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>erofsfuse_ll_fill_stat(&vi, &stbuf);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>stbuf.st_ino = ino;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>fuse_reply_attr(req, &stbuf, EROFS_TIMEOUT);<br>+}<br>+<br>+void erofsfuse_ll_opendir(fuse_req_t req, fuse_ino_t ino,<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>  struct fuse_file_info *fi)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>int ret;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>struct erofs_inode *vi;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>erofs_dbg("opendir, ino = %lu\n", ino);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>vi = (struct erofs_inode *)malloc(sizeof(struct erofs_inode));<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!vi) {<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOMEM);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>vi->nid = ino == FUSE_ROOT_ID ? sbi.root_nid : (erofs_nid_t)ino;<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>ret = erofs_read_inode_from_disk(vi);<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>if (ret < 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto out;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>if (!S_ISDIR(vi->i_mode)) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOTDIR);<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto out;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>fi->fh = (uint64_t)vi;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>fuse_reply_open(req, fi);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>return;<br>+<br>+out:<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>free(vi);<br>+}<br>+<br>+void erofsfuse_ll_releasedir(fuse_req_t req, fuse_ino_t ino,<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>     struct fuse_file_info *fi)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>free((struct erofs_inode *)fi->fh);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>fi->fh = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>fuse_reply_err(req, 0);<br>+}<br>+<br>+void erofsfuse_ll_release(fuse_req_t req, fuse_ino_t ino,<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>  struct fuse_file_info *fi)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>free((struct erofs_inode *)fi->fh);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>fi->fh = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>fuse_reply_err(req, 0);<br>+}<br></blockquote><br>duplicated function code.<br></blockquote><div><br></div>Thanks. erofsfuse_ll_release is enough.<blockquote type="cite"><blockquote type="cite">+<br>+void erofsfuse_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>int err, ret;<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>struct erofs_inode *vi;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>struct fuse_entry_param fentry;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>struct erofsfuse_ll_dir_search_context ctx;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>vi = (struct erofs_inode *)malloc(sizeof(struct erofs_inode));<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!vi) {<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOMEM);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>vi->nid = parent == FUSE_ROOT_ID ? sbi.root_nid : (erofs_nid_t)parent;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>ret = erofs_read_inode_from_disk(vi);<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>if (ret < 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto out;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>if (!S_ISDIR(vi->i_mode)) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOTDIR);<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto out;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>memset(&fentry, 0, sizeof(fentry));<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>fentry.ino = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>fentry.attr_timeout = fentry.entry_timeout = EROFS_TIMEOUT;<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>ctx.ctx.dir = vi;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>ctx.ctx.cb = erofsfuse_ll_search_dentries;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>ctx.ent = &fentry;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>ctx.target_name = name;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>ctx.target_name_len = strlen(name);<br>+<br>+#ifdef NDEBUG<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>err = erofs_iterate_dir(&ctx.ctx, false);<br>+#else<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>err = erofs_iterate_dir(&ctx.ctx, true);<br>+#endif<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>if (err < 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto out;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>fuse_reply_entry(req, &fentry);<br>+<br>+out:<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>free(vi);<br>+}<br>+<br>+void erofsfuse_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>       struct fuse_file_info *fi)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>int ret;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>struct erofs_inode *vi = (struct erofs_inode *)fi->fh;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>char *buf = malloc(size);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>erofs_dbg("read, ino = %lu, size = %lu, off = %lu, fh = %lu\n", ino,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>  size, off, fi->fh);<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>if (!buf) {<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOMEM);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>if (!S_ISREG(vi->i_mode)) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto out;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>ret = erofs_pread(vi, buf, size, off);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (ret == 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (off >= vi->i_size)<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>ret = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>else if (off + size > vi->i_size)<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>ret = vi->i_size - off;<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span>else<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>ret = size;<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>} else {<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto out;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br></blockquote><br><span class="Apple-tab-span" style="white-space: pre;">  </span>if (ret) {<br><span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto out;<br><span class="Apple-tab-span" style="white-space: pre;">       </span>}<br><span class="Apple-tab-span" style="white-space: pre;">       </span>if (off >= vi->i_size)<br><span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>ret = 0;<br><span class="Apple-tab-span" style="white-space: pre;">        </span>else if (off + size > vi->i_size)<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>ret = vi->i_size - off;<br><span class="Apple-tab-span" style="white-space: pre;">      </span>else<br><span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>ret = size;<br><br><blockquote type="cite">+<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>fuse_reply_buf(req, buf, ret);<br>+<br>+out:<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>free(buf);<br>+}<br>+<br>+void erofsfuse_ll_readlink(fuse_req_t req, fuse_ino_t ino)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>int ret;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>char *dst;<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>struct erofs_inode vi;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>erofs_dbg("read_link, ino = %lu\n", ino);<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>vi.nid = ino == FUSE_ROOT_ID ? sbi.root_nid : (erofs_nid_t)ino;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>ret = erofs_read_inode_from_disk(&vi);<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>if (ret < 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>if (!S_ISLNK(vi.i_mode)) {<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EINVAL);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>dst = malloc(vi.i_size + 1);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>if (!dst) {<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOMEM);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>ret = erofs_pread(&vi, dst, vi.i_size, 0);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (ret < 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto out;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>dst[vi.i_size] = '\0';<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>fuse_reply_readlink(req, dst);<br>+<br>+out:<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>free(dst);<br>+}<br>+<br>+void erofsfuse_ll_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>   size_t size)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>int ret;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>char *buf = NULL;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>struct erofs_inode vi;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>size_t real = size == 0 ? TMP_BUF_SIZE : size;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>erofs_dbg("getxattr, ino = %lu, name = %s, size = %lu\n", ino, name,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>  size);<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>vi.nid = ino == FUSE_ROOT_ID ? sbi.root_nid : (erofs_nid_t)ino;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>ret = erofs_read_inode_from_disk(&vi);<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>if (ret < 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>buf = malloc(real);<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>if (!buf) {<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOMEM);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>ret = erofs_getxattr(&vi, name, buf, real);<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>if (ret < 0)<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, -ret);<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>else if (size == 0)<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_xattr(req, ret);<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>else<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_buf(req, buf, ret);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>free(buf);<br>+}<br>+<br>+void erofsfuse_ll_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>int ret;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>char *buf = NULL;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>struct erofs_inode vi;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>size_t real = size == 0 ? TMP_BUF_SIZE : size;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>erofs_dbg("listxattr, ino = %lu, size = %lu\n", ino, size);<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>vi.nid = ino == FUSE_ROOT_ID ? sbi.root_nid : (erofs_nid_t)ino;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>ret = erofs_read_inode_from_disk(&vi);<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>if (ret < 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>buf = malloc(real);<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>if (!buf) {<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOMEM);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>ret = erofs_listxattr(&vi, buf, real);<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>if (ret < 0)<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, -ret);<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>else if (size == 0)<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_xattr(req, ret);<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>else<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_buf(req, buf, ret);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>free(buf);<br>+}<br>+<br>+#if FUSE_USE_VERSION >= 30<br>+void erofsfuse_ll_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>      off_t off, struct fuse_file_info *fi)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>int err = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>char *buf = malloc(size);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>struct erofsfuse_ll_dir_context ctx;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>struct erofs_inode *vi = (struct erofs_inode *)fi->fh;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>erofs_dbg("readdirplus, ino = %lu, size = %lu, off = %lu, fh = %lu\n",<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>  ino, size, off, fi->fh);<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>if (!buf) {<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, ENOMEM);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>ctx.ctx.dir = vi;<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>ctx.ctx.cb = erofsfuse_ll_fill_dentries;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>ctx.fi = fi;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>ctx.buf = buf;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>ctx.buf_size = size;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>ctx.req = req;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>ctx.offset = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>ctx.is_plus = 1;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>ctx.start_off = off;<br>+<br>+#ifdef NDEBUG<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>err = erofs_iterate_dir(&ctx.ctx, false);<br>+#else<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>err = erofs_iterate_dir(&ctx.ctx, true);<br>+#endif<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>if (err < 0) /* if buffer insufficient, return 1 */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_err(req, EIO);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>else<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_reply_buf(req, buf, size - ctx.buf_size);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>free(buf);<br>+}<br></blockquote><br>almost same as _readdir() except `is_plus`.<br></blockquote><div><br></div><div>Thanks.</div><br><blockquote type="cite"><br><blockquote type="cite">+#endif<br>+<br>+struct fuse_lowlevel_ops erofsfuse_lops = {<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>.getxattr = erofsfuse_ll_getxattr,<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>.opendir = erofsfuse_ll_opendir,<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>.releasedir = erofsfuse_ll_releasedir,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>.release = erofsfuse_ll_release,<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>.lookup = erofsfuse_ll_lookup,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>.listxattr = erofsfuse_ll_listxattr,<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>.readlink = erofsfuse_ll_readlink,<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>.getattr = erofsfuse_ll_getattr,<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>.readdir = erofsfuse_ll_readdir,<br>+#if FUSE_USE_VERSION >= 30<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>.readdirplus = erofsfuse_ll_readdirplus,<br>+#endif<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>.open = erofsfuse_ll_open,<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>.read = erofsfuse_ll_read,<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span>.init = erofsfuse_ll_init,<br>+};<br></blockquote><br>all functions above should be static.<br></blockquote><div><br></div>Thanks.<br><blockquote type="cite"><br><blockquote type="cite">diff --git a/fuse/main.c b/fuse/main.c<br>index b060e06..11726c1 100644<br>--- a/fuse/main.c<br>+++ b/fuse/main.c<br>@@ -6,8 +6,6 @@<br>#include <string.h><br>#include <signal.h><br>#include <libgen.h><br>-#include <fuse.h><br>-#include <fuse_opt.h><br>#include "macosx.h"<br>#include "erofs/config.h"<br>#include "erofs/print.h"<br>@@ -15,6 +13,23 @@<br>#include "erofs/dir.h"<br>#include "erofs/inode.h"<br><br>+#if FUSE_USE_VERSION >= 30<br>+#include <fuse3/fuse.h><br>+#include <fuse3/fuse_lowlevel.h><br>+#else<br>+#include <fuse.h><br>+#include <fuse_lowlevel.h><br>+#endif<br>+<br>+#if USE_LOWLEVEL<br></blockquote><br>no needed.<br><br><blockquote type="cite">+#include <float.h><br>+<br>+extern struct fuse_lowlevel_ops erofsfuse_lops;<br>+<br>+struct erofs_ll_ctx {<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>unsigned int debug_lvl;<br></blockquote><br>any user?<br></blockquote><div><br></div>Just prepare for future use. I’ll delete it.<br><blockquote type="cite"><br><blockquote type="cite">+};<br>+#else<br>struct erofsfuse_dir_context {<br><span class="Apple-tab-span" style="white-space: pre;">      </span>struct erofs_dir_context ctx;<br><span class="Apple-tab-span" style="white-space: pre;">   </span>fuse_fill_dir_t filler;<br>@@ -176,7 +191,7 @@ static int erofsfuse_listxattr(const char *path, char *list, size_t size)<br><span class="Apple-tab-span" style="white-space: pre;">  </span>return erofs_listxattr(&vi, list, size);<br>}<br><br>-static struct fuse_operations erofs_ops = {<br>+static struct fuse_operations erofsfuse_ops = {<br><span class="Apple-tab-span" style="white-space: pre;">       </span>.getxattr = erofsfuse_getxattr,<br><span class="Apple-tab-span" style="white-space: pre;"> </span>.listxattr = erofsfuse_listxattr,<br><span class="Apple-tab-span" style="white-space: pre;">       </span>.readlink = erofsfuse_readlink,<br>@@ -187,6 +202,8 @@ static struct fuse_operations erofs_ops = {<br><span class="Apple-tab-span" style="white-space: pre;">        </span>.init = erofsfuse_init,<br>};<br><br>+#endif<br>+<br>static struct options {<br><span class="Apple-tab-span" style="white-space: pre;">      </span>const char *disk;<br><span class="Apple-tab-span" style="white-space: pre;">       </span>const char *mountpoint;<br>@@ -207,7 +224,9 @@ static const struct fuse_opt option_spec[] = {<br><br>static void usage(void)<br>{<br>+#if FUSE_MAJOR_VERSION < 3<br><span class="Apple-tab-span" style="white-space: pre;">       </span>struct fuse_args args = FUSE_ARGS_INIT(0, NULL);<br>+#endif<br><br><span class="Apple-tab-span" style="white-space: pre;">     </span>fputs("usage: [options] IMAGE MOUNTPOINT\n\n"<br><span class="Apple-tab-span" style="white-space: pre;"> </span>      "Options:\n"<br>@@ -257,8 +276,12 @@ static int optional_opt_func(void *data, const char *arg, int key,<br><span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fusecfg.disk = strdup(arg);<br><span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return 0;<br><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>}<br>-<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (!fusecfg.mountpoint)<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (!fusecfg.mountpoint) {<br><span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fusecfg.mountpoint = strdup(arg);<br>+#if USE_LOWLEVEL<br></blockquote><br>no needed.<br><br><blockquote type="cite">+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>return 0;<br>+#endif<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span>}<br><span class="Apple-tab-span" style="white-space: pre;">       </span>case FUSE_OPT_KEY_OPT:<br><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (!strcmp(arg, "-d"))<br><span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fusecfg.odebug = true;<br>@@ -337,8 +360,58 @@ int main(int argc, char *argv[])<br><span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto err_dev_close;<br><span class="Apple-tab-span" style="white-space: pre;">     </span>}<br><br>-<span class="Apple-tab-span" style="white-space: pre;">    </span>ret = fuse_main(args.argc, args.argv, &erofs_ops, NULL);<br>+#if USE_LOWLEVEL<br></blockquote><br>no needed.<br><br><blockquote type="cite">+<span class="Apple-tab-span" style="white-space: pre;">     </span>struct erofs_ll_ctx *ll_ctx;<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>struct fuse_session *se;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">    </span>ll_ctx = malloc(sizeof(struct erofs_ll_ctx));<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>if (!ll_ctx) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fprintf(stderr, "failed to alloc memory for ll_ctx\n");<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>goto err_sb_put;<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>}<br>+<br>+#if FUSE_USE_VERSION >= 30<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>se = fuse_session_new(&args, &erofsfuse_lops, sizeof(erofsfuse_lops),<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>      ll_ctx);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span>if (se != NULL) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_set_signal_handlers(se);<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_session_mount(se, fusecfg.mountpoint);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span>ret = fuse_session_loop(se);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_remove_signal_handlers(se);<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_session_unmount(se);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_session_destroy(se);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>}<br>+#else<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span>struct fuse_chan *ch;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span>ch = fuse_mount(fusecfg.mountpoint, &args);<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>if (ch != NULL) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>se = fuse_lowlevel_new(&args, &erofsfuse_lops,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>       sizeof(erofsfuse_lops), ll_ctx);<br>+<span class="Apple-tab-span" style="white-space: pre;">     </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (se != NULL) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>if (fuse_set_signal_handlers(se) != -1) {<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_session_add_chan(se, ch);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>ret = fuse_session_loop(se);<br>+<span class="Apple-tab-span" style="white-space: pre;">   </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_remove_signal_handlers(se);<br>+<span class="Apple-tab-span" style="white-space: pre;">       </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_session_remove_chan(ch);<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_session_destroy(se);<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;">      </span><span class="Apple-tab-span" style="white-space: pre;">  </span>fuse_unmount(fusecfg.mountpoint, ch);<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>}<br>+#endif<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;">  </span>free(ll_ctx);<br><br>+#else<br>+<span class="Apple-tab-span" style="white-space: pre;">        </span>ret = fuse_main(args.argc, args.argv, &erofsfuse_ops, NULL);<br>+#endif<br>+<br>+#if USE_LOWLEVEL<br></blockquote><br>no needed.<br><br><blockquote type="cite">+err_sb_put:<br>+#endif<br><span class="Apple-tab-span" style="white-space: pre;">       </span>erofs_put_super();<br>err_dev_close:<br><span class="Apple-tab-span" style="white-space: pre;">      </span>blob_closeall();</blockquote></blockquote></div><br class="Apple-interchange-newline"></div></body></html>