summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Adam <obnox@samba.org>2019-05-18 11:28:54 +0200
committerKarolin Seeger <kseeger@samba.org>2019-08-26 10:23:23 +0000
commitc7e983321921e4b39e3e63d2a89112ab35263092 (patch)
tree60d5c85fcf7a4c3b6924b198d9960a524556c132
parentbf5ac945151b83f7eb3158e0d18aec97c712c8ba (diff)
downloadsamba-c7e983321921e4b39e3e63d2a89112ab35263092.tar.gz
vfs:glusterfs_fuse: ensure fileids are constant across nodes
Instead of adding a new gluster-specific mode to the fileid module, this patches provides a fileid algorithm as part of the glusterfs_fuse vfs module. This can not be configured further, simply adding the glusterfs_fuse vfs module to the vfs objects configuration will enable the new fileid mode. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13972 Signed-off-by: Michael Adam <obnox@samba.org> Signed-off-by: Guenther Deschner <gd@samba.org> Autobuild-User(master): Günther Deschner <gd@samba.org> Autobuild-Date(master): Sat Jul 13 22:54:56 UTC 2019 on sn-devel-184
-rw-r--r--docs-xml/manpages/vfs_glusterfs_fuse.8.xml8
-rw-r--r--source3/modules/vfs_glusterfs_fuse.c193
2 files changed, 200 insertions, 1 deletions
diff --git a/docs-xml/manpages/vfs_glusterfs_fuse.8.xml b/docs-xml/manpages/vfs_glusterfs_fuse.8.xml
index b9f7f42c6f2..f2aa624353e 100644
--- a/docs-xml/manpages/vfs_glusterfs_fuse.8.xml
+++ b/docs-xml/manpages/vfs_glusterfs_fuse.8.xml
@@ -49,6 +49,14 @@
</para>
<para>
+ Furthermore, this module implements a substitute file-id
+ mechanism. The default file-id mechanism is not working
+ correctly for gluster fuse mount re-exports, so in order to
+ avoid data loss, users exporting gluster fuse mounts with
+ Samba should enable this module.
+ </para>
+
+ <para>
This module can be combined with other modules, but it
should be the last module in the <command>vfs objects</command>
list. Modules added to this list to the right of the glusterfs
diff --git a/source3/modules/vfs_glusterfs_fuse.c b/source3/modules/vfs_glusterfs_fuse.c
index 51515aa0df4..c621f9abf8e 100644
--- a/source3/modules/vfs_glusterfs_fuse.c
+++ b/source3/modules/vfs_glusterfs_fuse.c
@@ -59,10 +59,201 @@ static int vfs_gluster_fuse_get_real_filename(struct vfs_handle_struct *handle,
return 0;
}
+struct device_mapping_entry {
+ SMB_DEV_T device; /* the local device, for reference */
+ uint64_t mapped_device; /* the mapped device */
+};
+
+struct vfs_glusterfs_fuse_handle_data {
+ unsigned num_mapped_devices;
+ struct device_mapping_entry *mapped_devices;
+};
+
+/* a 64 bit hash, based on the one in tdb, copied from vfs_fileied */
+static uint64_t vfs_glusterfs_fuse_uint64_hash(const uint8_t *s, size_t len)
+{
+ uint64_t value; /* Used to compute the hash value. */
+ uint32_t i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AFLL * len, i=0; i < len; i++)
+ value = (value + (((uint64_t)s[i]) << (i*5 % 24)));
+
+ return (1103515243LL * value + 12345LL);
+}
+
+static void vfs_glusterfs_fuse_load_devices(
+ struct vfs_glusterfs_fuse_handle_data *data)
+{
+ FILE *f;
+ struct mntent *m;
+
+ data->num_mapped_devices = 0;
+ TALLOC_FREE(data->mapped_devices);
+
+ f = setmntent("/etc/mtab", "r");
+ if (!f) {
+ return;
+ }
+
+ while ((m = getmntent(f))) {
+ struct stat st;
+ char *p;
+ uint64_t mapped_device;
+
+ if (stat(m->mnt_dir, &st) != 0) {
+ /* TODO: log? */
+ continue;
+ }
+
+ /* strip the host part off of the fsname */
+ p = strrchr(m->mnt_fsname, ':');
+ if (p == NULL) {
+ p = m->mnt_fsname;
+ } else {
+ /* TODO: consider the case of '' ? */
+ p++;
+ }
+
+ mapped_device = vfs_glusterfs_fuse_uint64_hash(
+ (const uint8_t *)p,
+ strlen(p));
+
+ data->mapped_devices = talloc_realloc(data,
+ data->mapped_devices,
+ struct device_mapping_entry,
+ data->num_mapped_devices + 1);
+ if (data->mapped_devices == NULL) {
+ goto nomem;
+ }
+
+ data->mapped_devices[data->num_mapped_devices].device =
+ st.st_dev;
+ data->mapped_devices[data->num_mapped_devices].mapped_device =
+ mapped_device;
+
+ data->num_mapped_devices++;
+ }
+
+ endmntent(f);
+ return;
+
+nomem:
+ data->num_mapped_devices = 0;
+ TALLOC_FREE(data->mapped_devices);
+
+ endmntent(f);
+ return;
+}
+
+static int vfs_glusterfs_fuse_map_device_cached(
+ struct vfs_glusterfs_fuse_handle_data *data,
+ SMB_DEV_T device,
+ uint64_t *mapped_device)
+{
+ unsigned i;
+
+ for (i = 0; i < data->num_mapped_devices; i++) {
+ if (data->mapped_devices[i].device == device) {
+ *mapped_device = data->mapped_devices[i].mapped_device;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int vfs_glusterfs_fuse_map_device(
+ struct vfs_glusterfs_fuse_handle_data *data,
+ SMB_DEV_T device,
+ uint64_t *mapped_device)
+{
+ int ret;
+
+ ret = vfs_glusterfs_fuse_map_device_cached(data, device, mapped_device);
+ if (ret == 0) {
+ return 0;
+ }
+
+ vfs_glusterfs_fuse_load_devices(data);
+
+ ret = vfs_glusterfs_fuse_map_device_cached(data, device, mapped_device);
+
+ return ret;
+}
+
+static struct file_id vfs_glusterfs_fuse_file_id_create(
+ struct vfs_handle_struct *handle,
+ const SMB_STRUCT_STAT *sbuf)
+{
+ struct vfs_glusterfs_fuse_handle_data *data;
+ struct file_id id;
+ uint64_t mapped_device;
+ int ret;
+
+ ZERO_STRUCT(id);
+
+ id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, sbuf);
+
+ SMB_VFS_HANDLE_GET_DATA(handle, data,
+ struct vfs_glusterfs_fuse_handle_data,
+ return id);
+
+ ret = vfs_glusterfs_fuse_map_device(data, sbuf->st_ex_dev,
+ &mapped_device);
+ if (ret == 0) {
+ id.devid = mapped_device;
+ } else {
+ DBG_WARNING("Failed to map device [%jx], falling back to "
+ "standard file_id [%jx]",
+ (uintmax_t)sbuf->st_ex_dev,
+ (uintmax_t)id.devid);
+ }
+
+ DBG_DEBUG("Returning dev [%jx] inode [%jx]\n",
+ (uintmax_t)id.devid, (uintmax_t)id.inode);
+
+ return id;
+}
+
+static int vfs_glusterfs_fuse_connect(struct vfs_handle_struct *handle,
+ const char *service, const char *user)
+{
+ struct vfs_glusterfs_fuse_handle_data *data;
+ int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ data = talloc_zero(handle->conn, struct vfs_glusterfs_fuse_handle_data);
+ if (data == NULL) {
+ DBG_ERR("talloc_zero() failed.\n");
+ SMB_VFS_NEXT_DISCONNECT(handle);
+ return -1;
+ }
+
+ /*
+ * Fill the cache in the tree connect, so that the first file/dir access
+ * has chances of being fast...
+ */
+ vfs_glusterfs_fuse_load_devices(data);
+
+ SMB_VFS_HANDLE_SET_DATA(handle, data, NULL,
+ struct vfs_glusterfs_fuse_handle_data,
+ return -1);
+
+ DBG_DEBUG("vfs_glusterfs_fuse_connect(): connected to service[%s]\n",
+ service);
+
+ return 0;
+}
+
struct vfs_fn_pointers glusterfs_fuse_fns = {
- /* File Operations */
+ .connect_fn = vfs_glusterfs_fuse_connect,
.get_real_filename_fn = vfs_gluster_fuse_get_real_filename,
+ .file_id_create_fn = vfs_glusterfs_fuse_file_id_create,
};
static_decl_vfs;