aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2021-06-12 17:37:13 +0300
committerNikolaus Rath <Nikolaus@rath.org>2021-06-14 09:13:12 +0100
commit80f2b8b469d97349d87cfd59725cbc7c19959bf6 (patch)
tree96a378dfd67f3cbadcf30a80d803d3cb8c7d3e31
parent10ecd4fda404f3403e571a7dbfe6bb295d0f208b (diff)
downloadlibfuse-80f2b8b469d97349d87cfd59725cbc7c19959bf6.tar.gz
passthrough_hp: excercise reusing inode numbers
Before last unlink() release the reference on inode.fd to allow reuse of underlying fs inode number, mark the server inode "deleted" and bump it's generation counter. When same inode number is found on lookup(), the server inode object will be reused as well. Skip this when inode has an open file and when writeback cache is enabled. This will be used to verify inode reuse bug fix in the kernel. Signed-off-by: Amir Goldstein <amir73il@gmail.com>
-rw-r--r--example/passthrough_hp.cc57
1 files changed, 50 insertions, 7 deletions
diff --git a/example/passthrough_hp.cc b/example/passthrough_hp.cc
index e976166..872fc73 100644
--- a/example/passthrough_hp.cc
+++ b/example/passthrough_hp.cc
@@ -123,6 +123,8 @@ struct Inode {
int fd {-1};
dev_t src_dev {0};
ino_t src_ino {0};
+ int generation {0};
+ uint64_t nopen {0};
uint64_t nlookup {0};
std::mutex m;
@@ -340,12 +342,20 @@ static int do_lookup(fuse_ino_t parent, const char *name,
}
e->ino = reinterpret_cast<fuse_ino_t>(inode_p);
Inode& inode {*inode_p};
+ e->generation = inode.generation;
- if(inode.fd != -1) { // found existing inode
+ if (inode.fd == -ENOENT) { // found unlinked inode
+ if (fs.debug)
+ cerr << "DEBUG: lookup(): inode " << e->attr.st_ino
+ << " recycled; generation=" << inode.generation << endl;
+ /* fallthrough to new inode but keep existing inode.nlookup */
+ }
+
+ if (inode.fd > 0) { // found existing inode
fs_lock.unlock();
if (fs.debug)
cerr << "DEBUG: lookup(): inode " << e->attr.st_ino
- << " (userspace) already known." << endl;
+ << " (userspace) already known; fd = " << inode.fd << endl;
lock_guard<mutex> g {inode.m};
inode.nlookup++;
close(newfd);
@@ -357,13 +367,13 @@ static int do_lookup(fuse_ino_t parent, const char *name,
lock_guard<mutex> g {inode.m};
inode.src_ino = e->attr.st_ino;
inode.src_dev = e->attr.st_dev;
- inode.nlookup = 1;
+ inode.nlookup++;
inode.fd = newfd;
fs_lock.unlock();
if (fs.debug)
cerr << "DEBUG: lookup(): created userspace inode " << e->attr.st_ino
- << endl;
+ << "; fd = " << inode.fd << endl;
}
return 0;
@@ -496,6 +506,30 @@ static void sfs_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
static void sfs_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) {
Inode& inode_p = get_inode(parent);
+ // Release inode.fd before last unlink like nfsd EXPORT_OP_CLOSE_BEFORE_UNLINK
+ // to test reused inode numbers.
+ // Skip this when inode has an open file and when writeback cache is enabled.
+ if (!fs.timeout) {
+ fuse_entry_param e;
+ auto err = do_lookup(parent, name, &e);
+ if (err) {
+ fuse_reply_err(req, err);
+ return;
+ }
+ if (e.attr.st_nlink == 1) {
+ Inode& inode = get_inode(e.ino);
+ lock_guard<mutex> g {inode.m};
+ if (inode.fd > 0 && !inode.nopen) {
+ if (fs.debug)
+ cerr << "DEBUG: unlink: release inode " << e.attr.st_ino
+ << "; fd=" << inode.fd << endl;
+ lock_guard<mutex> g_fs {fs.mutex};
+ close(inode.fd);
+ inode.fd = -ENOENT;
+ inode.generation++;
+ }
+ }
+ }
auto res = unlinkat(inode_p.fd, name, 0);
fuse_reply_err(req, res == -1 ? errno : 0);
}
@@ -764,8 +798,13 @@ static void sfs_create(fuse_req_t req, fuse_ino_t parent, const char *name,
if (err == ENFILE || err == EMFILE)
cerr << "ERROR: Reached maximum number of file descriptors." << endl;
fuse_reply_err(req, err);
- } else
- fuse_reply_create(req, &e, fi);
+ return;
+ }
+
+ Inode& inode = get_inode(e.ino);
+ lock_guard<mutex> g {inode.m};
+ inode.nopen++;
+ fuse_reply_create(req, &e, fi);
}
@@ -814,6 +853,8 @@ static void sfs_open(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi) {
return;
}
+ lock_guard<mutex> g {inode.m};
+ inode.nopen++;
fi->keep_cache = (fs.timeout != 0);
fi->fh = fd;
fuse_reply_open(req, fi);
@@ -821,7 +862,9 @@ static void sfs_open(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi) {
static void sfs_release(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi) {
- (void) ino;
+ Inode& inode = get_inode(ino);
+ lock_guard<mutex> g {inode.m};
+ inode.nopen--;
close(fi->fh);
fuse_reply_err(req, 0);
}