summaryrefslogtreecommitdiff
path: root/fs/gfs2/super.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2023-08-28 18:14:32 +0300
committerAndreas Gruenbacher <agruenba@redhat.com>2023-09-05 16:58:17 +0300
commitfe4f7940d212440334f06783e06a15d674013bb1 (patch)
tree17d5c8387e7da59ef005e9398629f72dfd0ab710 /fs/gfs2/super.c
parentf66af88e33212b57ea86da2c5d66c0d9d5c46344 (diff)
downloadlinux-fe4f7940d212440334f06783e06a15d674013bb1.tar.xz
gfs2: Fix asynchronous thread destruction
The kernel threads are currently stopped and destroyed synchronously by gfs2_make_fs_ro() and gfs2_put_super(), and asynchronously by signal_our_withdraw(), with no synchronization, so the synchronous and asynchronous contexts can race with each other. First, when creating the kernel threads, take an extra task struct reference so that the task struct won't go away immediately when they terminate. This allows those kthreads to terminate immediately when they're done rather than hanging around as zombies until they are reaped by kthread_stop(). When kthread_stop() is called on a terminated kthread, it will return immediately. Second, in signal_our_withdraw(), once the SDF_JOURNAL_LIVE flag has been cleared, wake up the logd and quotad wait queues instead of stopping the logd and quotad kthreads. The kthreads are then expected to terminate automatically within short time, but if they cannot, they will not block the withdraw. For example, if a user process and one of the kthread decide to withdraw at the same time, only one of them will perform the actual withdraw and the other will wait for it to be done. If the kthread ends up being the one to wait, the withdrawing user process won't be able to stop it. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Diffstat (limited to 'fs/gfs2/super.c')
-rw-r--r--fs/gfs2/super.c16
1 files changed, 4 insertions, 12 deletions
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 119a5b20eb00..be3f69c15edc 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -549,17 +549,7 @@ void gfs2_make_fs_ro(struct gfs2_sbd *sdp)
if (!test_bit(SDF_KILL, &sdp->sd_flags))
gfs2_flush_delete_work(sdp);
- if (!log_write_allowed && current == sdp->sd_quotad_process)
- fs_warn(sdp, "The quotad daemon is withdrawing.\n");
- else if (sdp->sd_quotad_process)
- kthread_stop(sdp->sd_quotad_process);
- sdp->sd_quotad_process = NULL;
-
- if (!log_write_allowed && current == sdp->sd_logd_process)
- fs_warn(sdp, "The logd daemon is withdrawing.\n");
- else if (sdp->sd_logd_process)
- kthread_stop(sdp->sd_logd_process);
- sdp->sd_logd_process = NULL;
+ gfs2_destroy_threads(sdp);
if (log_write_allowed) {
gfs2_quota_sync(sdp->sd_vfs, 0);
@@ -615,8 +605,10 @@ restart:
if (!sb_rdonly(sb)) {
gfs2_make_fs_ro(sdp);
}
- if (gfs2_withdrawn(sdp))
+ if (gfs2_withdrawn(sdp)) {
+ gfs2_destroy_threads(sdp);
gfs2_quota_cleanup(sdp);
+ }
WARN_ON(gfs2_withdrawing(sdp));
/* At this point, we're through modifying the disk */