From 591ea9172deb7f3084fa9e70458c757a50c45f59 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Sat, 18 May 2019 11:28:54 +0200 Subject: [PATCH 1/2] vfs:glusterfs_fuse: ensure fileids are constant across nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Guenther Deschner Autobuild-User(master): Günther Deschner Autobuild-Date(master): Sat Jul 13 22:54:56 UTC 2019 on sn-devel-184 (cherry picked from commit 5522aa1a4c34ee1a1e81db73cf41594bb10bd989) --- docs-xml/manpages/vfs_glusterfs_fuse.8.xml | 8 + source3/modules/vfs_glusterfs_fuse.c | 193 ++++++++++++++++++++- 2 files changed, 200 insertions(+), 1 deletion(-) 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 @@ -48,6 +48,14 @@ case of an exisiting filename. + + 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. + + This module can be combined with other modules, but it should be the last module in the vfs objects 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; -- 2.21.0 From a89e5f988fde1798356e82a93322573ec5690072 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 1 Aug 2019 00:47:29 +0200 Subject: [PATCH 2/2] vfs:glusterfs_fuse: build only if we have setmntent() FreeBSD and other platforms that don't have setmntent() and friends can not compile this module. This patch lets changes the build to only compile this module if the setmntent() function is found. This is the a follow-up fix to the actual fix for bug #13972. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13972 Signed-off-by: Michael Adam Reviewed-by: Amitay Isaacs Autobuild-User(master): Amitay Isaacs Autobuild-Date(master): Thu Aug 1 09:49:04 UTC 2019 on sn-devel-184 (cherry picked from commit f258cfaa1d07af6ac6e996006f6e59955cfe34ce) --- source3/wscript | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source3/wscript b/source3/wscript index ff72a173a4b..4a3e75605e7 100644 --- a/source3/wscript +++ b/source3/wscript @@ -1713,7 +1713,6 @@ main() { vfs_media_harmony vfs_unityed_media vfs_fruit vfs_shell_snap vfs_commit vfs_worm vfs_crossrename vfs_linux_xfs_sgid vfs_time_audit vfs_offline vfs_virusfilter - vfs_glusterfs_fuse ''')) default_shared_modules.extend(TO_LIST('auth_script idmap_tdb2 idmap_script')) # these have broken dependencies @@ -1775,6 +1774,9 @@ main() { if conf.CONFIG_SET('HAVE_GLUSTERFS'): default_shared_modules.extend(TO_LIST('vfs_glusterfs')) + if conf.CONFIG_SET('HAVE_SETMNTENT'): + default_shared_modules.extend(TO_LIST('vfs_glusterfs_fuse')) + if conf.CONFIG_SET('HAVE_VXFS'): default_shared_modules.extend(TO_LIST('vfs_vxfs')) -- 2.21.0