From 540f80dbe8f71649767b675b810f53e65053018b Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 6 Oct 2020 09:40:59 +0200 Subject: [PATCH 1/6] main: record how many objects are in memory Signed-off-by: Giuseppe Scrivano --- main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/main.c b/main.c index 37abd8a..a1b264d 100644 --- a/main.c +++ b/main.c @@ -168,6 +168,14 @@ static gid_t overflow_gid; static struct ovl_ino dummy_ino; +struct stats_s +{ + size_t nodes; + size_t inodes; +}; + +static struct stats_s stats; + static double get_timeout (struct ovl_data *lo) { @@ -905,6 +913,7 @@ node_free (void *p) if (n->do_rmdir) unlinkat (n->hidden_dirfd, n->path, AT_REMOVEDIR); + stats.nodes--; free (n->name); free (n->path); free (n); @@ -926,6 +935,7 @@ inode_free (void *p) node_free (tmp); } + stats.inodes--; free (i); } @@ -1143,6 +1153,7 @@ register_inode (struct ovl_data *lo, struct ovl_node *n, mode_t mode) return NULL; } + stats.inodes++; return ino->node; } @@ -1248,6 +1259,7 @@ make_whiteout_node (const char *path, const char *name) ret_xchg = ret; ret = NULL; + stats.nodes++; return ret_xchg; } @@ -1460,6 +1472,7 @@ no_fd: ret_xchg = ret; ret = NULL; + stats.nodes++; return register_inode (lo, ret_xchg, mode); } From e9cdbc444c503733652fac65687e5077d4b4f1a3 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 6 Oct 2020 09:48:48 +0200 Subject: [PATCH 2/6] main: print usage statistics on USR1 Signed-off-by: Giuseppe Scrivano --- main.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/main.c b/main.c index a1b264d..20f61ab 100644 --- a/main.c +++ b/main.c @@ -50,23 +50,18 @@ #include #include #include - +#include #include #include #include #include - #include - #include - #include #include - -#include - #include +#include #include #ifndef TEMP_FAILURE_RETRY @@ -174,7 +169,16 @@ struct stats_s size_t inodes; }; -static struct stats_s stats; +static volatile struct stats_s stats; + +static void +print_stats (int sig) +{ + char fmt[128]; + int l = snprintf (fmt, sizeof (fmt) - 1, "# INODES: %zu\n# NODES: %zu\n", stats.inodes, stats.nodes); + fmt[l] = '\0'; + write (STDERR_FILENO, fmt, l + 1); +} static double get_timeout (struct ovl_data *lo) @@ -5462,6 +5466,9 @@ main (int argc, char *argv[]) error (0, errno, "cannot set signal handler"); goto err_out2; } + + signal (SIGUSR1, print_stats); + if (fuse_session_mount (se, lo.mountpoint) != 0) { error (0, errno, "cannot mount"); From 6e2675593ca8e5d7995c7dfd19e7d87b86c6d0e3 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 6 Oct 2020 09:33:28 +0200 Subject: [PATCH 3/6] main: attempt an inode free on releasedir if the reference held by the directory is the last one, it would miss to clean up the inode. Fix it by calling do_forget. Closes: https://github.com/containers/fuse-overlayfs/issues/238 Signed-off-by: Giuseppe Scrivano --- main.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/main.c b/main.c index 20f61ab..f1705ba 100644 --- a/main.c +++ b/main.c @@ -948,18 +948,14 @@ drop_node_from_ino (Hash_table *inodes, struct ovl_node *node) { struct ovl_ino *ino; struct ovl_node *it, *prev = NULL; - size_t len = 0; ino = node->ino; - for (it = ino->node; it; it = it->next_link) - len++; - - if (len == 1 && node->ino->lookups > 0) + /* If it is the only node referenced by the inode, do not destroy it. */ + if (ino->node == node && node->next_link == NULL) return; node->ino = NULL; - ino->lookups -= node->node_lookups; for (it = ino->node; it; it = it->next_link) { @@ -1161,17 +1157,17 @@ register_inode (struct ovl_data *lo, struct ovl_node *n, mode_t mode) return ino->node; } -static void +static bool do_forget (struct ovl_data *lo, fuse_ino_t ino, uint64_t nlookup) { struct ovl_ino *i; if (ino == FUSE_ROOT_ID || ino == 0) - return; + return false; i = lookup_inode (lo, ino); - if (i == NULL) - return; + if (i == NULL || i == &dummy_ino) + return false; i->lookups -= nlookup; if (i->lookups <= 0) @@ -1179,6 +1175,7 @@ do_forget (struct ovl_data *lo, fuse_ino_t ino, uint64_t nlookup) hash_delete (lo->inodes, i); inode_free (i); } + return true; } static void @@ -2338,6 +2335,7 @@ ovl_releasedir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) cleanup_lock int l = enter_big_lock (); size_t s; struct ovl_dirp *d = ovl_dirp (fi); + struct ovl_data *lo = ovl_data (req); if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_releasedir(ino=%" PRIu64 ")\n", ino); @@ -2345,9 +2343,7 @@ ovl_releasedir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) for (s = 2; s < d->tbl_size; s++) { d->tbl[s]->node_lookups--; - if (d->tbl[s]->ino) - d->tbl[s]->ino->lookups--; - else + if (! do_forget (lo, (fuse_ino_t) d->tbl[s]->ino, 1)) { if (d->tbl[s]->node_lookups == 0) node_free (d->tbl[s]); From 228544e71dcece8b4f6394254d4bba9d5a223032 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 6 Oct 2020 17:27:59 +0200 Subject: [PATCH 4/6] main: remove unreferenced inodes on forget_multi Signed-off-by: Giuseppe Scrivano --- main.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/main.c b/main.c index f1705ba..d16755c 100644 --- a/main.c +++ b/main.c @@ -1178,6 +1178,37 @@ do_forget (struct ovl_data *lo, fuse_ino_t ino, uint64_t nlookup) return true; } +/* cleanup any inode that has 0 lookups. */ +static void +cleanup_inodes (struct ovl_data *lo) +{ + cleanup_free struct ovl_ino **to_cleanup = NULL; + size_t no_lookups = 0; + struct ovl_ino *it; + size_t i; + + /* Also attempt to cleanup any inode that has 0 lookups. */ + for (it = hash_get_first (lo->inodes); it; it = hash_get_next (lo->inodes, it)) + { + if (it->lookups == 0) + no_lookups++; + } + if (no_lookups > 0) + { + to_cleanup = malloc (sizeof (*to_cleanup) * no_lookups); + if (! to_cleanup) + return; + + for (i = 0, it = hash_get_first (lo->inodes); it; it = hash_get_next (lo->inodes, it)) + { + if (it->lookups == 0) + to_cleanup[i++] = it; + } + for (i = 0; i < no_lookups; i++) + do_forget (lo, (fuse_ino_t) to_cleanup[i], 0); + } +} + static void ovl_forget (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) { @@ -1205,6 +1236,8 @@ ovl_forget_multi (fuse_req_t req, size_t count, struct fuse_forget_data *forgets for (i = 0; i < count; i++) do_forget (lo, forgets[i].ino, forgets[i].nlookup); + cleanup_inodes (lo); + fuse_reply_none (req); } From 0e33eb5da8019bd8f50e2dba77c5a90c45ee5e81 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 6 Oct 2020 17:29:07 +0200 Subject: [PATCH 5/6] main: drop the ino if the last node is removed Signed-off-by: Giuseppe Scrivano --- main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/main.c b/main.c index d16755c..3f74933 100644 --- a/main.c +++ b/main.c @@ -951,6 +951,13 @@ drop_node_from_ino (Hash_table *inodes, struct ovl_node *node) ino = node->ino; + if (ino->lookups == 0) + { + hash_delete (inodes, ino); + inode_free (ino); + return; + } + /* If it is the only node referenced by the inode, do not destroy it. */ if (ino->node == node && node->next_link == NULL) return; From da71779dd9907b4eb8e75bc989eec883ee93040e Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 6 Oct 2020 17:51:47 +0200 Subject: [PATCH 6/6] fuse-overlayfs.1: regenerate Signed-off-by: Giuseppe Scrivano --- fuse-overlayfs.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuse-overlayfs.1 b/fuse-overlayfs.1 index f0f7362..9c3c6d3 100644 --- a/fuse-overlayfs.1 +++ b/fuse-overlayfs.1 @@ -55,7 +55,7 @@ reading/writing files to the system. .PP The fuse\-overlayfs dynamic mapping is an alternative and cheaper way -to chown'ing the files on the host to accomodate the user namespace +to chown'ing the files on the host to accommodate the user namespace settings. .PP