]> git.proxmox.com Git - pve-cluster.git/commitdiff
cfs-func-plug: use RW lock for safe cached data access
authorThomas Lamprecht <t.lamprecht@proxmox.com>
Thu, 21 Sep 2017 12:08:00 +0000 (14:08 +0200)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Thu, 21 Sep 2017 12:27:58 +0000 (14:27 +0200)
fuse may spawn multiple threads if there are concurrent accesses.

Our virtual files, e.g. ".members", ".rrd", are registered over our
"func" cfs plug which is a bit special.

For each unique virtual file there exists a single cfs_plug_func_t
instance, shared between all threads.
As we directly operated unlocked on members of this structure
parallel accesses raced between each other.
This could result in quite visible problems like a crash after a
double free (Bug 1504) or in less noticeable effects where one thread
may read from an inconsistent, or already freed memory region.

Add a Reader/Writer lock to efficiently address this problem.
Other plugs implement more functions and use a mutex to ensure
consistency and thus do not have this problem.

Fixes: #1504
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
data/src/cfs-plug-func.c
data/src/cfs-plug.h

index 19823905ba5c46b4e65cd3f196d8e78c751c2c80..c36968870155997b53578c39a10086dbc3edddf8 100644 (file)
@@ -81,14 +81,18 @@ cfs_plug_func_getattr(
 
        memset(stbuf, 0, sizeof(struct stat));
 
+       g_rw_lock_writer_lock(&fplug->data_rw_lock);
        if (fplug->data)
                g_free(fplug->data);
 
        fplug->data = fplug->update_callback(plug);
 
+       stbuf->st_size = fplug->data ? strlen(fplug->data) : 0;
+
+       g_rw_lock_writer_unlock(&fplug->data_rw_lock);
+
        stbuf->st_mode = fplug->mode;
        stbuf->st_nlink = 1;
-       stbuf->st_size = fplug->data ? strlen(fplug->data) : 0;
 
        return 0;
 }
@@ -111,12 +115,15 @@ cfs_plug_func_read(
 
        cfs_plug_func_t *fplug = (cfs_plug_func_t *)plug;
 
+       g_rw_lock_reader_lock(&fplug->data_rw_lock);
        char *data = fplug->data;
 
        cfs_debug("enter cfs_plug_func_read %s", data);
 
-       if (!data)
+       if (!data) {
+               g_rw_lock_reader_unlock(&fplug->data_rw_lock);
                return 0;
+       }
 
        int len = strlen(data);
 
@@ -127,6 +134,7 @@ cfs_plug_func_read(
        } else {
                size = 0;
        }
+       g_rw_lock_reader_unlock(&fplug->data_rw_lock);
 
        return size;
 }
index 1aef6ce5f72f617d281611e83874ab27a108c521..ac12ad6c1d8853ac6101ab42e6c0933a0965ae75 100644 (file)
@@ -85,6 +85,7 @@ typedef int (*cfs_plug_func_write_data_fn_t)(
 typedef struct {
        cfs_plug_t plug;
        char *data;
+       GRWLock data_rw_lock;
        mode_t mode;
        cfs_plug_func_udpate_data_fn_t update_callback;
        cfs_plug_func_write_data_fn_t write_callback;