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 NTSTATUS
vfs_gluster_fuse_get_real_filename_at(
27 struct vfs_handle_struct
*handle
,
28 struct files_struct
*dirfsp
,
34 char key_buf
[GLUSTER_NAME_MAX
+ 64];
35 char val_buf
[GLUSTER_NAME_MAX
+ 1];
36 char *found_name
= NULL
;
38 if (strlen(name
) >= GLUSTER_NAME_MAX
) {
39 return NT_STATUS_OBJECT_NAME_INVALID
;
42 snprintf(key_buf
, GLUSTER_NAME_MAX
+ 64,
43 "glusterfs.get_real_filename:%s", name
);
45 dirfd
= openat(fsp_get_pathref_fd(dirfsp
), ".", O_RDONLY
);
47 NTSTATUS status
= map_nt_error_from_unix(errno
);
48 DBG_DEBUG("Could not open '.' in %s: %s\n",
54 ret
= fgetxattr(dirfd
, key_buf
, val_buf
, GLUSTER_NAME_MAX
+ 1);
57 if (errno
== ENOATTR
) {
60 return map_nt_error_from_unix(errno
);
63 found_name
= talloc_strdup(mem_ctx
, val_buf
);
64 if (found_name
== NULL
) {
65 return NT_STATUS_NO_MEMORY
;
67 *_found_name
= found_name
;
71 struct device_mapping_entry
{
72 SMB_DEV_T device
; /* the local device, for reference */
73 uint64_t mapped_device
; /* the mapped device */
76 struct vfs_glusterfs_fuse_handle_data
{
77 unsigned num_mapped_devices
;
78 struct device_mapping_entry
*mapped_devices
;
81 /* a 64 bit hash, based on the one in tdb, copied from vfs_fileied */
82 static uint64_t vfs_glusterfs_fuse_uint64_hash(const uint8_t *s
, size_t len
)
84 uint64_t value
; /* Used to compute the hash value. */
85 uint32_t i
; /* Used to cycle through random values. */
87 /* Set the initial value from the key size. */
88 for (value
= 0x238F13AFLL
* len
, i
=0; i
< len
; i
++)
89 value
= (value
+ (((uint64_t)s
[i
]) << (i
*5 % 24)));
91 return (1103515243LL * value
+ 12345LL);
94 static void vfs_glusterfs_fuse_load_devices(
95 struct vfs_glusterfs_fuse_handle_data
*data
)
100 data
->num_mapped_devices
= 0;
101 TALLOC_FREE(data
->mapped_devices
);
103 f
= setmntent("/etc/mtab", "r");
108 while ((m
= getmntent(f
))) {
111 uint64_t mapped_device
;
113 if (stat(m
->mnt_dir
, &st
) != 0) {
118 /* strip the host part off of the fsname */
119 p
= strrchr(m
->mnt_fsname
, ':');
123 /* TODO: consider the case of '' ? */
127 mapped_device
= vfs_glusterfs_fuse_uint64_hash(
131 data
->mapped_devices
= talloc_realloc(data
,
132 data
->mapped_devices
,
133 struct device_mapping_entry
,
134 data
->num_mapped_devices
+ 1);
135 if (data
->mapped_devices
== NULL
) {
139 data
->mapped_devices
[data
->num_mapped_devices
].device
=
141 data
->mapped_devices
[data
->num_mapped_devices
].mapped_device
=
144 data
->num_mapped_devices
++;
151 data
->num_mapped_devices
= 0;
152 TALLOC_FREE(data
->mapped_devices
);
158 static int vfs_glusterfs_fuse_map_device_cached(
159 struct vfs_glusterfs_fuse_handle_data
*data
,
161 uint64_t *mapped_device
)
165 for (i
= 0; i
< data
->num_mapped_devices
; i
++) {
166 if (data
->mapped_devices
[i
].device
== device
) {
167 *mapped_device
= data
->mapped_devices
[i
].mapped_device
;
175 static int vfs_glusterfs_fuse_map_device(
176 struct vfs_glusterfs_fuse_handle_data
*data
,
178 uint64_t *mapped_device
)
182 ret
= vfs_glusterfs_fuse_map_device_cached(data
, device
, mapped_device
);
187 vfs_glusterfs_fuse_load_devices(data
);
189 ret
= vfs_glusterfs_fuse_map_device_cached(data
, device
, mapped_device
);
194 static struct file_id
vfs_glusterfs_fuse_file_id_create(
195 struct vfs_handle_struct
*handle
,
196 const SMB_STRUCT_STAT
*sbuf
)
198 struct vfs_glusterfs_fuse_handle_data
*data
;
200 uint64_t mapped_device
;
205 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, sbuf
);
207 SMB_VFS_HANDLE_GET_DATA(handle
, data
,
208 struct vfs_glusterfs_fuse_handle_data
,
211 ret
= vfs_glusterfs_fuse_map_device(data
, sbuf
->st_ex_dev
,
214 id
.devid
= mapped_device
;
216 DBG_WARNING("Failed to map device [%jx], falling back to "
217 "standard file_id [%jx]\n",
218 (uintmax_t)sbuf
->st_ex_dev
,
219 (uintmax_t)id
.devid
);
222 DBG_DEBUG("Returning dev [%jx] inode [%jx]\n",
223 (uintmax_t)id
.devid
, (uintmax_t)id
.inode
);
228 static int vfs_glusterfs_fuse_connect(struct vfs_handle_struct
*handle
,
229 const char *service
, const char *user
)
231 struct vfs_glusterfs_fuse_handle_data
*data
;
232 int ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
238 data
= talloc_zero(handle
->conn
, struct vfs_glusterfs_fuse_handle_data
);
240 DBG_ERR("talloc_zero() failed.\n");
241 SMB_VFS_NEXT_DISCONNECT(handle
);
246 * Fill the cache in the tree connect, so that the first file/dir access
247 * has chances of being fast...
249 vfs_glusterfs_fuse_load_devices(data
);
251 SMB_VFS_HANDLE_SET_DATA(handle
, data
, NULL
,
252 struct vfs_glusterfs_fuse_handle_data
,
255 DBG_DEBUG("vfs_glusterfs_fuse_connect(): connected to service[%s]\n",
261 struct vfs_fn_pointers glusterfs_fuse_fns
= {
263 .connect_fn
= vfs_glusterfs_fuse_connect
,
264 .get_real_filename_at_fn
= vfs_gluster_fuse_get_real_filename_at
,
265 .file_id_create_fn
= vfs_glusterfs_fuse_file_id_create
,
269 NTSTATUS
vfs_glusterfs_fuse_init(TALLOC_CTX
*ctx
)
271 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
,
272 "glusterfs_fuse", &glusterfs_fuse_fns
);