From 4ec109d1c447bbf5be05854e32d8683bb1df5a80 Mon Sep 17 00:00:00 2001 From: Horst Birthelmer Date: Wed, 20 Nov 2024 16:14:43 +0100 Subject: support FUSE_TMPFILE in the low level API Note that name hashes and using paths as parameters makes it very hard to support anonymous files in the high level API. Known Issues: - tests have to bail out when O_TMPFILE is not supported. This will always be the case with high level passthrough implementations. - test_create_and_link_tmpfile has to be skipped due to unidentified problems with github runner --- example/passthrough_hp.cc | 81 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'example/passthrough_hp.cc') diff --git a/example/passthrough_hp.cc b/example/passthrough_hp.cc index c393f04..41904e5 100644 --- a/example/passthrough_hp.cc +++ b/example/passthrough_hp.cc @@ -914,6 +914,86 @@ static void sfs_create(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_reply_create(req, &e, fi); } +static Inode *create_new_inode(int fd, fuse_entry_param *e) +{ + memset(e, 0, sizeof(*e)); + e->attr_timeout = fs.timeout; + e->entry_timeout = fs.timeout; + + auto res = fstatat(fd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); + if (res == -1) { + if (fs.debug) + cerr << "DEBUG: lookup(): fstatat failed" << endl; + return NULL; + } + + SrcId id {e->attr.st_ino, e->attr.st_dev}; + unique_lock fs_lock {fs.mutex}; + Inode* p_inode; + try { + p_inode = &fs.inodes[id]; + } catch (std::bad_alloc&) { + return NULL; + } + + e->ino = reinterpret_cast(p_inode); + e->generation = p_inode->generation; + + lock_guard g {p_inode->m}; + p_inode->src_ino = e->attr.st_ino; + p_inode->src_dev = e->attr.st_dev; + + p_inode->nlookup++; + if (fs.debug) + cerr << "DEBUG:" << __func__ << ":" << __LINE__ << " " + << "inode " << p_inode->src_ino + << " count " << p_inode->nlookup << endl; + + p_inode->fd = fd; + fs_lock.unlock(); + + if (fs.debug) + cerr << "DEBUG: lookup(): created userspace inode " << e->attr.st_ino + << "; fd = " << p_inode->fd << endl; + return p_inode; +} + +static void sfs_tmpfile(fuse_req_t req, fuse_ino_t parent, + mode_t mode, fuse_file_info *fi) { + Inode& parent_inode = get_inode(parent); + + auto fd = openat(parent_inode.fd, ".", + (fi->flags | O_TMPFILE) & ~O_NOFOLLOW, mode); + if (fd == -1) { + auto err = errno; + if (err == ENFILE || err == EMFILE) + cerr << "ERROR: Reached maximum number of file descriptors." << endl; + fuse_reply_err(req, err); + return; + } + + fi->fh = fd; + fuse_entry_param e; + + Inode *inode = create_new_inode(dup(fd), &e); + if (inode == NULL) { + auto err = errno; + cerr << "ERROR: could not create new inode." << endl; + close(fd); + fuse_reply_err(req, err); + return; + } + + lock_guard g {inode->m}; + + sfs_create_open_flags(fi); + + if (fs.passthrough) + do_passthrough_open(req, e.ino, fd, fi); + + fuse_reply_create(req, &e, fi); +} + static void sfs_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, fuse_file_info *fi) { @@ -1237,6 +1317,7 @@ static void assign_operations(fuse_lowlevel_ops &sfs_oper) { sfs_oper.releasedir = sfs_releasedir; sfs_oper.fsyncdir = sfs_fsyncdir; sfs_oper.create = sfs_create; + sfs_oper.tmpfile = sfs_tmpfile; sfs_oper.open = sfs_open; sfs_oper.release = sfs_release; sfs_oper.flush = sfs_flush; -- cgit v1.2.3