[pve-devel] [PATCH cluster] cfs-func-plug: use RW lock for save cached data access
Thomas Lamprecht
t.lamprecht at proxmox.com
Thu Sep 21 14:08:00 CEST 2017
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: #1505
Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
---
As this can lead to crashes I suggest master and stable-4 as apply
targets
data/src/cfs-plug-func.c | 12 ++++++++++--
data/src/cfs-plug.h | 1 +
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/data/src/cfs-plug-func.c b/data/src/cfs-plug-func.c
index 1982390..c369688 100644
--- a/data/src/cfs-plug-func.c
+++ b/data/src/cfs-plug-func.c
@@ -79,18 +79,22 @@ cfs_plug_func_getattr(
cfs_plug_func_t *fplug = (cfs_plug_func_t *)plug;
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;
}
static int
@@ -109,26 +113,30 @@ cfs_plug_func_read(
g_return_val_if_fail(path != NULL, PARAM_CHECK_ERRNO);
g_return_val_if_fail(buf != NULL, PARAM_CHECK_ERRNO);
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);
if (offset < len) {
if (offset + size > len)
size = len - offset;
memcpy(buf, data + offset, size);
} else {
size = 0;
}
+ g_rw_lock_reader_unlock(&fplug->data_rw_lock);
return size;
}
static int
diff --git a/data/src/cfs-plug.h b/data/src/cfs-plug.h
index 1aef6ce..ac12ad6 100644
--- a/data/src/cfs-plug.h
+++ b/data/src/cfs-plug.h
@@ -83,10 +83,11 @@ typedef int (*cfs_plug_func_write_data_fn_t)(
size_t size);
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;
} cfs_plug_func_t;
--
2.11.0
More information about the pve-devel
mailing list