From 6f5bf154ba60bc5067760fcaf52a222ee7e2bc2e Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sat, 12 Aug 2023 21:22:12 +0200 Subject: file-syncfs: Avoid deadlock This is a four-player problem (here for diskfs): - One runs sync, which calls diskfs_S_file_syncfs, which triggers fsys_syncfs on all active translators, while keeping the translator_ihash_lock lock. - One of the active translators is hung, for some reason - Another ext2fs thread is trying to call fshelp_set_active_translator from dir_lookup. It is stuck on trying to acquire translator_ihash_lock, and it holds the np. - The ext2fs thread running diskfs_sync_everything tries to lock that np, while holding the nodecache_lock. In the end everything is locked. While diskfs_S_file_syncfs can as well just atomically get the list of active translators, and then call fsys_syncfs without keeping translator_ihash_lock held. --- libnetfs/file-syncfs.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'libnetfs/file-syncfs.c') diff --git a/libnetfs/file-syncfs.c b/libnetfs/file-syncfs.c index 0b14bb87..6a388daa 100644 --- a/libnetfs/file-syncfs.c +++ b/libnetfs/file-syncfs.c @@ -22,33 +22,36 @@ #include "fs_S.h" #include -struct args -{ - int wait; -}; - -static error_t -helper (void *cookie, const char *name, mach_port_t control) -{ - struct args *args = cookie; - (void) name; - fsys_syncfs (control, args->wait, 1); - return 0; -} - error_t netfs_S_file_syncfs (struct protid *user, int wait, int dochildren) { error_t err; - struct args args = { wait }; if (!user) return EOPNOTSUPP; if (dochildren) - fshelp_map_active_translators (helper, &args); + { + char *n = NULL; + size_t n_len = 0; + mach_port_t *c; + size_t c_count, i; + + err = fshelp_get_active_translators (&n, &n_len, &c, &c_count); + if (err) + return err; + free(n); + + for (i = 0; i < c_count; i++) + fsys_syncfs (c[i], wait, 1); + + free(c); + if (err) + return err; + } + pthread_mutex_lock (&user->po->np->lock); err = netfs_attempt_syncfs (user->user, wait); -- cgit v1.2.3