summaryrefslogtreecommitdiffstats
path: root/src/bftw.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2023-07-18 11:43:21 -0400
committerTavian Barnes <tavianator@tavianator.com>2023-07-18 11:43:21 -0400
commit815798e1eea7fc8dacd5acab40202ec4d251d517 (patch)
tree8a9ba346285d7443732a03e5a3985b56cca6e7d1 /src/bftw.c
parenteb466474e7b5ab79bbeccb2d99bb7b1cfc57af5f (diff)
downloadbfs-815798e1eea7fc8dacd5acab40202ec4d251d517.tar.xz
bftw: Add a queue of directories to unwrap
For !BFS_USE_UNWRAPDIR, if a file is still pinned in bftw_closedir(), it has to stay open until its pincount drops to zero. Since this happens in bftw_ioq_pop(), we can't immediately call bftw_unwrapdir() as that adds to the ioq. Instead, add it to a list that gets drained by the next bftw_gc().
Diffstat (limited to 'src/bftw.c')
-rw-r--r--src/bftw.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/src/bftw.c b/src/bftw.c
index 0b90f55..dd34d64 100644
--- a/src/bftw.c
+++ b/src/bftw.c
@@ -119,6 +119,8 @@ struct bftw_file {
struct { struct bftw_file *next; } to_open;
/** The next directory to read. */
struct { struct bftw_file *next; } to_read;
+ /** The next directory to close. */
+ struct { struct bftw_file *next; } to_close;
/** The next file to visit. */
struct { struct bftw_file *next; } to_visit;
@@ -336,6 +338,7 @@ static struct bftw_file *bftw_file_new(struct bftw_cache *cache, struct bftw_fil
file->to_open.next = NULL;
file->to_read.next = NULL;
+ file->to_close.next = NULL;
file->to_visit.next = NULL;
file->lru.prev = file->lru.next = NULL;
@@ -411,6 +414,8 @@ struct bftw_state {
struct bftw_list to_open;
/** The queue of directories to read. */
struct bftw_list to_read;
+ /** The queue of unpinned directories to unwrap. */
+ struct bftw_list to_close;
/** Available capacity in to_read. */
size_t dirlimit;
@@ -487,6 +492,7 @@ static int bftw_state_init(struct bftw_state *state, const struct bftw_args *arg
SLIST_INIT(&state->to_open);
SLIST_INIT(&state->to_read);
+ SLIST_INIT(&state->to_close);
state->dirlimit = qdepth;
SLIST_INIT(&state->to_visit);
@@ -516,6 +522,7 @@ static int bftw_ioq_pop(struct bftw_state *state, bool block) {
struct bftw_cache *cache = &state->cache;
struct bftw_file *file;
+ struct bftw_file *parent;
struct bfs_dir *dir;
enum ioq_op op = ent->op;
@@ -535,8 +542,12 @@ static int bftw_ioq_pop(struct bftw_state *state, bool block) {
file->ioqueued = false;
++cache->capacity;
- if (file->parent) {
- bftw_cache_unpin(cache, file->parent);
+ parent = file->parent;
+ if (parent) {
+ bftw_cache_unpin(cache, parent);
+ if (parent->pincount == 0 && parent->dir) {
+ SLIST_APPEND(&state->to_close, parent, to_close);
+ }
}
dir = ent->opendir.dir;
@@ -1228,9 +1239,10 @@ enum bftw_gc_flags {
static int bftw_gc(struct bftw_state *state, enum bftw_gc_flags flags) {
int ret = 0;
- if (state->dir) {
- bftw_cache_unpin(&state->cache, state->file);
- bftw_unwrapdir(state, state->file);
+ struct bftw_file *file = state->file;
+ if (file && file->dir) {
+ bftw_cache_unpin(&state->cache, file);
+ SLIST_APPEND(&state->to_close, file, to_close);
}
state->dir = NULL;
state->de = NULL;
@@ -1247,9 +1259,12 @@ static int bftw_gc(struct bftw_state *state, enum bftw_gc_flags flags) {
}
state->direrror = 0;
+ while ((file = SLIST_POP(&state->to_close, to_close))) {
+ bftw_unwrapdir(state, file);
+ }
+
enum bftw_gc_flags visit = BFTW_VISIT_FILE;
- while (state->file) {
- struct bftw_file *file = state->file;
+ while ((file = state->file)) {
if (--file->refcount > 0) {
state->file = NULL;
break;