Skip to content

Commit 3c4eb36

Browse files
authored
Merge pull request #239 from giuseppe/leak-fix
main: fix a potential leak and be more aggressive on releasing inodes
2 parents 04ed72d + da71779 commit 3c4eb36

File tree

2 files changed

+76
-20
lines changed

2 files changed

+76
-20
lines changed

fuse-overlayfs.1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ reading/writing files to the system.
5555

5656
.PP
5757
The fuse\-overlayfs dynamic mapping is an alternative and cheaper way
58-
to chown'ing the files on the host to accomodate the user namespace
58+
to chown'ing the files on the host to accommodate the user namespace
5959
settings.
6060

6161
.PP

main.c

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,18 @@
5050
#include <hash.h>
5151
#include <sys/statvfs.h>
5252
#include <sys/file.h>
53-
53+
#include <signal.h>
5454
#include <sys/types.h>
5555
#include <sys/stat.h>
5656
#include <sys/syscall.h>
5757
#include <sys/sysmacros.h>
58-
5958
#include <sys/xattr.h>
60-
6159
#include <linux/fs.h>
62-
6360
#include <sys/time.h>
6461
#include <sys/resource.h>
65-
66-
#include <utils.h>
67-
6862
#include <pthread.h>
6963

64+
#include <utils.h>
7065
#include <plugin.h>
7166

7267
#ifndef TEMP_FAILURE_RETRY
@@ -169,6 +164,23 @@ static gid_t overflow_gid;
169164

170165
static struct ovl_ino dummy_ino;
171166

167+
struct stats_s
168+
{
169+
size_t nodes;
170+
size_t inodes;
171+
};
172+
173+
static volatile struct stats_s stats;
174+
175+
static void
176+
print_stats (int sig)
177+
{
178+
char fmt[128];
179+
int l = snprintf (fmt, sizeof (fmt) - 1, "# INODES: %zu\n# NODES: %zu\n", stats.inodes, stats.nodes);
180+
fmt[l] = '\0';
181+
write (STDERR_FILENO, fmt, l + 1);
182+
}
183+
172184
static double
173185
get_timeout (struct ovl_data *lo)
174186
{
@@ -906,6 +918,7 @@ node_free (void *p)
906918
if (n->do_rmdir)
907919
unlinkat (n->hidden_dirfd, n->path, AT_REMOVEDIR);
908920

921+
stats.nodes--;
909922
free (n->name);
910923
free (n->path);
911924
free (n);
@@ -927,6 +940,7 @@ inode_free (void *p)
927940
node_free (tmp);
928941
}
929942

943+
stats.inodes--;
930944
free (i);
931945
}
932946

@@ -935,18 +949,21 @@ drop_node_from_ino (Hash_table *inodes, struct ovl_node *node)
935949
{
936950
struct ovl_ino *ino;
937951
struct ovl_node *it, *prev = NULL;
938-
size_t len = 0;
939952

940953
ino = node->ino;
941954

942-
for (it = ino->node; it; it = it->next_link)
943-
len++;
955+
if (ino->lookups == 0)
956+
{
957+
hash_delete (inodes, ino);
958+
inode_free (ino);
959+
return;
960+
}
944961

945-
if (len == 1 && node->ino->lookups > 0)
962+
/* If it is the only node referenced by the inode, do not destroy it. */
963+
if (ino->node == node && node->next_link == NULL)
946964
return;
947965

948966
node->ino = NULL;
949-
ino->lookups -= node->node_lookups;
950967

951968
for (it = ino->node; it; it = it->next_link)
952969
{
@@ -1144,27 +1161,60 @@ register_inode (struct ovl_data *lo, struct ovl_node *n, mode_t mode)
11441161
return NULL;
11451162
}
11461163

1164+
stats.inodes++;
11471165
return ino->node;
11481166
}
11491167

