diff options
author | Horst Birthelmer <hbirthelmer@ddn.com> | 2024-11-20 16:14:43 +0100 |
---|---|---|
committer | Bernd Schubert <bernd.schubert@fastmail.fm> | 2024-11-27 13:38:56 +0100 |
commit | 4ec109d1c447bbf5be05854e32d8683bb1df5a80 (patch) | |
tree | 4283922b8aee6846ea111499285174232ed062b8 /example | |
parent | 8b34ed03682bb7806a6083b05187c4fc5475a135 (diff) | |
download | libfuse-4ec109d1c447bbf5be05854e32d8683bb1df5a80.tar.gz |
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
Diffstat (limited to 'example')
-rw-r--r-- | example/passthrough_hp.cc | 81 | ||||
-rw-r--r-- | example/passthrough_ll.c | 106 |
2 files changed, 168 insertions, 19 deletions
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<mutex> fs_lock {fs.mutex}; + Inode* p_inode; + try { + p_inode = &fs.inodes[id]; + } catch (std::bad_alloc&) { + return NULL; + } + + e->ino = reinterpret_cast<fuse_ino_t>(p_inode); + e->generation = p_inode->generation; + + lock_guard<mutex> 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<mutex> 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; diff --git a/example/passthrough_ll.c b/example/passthrough_ll.c index 62a42f4..309d8dd 100644 --- a/example/passthrough_ll.c +++ b/example/passthrough_ll.c @@ -308,6 +308,55 @@ static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st) return ret; } + +static struct lo_inode *create_new_inode(int fd, struct fuse_entry_param *e, struct lo_data* lo) +{ + struct lo_inode *inode = NULL; + struct lo_inode *prev, *next; + + inode = calloc(1, sizeof(struct lo_inode)); + if (!inode) + return NULL; + + inode->refcount = 1; + inode->fd = fd; + inode->ino = e->attr.st_ino; + inode->dev = e->attr.st_dev; + + pthread_mutex_lock(&lo->mutex); + prev = &lo->root; + next = prev->next; + next->prev = inode; + inode->next = next; + inode->prev = prev; + prev->next = inode; + pthread_mutex_unlock(&lo->mutex); + return inode; +} + +static int fill_entry_param_new_inode(fuse_req_t req, fuse_ino_t parent, int fd, struct fuse_entry_param *e) +{ + int res; + struct lo_data *lo = lo_data(req); + + memset(e, 0, sizeof(*e)); + e->attr_timeout = lo->timeout; + e->entry_timeout = lo->timeout; + + res = fstatat(fd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); + if (res == -1) + return errno; + + e->ino = (uintptr_t) create_new_inode(dup(fd), e, lo); + + if (lo_debug(req)) + fuse_log(FUSE_LOG_DEBUG, " %lli/%lli -> %lli\n", + (unsigned long long) parent, fd, (unsigned long long) e->ino); + + return 0; + +} + static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name, struct fuse_entry_param *e) { @@ -334,26 +383,9 @@ static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name, close(newfd); newfd = -1; } else { - struct lo_inode *prev, *next; - - saverr = ENOMEM; - inode = calloc(1, sizeof(struct lo_inode)); + inode = create_new_inode(newfd, e, lo); if (!inode) goto out_err; - - inode->refcount = 1; - inode->fd = newfd; - inode->ino = e->attr.st_ino; - inode->dev = e->attr.st_dev; - - pthread_mutex_lock(&lo->mutex); - prev = &lo->root; - next = prev->next; - next->prev = inode; - inode->next = next; - inode->prev = prev; - prev->next = inode; - pthread_mutex_unlock(&lo->mutex); } e->ino = (uintptr_t) inode; @@ -754,7 +786,7 @@ static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info fuse_reply_err(req, 0); } -static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, +static void lo_tmpfile(fuse_req_t req, fuse_ino_t parent, mode_t mode, struct fuse_file_info *fi) { int fd; @@ -763,6 +795,41 @@ static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, int err; if (lo_debug(req)) + fuse_log(FUSE_LOG_DEBUG, "lo_tmpfile(parent=%" PRIu64 ")\n", + parent); + + fd = openat(lo_fd(req, parent), ".", + (fi->flags | O_TMPFILE) & ~O_NOFOLLOW, mode); + if (fd == -1) + return (void) fuse_reply_err(req, errno); + + fi->fh = fd; + if (lo->cache == CACHE_NEVER) + fi->direct_io = 1; + else if (lo->cache == CACHE_ALWAYS) + fi->keep_cache = 1; + + /* parallel_direct_writes feature depends on direct_io features. + To make parallel_direct_writes valid, need set fi->direct_io + in current function. */ + fi->parallel_direct_writes = 1; + + err = fill_entry_param_new_inode(req, parent, fd, &e); + if (err) + fuse_reply_err(req, err); + else + fuse_reply_create(req, &e, fi); +} + +static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_file_info *fi) +{ + int fd; + struct lo_data *lo = lo_data(req); + struct fuse_entry_param e; + int err; + + if (lo_debug(req)) fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n", parent, name); @@ -1178,6 +1245,7 @@ static const struct fuse_lowlevel_ops lo_oper = { .releasedir = lo_releasedir, .fsyncdir = lo_fsyncdir, .create = lo_create, + .tmpfile = lo_tmpfile, .open = lo_open, .release = lo_release, .flush = lo_flush, |