s3: VFS: gluster: Add vfs_gluster_read_dfs_pathat().
[Samba.git] / source3 / modules / vfs_glusterfs.c
blobd4b68fba37671892f6634eb283f314568410b746
1 /*
2 Unix SMB/CIFS implementation.
4 Wrap GlusterFS GFAPI calls in vfs functions.
6 Copyright (c) 2013 Anand Avati <avati@redhat.com>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /**
23 * @file vfs_glusterfs.c
24 * @author Anand Avati <avati@redhat.com>
25 * @date May 2013
26 * @brief Samba VFS module for glusterfs
28 * @todo
29 * - sendfile/recvfile support
31 * A Samba VFS module for GlusterFS, based on Gluster's libgfapi.
32 * This is a "bottom" vfs module (not something to be stacked on top of
33 * another module), and translates (most) calls to the closest actions
34 * available in libgfapi.
38 #include "includes.h"
39 #include "smbd/smbd.h"
40 #include <stdio.h>
41 #include <glusterfs/api/glfs.h>
42 #include "lib/util/dlinklist.h"
43 #include "lib/util/tevent_unix.h"
44 #include "smbd/globals.h"
45 #include "lib/util/sys_rw.h"
46 #include "smbprofile.h"
47 #include "modules/posixacl_xattr.h"
48 #include "lib/pthreadpool/pthreadpool_tevent.h"
50 #define DEFAULT_VOLFILE_SERVER "localhost"
51 #define GLUSTER_NAME_MAX 255
53 /**
54 * Helper to convert struct stat to struct stat_ex.
56 static void smb_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src)
58 ZERO_STRUCTP(dst);
60 dst->st_ex_dev = src->st_dev;
61 dst->st_ex_ino = src->st_ino;
62 dst->st_ex_mode = src->st_mode;
63 dst->st_ex_nlink = src->st_nlink;
64 dst->st_ex_uid = src->st_uid;
65 dst->st_ex_gid = src->st_gid;
66 dst->st_ex_rdev = src->st_rdev;
67 dst->st_ex_size = src->st_size;
68 dst->st_ex_atime.tv_sec = src->st_atime;
69 dst->st_ex_mtime.tv_sec = src->st_mtime;
70 dst->st_ex_ctime.tv_sec = src->st_ctime;
71 dst->st_ex_btime.tv_sec = src->st_mtime;
72 dst->st_ex_blksize = src->st_blksize;
73 dst->st_ex_blocks = src->st_blocks;
74 dst->st_ex_file_id = dst->st_ex_ino;
75 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_FILE_ID;
76 #ifdef STAT_HAVE_NSEC
77 dst->st_ex_atime.tv_nsec = src->st_atime_nsec;
78 dst->st_ex_mtime.tv_nsec = src->st_mtime_nsec;
79 dst->st_ex_ctime.tv_nsec = src->st_ctime_nsec;
80 dst->st_ex_btime.tv_nsec = src->st_mtime_nsec;
81 #endif
82 dst->st_ex_itime = dst->st_ex_btime;
83 dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_ITIME;
86 /* pre-opened glfs_t */
88 static struct glfs_preopened {
89 char *volume;
90 char *connectpath;
91 glfs_t *fs;
92 int ref;
93 struct glfs_preopened *next, *prev;
94 } *glfs_preopened;
97 static int glfs_set_preopened(const char *volume, const char *connectpath, glfs_t *fs)
99 struct glfs_preopened *entry = NULL;
101 entry = talloc_zero(NULL, struct glfs_preopened);
102 if (!entry) {
103 errno = ENOMEM;
104 return -1;
107 entry->volume = talloc_strdup(entry, volume);
108 if (!entry->volume) {
109 talloc_free(entry);
110 errno = ENOMEM;
111 return -1;
114 entry->connectpath = talloc_strdup(entry, connectpath);
115 if (entry->connectpath == NULL) {
116 talloc_free(entry);
117 errno = ENOMEM;
118 return -1;
121 entry->fs = fs;
122 entry->ref = 1;
124 DLIST_ADD(glfs_preopened, entry);
126 return 0;
129 static glfs_t *glfs_find_preopened(const char *volume, const char *connectpath)
131 struct glfs_preopened *entry = NULL;
133 for (entry = glfs_preopened; entry; entry = entry->next) {
134 if (strcmp(entry->volume, volume) == 0 &&
135 strcmp(entry->connectpath, connectpath) == 0)
137 entry->ref++;
138 return entry->fs;
142 return NULL;
145 static void glfs_clear_preopened(glfs_t *fs)
147 struct glfs_preopened *entry = NULL;
149 for (entry = glfs_preopened; entry; entry = entry->next) {
150 if (entry->fs == fs) {
151 if (--entry->ref)
152 return;
154 DLIST_REMOVE(glfs_preopened, entry);
156 glfs_fini(entry->fs);
157 talloc_free(entry);
162 static int vfs_gluster_set_volfile_servers(glfs_t *fs,
163 const char *volfile_servers)
165 char *server = NULL;
166 size_t server_count = 0;
167 size_t server_success = 0;
168 int ret = -1;
169 TALLOC_CTX *frame = talloc_stackframe();
171 DBG_INFO("servers list %s\n", volfile_servers);
173 while (next_token_talloc(frame, &volfile_servers, &server, " \t")) {
174 char *transport = NULL;
175 char *host = NULL;
176 int port = 0;
178 server_count++;
179 DBG_INFO("server %zu %s\n", server_count, server);
181 /* Determine the transport type */
182 if (strncmp(server, "unix+", 5) == 0) {
183 port = 0;
184 transport = talloc_strdup(frame, "unix");
185 if (!transport) {
186 errno = ENOMEM;
187 goto out;
189 host = talloc_strdup(frame, server + 5);
190 if (!host) {
191 errno = ENOMEM;
192 goto out;
194 } else {
195 char *p = NULL;
196 char *port_index = NULL;
198 if (strncmp(server, "tcp+", 4) == 0) {
199 server += 4;
202 /* IPv6 is enclosed in []
203 * ':' before ']' is part of IPv6
204 * ':' after ']' indicates port
206 p = server;
207 if (server[0] == '[') {
208 server++;
209 p = index(server, ']');
210 if (p == NULL) {
211 /* Malformed IPv6 */
212 continue;
214 p[0] = '\0';
215 p++;
218 port_index = index(p, ':');
220 if (port_index == NULL) {
221 port = 0;
222 } else {
223 port = atoi(port_index + 1);
224 port_index[0] = '\0';
226 transport = talloc_strdup(frame, "tcp");
227 if (!transport) {
228 errno = ENOMEM;
229 goto out;
231 host = talloc_strdup(frame, server);
232 if (!host) {
233 errno = ENOMEM;
234 goto out;
238 DBG_INFO("Calling set volfile server with params "
239 "transport=%s, host=%s, port=%d\n", transport,
240 host, port);
242 ret = glfs_set_volfile_server(fs, transport, host, port);
243 if (ret < 0) {
244 DBG_WARNING("Failed to set volfile_server "
245 "transport=%s, host=%s, port=%d (%s)\n",
246 transport, host, port, strerror(errno));
247 } else {
248 server_success++;
252 out:
253 if (server_count == 0) {
254 ret = -1;
255 } else if (server_success < server_count) {
256 DBG_WARNING("Failed to set %zu out of %zu servers parsed\n",
257 server_count - server_success, server_count);
258 ret = 0;
261 TALLOC_FREE(frame);
262 return ret;
265 /* Disk Operations */
267 static int vfs_gluster_connect(struct vfs_handle_struct *handle,
268 const char *service,
269 const char *user)
271 const struct loadparm_substitution *lp_sub =
272 loadparm_s3_global_substitution();
273 const char *volfile_servers;
274 const char *volume;
275 char *logfile;
276 int loglevel;
277 glfs_t *fs = NULL;
278 TALLOC_CTX *tmp_ctx;
279 int ret = 0;
281 tmp_ctx = talloc_new(NULL);
282 if (tmp_ctx == NULL) {
283 ret = -1;
284 goto done;
286 logfile = lp_parm_substituted_string(tmp_ctx,
287 lp_sub,
288 SNUM(handle->conn),
289 "glusterfs",
290 "logfile",
291 NULL);
293 loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
295 volfile_servers = lp_parm_substituted_string(tmp_ctx,
296 lp_sub,
297 SNUM(handle->conn),
298 "glusterfs",
299 "volfile_server",
300 NULL);
301 if (volfile_servers == NULL) {
302 volfile_servers = DEFAULT_VOLFILE_SERVER;
305 volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
306 NULL);
307 if (volume == NULL) {
308 volume = service;
311 fs = glfs_find_preopened(volume, handle->conn->connectpath);
312 if (fs) {
313 goto done;
316 fs = glfs_new(volume);
317 if (fs == NULL) {
318 ret = -1;
319 goto done;
322 ret = vfs_gluster_set_volfile_servers(fs, volfile_servers);
323 if (ret < 0) {
324 DBG_ERR("Failed to set volfile_servers from list %s\n",
325 volfile_servers);
326 goto done;
329 ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-posix-acl",
330 "true");
331 if (ret < 0) {
332 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
333 goto done;
337 ret = glfs_set_xlator_option(fs, "*-snapview-client",
338 "snapdir-entry-path",
339 handle->conn->connectpath);
340 if (ret < 0) {
341 DEBUG(0, ("%s: Failed to set xlator option:"
342 " snapdir-entry-path\n", volume));
343 goto done;
346 ret = glfs_set_logging(fs, logfile, loglevel);
347 if (ret < 0) {
348 DEBUG(0, ("%s: Failed to set logfile %s loglevel %d\n",
349 volume, logfile, loglevel));
350 goto done;
353 ret = glfs_init(fs);
354 if (ret < 0) {
355 DEBUG(0, ("%s: Failed to initialize volume (%s)\n",
356 volume, strerror(errno)));
357 goto done;
360 ret = glfs_set_preopened(volume, handle->conn->connectpath, fs);
361 if (ret < 0) {
362 DEBUG(0, ("%s: Failed to register volume (%s)\n",
363 volume, strerror(errno)));
364 goto done;
368 * The shadow_copy2 module will fail to export subdirectories
369 * of a gluster volume unless we specify the mount point,
370 * because the detection fails if the file system is not
371 * locally mounted:
372 * https://bugzilla.samba.org/show_bug.cgi?id=13091
374 lp_do_parameter(SNUM(handle->conn), "shadow:mountpoint", "/");
377 * Unless we have an async implementation of getxattrat turn this off.
379 lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false");
381 done:
382 if (ret < 0) {
383 if (fs)
384 glfs_fini(fs);
385 } else {
386 DBG_ERR("%s: Initialized volume from servers %s\n",
387 volume, volfile_servers);
388 handle->data = fs;
390 talloc_free(tmp_ctx);
391 return ret;
394 static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
396 glfs_t *fs = NULL;
398 fs = handle->data;
400 glfs_clear_preopened(fs);
403 static uint64_t vfs_gluster_disk_free(struct vfs_handle_struct *handle,
404 const struct smb_filename *smb_fname,
405 uint64_t *bsize_p,
406 uint64_t *dfree_p,
407 uint64_t *dsize_p)
409 struct statvfs statvfs = { 0, };
410 int ret;
412 ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
413 if (ret < 0) {
414 return -1;
417 if (bsize_p != NULL) {
418 *bsize_p = (uint64_t)statvfs.f_bsize; /* Block size */
420 if (dfree_p != NULL) {
421 *dfree_p = (uint64_t)statvfs.f_bavail; /* Available Block units */
423 if (dsize_p != NULL) {
424 *dsize_p = (uint64_t)statvfs.f_blocks; /* Total Block units */
427 return (uint64_t)statvfs.f_bavail;
430 static int vfs_gluster_get_quota(struct vfs_handle_struct *handle,
431 const struct smb_filename *smb_fname,
432 enum SMB_QUOTA_TYPE qtype,
433 unid_t id,
434 SMB_DISK_QUOTA *qt)
436 errno = ENOSYS;
437 return -1;
440 static int
441 vfs_gluster_set_quota(struct vfs_handle_struct *handle,
442 enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
444 errno = ENOSYS;
445 return -1;
448 static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
449 const struct smb_filename *smb_fname,
450 struct vfs_statvfs_struct *vfs_statvfs)
452 struct statvfs statvfs = { 0, };
453 int ret;
455 ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
456 if (ret < 0) {
457 DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
458 smb_fname->base_name, strerror(errno)));
459 return -1;
462 ZERO_STRUCTP(vfs_statvfs);
464 vfs_statvfs->OptimalTransferSize = statvfs.f_frsize;
465 vfs_statvfs->BlockSize = statvfs.f_bsize;
466 vfs_statvfs->TotalBlocks = statvfs.f_blocks;
467 vfs_statvfs->BlocksAvail = statvfs.f_bfree;
468 vfs_statvfs->UserBlocksAvail = statvfs.f_bavail;
469 vfs_statvfs->TotalFileNodes = statvfs.f_files;
470 vfs_statvfs->FreeFileNodes = statvfs.f_ffree;
471 vfs_statvfs->FsIdentifier = statvfs.f_fsid;
472 vfs_statvfs->FsCapabilities =
473 FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
475 return ret;
478 static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
479 enum timestamp_set_resolution *p_ts_res)
481 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
483 #ifdef HAVE_GFAPI_VER_6
484 caps |= FILE_SUPPORTS_SPARSE_FILES;
485 #endif
487 #ifdef STAT_HAVE_NSEC
488 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
489 #endif
491 return caps;
494 static DIR *vfs_gluster_opendir(struct vfs_handle_struct *handle,
495 const struct smb_filename *smb_fname,
496 const char *mask,
497 uint32_t attributes)
499 glfs_fd_t *fd;
501 START_PROFILE(syscall_opendir);
503 fd = glfs_opendir(handle->data, smb_fname->base_name);
504 if (fd == NULL) {
505 DEBUG(0, ("glfs_opendir(%s) failed: %s\n",
506 smb_fname->base_name, strerror(errno)));
509 END_PROFILE(syscall_opendir);
511 return (DIR *) fd;
514 static glfs_fd_t *vfs_gluster_fetch_glfd(struct vfs_handle_struct *handle,
515 files_struct *fsp)
517 glfs_fd_t **glfd = (glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
518 if (glfd == NULL) {
519 DBG_INFO("Failed to fetch fsp extension\n");
520 return NULL;
522 if (*glfd == NULL) {
523 DBG_INFO("Empty glfs_fd_t pointer\n");
524 return NULL;
527 return *glfd;
530 static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle,
531 files_struct *fsp, const char *mask,
532 uint32_t attributes)
534 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
535 if (glfd == NULL) {
536 DBG_ERR("Failed to fetch gluster fd\n");
537 return NULL;
540 return (DIR *)glfd;
543 static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp)
545 int ret;
547 START_PROFILE(syscall_closedir);
548 ret = glfs_closedir((void *)dirp);
549 END_PROFILE(syscall_closedir);
551 return ret;
554 static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle,
555 DIR *dirp, SMB_STRUCT_STAT *sbuf)
557 static char direntbuf[512];
558 int ret;
559 struct stat stat;
560 struct dirent *dirent = 0;
562 START_PROFILE(syscall_readdir);
563 if (sbuf != NULL) {
564 ret = glfs_readdirplus_r((void *)dirp, &stat, (void *)direntbuf,
565 &dirent);
566 } else {
567 ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
570 if ((ret < 0) || (dirent == NULL)) {
571 END_PROFILE(syscall_readdir);
572 return NULL;
575 if (sbuf != NULL) {
576 SET_STAT_INVALID(*sbuf);
577 if (!S_ISLNK(stat.st_mode)) {
578 smb_stat_ex_from_stat(sbuf, &stat);
582 END_PROFILE(syscall_readdir);
583 return dirent;
586 static long vfs_gluster_telldir(struct vfs_handle_struct *handle, DIR *dirp)
588 long ret;
590 START_PROFILE(syscall_telldir);
591 ret = glfs_telldir((void *)dirp);
592 END_PROFILE(syscall_telldir);
594 return ret;
597 static void vfs_gluster_seekdir(struct vfs_handle_struct *handle, DIR *dirp,
598 long offset)
600 START_PROFILE(syscall_seekdir);
601 glfs_seekdir((void *)dirp, offset);
602 END_PROFILE(syscall_seekdir);
605 static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
607 START_PROFILE(syscall_rewinddir);
608 glfs_seekdir((void *)dirp, 0);
609 END_PROFILE(syscall_rewinddir);
612 static int vfs_gluster_mkdirat(struct vfs_handle_struct *handle,
613 struct files_struct *dirfsp,
614 const struct smb_filename *smb_fname,
615 mode_t mode)
617 int ret;
619 START_PROFILE(syscall_mkdirat);
620 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
621 ret = glfs_mkdir(handle->data, smb_fname->base_name, mode);
622 END_PROFILE(syscall_mkdirat);
624 return ret;
627 static int vfs_gluster_open(struct vfs_handle_struct *handle,
628 struct smb_filename *smb_fname, files_struct *fsp,
629 int flags, mode_t mode)
631 glfs_fd_t *glfd;
632 glfs_fd_t **p_tmp;
634 START_PROFILE(syscall_open);
636 p_tmp = VFS_ADD_FSP_EXTENSION(handle, fsp, glfs_fd_t *, NULL);
637 if (p_tmp == NULL) {
638 END_PROFILE(syscall_open);
639 errno = ENOMEM;
640 return -1;
643 if (flags & O_DIRECTORY) {
644 glfd = glfs_opendir(handle->data, smb_fname->base_name);
645 } else if (flags & O_CREAT) {
646 glfd = glfs_creat(handle->data, smb_fname->base_name, flags,
647 mode);
648 } else {
649 glfd = glfs_open(handle->data, smb_fname->base_name, flags);
652 if (glfd == NULL) {
653 END_PROFILE(syscall_open);
654 /* no extension destroy_fn, so no need to save errno */
655 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
656 return -1;
659 *p_tmp = glfd;
661 END_PROFILE(syscall_open);
662 /* An arbitrary value for error reporting, so you know its us. */
663 return 13371337;
666 static int vfs_gluster_close(struct vfs_handle_struct *handle,
667 files_struct *fsp)
669 int ret;
670 glfs_fd_t *glfd = NULL;
672 START_PROFILE(syscall_close);
674 glfd = vfs_gluster_fetch_glfd(handle, fsp);
675 if (glfd == NULL) {
676 END_PROFILE(syscall_close);
677 DBG_ERR("Failed to fetch gluster fd\n");
678 return -1;
681 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
683 ret = glfs_close(glfd);
684 END_PROFILE(syscall_close);
686 return ret;
689 static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
690 files_struct *fsp, void *data, size_t n,
691 off_t offset)
693 ssize_t ret;
694 glfs_fd_t *glfd = NULL;
696 START_PROFILE_BYTES(syscall_pread, n);
698 glfd = vfs_gluster_fetch_glfd(handle, fsp);
699 if (glfd == NULL) {
700 END_PROFILE_BYTES(syscall_pread);
701 DBG_ERR("Failed to fetch gluster fd\n");
702 return -1;
705 #ifdef HAVE_GFAPI_VER_7_6
706 ret = glfs_pread(glfd, data, n, offset, 0, NULL);
707 #else
708 ret = glfs_pread(glfd, data, n, offset, 0);
709 #endif
710 END_PROFILE_BYTES(syscall_pread);
712 return ret;
715 struct vfs_gluster_pread_state {
716 ssize_t ret;
717 glfs_fd_t *fd;
718 void *buf;
719 size_t count;
720 off_t offset;
722 struct vfs_aio_state vfs_aio_state;
723 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
726 static void vfs_gluster_pread_do(void *private_data);
727 static void vfs_gluster_pread_done(struct tevent_req *subreq);
728 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state);
730 static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
731 *handle, TALLOC_CTX *mem_ctx,
732 struct tevent_context *ev,
733 files_struct *fsp,
734 void *data, size_t n,
735 off_t offset)
737 struct vfs_gluster_pread_state *state;
738 struct tevent_req *req, *subreq;
740 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
741 if (glfd == NULL) {
742 DBG_ERR("Failed to fetch gluster fd\n");
743 return NULL;
746 req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pread_state);
747 if (req == NULL) {
748 return NULL;
751 state->ret = -1;
752 state->fd = glfd;
753 state->buf = data;
754 state->count = n;
755 state->offset = offset;
757 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
758 state->profile_bytes, n);
759 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
761 subreq = pthreadpool_tevent_job_send(
762 state, ev, handle->conn->sconn->pool,
763 vfs_gluster_pread_do, state);
764 if (tevent_req_nomem(subreq, req)) {
765 return tevent_req_post(req, ev);
767 tevent_req_set_callback(subreq, vfs_gluster_pread_done, req);
769 talloc_set_destructor(state, vfs_gluster_pread_state_destructor);
771 return req;
774 static void vfs_gluster_pread_do(void *private_data)
776 struct vfs_gluster_pread_state *state = talloc_get_type_abort(
777 private_data, struct vfs_gluster_pread_state);
778 struct timespec start_time;
779 struct timespec end_time;
781 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
783 PROFILE_TIMESTAMP(&start_time);
785 do {
786 #ifdef HAVE_GFAPI_VER_7_6
787 state->ret = glfs_pread(state->fd, state->buf, state->count,
788 state->offset, 0, NULL);
789 #else
790 state->ret = glfs_pread(state->fd, state->buf, state->count,
791 state->offset, 0);
792 #endif
793 } while ((state->ret == -1) && (errno == EINTR));
795 if (state->ret == -1) {
796 state->vfs_aio_state.error = errno;
799 PROFILE_TIMESTAMP(&end_time);
801 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
803 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
806 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state)
808 return -1;
811 static void vfs_gluster_pread_done(struct tevent_req *subreq)
813 struct tevent_req *req = tevent_req_callback_data(
814 subreq, struct tevent_req);
815 struct vfs_gluster_pread_state *state = tevent_req_data(
816 req, struct vfs_gluster_pread_state);
817 int ret;
819 ret = pthreadpool_tevent_job_recv(subreq);
820 TALLOC_FREE(subreq);
821 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
822 talloc_set_destructor(state, NULL);
823 if (ret != 0) {
824 if (ret != EAGAIN) {
825 tevent_req_error(req, ret);
826 return;
829 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
830 * means the lower level pthreadpool failed to create a new
831 * thread. Fallback to sync processing in that case to allow
832 * some progress for the client.
834 vfs_gluster_pread_do(state);
837 tevent_req_done(req);
840 static ssize_t vfs_gluster_pread_recv(struct tevent_req *req,
841 struct vfs_aio_state *vfs_aio_state)
843 struct vfs_gluster_pread_state *state = tevent_req_data(
844 req, struct vfs_gluster_pread_state);
846 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
847 return -1;
850 *vfs_aio_state = state->vfs_aio_state;
851 return state->ret;
854 struct vfs_gluster_pwrite_state {
855 ssize_t ret;
856 glfs_fd_t *fd;
857 const void *buf;
858 size_t count;
859 off_t offset;
861 struct vfs_aio_state vfs_aio_state;
862 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
865 static void vfs_gluster_pwrite_do(void *private_data);
866 static void vfs_gluster_pwrite_done(struct tevent_req *subreq);
867 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state);
869 static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
870 *handle, TALLOC_CTX *mem_ctx,
871 struct tevent_context *ev,
872 files_struct *fsp,
873 const void *data, size_t n,
874 off_t offset)
876 struct tevent_req *req, *subreq;
877 struct vfs_gluster_pwrite_state *state;
879 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
880 if (glfd == NULL) {
881 DBG_ERR("Failed to fetch gluster fd\n");
882 return NULL;
885 req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pwrite_state);
886 if (req == NULL) {
887 return NULL;
890 state->ret = -1;
891 state->fd = glfd;
892 state->buf = data;
893 state->count = n;
894 state->offset = offset;
896 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
897 state->profile_bytes, n);
898 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
900 subreq = pthreadpool_tevent_job_send(
901 state, ev, handle->conn->sconn->pool,
902 vfs_gluster_pwrite_do, state);
903 if (tevent_req_nomem(subreq, req)) {
904 return tevent_req_post(req, ev);
906 tevent_req_set_callback(subreq, vfs_gluster_pwrite_done, req);
908 talloc_set_destructor(state, vfs_gluster_pwrite_state_destructor);
910 return req;
913 static void vfs_gluster_pwrite_do(void *private_data)
915 struct vfs_gluster_pwrite_state *state = talloc_get_type_abort(
916 private_data, struct vfs_gluster_pwrite_state);
917 struct timespec start_time;
918 struct timespec end_time;
920 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
922 PROFILE_TIMESTAMP(&start_time);
924 do {
925 #ifdef HAVE_GFAPI_VER_7_6
926 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
927 state->offset, 0, NULL, NULL);
928 #else
929 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
930 state->offset, 0);
931 #endif
932 } while ((state->ret == -1) && (errno == EINTR));
934 if (state->ret == -1) {
935 state->vfs_aio_state.error = errno;
938 PROFILE_TIMESTAMP(&end_time);
940 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
942 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
945 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state)
947 return -1;
950 static void vfs_gluster_pwrite_done(struct tevent_req *subreq)
952 struct tevent_req *req = tevent_req_callback_data(
953 subreq, struct tevent_req);
954 struct vfs_gluster_pwrite_state *state = tevent_req_data(
955 req, struct vfs_gluster_pwrite_state);
956 int ret;
958 ret = pthreadpool_tevent_job_recv(subreq);
959 TALLOC_FREE(subreq);
960 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
961 talloc_set_destructor(state, NULL);
962 if (ret != 0) {
963 if (ret != EAGAIN) {
964 tevent_req_error(req, ret);
965 return;
968 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
969 * means the lower level pthreadpool failed to create a new
970 * thread. Fallback to sync processing in that case to allow
971 * some progress for the client.
973 vfs_gluster_pwrite_do(state);
976 tevent_req_done(req);
979 static ssize_t vfs_gluster_pwrite_recv(struct tevent_req *req,
980 struct vfs_aio_state *vfs_aio_state)
982 struct vfs_gluster_pwrite_state *state = tevent_req_data(
983 req, struct vfs_gluster_pwrite_state);
985 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
986 return -1;
989 *vfs_aio_state = state->vfs_aio_state;
991 return state->ret;
994 static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
995 files_struct *fsp, const void *data,
996 size_t n, off_t offset)
998 ssize_t ret;
999 glfs_fd_t *glfd = NULL;
1001 START_PROFILE_BYTES(syscall_pwrite, n);
1003 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1004 if (glfd == NULL) {
1005 END_PROFILE_BYTES(syscall_pwrite);
1006 DBG_ERR("Failed to fetch gluster fd\n");
1007 return -1;
1010 #ifdef HAVE_GFAPI_VER_7_6
1011 ret = glfs_pwrite(glfd, data, n, offset, 0, NULL, NULL);
1012 #else
1013 ret = glfs_pwrite(glfd, data, n, offset, 0);
1014 #endif
1015 END_PROFILE_BYTES(syscall_pwrite);
1017 return ret;
1020 static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
1021 files_struct *fsp, off_t offset, int whence)
1023 off_t ret = 0;
1024 glfs_fd_t *glfd = NULL;
1026 START_PROFILE(syscall_lseek);
1028 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1029 if (glfd == NULL) {
1030 END_PROFILE(syscall_lseek);
1031 DBG_ERR("Failed to fetch gluster fd\n");
1032 return -1;
1035 ret = glfs_lseek(glfd, offset, whence);
1036 END_PROFILE(syscall_lseek);
1038 return ret;
1041 static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd,
1042 files_struct *fromfsp,
1043 const DATA_BLOB *hdr,
1044 off_t offset, size_t n)
1046 errno = ENOTSUP;
1047 return -1;
1050 static ssize_t vfs_gluster_recvfile(struct vfs_handle_struct *handle,
1051 int fromfd, files_struct *tofsp,
1052 off_t offset, size_t n)
1054 errno = ENOTSUP;
1055 return -1;
1058 static int vfs_gluster_renameat(struct vfs_handle_struct *handle,
1059 files_struct *srcfsp,
1060 const struct smb_filename *smb_fname_src,
1061 files_struct *dstfsp,
1062 const struct smb_filename *smb_fname_dst)
1064 int ret;
1066 START_PROFILE(syscall_renameat);
1067 ret = glfs_rename(handle->data, smb_fname_src->base_name,
1068 smb_fname_dst->base_name);
1069 END_PROFILE(syscall_renameat);
1071 return ret;
1074 struct vfs_gluster_fsync_state {
1075 ssize_t ret;
1076 glfs_fd_t *fd;
1078 struct vfs_aio_state vfs_aio_state;
1079 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1082 static void vfs_gluster_fsync_do(void *private_data);
1083 static void vfs_gluster_fsync_done(struct tevent_req *subreq);
1084 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state);
1086 static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
1087 *handle, TALLOC_CTX *mem_ctx,
1088 struct tevent_context *ev,
1089 files_struct *fsp)
1091 struct tevent_req *req, *subreq;
1092 struct vfs_gluster_fsync_state *state;
1094 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1095 if (glfd == NULL) {
1096 DBG_ERR("Failed to fetch gluster fd\n");
1097 return NULL;
1100 req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_fsync_state);
1101 if (req == NULL) {
1102 return NULL;
1105 state->ret = -1;
1106 state->fd = glfd;
1108 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1109 state->profile_bytes, 0);
1110 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1112 subreq = pthreadpool_tevent_job_send(
1113 state, ev, handle->conn->sconn->pool, vfs_gluster_fsync_do, state);
1114 if (tevent_req_nomem(subreq, req)) {
1115 return tevent_req_post(req, ev);
1117 tevent_req_set_callback(subreq, vfs_gluster_fsync_done, req);
1119 talloc_set_destructor(state, vfs_gluster_fsync_state_destructor);
1121 return req;
1124 static void vfs_gluster_fsync_do(void *private_data)
1126 struct vfs_gluster_fsync_state *state = talloc_get_type_abort(
1127 private_data, struct vfs_gluster_fsync_state);
1128 struct timespec start_time;
1129 struct timespec end_time;
1131 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1133 PROFILE_TIMESTAMP(&start_time);
1135 do {
1136 #ifdef HAVE_GFAPI_VER_7_6
1137 state->ret = glfs_fsync(state->fd, NULL, NULL);
1138 #else
1139 state->ret = glfs_fsync(state->fd);
1140 #endif
1141 } while ((state->ret == -1) && (errno == EINTR));
1143 if (state->ret == -1) {
1144 state->vfs_aio_state.error = errno;
1147 PROFILE_TIMESTAMP(&end_time);
1149 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1151 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1154 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state)
1156 return -1;
1159 static void vfs_gluster_fsync_done(struct tevent_req *subreq)
1161 struct tevent_req *req = tevent_req_callback_data(
1162 subreq, struct tevent_req);
1163 struct vfs_gluster_fsync_state *state = tevent_req_data(
1164 req, struct vfs_gluster_fsync_state);
1165 int ret;
1167 ret = pthreadpool_tevent_job_recv(subreq);
1168 TALLOC_FREE(subreq);
1169 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1170 talloc_set_destructor(state, NULL);
1171 if (ret != 0) {
1172 if (ret != EAGAIN) {
1173 tevent_req_error(req, ret);
1174 return;
1177 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1178 * means the lower level pthreadpool failed to create a new
1179 * thread. Fallback to sync processing in that case to allow
1180 * some progress for the client.
1182 vfs_gluster_fsync_do(state);
1185 tevent_req_done(req);
1188 static int vfs_gluster_fsync_recv(struct tevent_req *req,
1189 struct vfs_aio_state *vfs_aio_state)
1191 struct vfs_gluster_fsync_state *state = tevent_req_data(
1192 req, struct vfs_gluster_fsync_state);
1194 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1195 return -1;
1198 *vfs_aio_state = state->vfs_aio_state;
1199 return state->ret;
1202 static int vfs_gluster_stat(struct vfs_handle_struct *handle,
1203 struct smb_filename *smb_fname)
1205 struct stat st;
1206 int ret;
1208 START_PROFILE(syscall_stat);
1209 ret = glfs_stat(handle->data, smb_fname->base_name, &st);
1210 if (ret == 0) {
1211 smb_stat_ex_from_stat(&smb_fname->st, &st);
1213 if (ret < 0 && errno != ENOENT) {
1214 DEBUG(0, ("glfs_stat(%s) failed: %s\n",
1215 smb_fname->base_name, strerror(errno)));
1217 END_PROFILE(syscall_stat);
1219 return ret;
1222 static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
1223 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1225 struct stat st;
1226 int ret;
1227 glfs_fd_t *glfd = NULL;
1229 START_PROFILE(syscall_fstat);
1231 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1232 if (glfd == NULL) {
1233 END_PROFILE(syscall_fstat);
1234 DBG_ERR("Failed to fetch gluster fd\n");
1235 return -1;
1238 ret = glfs_fstat(glfd, &st);
1239 if (ret == 0) {
1240 smb_stat_ex_from_stat(sbuf, &st);
1242 if (ret < 0) {
1243 DEBUG(0, ("glfs_fstat(%d) failed: %s\n",
1244 fsp->fh->fd, strerror(errno)));
1246 END_PROFILE(syscall_fstat);
1248 return ret;
1251 static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
1252 struct smb_filename *smb_fname)
1254 struct stat st;
1255 int ret;
1257 START_PROFILE(syscall_lstat);
1258 ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
1259 if (ret == 0) {
1260 smb_stat_ex_from_stat(&smb_fname->st, &st);
1262 if (ret < 0 && errno != ENOENT) {
1263 DEBUG(0, ("glfs_lstat(%s) failed: %s\n",
1264 smb_fname->base_name, strerror(errno)));
1266 END_PROFILE(syscall_lstat);
1268 return ret;
1271 static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle,
1272 files_struct *fsp,
1273 const SMB_STRUCT_STAT *sbuf)
1275 uint64_t ret;
1277 START_PROFILE(syscall_get_alloc_size);
1278 ret = sbuf->st_ex_blocks * 512;
1279 END_PROFILE(syscall_get_alloc_size);
1281 return ret;
1284 static int vfs_gluster_unlinkat(struct vfs_handle_struct *handle,
1285 struct files_struct *dirfsp,
1286 const struct smb_filename *smb_fname,
1287 int flags)
1289 int ret;
1291 START_PROFILE(syscall_unlinkat);
1292 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1293 if (flags & AT_REMOVEDIR) {
1294 ret = glfs_rmdir(handle->data, smb_fname->base_name);
1295 } else {
1296 ret = glfs_unlink(handle->data, smb_fname->base_name);
1298 END_PROFILE(syscall_unlinkat);
1300 return ret;
1303 static int vfs_gluster_chmod(struct vfs_handle_struct *handle,
1304 const struct smb_filename *smb_fname,
1305 mode_t mode)
1307 int ret;
1309 START_PROFILE(syscall_chmod);
1310 ret = glfs_chmod(handle->data, smb_fname->base_name, mode);
1311 END_PROFILE(syscall_chmod);
1313 return ret;
1316 static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
1317 files_struct *fsp, mode_t mode)
1319 int ret;
1320 glfs_fd_t *glfd = NULL;
1322 START_PROFILE(syscall_fchmod);
1324 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1325 if (glfd == NULL) {
1326 END_PROFILE(syscall_fchmod);
1327 DBG_ERR("Failed to fetch gluster fd\n");
1328 return -1;
1331 ret = glfs_fchmod(glfd, mode);
1332 END_PROFILE(syscall_fchmod);
1334 return ret;
1337 static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
1338 files_struct *fsp, uid_t uid, gid_t gid)
1340 int ret;
1341 glfs_fd_t *glfd = NULL;
1343 START_PROFILE(syscall_fchown);
1345 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1346 if (glfd == NULL) {
1347 END_PROFILE(syscall_fchown);
1348 DBG_ERR("Failed to fetch gluster fd\n");
1349 return -1;
1352 ret = glfs_fchown(glfd, uid, gid);
1353 END_PROFILE(syscall_fchown);
1355 return ret;
1358 static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
1359 const struct smb_filename *smb_fname,
1360 uid_t uid,
1361 gid_t gid)
1363 int ret;
1365 START_PROFILE(syscall_lchown);
1366 ret = glfs_lchown(handle->data, smb_fname->base_name, uid, gid);
1367 END_PROFILE(syscall_lchown);
1369 return ret;
1372 static int vfs_gluster_chdir(struct vfs_handle_struct *handle,
1373 const struct smb_filename *smb_fname)
1375 int ret;
1377 START_PROFILE(syscall_chdir);
1378 ret = glfs_chdir(handle->data, smb_fname->base_name);
1379 END_PROFILE(syscall_chdir);
1381 return ret;
1384 static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
1385 TALLOC_CTX *ctx)
1387 char *cwd;
1388 char *ret;
1389 struct smb_filename *smb_fname = NULL;
1391 START_PROFILE(syscall_getwd);
1393 cwd = SMB_CALLOC_ARRAY(char, PATH_MAX);
1394 if (cwd == NULL) {
1395 END_PROFILE(syscall_getwd);
1396 return NULL;
1399 ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1);
1400 END_PROFILE(syscall_getwd);
1402 if (ret == NULL) {
1403 SAFE_FREE(cwd);
1404 return NULL;
1406 smb_fname = synthetic_smb_fname(ctx,
1407 ret,
1408 NULL,
1409 NULL,
1411 SAFE_FREE(cwd);
1412 return smb_fname;
1415 static int vfs_gluster_ntimes(struct vfs_handle_struct *handle,
1416 const struct smb_filename *smb_fname,
1417 struct smb_file_time *ft)
1419 int ret = -1;
1420 struct timespec times[2];
1422 START_PROFILE(syscall_ntimes);
1424 if (is_omit_timespec(&ft->atime)) {
1425 times[0].tv_sec = smb_fname->st.st_ex_atime.tv_sec;
1426 times[0].tv_nsec = smb_fname->st.st_ex_atime.tv_nsec;
1427 } else {
1428 times[0].tv_sec = ft->atime.tv_sec;
1429 times[0].tv_nsec = ft->atime.tv_nsec;
1432 if (is_omit_timespec(&ft->mtime)) {
1433 times[1].tv_sec = smb_fname->st.st_ex_mtime.tv_sec;
1434 times[1].tv_nsec = smb_fname->st.st_ex_mtime.tv_nsec;
1435 } else {
1436 times[1].tv_sec = ft->mtime.tv_sec;
1437 times[1].tv_nsec = ft->mtime.tv_nsec;
1440 if ((timespec_compare(&times[0],
1441 &smb_fname->st.st_ex_atime) == 0) &&
1442 (timespec_compare(&times[1],
1443 &smb_fname->st.st_ex_mtime) == 0)) {
1444 END_PROFILE(syscall_ntimes);
1445 return 0;
1448 ret = glfs_utimens(handle->data, smb_fname->base_name, times);
1449 END_PROFILE(syscall_ntimes);
1451 return ret;
1454 static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle,
1455 files_struct *fsp, off_t offset)
1457 int ret;
1458 glfs_fd_t *glfd = NULL;
1460 START_PROFILE(syscall_ftruncate);
1462 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1463 if (glfd == NULL) {
1464 END_PROFILE(syscall_ftruncate);
1465 DBG_ERR("Failed to fetch gluster fd\n");
1466 return -1;
1469 #ifdef HAVE_GFAPI_VER_7_6
1470 ret = glfs_ftruncate(glfd, offset, NULL, NULL);
1471 #else
1472 ret = glfs_ftruncate(glfd, offset);
1473 #endif
1474 END_PROFILE(syscall_ftruncate);
1476 return ret;
1479 static int vfs_gluster_fallocate(struct vfs_handle_struct *handle,
1480 struct files_struct *fsp,
1481 uint32_t mode,
1482 off_t offset, off_t len)
1484 int ret;
1485 #ifdef HAVE_GFAPI_VER_6
1486 glfs_fd_t *glfd = NULL;
1487 int keep_size, punch_hole;
1489 START_PROFILE(syscall_fallocate);
1491 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1492 if (glfd == NULL) {
1493 END_PROFILE(syscall_fallocate);
1494 DBG_ERR("Failed to fetch gluster fd\n");
1495 return -1;
1498 keep_size = mode & VFS_FALLOCATE_FL_KEEP_SIZE;
1499 punch_hole = mode & VFS_FALLOCATE_FL_PUNCH_HOLE;
1501 mode &= ~(VFS_FALLOCATE_FL_KEEP_SIZE|VFS_FALLOCATE_FL_PUNCH_HOLE);
1502 if (mode != 0) {
1503 END_PROFILE(syscall_fallocate);
1504 errno = ENOTSUP;
1505 return -1;
1508 if (punch_hole) {
1509 ret = glfs_discard(glfd, offset, len);
1510 if (ret != 0) {
1511 DBG_DEBUG("glfs_discard failed: %s\n",
1512 strerror(errno));
1516 ret = glfs_fallocate(glfd, keep_size, offset, len);
1517 END_PROFILE(syscall_fallocate);
1518 #else
1519 errno = ENOTSUP;
1520 ret = -1;
1521 #endif
1522 return ret;
1525 static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handle,
1526 TALLOC_CTX *ctx,
1527 const struct smb_filename *smb_fname)
1529 char *result = NULL;
1530 struct smb_filename *result_fname = NULL;
1531 char *resolved_path = NULL;
1533 START_PROFILE(syscall_realpath);
1535 resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1536 if (resolved_path == NULL) {
1537 END_PROFILE(syscall_realpath);
1538 errno = ENOMEM;
1539 return NULL;
1542 result = glfs_realpath(handle->data,
1543 smb_fname->base_name,
1544 resolved_path);
1545 if (result != NULL) {
1546 result_fname = synthetic_smb_fname(ctx, result, NULL, NULL, 0);
1549 SAFE_FREE(resolved_path);
1550 END_PROFILE(syscall_realpath);
1552 return result_fname;
1555 static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
1556 files_struct *fsp, int op, off_t offset,
1557 off_t count, int type)
1559 struct flock flock = { 0, };
1560 int ret;
1561 glfs_fd_t *glfd = NULL;
1562 bool ok = false;
1564 START_PROFILE(syscall_fcntl_lock);
1566 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1567 if (glfd == NULL) {
1568 DBG_ERR("Failed to fetch gluster fd\n");
1569 ok = false;
1570 goto out;
1573 flock.l_type = type;
1574 flock.l_whence = SEEK_SET;
1575 flock.l_start = offset;
1576 flock.l_len = count;
1577 flock.l_pid = 0;
1579 ret = glfs_posix_lock(glfd, op, &flock);
1581 if (op == F_GETLK) {
1582 /* lock query, true if someone else has locked */
1583 if ((ret != -1) &&
1584 (flock.l_type != F_UNLCK) &&
1585 (flock.l_pid != 0) && (flock.l_pid != getpid())) {
1586 ok = true;
1587 goto out;
1589 /* not me */
1590 ok = false;
1591 goto out;
1594 if (ret == -1) {
1595 ok = false;
1596 goto out;
1599 ok = true;
1600 out:
1601 END_PROFILE(syscall_fcntl_lock);
1603 return ok;
1606 static int vfs_gluster_kernel_flock(struct vfs_handle_struct *handle,
1607 files_struct *fsp, uint32_t share_access,
1608 uint32_t access_mask)
1610 errno = ENOSYS;
1611 return -1;
1614 static int vfs_gluster_fcntl(vfs_handle_struct *handle,
1615 files_struct *fsp, int cmd, va_list cmd_arg)
1618 * SMB_VFS_FCNTL() is currently only called by vfs_set_blocking() to
1619 * clear O_NONBLOCK, etc for LOCK_MAND and FIFOs. Ignore it.
1621 if (cmd == F_GETFL) {
1622 return 0;
1623 } else if (cmd == F_SETFL) {
1624 va_list dup_cmd_arg;
1625 int opt;
1627 va_copy(dup_cmd_arg, cmd_arg);
1628 opt = va_arg(dup_cmd_arg, int);
1629 va_end(dup_cmd_arg);
1630 if (opt == 0) {
1631 return 0;
1633 DBG_ERR("unexpected fcntl SETFL(%d)\n", opt);
1634 goto err_out;
1636 DBG_ERR("unexpected fcntl: %d\n", cmd);
1637 err_out:
1638 errno = EINVAL;
1639 return -1;
1642 static int vfs_gluster_linux_setlease(struct vfs_handle_struct *handle,
1643 files_struct *fsp, int leasetype)
1645 errno = ENOSYS;
1646 return -1;
1649 static bool vfs_gluster_getlock(struct vfs_handle_struct *handle,
1650 files_struct *fsp, off_t *poffset,
1651 off_t *pcount, int *ptype, pid_t *ppid)
1653 struct flock flock = { 0, };
1654 int ret;
1655 glfs_fd_t *glfd = NULL;
1657 START_PROFILE(syscall_fcntl_getlock);
1659 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1660 if (glfd == NULL) {
1661 END_PROFILE(syscall_fcntl_getlock);
1662 DBG_ERR("Failed to fetch gluster fd\n");
1663 return false;
1666 flock.l_type = *ptype;
1667 flock.l_whence = SEEK_SET;
1668 flock.l_start = *poffset;
1669 flock.l_len = *pcount;
1670 flock.l_pid = 0;
1672 ret = glfs_posix_lock(glfd, F_GETLK, &flock);
1674 if (ret == -1) {
1675 END_PROFILE(syscall_fcntl_getlock);
1676 return false;
1679 *ptype = flock.l_type;
1680 *poffset = flock.l_start;
1681 *pcount = flock.l_len;
1682 *ppid = flock.l_pid;
1683 END_PROFILE(syscall_fcntl_getlock);
1685 return true;
1688 static int vfs_gluster_symlinkat(struct vfs_handle_struct *handle,
1689 const char *link_target,
1690 struct files_struct *dirfsp,
1691 const struct smb_filename *new_smb_fname)
1693 int ret;
1695 START_PROFILE(syscall_symlinkat);
1696 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1697 ret = glfs_symlink(handle->data,
1698 link_target,
1699 new_smb_fname->base_name);
1700 END_PROFILE(syscall_symlinkat);
1702 return ret;
1705 static int vfs_gluster_readlinkat(struct vfs_handle_struct *handle,
1706 files_struct *dirfsp,
1707 const struct smb_filename *smb_fname,
1708 char *buf,
1709 size_t bufsiz)
1711 int ret;
1713 START_PROFILE(syscall_readlinkat);
1714 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1715 ret = glfs_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1716 END_PROFILE(syscall_readlinkat);
1718 return ret;
1721 static int vfs_gluster_linkat(struct vfs_handle_struct *handle,
1722 files_struct *srcfsp,
1723 const struct smb_filename *old_smb_fname,
1724 files_struct *dstfsp,
1725 const struct smb_filename *new_smb_fname,
1726 int flags)
1728 int ret;
1730 START_PROFILE(syscall_linkat);
1732 SMB_ASSERT(srcfsp == srcfsp->conn->cwd_fsp);
1733 SMB_ASSERT(dstfsp == dstfsp->conn->cwd_fsp);
1735 ret = glfs_link(handle->data,
1736 old_smb_fname->base_name,
1737 new_smb_fname->base_name);
1738 END_PROFILE(syscall_linkat);
1740 return ret;
1743 static int vfs_gluster_mknodat(struct vfs_handle_struct *handle,
1744 files_struct *dirfsp,
1745 const struct smb_filename *smb_fname,
1746 mode_t mode,
1747 SMB_DEV_T dev)
1749 int ret;
1751 START_PROFILE(syscall_mknodat);
1752 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1753 ret = glfs_mknod(handle->data, smb_fname->base_name, mode, dev);
1754 END_PROFILE(syscall_mknodat);
1756 return ret;
1759 static int vfs_gluster_chflags(struct vfs_handle_struct *handle,
1760 const struct smb_filename *smb_fname,
1761 unsigned int flags)
1763 errno = ENOSYS;
1764 return -1;
1767 static int vfs_gluster_get_real_filename(struct vfs_handle_struct *handle,
1768 const char *path, const char *name,
1769 TALLOC_CTX *mem_ctx, char **found_name)
1771 int ret;
1772 char key_buf[GLUSTER_NAME_MAX + 64];
1773 char val_buf[GLUSTER_NAME_MAX + 1];
1775 if (strlen(name) >= GLUSTER_NAME_MAX) {
1776 errno = ENAMETOOLONG;
1777 return -1;
1780 snprintf(key_buf, GLUSTER_NAME_MAX + 64,
1781 "glusterfs.get_real_filename:%s", name);
1783 ret = glfs_getxattr(handle->data, path, key_buf, val_buf,
1784 GLUSTER_NAME_MAX + 1);
1785 if (ret == -1) {
1786 if (errno == ENOATTR) {
1787 errno = ENOENT;
1789 return -1;
1792 *found_name = talloc_strdup(mem_ctx, val_buf);
1793 if (found_name[0] == NULL) {
1794 errno = ENOMEM;
1795 return -1;
1797 return 0;
1800 static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle,
1801 const struct smb_filename *smb_fname)
1803 return handle->conn->connectpath;
1806 /* EA Operations */
1808 static ssize_t vfs_gluster_getxattr(struct vfs_handle_struct *handle,
1809 const struct smb_filename *smb_fname,
1810 const char *name,
1811 void *value,
1812 size_t size)
1814 return glfs_getxattr(handle->data, smb_fname->base_name,
1815 name, value, size);
1818 static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
1819 files_struct *fsp, const char *name,
1820 void *value, size_t size)
1822 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1823 if (glfd == NULL) {
1824 DBG_ERR("Failed to fetch gluster fd\n");
1825 return -1;
1828 return glfs_fgetxattr(glfd, name, value, size);
1831 static ssize_t vfs_gluster_listxattr(struct vfs_handle_struct *handle,
1832 const struct smb_filename *smb_fname,
1833 char *list,
1834 size_t size)
1836 return glfs_listxattr(handle->data, smb_fname->base_name, list, size);
1839 static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
1840 files_struct *fsp, char *list,
1841 size_t size)
1843 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1844 if (glfd == NULL) {
1845 DBG_ERR("Failed to fetch gluster fd\n");
1846 return -1;
1849 return glfs_flistxattr(glfd, list, size);
1852 static int vfs_gluster_removexattr(struct vfs_handle_struct *handle,
1853 const struct smb_filename *smb_fname,
1854 const char *name)
1856 return glfs_removexattr(handle->data, smb_fname->base_name, name);
1859 static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
1860 files_struct *fsp, const char *name)
1862 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1863 if (glfd == NULL) {
1864 DBG_ERR("Failed to fetch gluster fd\n");
1865 return -1;
1868 return glfs_fremovexattr(glfd, name);
1871 static int vfs_gluster_setxattr(struct vfs_handle_struct *handle,
1872 const struct smb_filename *smb_fname,
1873 const char *name,
1874 const void *value, size_t size, int flags)
1876 return glfs_setxattr(handle->data, smb_fname->base_name, name, value, size, flags);
1879 static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
1880 files_struct *fsp, const char *name,
1881 const void *value, size_t size, int flags)
1883 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1884 if (glfd == NULL) {
1885 DBG_ERR("Failed to fetch gluster fd\n");
1886 return -1;
1889 return glfs_fsetxattr(glfd, name, value, size, flags);
1892 /* AIO Operations */
1894 static bool vfs_gluster_aio_force(struct vfs_handle_struct *handle,
1895 files_struct *fsp)
1897 return false;
1900 static NTSTATUS vfs_gluster_create_dfs_pathat(struct vfs_handle_struct *handle,
1901 struct files_struct *dirfsp,
1902 const struct smb_filename *smb_fname,
1903 const struct referral *reflist,
1904 size_t referral_count)
1906 TALLOC_CTX *frame = talloc_stackframe();
1907 NTSTATUS status = NT_STATUS_NO_MEMORY;
1908 int ret;
1909 char *msdfs_link = NULL;
1911 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1913 /* Form the msdfs_link contents */
1914 msdfs_link = msdfs_link_string(frame,
1915 reflist,
1916 referral_count);
1917 if (msdfs_link == NULL) {
1918 goto out;
1921 ret = glfs_symlink(handle->data,
1922 msdfs_link,
1923 smb_fname->base_name);
1924 if (ret == 0) {
1925 status = NT_STATUS_OK;
1926 } else {
1927 status = map_nt_error_from_unix(errno);
1930 out:
1932 TALLOC_FREE(frame);
1933 return status;
1937 * Read and return the contents of a DFS redirect given a
1938 * pathname. A caller can pass in NULL for ppreflist and
1939 * preferral_count but still determine if this was a
1940 * DFS redirect point by getting NT_STATUS_OK back
1941 * without incurring the overhead of reading and parsing
1942 * the referral contents.
1945 static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
1946 TALLOC_CTX *mem_ctx,
1947 struct files_struct *dirfsp,
1948 const struct smb_filename *smb_fname,
1949 struct referral **ppreflist,
1950 size_t *preferral_count)
1952 NTSTATUS status = NT_STATUS_NO_MEMORY;
1953 size_t bufsize;
1954 char *link_target = NULL;
1955 int referral_len;
1956 bool ok;
1957 #if defined(HAVE_BROKEN_READLINK)
1958 char link_target_buf[PATH_MAX];
1959 #else
1960 char link_target_buf[7];
1961 #endif
1963 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1965 if (ppreflist == NULL && preferral_count == NULL) {
1967 * We're only checking if this is a DFS
1968 * redirect. We don't need to return data.
1970 bufsize = sizeof(link_target_buf);
1971 link_target = link_target_buf;
1972 } else {
1973 bufsize = PATH_MAX;
1974 link_target = talloc_array(mem_ctx, char, bufsize);
1975 if (!link_target) {
1976 goto err;
1980 referral_len = glfs_readlink(handle->data,
1981 smb_fname->base_name,
1982 link_target,
1983 bufsize - 1);
1984 if (referral_len < 0) {
1985 if (errno == EINVAL) {
1986 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
1987 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
1988 } else {
1989 status = map_nt_error_from_unix(errno);
1990 DBG_ERR("Error reading "
1991 "msdfs link %s: %s\n",
1992 smb_fname->base_name,
1993 strerror(errno));
1995 goto err;
1997 link_target[referral_len] = '\0';
1999 DBG_INFO("%s -> %s\n",
2000 smb_fname->base_name,
2001 link_target);
2003 if (!strnequal(link_target, "msdfs:", 6)) {
2004 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2005 goto err;
2008 if (ppreflist == NULL && preferral_count == NULL) {
2009 /* Early return for checking if this is a DFS link. */
2010 return NT_STATUS_OK;
2013 ok = parse_msdfs_symlink(mem_ctx,
2014 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
2015 link_target,
2016 ppreflist,
2017 preferral_count);
2019 if (ok) {
2020 status = NT_STATUS_OK;
2021 } else {
2022 status = NT_STATUS_NO_MEMORY;
2025 err:
2027 if (link_target != link_target_buf) {
2028 TALLOC_FREE(link_target);
2030 return status;
2033 static struct vfs_fn_pointers glusterfs_fns = {
2035 /* Disk Operations */
2037 .connect_fn = vfs_gluster_connect,
2038 .disconnect_fn = vfs_gluster_disconnect,
2039 .disk_free_fn = vfs_gluster_disk_free,
2040 .get_quota_fn = vfs_gluster_get_quota,
2041 .set_quota_fn = vfs_gluster_set_quota,
2042 .statvfs_fn = vfs_gluster_statvfs,
2043 .fs_capabilities_fn = vfs_gluster_fs_capabilities,
2045 .get_dfs_referrals_fn = NULL,
2047 /* Directory Operations */
2049 .opendir_fn = vfs_gluster_opendir,
2050 .fdopendir_fn = vfs_gluster_fdopendir,
2051 .readdir_fn = vfs_gluster_readdir,
2052 .seekdir_fn = vfs_gluster_seekdir,
2053 .telldir_fn = vfs_gluster_telldir,
2054 .rewind_dir_fn = vfs_gluster_rewinddir,
2055 .mkdirat_fn = vfs_gluster_mkdirat,
2056 .closedir_fn = vfs_gluster_closedir,
2058 /* File Operations */
2060 .open_fn = vfs_gluster_open,
2061 .create_file_fn = NULL,
2062 .close_fn = vfs_gluster_close,
2063 .pread_fn = vfs_gluster_pread,
2064 .pread_send_fn = vfs_gluster_pread_send,
2065 .pread_recv_fn = vfs_gluster_pread_recv,
2066 .pwrite_fn = vfs_gluster_pwrite,
2067 .pwrite_send_fn = vfs_gluster_pwrite_send,
2068 .pwrite_recv_fn = vfs_gluster_pwrite_recv,
2069 .lseek_fn = vfs_gluster_lseek,
2070 .sendfile_fn = vfs_gluster_sendfile,
2071 .recvfile_fn = vfs_gluster_recvfile,
2072 .renameat_fn = vfs_gluster_renameat,
2073 .fsync_send_fn = vfs_gluster_fsync_send,
2074 .fsync_recv_fn = vfs_gluster_fsync_recv,
2076 .stat_fn = vfs_gluster_stat,
2077 .fstat_fn = vfs_gluster_fstat,
2078 .lstat_fn = vfs_gluster_lstat,
2079 .get_alloc_size_fn = vfs_gluster_get_alloc_size,
2080 .unlinkat_fn = vfs_gluster_unlinkat,
2082 .chmod_fn = vfs_gluster_chmod,
2083 .fchmod_fn = vfs_gluster_fchmod,
2084 .fchown_fn = vfs_gluster_fchown,
2085 .lchown_fn = vfs_gluster_lchown,
2086 .chdir_fn = vfs_gluster_chdir,
2087 .getwd_fn = vfs_gluster_getwd,
2088 .ntimes_fn = vfs_gluster_ntimes,
2089 .ftruncate_fn = vfs_gluster_ftruncate,
2090 .fallocate_fn = vfs_gluster_fallocate,
2091 .lock_fn = vfs_gluster_lock,
2092 .kernel_flock_fn = vfs_gluster_kernel_flock,
2093 .fcntl_fn = vfs_gluster_fcntl,
2094 .linux_setlease_fn = vfs_gluster_linux_setlease,
2095 .getlock_fn = vfs_gluster_getlock,
2096 .symlinkat_fn = vfs_gluster_symlinkat,
2097 .readlinkat_fn = vfs_gluster_readlinkat,
2098 .linkat_fn = vfs_gluster_linkat,
2099 .mknodat_fn = vfs_gluster_mknodat,
2100 .realpath_fn = vfs_gluster_realpath,
2101 .chflags_fn = vfs_gluster_chflags,
2102 .file_id_create_fn = NULL,
2103 .streaminfo_fn = NULL,
2104 .get_real_filename_fn = vfs_gluster_get_real_filename,
2105 .connectpath_fn = vfs_gluster_connectpath,
2106 .create_dfs_pathat_fn = vfs_gluster_create_dfs_pathat,
2107 .read_dfs_pathat_fn = vfs_gluster_read_dfs_pathat,
2109 .brl_lock_windows_fn = NULL,
2110 .brl_unlock_windows_fn = NULL,
2111 .strict_lock_check_fn = NULL,
2112 .translate_name_fn = NULL,
2113 .fsctl_fn = NULL,
2115 /* NT ACL Operations */
2116 .fget_nt_acl_fn = NULL,
2117 .get_nt_acl_fn = NULL,
2118 .fset_nt_acl_fn = NULL,
2119 .audit_file_fn = NULL,
2121 /* Posix ACL Operations */
2122 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
2123 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
2124 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
2125 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
2126 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
2127 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
2128 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
2130 /* EA Operations */
2131 .getxattr_fn = vfs_gluster_getxattr,
2132 .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2133 .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2134 .fgetxattr_fn = vfs_gluster_fgetxattr,
2135 .listxattr_fn = vfs_gluster_listxattr,
2136 .flistxattr_fn = vfs_gluster_flistxattr,
2137 .removexattr_fn = vfs_gluster_removexattr,
2138 .fremovexattr_fn = vfs_gluster_fremovexattr,
2139 .setxattr_fn = vfs_gluster_setxattr,
2140 .fsetxattr_fn = vfs_gluster_fsetxattr,
2142 /* AIO Operations */
2143 .aio_force_fn = vfs_gluster_aio_force,
2145 /* Durable handle Operations */
2146 .durable_cookie_fn = NULL,
2147 .durable_disconnect_fn = NULL,
2148 .durable_reconnect_fn = NULL,
2151 static_decl_vfs;
2152 NTSTATUS vfs_glusterfs_init(TALLOC_CTX *ctx)
2154 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2155 "glusterfs", &glusterfs_fns);