1150-
static void
1168+
static bool
11511169
do_forget (struct ovl_data *lo, fuse_ino_t ino, uint64_t nlookup)
11521170
{
11531171
struct ovl_ino *i;
11541172

11551173
if (ino == FUSE_ROOT_ID || ino == 0)
1156-
return;
1174+
return false;
11571175

11581176
i = lookup_inode (lo, ino);
1159-
if (i == NULL)
1160-
return;
1177+
if (i == NULL || i == &dummy_ino)
1178+
return false;
11611179

11621180
i->lookups -= nlookup;
11631181
if (i->lookups <= 0)
11641182
{
11651183
hash_delete (lo->inodes, i);
11661184
inode_free (i);
11671185
}
1186+
return true;
1187+
}
1188+
1189+
/* cleanup any inode that has 0 lookups. */
1190+
static void
1191+
cleanup_inodes (struct ovl_data *lo)
1192+
{
1193+
cleanup_free struct ovl_ino **to_cleanup = NULL;
1194+
size_t no_lookups = 0;
1195+
struct ovl_ino *it;
1196+
size_t i;
1197+
1198+
/* Also attempt to cleanup any inode that has 0 lookups. */
1199+
for (it = hash_get_first (lo->inodes); it; it = hash_get_next (lo->inodes, it))
1200+
{
1201+
if (it->lookups == 0)
1202+
no_lookups++;
1203+
}
1204+
if (no_lookups > 0)
1205+
{
1206+
to_cleanup = malloc (sizeof (*to_cleanup) * no_lookups);
1207+
if (! to_cleanup)
1208+
return;
1209+
1210+
for (i = 0, it = hash_get_first (lo->inodes); it; it = hash_get_next (lo->inodes, it))
1211+
{
1212+
if (it->lookups == 0)
1213+
to_cleanup[i++] = it;
1214+
}
1215+
for (i = 0; i < no_lookups; i++)
1216+
do_forget (lo, (fuse_ino_t) to_cleanup[i], 0);
1217+
}
11681218
}
11691219

11701220
static void
@@ -1194,6 +1244,8 @@ ovl_forget_multi (fuse_req_t req, size_t count, struct fuse_forget_data *forgets
11941244
for (i = 0; i < count; i++)
11951245
do_forget (lo, forgets[i].ino, forgets[i].nlookup);
11961246

1247+
cleanup_inodes (lo);
1248+
11971249
fuse_reply_none (req);
11981250
}
11991251

@@ -1249,6 +1301,7 @@ make_whiteout_node (const char *path, const char *name)
12491301
ret_xchg = ret;
12501302
ret = NULL;
12511303

1304+
stats.nodes++;
12521305
return ret_xchg;
12531306
}
12541307

@@ -1461,6 +1514,7 @@ make_ovl_node (struct ovl_data *lo, const char *path, struct ovl_layer *layer, c
14611514
ret_xchg = ret;
14621515
ret = NULL;
14631516

1517+
stats.nodes++;
14641518
return register_inode (lo, ret_xchg, mode);
14651519
}
14661520

@@ -2322,16 +2376,15 @@ ovl_releasedir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
23222376
cleanup_lock int l = enter_big_lock ();
23232377
size_t s;
23242378
struct ovl_dirp *d = ovl_dirp (fi);
2379+
struct ovl_data *lo = ovl_data (req);
23252380

23262381
if (UNLIKELY (ovl_debug (req)))
23272382
fprintf (stderr, "ovl_releasedir(ino=%" PRIu64 ")\n", ino);
23282383

23292384
for (s = 2; s < d->tbl_size; s++)
23302385
{
23312386
d->tbl[s]->node_lookups--;
2332-
if (d->tbl[s]->ino)
2333-
d->tbl[s]->ino->lookups--;
2334-
else
2387+
if (! do_forget (lo, (fuse_ino_t) d->tbl[s]->ino, 1))
23352388
{
23362389
if (d->tbl[s]->node_lookups == 0)
23372390
node_free (d->tbl[s]);
@@ -5520,6 +5573,9 @@ main (int argc, char *argv[])
55205573
error (0, errno, "cannot set signal handler");
55215574
goto err_out2;
55225575
}
5576+
5577+
signal (SIGUSR1, print_stats);
5578+
55235579
if (fuse_session_mount (se, lo.mountpoint) != 0)
55245580
{
55255581
error (0, errno, "cannot mount");

0 commit comments

Comments
 (0)