summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2023-08-12 21:22:12 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2023-08-12 21:22:12 +0200
commit6f5bf154ba60bc5067760fcaf52a222ee7e2bc2e (patch)
treeef72fd17d730d46241aa138e3ef38c4049336f99
parentf6a589a59ea88c895d35a595c3d0580495dbc548 (diff)
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.
-rw-r--r--libdiskfs/file-syncfs.c36
-rw-r--r--libnetfs/file-syncfs.c35
2 files changed, 38 insertions, 33 deletions
diff --git a/libdiskfs/file-syncfs.c b/libdiskfs/file-syncfs.c
index 8cd4003b..d271ab1e 100644
--- a/libdiskfs/file-syncfs.c
+++ b/libdiskfs/file-syncfs.c
@@ -19,33 +19,35 @@
#include "fs_S.h"
#include <hurd/fsys.h>
-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;
-}
-
/* Implement file_syncfs as described in <hurd/fs.defs>. */
kern_return_t
diskfs_S_file_syncfs (struct protid *cred,
int wait,
int dochildren)
{
- struct args args = { wait };
-
if (!cred)
return EOPNOTSUPP;
if (dochildren)
- fshelp_map_active_translators (helper, &args);
+ {
+ error_t err;
+ 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;
+ }
if (diskfs_synchronous)
wait = 1;
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 <hurd/fsys.h>
-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);