From 4689bf08811bce7cf433edb6e9dd7918328715a1 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 1 Jun 2016 21:17:30 -0700 Subject: [PATCH] scoutfs: free once granted wrlock entries The entry free routine only frees entries that don't have any references from its context. Callers are supposed to try to free entries after removing references to them. Callers that were removing entries from a shard's granted pointer were trying to free the entry before removing the pointer to the entry. Entries that were last removed from shard granted pointers were never freed. Signed-off-by: Zach Brown --- kmod/src/wrlock.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/kmod/src/wrlock.c b/kmod/src/wrlock.c index 21c3f07e..9bb7b06c 100644 --- a/kmod/src/wrlock.c +++ b/kmod/src/wrlock.c @@ -299,7 +299,9 @@ static struct wrlock_entry *alloc_ent(void) /* * Callers try to free the ent every time they remove a reference to it * from the context and are done with it. We only free it if there are - * no more references to it in the context. + * no more references to it in the context. This is called with the + * context lock held so it's not racing with other tasks that are + * removing references and trying to free. */ static void try_free_ent(struct wrlock_context *ctx, struct wrlock_entry *ent) { @@ -418,6 +420,7 @@ static void unblock_shard(struct wrlock_context *ctx, struct wrlock_context_shard *shard) { struct wrlock_entry *ent; + struct wrlock_entry *gr; int i; ent = blocked_ent(shard); @@ -440,10 +443,13 @@ static void unblock_shard(struct wrlock_context *ctx, if (!is_local(ctx, ent)) { for (i = 0; i < ent->nr_shards; i++) { shard = &ctx->shards[ent->shards[i].shd]; + if (shard->granted) { - WARN_ON_ONCE(shard->granted->writers); - try_free_ent(ctx, shard->granted); + gr = shard->granted; + WARN_ON_ONCE(gr->writers); + shard->granted = NULL; + try_free_ent(ctx, gr); } } @@ -459,8 +465,11 @@ static void unblock_shard(struct wrlock_context *ctx, WARN_ON_ONCE(shard->granted == ent); if (shard->granted) { - ent->writers += shard->granted->writers; - try_free_ent(ctx, shard->granted); + gr = shard->granted; + ent->writers += gr->writers; + + shard->granted = NULL; + try_free_ent(ctx, gr); } shard->granted = ent; @@ -970,8 +979,11 @@ void scoutfs_wrlock_teardown(struct super_block *sb) for (i = 0; i < ctx->nr_shards; i++) { shard = &ctx->shards[i]; - try_free_ent(ctx, shard->granted); - shard->granted = NULL; + if (shard->granted) { + ent = shard->granted; + shard->granted = NULL; + try_free_ent(ctx, ent); + } list_for_each_entry_safe(ent, tmp, &ctx->send_list, send_head) { list_del_init(&ent->send_head);