50
50
#include <hash.h>
51
51
#include <sys/statvfs.h>
52
52
#include <sys/file.h>
53
-
53
+ #include <signal.h>
54
54
#include <sys/types.h>
55
55
#include <sys/stat.h>
56
56
#include <sys/syscall.h>
57
57
#include <sys/sysmacros.h>
58
-
59
58
#include <sys/xattr.h>
60
-
61
59
#include <linux/fs.h>
62
-
63
60
#include <sys/time.h>
64
61
#include <sys/resource.h>
65
-
66
- #include <utils.h>
67
-
68
62
#include <pthread.h>
69
63
64
+ #include <utils.h>
70
65
#include <plugin.h>
71
66
72
67
#ifndef TEMP_FAILURE_RETRY
@@ -169,6 +164,23 @@ static gid_t overflow_gid;
169
164
170
165
static struct ovl_ino dummy_ino ;
171
166
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
+
172
184
static double
173
185
get_timeout (struct ovl_data * lo )
174
186
{
@@ -906,6 +918,7 @@ node_free (void *p)
906
918
if (n -> do_rmdir )
907
919
unlinkat (n -> hidden_dirfd , n -> path , AT_REMOVEDIR );
908
920
921
+ stats .nodes -- ;
909
922
free (n -> name );
910
923
free (n -> path );
911
924
free (n );
@@ -927,6 +940,7 @@ inode_free (void *p)
927
940
node_free (tmp );
928
941
}
929
942
943
+ stats .inodes -- ;
930
944
free (i );
931
945
}
932
946
@@ -935,18 +949,21 @@ drop_node_from_ino (Hash_table *inodes, struct ovl_node *node)
935
949
{
936
950
struct ovl_ino * ino ;
937
951
struct ovl_node * it , * prev = NULL ;
938
- size_t len = 0 ;
939
952
940
953
ino = node -> ino ;
941
954
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
+ }
944
961
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 )
946
964
return ;
947
965
948
966
node -> ino = NULL ;
949
- ino -> lookups -= node -> node_lookups ;
950
967
951
968
for (it = ino -> node ; it ; it = it -> next_link )
952
969
{
@@ -1144,27 +1161,60 @@ register_inode (struct ovl_data *lo, struct ovl_node *n, mode_t mode)
1144
1161
return NULL ;
1145
1162
}
1146
1163
1164
+ stats .inodes ++ ;
1147
1165
return ino -> node ;
1148
1166
}
1149
1167
1150
- static void
1168
+ static bool
1151
1169
do_forget (struct ovl_data * lo , fuse_ino_t ino , uint64_t nlookup )
1152
1170
{
1153
1171
struct ovl_ino * i ;
1154
1172
1155
1173
if (ino == FUSE_ROOT_ID || ino == 0 )
1156
- return ;
1174
+ return false ;
1157
1175
1158
1176
i = lookup_inode (lo , ino );
1159
- if (i == NULL )
1160
- return ;
1177
+ if (i == NULL || i == & dummy_ino )
1178
+ return false ;
1161
1179
1162
1180
i -> lookups -= nlookup ;
1163
1181
if (i -> lookups <= 0 )
1164
1182
{
1165
1183
hash_delete (lo -> inodes , i );
1166
1184
inode_free (i );
1167
1185
}
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
+ }
1168
1218
}
1169
1219
1170
1220
static void
@@ -1194,6 +1244,8 @@ ovl_forget_multi (fuse_req_t req, size_t count, struct fuse_forget_data *forgets
1194
1244
for (i = 0 ; i < count ; i ++ )
1195
1245
do_forget (lo , forgets [i ].ino , forgets [i ].nlookup );
1196
1246
1247
+ cleanup_inodes (lo );
1248
+
1197
1249
fuse_reply_none (req );
1198
1250
}
1199
1251
@@ -1249,6 +1301,7 @@ make_whiteout_node (const char *path, const char *name)
1249
1301
ret_xchg = ret ;
1250
1302
ret = NULL ;
1251
1303
1304
+ stats .nodes ++ ;
1252
1305
return ret_xchg ;
1253
1306
}
1254
1307
@@ -1461,6 +1514,7 @@ make_ovl_node (struct ovl_data *lo, const char *path, struct ovl_layer *layer, c
1461
1514
ret_xchg = ret ;
1462
1515
ret = NULL ;
1463
1516
1517
+ stats .nodes ++ ;
1464
1518
return register_inode (lo , ret_xchg , mode );
1465
1519
}
1466
1520
@@ -2322,16 +2376,15 @@ ovl_releasedir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
2322
2376
cleanup_lock int l = enter_big_lock ();
2323
2377
size_t s ;
2324
2378
struct ovl_dirp * d = ovl_dirp (fi );
2379
+ struct ovl_data * lo = ovl_data (req );
2325
2380
2326
2381
if (UNLIKELY (ovl_debug (req )))
2327
2382
fprintf (stderr , "ovl_releasedir(ino=%" PRIu64 ")\n" , ino );
2328
2383
2329
2384
for (s = 2 ; s < d -> tbl_size ; s ++ )
2330
2385
{
2331
2386
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 ))
2335
2388
{
2336
2389
if (d -> tbl [s ]-> node_lookups == 0 )
2337
2390
node_free (d -> tbl [s ]);
@@ -5520,6 +5573,9 @@ main (int argc, char *argv[])
5520
5573
error (0 , errno , "cannot set signal handler" );
5521
5574
goto err_out2 ;
5522
5575
}
5576
+
5577
+ signal (SIGUSR1 , print_stats );
5578
+
5523
5579
if (fuse_session_mount (se , lo .mountpoint ) != 0 )
5524
5580
{
5525
5581
error (0 , errno , "cannot mount" );
0 commit comments