Loading src/client/fuse/fuse_client.cpp +129 −6 Original line number Diff line number Diff line Loading @@ -200,8 +200,8 @@ init_handler(void* userdata, struct fuse_conn_info* conn) { conn->want |= FUSE_CAP_ASYNC_DIO; } // conn->want |= FUSE_CAP_READDIRPLUS; // conn->want |= FUSE_CAP_READDIRPLUS_AUTO; conn->want |= FUSE_CAP_READDIRPLUS; conn->want |= FUSE_CAP_READDIRPLUS_AUTO; if(ud->splice) { conn->want |= FUSE_CAP_SPLICE_READ; Loading Loading @@ -530,14 +530,13 @@ readdir_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, DEBUG_INFO(ud, "readdir handler"); auto open_dir = CTX->file_map()->get_dir(fi->fh); DEBUG_INFO(ud, "read dir %s", open_dir->path().c_str()); if(open_dir == nullptr) { fuse_reply_err(req, EBADF); return; } DEBUG_INFO(ud, "read dir %s", open_dir->path().c_str()); // Allocate a buffer to accumulate entries char* buf = static_cast<char*>(malloc(size)); if(!buf) { Loading Loading @@ -602,6 +601,130 @@ readdir_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, free(buf); } static void readdirplus_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info* fi) { auto* ud = udata(req); DEBUG_INFO(ud, "readdirplus handler"); auto open_dir = CTX->file_map()->get_dir(fi->fh); if(open_dir == nullptr) { fuse_reply_err(req, EBADF); return; } DEBUG_INFO(ud, "read dirplus %s", open_dir->path().c_str()); // Allocate a buffer to accumulate entries char* buf = static_cast<char*>(malloc(size)); if(!buf) { fuse_reply_err(req, ENOMEM); return; } size_t bytes_filled = 0; size_t pos = off; // Only include GekkoFS entries (skip standard files) while(pos < open_dir->size()) { auto de = open_dir->getdent(pos); // --- TODO maybe refactor into fn with lookup_handler std::string child = open_dir->path() == "/" ? "/" + de.name() : open_dir->path() + "/" + de.name(); DEBUG_INFO(ud, "read dirplus child %s", child.c_str()); struct stat st{}; fuse_entry_param e = {}; if(de.name() == "." || de.name() == "..") { st.st_ino = std::hash<std::string>()(open_dir->path() + "/" + de.name()); st.st_mode = (de.type() == gkfs::filemap::FileType::regular) ? S_IFREG : S_IFDIR; } else { int rc = gkfs::syscall::gkfs_stat(child, &st); if(rc < 0) { fuse_reply_err(req, ENOENT); return; } // See if we already have this path // TODO Do we have to lock here? The test ends up in a deadlock! // std::lock_guard<std::mutex> lk(ino_mutex); auto it = path_map.find(child); fuse_ino_t ino; if(it != path_map.end()) { ino = it->second; auto inode = get_inode(ino); if(inode) { inode->lookup_count++; } } else { ino = alloc_inode(child); } e.ino = ino; } e.attr = st; e.attr_timeout = ud->timeout; e.entry_timeout = ud->timeout; // --- size_t entry_size = fuse_add_direntry_plus( req, buf + bytes_filled, size - bytes_filled, de.name().c_str(), &e, pos + 1); if(entry_size > size - bytes_filled) break; // not enough space left bytes_filled += entry_size; pos += 1; } // FIFO entries if(ud->fifo) { int i = 0; for(auto const& kv : local_fifos) { if(i < off) { i++; continue; } std::filesystem::path vpath = kv.first; const struct stat& st = kv.second; // check if FIFO belongs to this directory if(vpath.parent_path() != open_dir->path()) continue; std::string fname = vpath.filename(); fuse_entry_param e{}; e.ino = st.st_ino; e.attr = st; e.attr_timeout = ud->timeout; e.entry_timeout = ud->timeout; size_t entry_size = fuse_add_direntry_plus( req, buf + bytes_filled, size - bytes_filled, fname.c_str(), &e, pos + 1); if(entry_size > size - bytes_filled) break; bytes_filled += entry_size; pos += 1; } } open_dir->pos(pos); // update internal position if needed fuse_reply_buf(req, buf, bytes_filled); free(buf); } static void releasedir_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) { auto* ud = udata(req); Loading Loading @@ -1021,7 +1144,7 @@ init_ll_ops(fuse_lowlevel_ops* ops) { ops->readdir = readdir_handler; ops->opendir = opendir_handler; ops->releasedir = releasedir_handler; // ops->readdirplus = readdirplus_handler; ops->readdirplus = readdirplus_handler; // ops->fsyncdir = nullptr; // I/O Loading Loading
src/client/fuse/fuse_client.cpp +129 −6 Original line number Diff line number Diff line Loading @@ -200,8 +200,8 @@ init_handler(void* userdata, struct fuse_conn_info* conn) { conn->want |= FUSE_CAP_ASYNC_DIO; } // conn->want |= FUSE_CAP_READDIRPLUS; // conn->want |= FUSE_CAP_READDIRPLUS_AUTO; conn->want |= FUSE_CAP_READDIRPLUS; conn->want |= FUSE_CAP_READDIRPLUS_AUTO; if(ud->splice) { conn->want |= FUSE_CAP_SPLICE_READ; Loading Loading @@ -530,14 +530,13 @@ readdir_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, DEBUG_INFO(ud, "readdir handler"); auto open_dir = CTX->file_map()->get_dir(fi->fh); DEBUG_INFO(ud, "read dir %s", open_dir->path().c_str()); if(open_dir == nullptr) { fuse_reply_err(req, EBADF); return; } DEBUG_INFO(ud, "read dir %s", open_dir->path().c_str()); // Allocate a buffer to accumulate entries char* buf = static_cast<char*>(malloc(size)); if(!buf) { Loading Loading @@ -602,6 +601,130 @@ readdir_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, free(buf); } static void readdirplus_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info* fi) { auto* ud = udata(req); DEBUG_INFO(ud, "readdirplus handler"); auto open_dir = CTX->file_map()->get_dir(fi->fh); if(open_dir == nullptr) { fuse_reply_err(req, EBADF); return; } DEBUG_INFO(ud, "read dirplus %s", open_dir->path().c_str()); // Allocate a buffer to accumulate entries char* buf = static_cast<char*>(malloc(size)); if(!buf) { fuse_reply_err(req, ENOMEM); return; } size_t bytes_filled = 0; size_t pos = off; // Only include GekkoFS entries (skip standard files) while(pos < open_dir->size()) { auto de = open_dir->getdent(pos); // --- TODO maybe refactor into fn with lookup_handler std::string child = open_dir->path() == "/" ? "/" + de.name() : open_dir->path() + "/" + de.name(); DEBUG_INFO(ud, "read dirplus child %s", child.c_str()); struct stat st{}; fuse_entry_param e = {}; if(de.name() == "." || de.name() == "..") { st.st_ino = std::hash<std::string>()(open_dir->path() + "/" + de.name()); st.st_mode = (de.type() == gkfs::filemap::FileType::regular) ? S_IFREG : S_IFDIR; } else { int rc = gkfs::syscall::gkfs_stat(child, &st); if(rc < 0) { fuse_reply_err(req, ENOENT); return; } // See if we already have this path // TODO Do we have to lock here? The test ends up in a deadlock! // std::lock_guard<std::mutex> lk(ino_mutex); auto it = path_map.find(child); fuse_ino_t ino; if(it != path_map.end()) { ino = it->second; auto inode = get_inode(ino); if(inode) { inode->lookup_count++; } } else { ino = alloc_inode(child); } e.ino = ino; } e.attr = st; e.attr_timeout = ud->timeout; e.entry_timeout = ud->timeout; // --- size_t entry_size = fuse_add_direntry_plus( req, buf + bytes_filled, size - bytes_filled, de.name().c_str(), &e, pos + 1); if(entry_size > size - bytes_filled) break; // not enough space left bytes_filled += entry_size; pos += 1; } // FIFO entries if(ud->fifo) { int i = 0; for(auto const& kv : local_fifos) { if(i < off) { i++; continue; } std::filesystem::path vpath = kv.first; const struct stat& st = kv.second; // check if FIFO belongs to this directory if(vpath.parent_path() != open_dir->path()) continue; std::string fname = vpath.filename(); fuse_entry_param e{}; e.ino = st.st_ino; e.attr = st; e.attr_timeout = ud->timeout; e.entry_timeout = ud->timeout; size_t entry_size = fuse_add_direntry_plus( req, buf + bytes_filled, size - bytes_filled, fname.c_str(), &e, pos + 1); if(entry_size > size - bytes_filled) break; bytes_filled += entry_size; pos += 1; } } open_dir->pos(pos); // update internal position if needed fuse_reply_buf(req, buf, bytes_filled); free(buf); } static void releasedir_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) { auto* ud = udata(req); Loading Loading @@ -1021,7 +1144,7 @@ init_ll_ops(fuse_lowlevel_ops* ops) { ops->readdir = readdir_handler; ops->opendir = opendir_handler; ops->releasedir = releasedir_handler; // ops->readdirplus = readdirplus_handler; ops->readdirplus = readdirplus_handler; // ops->fsyncdir = nullptr; // I/O Loading