2 Unix SMB/CIFS implementation.
4 Copyright (c) 2019 Guenther Deschner <gd@samba.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "smbd/smbd.h"
22 #include "system/filesys.h"
24 #define GLUSTER_NAME_MAX 255
26 static int vfs_gluster_fuse_get_real_filename(struct vfs_handle_struct
*handle
,
27 const struct smb_filename
*path
,
33 char key_buf
[GLUSTER_NAME_MAX
+ 64];
34 char val_buf
[GLUSTER_NAME_MAX
+ 1];
35 char *found_name
= NULL
;
37 if (strlen(name
) >= GLUSTER_NAME_MAX
) {
42 snprintf(key_buf
, GLUSTER_NAME_MAX
+ 64,
43 "glusterfs.get_real_filename:%s", name
);
45 ret
= getxattr(path
->base_name
, key_buf
, val_buf
, GLUSTER_NAME_MAX
+ 1);
47 if (errno
== ENOATTR
) {
53 found_name
= talloc_strdup(mem_ctx
, val_buf
);
54 if (found_name
== NULL
) {
58 *_found_name
= found_name
;
62 struct device_mapping_entry
{
63 SMB_DEV_T device
; /* the local device, for reference */
64 uint64_t mapped_device
; /* the mapped device */
67 struct vfs_glusterfs_fuse_handle_data
{
68 unsigned num_mapped_devices
;
69 struct device_mapping_entry
*mapped_devices
;
72 /* a 64 bit hash, based on the one in tdb, copied from vfs_fileied */
73 static uint64_t vfs_glusterfs_fuse_uint64_hash(const uint8_t *s
, size_t len
)
75 uint64_t value
; /* Used to compute the hash value. */
76 uint32_t i
; /* Used to cycle through random values. */
78 /* Set the initial value from the key size. */
79 for (value
= 0x238F13AFLL
* len
, i
=0; i
< len
; i
++)
80 value
= (value
+ (((uint64_t)s
[i
]) << (i
*5 % 24)));
82 return (1103515243LL * value
+ 12345LL);
85 static void vfs_glusterfs_fuse_load_devices(
86 struct vfs_glusterfs_fuse_handle_data
*data
)
91 data
->num_mapped_devices
= 0;
92 TALLOC_FREE(data
->mapped_devices
);
94 f
= setmntent("/etc/mtab", "r");
99 while ((m
= getmntent(f
))) {
102 uint64_t mapped_device
;
104 if (stat(m
->mnt_dir
, &st
) != 0) {
109 /* strip the host part off of the fsname */
110 p
= strrchr(m
->mnt_fsname
, ':');
114 /* TODO: consider the case of '' ? */
118 mapped_device
= vfs_glusterfs_fuse_uint64_hash(
122 data
->mapped_devices
= talloc_realloc(data
,
123 data
->mapped_devices
,
124 struct device_mapping_entry
,
125 data
->num_mapped_devices
+ 1);
126 if (data
->mapped_devices
== NULL
) {
130 data
->mapped_devices
[data
->num_mapped_devices
].device
=
132 data
->mapped_devices
[data
->num_mapped_devices
].mapped_device
=
135 data
->num_mapped_devices
++;
142 data
->num_mapped_devices
= 0;
143 TALLOC_FREE(data
->mapped_devices
);
149 static int vfs_glusterfs_fuse_map_device_cached(
150 struct vfs_glusterfs_fuse_handle_data
*data
,
152 uint64_t *mapped_device
)
156 for (i
= 0; i
< data
->num_mapped_devices
; i
++) {
157 if (data
->mapped_devices
[i
].device
== device
) {
158 *mapped_device
= data
->mapped_devices
[i
].mapped_device
;
166 static int vfs_glusterfs_fuse_map_device(
167 struct vfs_glusterfs_fuse_handle_data
*data
,
169 uint64_t *mapped_device
)
173 ret
= vfs_glusterfs_fuse_map_device_cached(data
, device
, mapped_device
);
178 vfs_glusterfs_fuse_load_devices(data
);
180 ret
= vfs_glusterfs_fuse_map_device_cached(data
, device
, mapped_device
);
185 static struct file_id
vfs_glusterfs_fuse_file_id_create(
186 struct vfs_handle_struct
*handle
,
187 const SMB_STRUCT_STAT
*sbuf
)
189 struct vfs_glusterfs_fuse_handle_data
*data
;
191 uint64_t mapped_device
;
196 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, sbuf
);
198 SMB_VFS_HANDLE_GET_DATA(handle
, data
,
199 struct vfs_glusterfs_fuse_handle_data
,
202 ret
= vfs_glusterfs_fuse_map_device(data
, sbuf
->st_ex_dev
,
205 id
.devid
= mapped_device
;
207 DBG_WARNING("Failed to map device [%jx], falling back to "
208 "standard file_id [%jx]",
209 (uintmax_t)sbuf
->st_ex_dev
,
210 (uintmax_t)id
.devid
);
213 DBG_DEBUG("Returning dev [%jx] inode [%jx]\n",
214 (uintmax_t)id
.devid
, (uintmax_t)id
.inode
);
219 static int vfs_glusterfs_fuse_connect(struct vfs_handle_struct
*handle
,
220 const char *service
, const char *user
)
222 struct vfs_glusterfs_fuse_handle_data
*data
;
223 int ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
229 data
= talloc_zero(handle
->conn
, struct vfs_glusterfs_fuse_handle_data
);
231 DBG_ERR("talloc_zero() failed.\n");
232 SMB_VFS_NEXT_DISCONNECT(handle
);
237 * Fill the cache in the tree connect, so that the first file/dir access
238 * has chances of being fast...
240 vfs_glusterfs_fuse_load_devices(data
);
242 SMB_VFS_HANDLE_SET_DATA(handle
, data
, NULL
,
243 struct vfs_glusterfs_fuse_handle_data
,
246 DBG_DEBUG("vfs_glusterfs_fuse_connect(): connected to service[%s]\n",
252 struct vfs_fn_pointers glusterfs_fuse_fns
= {
254 .connect_fn
= vfs_glusterfs_fuse_connect
,
255 .get_real_filename_fn
= vfs_gluster_fuse_get_real_filename
,
256 .file_id_create_fn
= vfs_glusterfs_fuse_file_id_create
,
260 NTSTATUS
vfs_glusterfs_fuse_init(TALLOC_CTX
*ctx
)
262 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
,
263 "glusterfs_fuse", &glusterfs_fuse_fns
);