[patch] concurrency fixes for the fuse daemon
- From: David Zeuthen <david fubar dk>
- To: gvfs-list gnome org
- Subject: [patch] concurrency fixes for the fuse daemon
- Date: Fri, 18 Apr 2008 02:22:03 -0400
Hey,
So I've been stress-testing the fuse backend and found that it tended to
segfault under load. My test case is a MTP device (Sansa Sandisk with
basically the default factory-installed music) and running e.g.
rhythmbox /home/davidz/.gvfs/gphoto2 mount on usb%3A001,061
So SEGV's only happens when running multi-threaded which lead me to look
at locking / reference handling. I ended up using valgrind to figure out
that we're trying to access a FileHandle object that has been deleted
already. Which, not surprisingly, leads to a segfault.
The problem, I think, is that FileHandle objects are stored in the FUSE
user data and not reference counted. And this is a problem as
FileHandles are keyed off by path yet you can have several fuse
operations on the same file happening at the same time. So if you have
two operations in flight on the same file they'll share the FileHandle
object and then on the first vfs_release we free it and then we segfault
on the operation.
The attached patch adds some reference counting to FileHandle; seems to
fix the problems for me; at least no more valgrind warnings and no
SEGV's. As I'm not 100% familiar with the fuse daemon code base maybe
there's an easier and/or more correct fix. The locking seems a bit
fishy/racy in general but, as I said, I'm not 100% familiar with the
code base nor the operating constraints of libfuse.
Please review carefully. Thanks!
David
Index: client/gvfsfusedaemon.c
===================================================================
--- client/gvfsfusedaemon.c (revision 1744)
+++ client/gvfsfusedaemon.c (working copy)
@@ -71,6 +71,8 @@
} FileOp;
typedef struct {
+ gint refcount;
+
GMutex *mutex;
FileOp op;
gpointer stream;
@@ -188,12 +190,26 @@
FileHandle *file_handle;
file_handle = g_new0 (FileHandle, 1);
+ file_handle->refcount = 1;
file_handle->mutex = g_mutex_new ();
file_handle->op = FILE_OP_NONE;
return file_handle;
}
+static FileHandle *
+file_handle_ref (FileHandle *file_handle)
+{
+ g_atomic_int_inc (&file_handle->refcount);
+ return file_handle;
+}
+
+static gboolean
+file_handle_unref (FileHandle *file_handle)
+{
+ return g_atomic_int_dec_and_test (&file_handle->refcount);
+}
+
static void
file_handle_close_stream (FileHandle *file_handle)
{
@@ -278,21 +294,19 @@
g_static_mutex_unlock (&global_mutex);
}
-static gboolean
+static void
free_file_handle_for_path (const gchar *path)
{
FileHandle *fh;
- fh = get_file_handle_for_path (path);
+ g_static_mutex_lock (&global_mutex);
+ fh = g_hash_table_lookup (global_fh_table, path);
if (fh)
{
- g_static_mutex_lock (&global_mutex);
- g_hash_table_remove (global_fh_table, path);
- g_static_mutex_unlock (&global_mutex);
- return TRUE;
+ if (file_handle_unref (fh))
+ g_hash_table_remove (global_fh_table, path);
}
-
- return FALSE;
+ g_static_mutex_unlock (&global_mutex);
}
static MountRecord *
@@ -923,6 +937,7 @@
/* File exists */
+ file_handle_ref (fh);
SET_FILE_HANDLE (fi, fh);
debug_print ("vfs_open: flags=%o\n", fi->flags);
@@ -1013,6 +1028,7 @@
/* Success */
+ file_handle_ref (fh);
SET_FILE_HANDLE (fi, fh);
g_assert (fh->stream == NULL);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]