summaryrefslogtreecommitdiffstats
path: root/src/bftw.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2023-10-12 15:13:02 -0400
committerTavian Barnes <tavianator@tavianator.com>2023-10-12 15:13:02 -0400
commit773f4a446f03da62d88e6d17be49fdc0a3e38465 (patch)
tree4f2520957b0ead54e9282bf3ad4f0a444d205ba1 /src/bftw.c
parent1addab1e5f12cb0fddfa92872bf45653352cc212 (diff)
downloadbfs-773f4a446f03da62d88e6d17be49fdc0a3e38465.tar.xz
bftw: Fix to_close list corruption with !BFS_USE_UNWRAPDIR
It's possible for pincount to drop to zero, then get incremented and drop back to zero again. If this happens, we shouldn't add it to the to_close list twice. This should fix the intermittent hang on the macOS CI. Fixes: 815798e1eea7fc8dacd5acab40202ec4d251d517
Diffstat (limited to 'src/bftw.c')
-rw-r--r--src/bftw.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/src/bftw.c b/src/bftw.c
index c0bff75..1995e12 100644
--- a/src/bftw.c
+++ b/src/bftw.c
@@ -546,6 +546,17 @@ static int bftw_state_init(struct bftw_state *state, const struct bftw_args *arg
return 0;
}
+/** Unpin a directory, and possibly queue it for unwrapping. */
+static void bftw_unpin_dir(struct bftw_state *state, struct bftw_file *file, bool force) {
+ bftw_cache_unpin(&state->cache, file);
+
+ if (file->dir && (force || file->pincount == 0)) {
+ if (!SLIST_ATTACHED(&state->to_close, file)) {
+ SLIST_APPEND(&state->to_close, file);
+ }
+ }
+}
+
/** Pop a response from the I/O queue. */
static int bftw_ioq_pop(struct bftw_state *state, bool block) {
struct ioq *ioq = state->ioq;
@@ -582,10 +593,7 @@ static int bftw_ioq_pop(struct bftw_state *state, bool block) {
++cache->capacity;
parent = file->parent;
if (parent) {
- bftw_cache_unpin(cache, parent);
- if (parent->pincount == 0 && parent->dir) {
- SLIST_APPEND(&state->to_close, parent);
- }
+ bftw_unpin_dir(state, parent, false);
}
dir = ent->opendir.dir;
@@ -1285,8 +1293,7 @@ static int bftw_gc(struct bftw_state *state, enum bftw_gc_flags flags) {
struct bftw_file *file = state->file;
if (file && file->dir) {
- bftw_cache_unpin(&state->cache, file);
- SLIST_APPEND(&state->to_close, file);
+ bftw_unpin_dir(state, file, true);
}
state->dir = NULL;
state->de = NULL;