diff options
author | David Howells <dhowells@redhat.com> | 2020-10-15 11:05:01 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2020-10-16 14:38:26 +0100 |
commit | 286377f6bdf71568a4cf07104fe44006ae0dba6d (patch) | |
tree | 3ed060b86340bc31d7a6c6173e8426ff19e213eb /fs/afs | |
parent | 88c853c3f5c0a07c5db61b494ee25152535cfeee (diff) |
afs: Fix cell purging with aliases
When the afs module is removed, one of the things that has to be done is to
purge the cell database. afs_cell_purge() cancels the management timer and
then starts the cell manager work item to do the purging. This does a
single run through and then assumes that all cells are now purged - but
this is no longer the case.
With the introduction of alias detection, a later cell in the database can
now be holding an active count on an earlier cell (cell->alias_of). The
purge scan passes by the earlier cell first, but this can't be got rid of
until it has discarded the alias. Ordinarily, afs_unuse_cell() would
handle this by setting the management timer to trigger another pass - but
afs_set_cell_timer() doesn't do anything if the namespace is being removed
(net->live == false). rmmod then hangs in the wait on cells_outstanding in
afs_cell_purge().
Fix this by making afs_set_cell_timer() directly queue the cell manager if
net->live is false. This causes additional management passes.
Queueing the cell manager increments cells_outstanding to make sure the
wait won't complete until all cells are destroyed.
Fixes: 8a070a964877 ("afs: Detect cell aliases 1 - Cells with root volumes")
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs')
-rw-r--r-- | fs/afs/cell.c | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index c906000b0ff8..1944be78e9b0 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c @@ -19,6 +19,7 @@ static unsigned __read_mostly afs_cell_gc_delay = 10; static unsigned __read_mostly afs_cell_min_ttl = 10 * 60; static unsigned __read_mostly afs_cell_max_ttl = 24 * 60 * 60; +static void afs_queue_cell_manager(struct afs_net *); static void afs_manage_cell_work(struct work_struct *); static void afs_dec_cells_outstanding(struct afs_net *net) @@ -37,6 +38,8 @@ static void afs_set_cell_timer(struct afs_net *net, time64_t delay) atomic_inc(&net->cells_outstanding); if (timer_reduce(&net->cells_timer, jiffies + delay * HZ)) afs_dec_cells_outstanding(net); + } else { + afs_queue_cell_manager(net); } } |