s3: modules: gluster. Fix the error I made in preventing talloc leaks from a function.
[Samba.git] / source3 / modules / vfs_glusterfs.c
blobc338674ac3c6bc0251e69bf9aaf04ab0a755feda
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 check_for_write_behind_translator(TALLOC_CTX *mem_ctx,
268 glfs_t *fs,
269 const char *volume)
271 char *buf = NULL;
272 char **lines = NULL;
273 int numlines = 0;
274 int i;
275 char *option;
276 bool write_behind_present = false;
277 size_t newlen;
278 int ret;
280 ret = glfs_get_volfile(fs, NULL, 0);
281 if (ret == 0) {
282 DBG_ERR("%s: Failed to get volfile for "
283 "volume (%s): No volfile\n",
284 volume,
285 strerror(errno));
286 return -1;
288 if (ret > 0) {
289 DBG_ERR("%s: Invalid return %d for glfs_get_volfile for "
290 "volume (%s): No volfile\n",
291 volume,
292 ret,
293 strerror(errno));
294 return -1;
297 newlen = 0 - ret;
299 buf = talloc_zero_array(mem_ctx, char, newlen);
300 if (buf == NULL) {
301 return -1;
304 ret = glfs_get_volfile(fs, buf, newlen);
305 if (ret != newlen) {
306 TALLOC_FREE(buf);
307 DBG_ERR("%s: Failed to get volfile for volume (%s)\n",
308 volume, strerror(errno));
309 return -1;
312 option = talloc_asprintf(mem_ctx, "volume %s-write-behind", volume);
313 if (option == NULL) {
314 TALLOC_FREE(buf);
315 return -1;
319 * file_lines_parse() plays horrible tricks with
320 * the passed-in talloc pointers and the hierarcy
321 * which makes freeing hard to get right.
323 * As we know mem_ctx is freed by the caller, after
324 * this point don't free on exit and let the caller
325 * handle it. This violates good Samba coding practice
326 * but we know we're not leaking here.
329 lines = file_lines_parse(buf,
330 newlen,
331 &numlines,
332 mem_ctx);
333 if (lines == NULL || numlines <= 0) {
334 return -1;
336 /* On success, buf is now a talloc child of lines !! */
338 for (i=0; i < numlines; i++) {
339 if (strequal(lines[i], option)) {
340 write_behind_present = true;
341 break;
345 if (write_behind_present) {
346 DBG_ERR("Write behind translator is enabled for "
347 "volume (%s), refusing to connect! "
348 "Please check the vfs_glusterfs(8) manpage for "
349 "further details.\n",
350 volume);
351 return -1;
354 return 0;
357 static int vfs_gluster_connect(struct vfs_handle_struct *handle,
358 const char *service,
359 const char *user)
361 const struct loadparm_substitution *lp_sub =
362 loadparm_s3_global_substitution();
363 const char *volfile_servers;
364 const char *volume;
365 char *logfile;
366 int loglevel;
367 glfs_t *fs = NULL;
368 TALLOC_CTX *tmp_ctx;
369 int ret = 0;
370 bool write_behind_pass_through_set = false;
372 tmp_ctx = talloc_new(NULL);
373 if (tmp_ctx == NULL) {
374 ret = -1;
375 goto done;
377 logfile = lp_parm_substituted_string(tmp_ctx,
378 lp_sub,
379 SNUM(handle->conn),
380 "glusterfs",
381 "logfile",
382 NULL);
384 loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
386 volfile_servers = lp_parm_substituted_string(tmp_ctx,
387 lp_sub,
388 SNUM(handle->conn),
389 "glusterfs",
390 "volfile_server",
391 NULL);
392 if (volfile_servers == NULL) {
393 volfile_servers = DEFAULT_VOLFILE_SERVER;
396 volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
397 NULL);
398 if (volume == NULL) {
399 volume = service;
402 fs = glfs_find_preopened(volume, handle->conn->connectpath);
403 if (fs) {
404 goto done;
407 fs = glfs_new(volume);
408 if (fs == NULL) {
409 ret = -1;
410 goto done;
413 ret = vfs_gluster_set_volfile_servers(fs, volfile_servers);
414 if (ret < 0) {
415 DBG_ERR("Failed to set volfile_servers from list %s\n",
416 volfile_servers);
417 goto done;
420 ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-posix-acl",
421 "true");
422 if (ret < 0) {
423 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
424 goto done;
428 ret = glfs_set_xlator_option(fs, "*-snapview-client",
429 "snapdir-entry-path",
430 handle->conn->connectpath);
431 if (ret < 0) {
432 DEBUG(0, ("%s: Failed to set xlator option:"
433 " snapdir-entry-path\n", volume));
434 goto done;
437 #ifdef HAVE_GFAPI_VER_7_9
438 ret = glfs_set_xlator_option(fs, "*-write-behind", "pass-through",
439 "true");
440 if (ret < 0) {
441 DBG_ERR("%s: Failed to set xlator option: pass-through\n",
442 volume);
443 goto done;
445 write_behind_pass_through_set = true;
446 #endif
448 ret = glfs_set_logging(fs, logfile, loglevel);
449 if (ret < 0) {
450 DEBUG(0, ("%s: Failed to set logfile %s loglevel %d\n",
451 volume, logfile, loglevel));
452 goto done;
455 ret = glfs_init(fs);
456 if (ret < 0) {
457 DEBUG(0, ("%s: Failed to initialize volume (%s)\n",
458 volume, strerror(errno)));
459 goto done;
462 if (!write_behind_pass_through_set) {
463 ret = check_for_write_behind_translator(tmp_ctx, fs, volume);
464 if (ret < 0) {
465 goto done;
469 ret = glfs_set_preopened(volume, handle->conn->connectpath, fs);
470 if (ret < 0) {
471 DEBUG(0, ("%s: Failed to register volume (%s)\n",
472 volume, strerror(errno)));
473 goto done;
477 * The shadow_copy2 module will fail to export subdirectories
478 * of a gluster volume unless we specify the mount point,
479 * because the detection fails if the file system is not
480 * locally mounted:
481 * https://bugzilla.samba.org/show_bug.cgi?id=13091
483 lp_do_parameter(SNUM(handle->conn), "shadow:mountpoint", "/");
486 * Unless we have an async implementation of getxattrat turn this off.
488 lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false");
490 done:
491 if (ret < 0) {
492 if (fs)
493 glfs_fini(fs);
494 } else {
495 DBG_ERR("%s: Initialized volume from servers %s\n",
496 volume, volfile_servers);
497 handle->data = fs;
499 talloc_free(tmp_ctx);
500 return ret;
503 static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
505 glfs_t *fs = NULL;
507 fs = handle->data;
509 glfs_clear_preopened(fs);
512 static uint64_t vfs_gluster_disk_free(struct vfs_handle_struct *handle,
513 const struct smb_filename *smb_fname,
514 uint64_t *bsize_p,
515 uint64_t *dfree_p,
516 uint64_t *dsize_p)
518 struct statvfs statvfs = { 0, };
519 int ret;
521 ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
522 if (ret < 0) {
523 return -1;
526 if (bsize_p != NULL) {
527 *bsize_p = (uint64_t)statvfs.f_bsize; /* Block size */
529 if (dfree_p != NULL) {
530 *dfree_p = (uint64_t)statvfs.f_bavail; /* Available Block units */
532 if (dsize_p != NULL) {
533 *dsize_p = (uint64_t)statvfs.f_blocks; /* Total Block units */
536 return (uint64_t)statvfs.f_bavail;
539 static int vfs_gluster_get_quota(struct vfs_handle_struct *handle,
540 const struct smb_filename *smb_fname,
541 enum SMB_QUOTA_TYPE qtype,
542 unid_t id,
543 SMB_DISK_QUOTA *qt)
545 errno = ENOSYS;
546 return -1;
549 static int
550 vfs_gluster_set_quota(struct vfs_handle_struct *handle,
551 enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
553 errno = ENOSYS;
554 return -1;
557 static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
558 const struct smb_filename *smb_fname,
559 struct vfs_statvfs_struct *vfs_statvfs)
561 struct statvfs statvfs = { 0, };
562 int ret;
564 ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
565 if (ret < 0) {
566 DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
567 smb_fname->base_name, strerror(errno)));
568 return -1;
571 ZERO_STRUCTP(vfs_statvfs);
573 vfs_statvfs->OptimalTransferSize = statvfs.f_frsize;
574 vfs_statvfs->BlockSize = statvfs.f_bsize;
575 vfs_statvfs->TotalBlocks = statvfs.f_blocks;
576 vfs_statvfs->BlocksAvail = statvfs.f_bfree;
577 vfs_statvfs->UserBlocksAvail = statvfs.f_bavail;
578 vfs_statvfs->TotalFileNodes = statvfs.f_files;
579 vfs_statvfs->FreeFileNodes = statvfs.f_ffree;
580 vfs_statvfs->FsIdentifier = statvfs.f_fsid;
581 vfs_statvfs->FsCapabilities =
582 FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
584 return ret;
587 static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
588 enum timestamp_set_resolution *p_ts_res)
590 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
592 #ifdef HAVE_GFAPI_VER_6
593 caps |= FILE_SUPPORTS_SPARSE_FILES;
594 #endif
596 #ifdef STAT_HAVE_NSEC
597 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
598 #endif
600 return caps;
603 static DIR *vfs_gluster_opendir(struct vfs_handle_struct *handle,
604 const struct smb_filename *smb_fname,
605 const char *mask,
606 uint32_t attributes)
608 glfs_fd_t *fd;
610 START_PROFILE(syscall_opendir);
612 fd = glfs_opendir(handle->data, smb_fname->base_name);
613 if (fd == NULL) {
614 DEBUG(0, ("glfs_opendir(%s) failed: %s\n",
615 smb_fname->base_name, strerror(errno)));
618 END_PROFILE(syscall_opendir);
620 return (DIR *) fd;
623 static glfs_fd_t *vfs_gluster_fetch_glfd(struct vfs_handle_struct *handle,
624 files_struct *fsp)
626 glfs_fd_t **glfd = (glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
627 if (glfd == NULL) {
628 DBG_INFO("Failed to fetch fsp extension\n");
629 return NULL;
631 if (*glfd == NULL) {
632 DBG_INFO("Empty glfs_fd_t pointer\n");
633 return NULL;
636 return *glfd;
639 static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle,
640 files_struct *fsp, const char *mask,
641 uint32_t attributes)
643 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
644 if (glfd == NULL) {
645 DBG_ERR("Failed to fetch gluster fd\n");
646 return NULL;
649 return (DIR *)glfd;
652 static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp)
654 int ret;
656 START_PROFILE(syscall_closedir);
657 ret = glfs_closedir((void *)dirp);
658 END_PROFILE(syscall_closedir);
660 return ret;
663 static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle,
664 DIR *dirp, SMB_STRUCT_STAT *sbuf)
666 static char direntbuf[512];
667 int ret;
668 struct stat stat;
669 struct dirent *dirent = 0;
671 START_PROFILE(syscall_readdir);
672 if (sbuf != NULL) {
673 ret = glfs_readdirplus_r((void *)dirp, &stat, (void *)direntbuf,
674 &dirent);
675 } else {
676 ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
679 if ((ret < 0) || (dirent == NULL)) {
680 END_PROFILE(syscall_readdir);
681 return NULL;
684 if (sbuf != NULL) {
685 SET_STAT_INVALID(*sbuf);
686 if (!S_ISLNK(stat.st_mode)) {
687 smb_stat_ex_from_stat(sbuf, &stat);
691 END_PROFILE(syscall_readdir);
692 return dirent;
695 static long vfs_gluster_telldir(struct vfs_handle_struct *handle, DIR *dirp)
697 long ret;
699 START_PROFILE(syscall_telldir);
700 ret = glfs_telldir((void *)dirp);
701 END_PROFILE(syscall_telldir);
703 return ret;
706 static void vfs_gluster_seekdir(struct vfs_handle_struct *handle, DIR *dirp,
707 long offset)
709 START_PROFILE(syscall_seekdir);
710 glfs_seekdir((void *)dirp, offset);
711 END_PROFILE(syscall_seekdir);
714 static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
716 START_PROFILE(syscall_rewinddir);
717 glfs_seekdir((void *)dirp, 0);
718 END_PROFILE(syscall_rewinddir);
721 static int vfs_gluster_mkdirat(struct vfs_handle_struct *handle,
722 struct files_struct *dirfsp,
723 const struct smb_filename *smb_fname,
724 mode_t mode)
726 int ret;
728 START_PROFILE(syscall_mkdirat);
729 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
730 ret = glfs_mkdir(handle->data, smb_fname->base_name, mode);
731 END_PROFILE(syscall_mkdirat);
733 return ret;
736 static int vfs_gluster_open(struct vfs_handle_struct *handle,
737 struct smb_filename *smb_fname, files_struct *fsp,
738 int flags, mode_t mode)
740 glfs_fd_t *glfd;
741 glfs_fd_t **p_tmp;
743 START_PROFILE(syscall_open);
745 p_tmp = VFS_ADD_FSP_EXTENSION(handle, fsp, glfs_fd_t *, NULL);
746 if (p_tmp == NULL) {
747 END_PROFILE(syscall_open);
748 errno = ENOMEM;
749 return -1;
752 if (flags & O_DIRECTORY) {
753 glfd = glfs_opendir(handle->data, smb_fname->base_name);
754 } else if (flags & O_CREAT) {
755 glfd = glfs_creat(handle->data, smb_fname->base_name, flags,
756 mode);
757 } else {
758 glfd = glfs_open(handle->data, smb_fname->base_name, flags);
761 if (glfd == NULL) {
762 END_PROFILE(syscall_open);
763 /* no extension destroy_fn, so no need to save errno */
764 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
765 return -1;
768 *p_tmp = glfd;
770 END_PROFILE(syscall_open);
771 /* An arbitrary value for error reporting, so you know its us. */
772 return 13371337;
775 static int vfs_gluster_close(struct vfs_handle_struct *handle,
776 files_struct *fsp)
778 int ret;
779 glfs_fd_t *glfd = NULL;
781 START_PROFILE(syscall_close);
783 glfd = vfs_gluster_fetch_glfd(handle, fsp);
784 if (glfd == NULL) {
785 END_PROFILE(syscall_close);
786 DBG_ERR("Failed to fetch gluster fd\n");
787 return -1;
790 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
792 ret = glfs_close(glfd);
793 END_PROFILE(syscall_close);
795 return ret;
798 static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
799 files_struct *fsp, void *data, size_t n,
800 off_t offset)
802 ssize_t ret;
803 glfs_fd_t *glfd = NULL;
805 START_PROFILE_BYTES(syscall_pread, n);
807 glfd = vfs_gluster_fetch_glfd(handle, fsp);
808 if (glfd == NULL) {
809 END_PROFILE_BYTES(syscall_pread);
810 DBG_ERR("Failed to fetch gluster fd\n");
811 return -1;
814 #ifdef HAVE_GFAPI_VER_7_6
815 ret = glfs_pread(glfd, data, n, offset, 0, NULL);
816 #else
817 ret = glfs_pread(glfd, data, n, offset, 0);
818 #endif
819 END_PROFILE_BYTES(syscall_pread);
821 return ret;
824 struct vfs_gluster_pread_state {
825 ssize_t ret;
826 glfs_fd_t *fd;
827 void *buf;
828 size_t count;
829 off_t offset;
831 struct vfs_aio_state vfs_aio_state;
832 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
835 static void vfs_gluster_pread_do(void *private_data);
836 static void vfs_gluster_pread_done(struct tevent_req *subreq);
837 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state);
839 static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
840 *handle, TALLOC_CTX *mem_ctx,
841 struct tevent_context *ev,
842 files_struct *fsp,
843 void *data, size_t n,
844 off_t offset)
846 struct vfs_gluster_pread_state *state;
847 struct tevent_req *req, *subreq;
849 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
850 if (glfd == NULL) {
851 DBG_ERR("Failed to fetch gluster fd\n");
852 return NULL;
855 req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pread_state);
856 if (req == NULL) {
857 return NULL;
860 state->ret = -1;
861 state->fd = glfd;
862 state->buf = data;
863 state->count = n;
864 state->offset = offset;
866 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
867 state->profile_bytes, n);
868 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
870 subreq = pthreadpool_tevent_job_send(
871 state, ev, handle->conn->sconn->pool,
872 vfs_gluster_pread_do, state);
873 if (tevent_req_nomem(subreq, req)) {
874 return tevent_req_post(req, ev);
876 tevent_req_set_callback(subreq, vfs_gluster_pread_done, req);
878 talloc_set_destructor(state, vfs_gluster_pread_state_destructor);
880 return req;
883 static void vfs_gluster_pread_do(void *private_data)
885 struct vfs_gluster_pread_state *state = talloc_get_type_abort(
886 private_data, struct vfs_gluster_pread_state);
887 struct timespec start_time;
888 struct timespec end_time;
890 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
892 PROFILE_TIMESTAMP(&start_time);
894 do {
895 #ifdef HAVE_GFAPI_VER_7_6
896 state->ret = glfs_pread(state->fd, state->buf, state->count,
897 state->offset, 0, NULL);
898 #else
899 state->ret = glfs_pread(state->fd, state->buf, state->count,
900 state->offset, 0);
901 #endif
902 } while ((state->ret == -1) && (errno == EINTR));
904 if (state->ret == -1) {
905 state->vfs_aio_state.error = errno;
908 PROFILE_TIMESTAMP(&end_time);
910 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
912 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
915 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state)
917 return -1;
920 static void vfs_gluster_pread_done(struct tevent_req *subreq)
922 struct tevent_req *req = tevent_req_callback_data(
923 subreq, struct tevent_req);
924 struct vfs_gluster_pread_state *state = tevent_req_data(
925 req, struct vfs_gluster_pread_state);
926 int ret;
928 ret = pthreadpool_tevent_job_recv(subreq);
929 TALLOC_FREE(subreq);
930 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
931 talloc_set_destructor(state, NULL);
932 if (ret != 0) {
933 if (ret != EAGAIN) {
934 tevent_req_error(req, ret);
935 return;
938 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
939 * means the lower level pthreadpool failed to create a new
940 * thread. Fallback to sync processing in that case to allow
941 * some progress for the client.
943 vfs_gluster_pread_do(state);
946 tevent_req_done(req);
949 static ssize_t vfs_gluster_pread_recv(struct tevent_req *req,
950 struct vfs_aio_state *vfs_aio_state)
952 struct vfs_gluster_pread_state *state = tevent_req_data(
953 req, struct vfs_gluster_pread_state);
955 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
956 return -1;
959 *vfs_aio_state = state->vfs_aio_state;
960 return state->ret;
963 struct vfs_gluster_pwrite_state {
964 ssize_t ret;
965 glfs_fd_t *fd;
966 const void *buf;
967 size_t count;
968 off_t offset;
970 struct vfs_aio_state vfs_aio_state;
971 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
974 static void vfs_gluster_pwrite_do(void *private_data);
975 static void vfs_gluster_pwrite_done(struct tevent_req *subreq);
976 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state);
978 static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
979 *handle, TALLOC_CTX *mem_ctx,
980 struct tevent_context *ev,
981 files_struct *fsp,
982 const void *data, size_t n,
983 off_t offset)
985 struct tevent_req *req, *subreq;
986 struct vfs_gluster_pwrite_state *state;
988 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
989 if (glfd == NULL) {
990 DBG_ERR("Failed to fetch gluster fd\n");
991 return NULL;
994 req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pwrite_state);
995 if (req == NULL) {
996 return NULL;
999 state->ret = -1;
1000 state->fd = glfd;
1001 state->buf = data;
1002 state->count = n;
1003 state->offset = offset;
1005 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1006 state->profile_bytes, n);
1007 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1009 subreq = pthreadpool_tevent_job_send(
1010 state, ev, handle->conn->sconn->pool,
1011 vfs_gluster_pwrite_do, state);
1012 if (tevent_req_nomem(subreq, req)) {
1013 return tevent_req_post(req, ev);
1015 tevent_req_set_callback(subreq, vfs_gluster_pwrite_done, req);
1017 talloc_set_destructor(state, vfs_gluster_pwrite_state_destructor);
1019 return req;
1022 static void vfs_gluster_pwrite_do(void *private_data)
1024 struct vfs_gluster_pwrite_state *state = talloc_get_type_abort(
1025 private_data, struct vfs_gluster_pwrite_state);
1026 struct timespec start_time;
1027 struct timespec end_time;
1029 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1031 PROFILE_TIMESTAMP(&start_time);
1033 do {
1034 #ifdef HAVE_GFAPI_VER_7_6
1035 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
1036 state->offset, 0, NULL, NULL);
1037 #else
1038 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
1039 state->offset, 0);
1040 #endif
1041 } while ((state->ret == -1) && (errno == EINTR));
1043 if (state->ret == -1) {
1044 state->vfs_aio_state.error = errno;
1047 PROFILE_TIMESTAMP(&end_time);
1049 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1051 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1054 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state)
1056 return -1;
1059 static void vfs_gluster_pwrite_done(struct tevent_req *subreq)
1061 struct tevent_req *req = tevent_req_callback_data(
1062 subreq, struct tevent_req);
1063 struct vfs_gluster_pwrite_state *state = tevent_req_data(
1064 req, struct vfs_gluster_pwrite_state);
1065 int ret;
1067 ret = pthreadpool_tevent_job_recv(subreq);
1068 TALLOC_FREE(subreq);
1069 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1070 talloc_set_destructor(state, NULL);
1071 if (ret != 0) {
1072 if (ret != EAGAIN) {
1073 tevent_req_error(req, ret);
1074 return;
1077 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1078 * means the lower level pthreadpool failed to create a new
1079 * thread. Fallback to sync processing in that case to allow
1080 * some progress for the client.
1082 vfs_gluster_pwrite_do(state);
1085 tevent_req_done(req);
1088 static ssize_t vfs_gluster_pwrite_recv(struct tevent_req *req,
1089 struct vfs_aio_state *vfs_aio_state)
1091 struct vfs_gluster_pwrite_state *state = tevent_req_data(
1092 req, struct vfs_gluster_pwrite_state);
1094 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1095 return -1;
1098 *vfs_aio_state = state->vfs_aio_state;
1100 return state->ret;
1103 static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
1104 files_struct *fsp, const void *data,
1105 size_t n, off_t offset)
1107 ssize_t ret;
1108 glfs_fd_t *glfd = NULL;
1110 START_PROFILE_BYTES(syscall_pwrite, n);
1112 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1113 if (glfd == NULL) {
1114 END_PROFILE_BYTES(syscall_pwrite);
1115 DBG_ERR("Failed to fetch gluster fd\n");
1116 return -1;
1119 #ifdef HAVE_GFAPI_VER_7_6
1120 ret = glfs_pwrite(glfd, data, n, offset, 0, NULL, NULL);
1121 #else
1122 ret = glfs_pwrite(glfd, data, n, offset, 0);
1123 #endif
1124 END_PROFILE_BYTES(syscall_pwrite);
1126 return ret;
1129 static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
1130 files_struct *fsp, off_t offset, int whence)
1132 off_t ret = 0;
1133 glfs_fd_t *glfd = NULL;
1135 START_PROFILE(syscall_lseek);
1137 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1138 if (glfd == NULL) {
1139 END_PROFILE(syscall_lseek);
1140 DBG_ERR("Failed to fetch gluster fd\n");
1141 return -1;
1144 ret = glfs_lseek(glfd, offset, whence);
1145 END_PROFILE(syscall_lseek);
1147 return ret;
1150 static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd,
1151 files_struct *fromfsp,
1152 const DATA_BLOB *hdr,
1153 off_t offset, size_t n)
1155 errno = ENOTSUP;
1156 return -1;
1159 static ssize_t vfs_gluster_recvfile(struct vfs_handle_struct *handle,
1160 int fromfd, files_struct *tofsp,
1161 off_t offset, size_t n)
1163 errno = ENOTSUP;
1164 return -1;
1167 static int vfs_gluster_renameat(struct vfs_handle_struct *handle,
1168 files_struct *srcfsp,
1169 const struct smb_filename *smb_fname_src,
1170 files_struct *dstfsp,
1171 const struct smb_filename *smb_fname_dst)
1173 int ret;
1175 START_PROFILE(syscall_renameat);
1176 ret = glfs_rename(handle->data, smb_fname_src->base_name,
1177 smb_fname_dst->base_name);
1178 END_PROFILE(syscall_renameat);
1180 return ret;
1183 struct vfs_gluster_fsync_state {
1184 ssize_t ret;
1185 glfs_fd_t *fd;
1187 struct vfs_aio_state vfs_aio_state;
1188 SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1191 static void vfs_gluster_fsync_do(void *private_data);
1192 static void vfs_gluster_fsync_done(struct tevent_req *subreq);
1193 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state);
1195 static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
1196 *handle, TALLOC_CTX *mem_ctx,
1197 struct tevent_context *ev,
1198 files_struct *fsp)
1200 struct tevent_req *req, *subreq;
1201 struct vfs_gluster_fsync_state *state;
1203 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1204 if (glfd == NULL) {
1205 DBG_ERR("Failed to fetch gluster fd\n");
1206 return NULL;
1209 req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_fsync_state);
1210 if (req == NULL) {
1211 return NULL;
1214 state->ret = -1;
1215 state->fd = glfd;
1217 SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1218 state->profile_bytes, 0);
1219 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1221 subreq = pthreadpool_tevent_job_send(
1222 state, ev, handle->conn->sconn->pool, vfs_gluster_fsync_do, state);
1223 if (tevent_req_nomem(subreq, req)) {
1224 return tevent_req_post(req, ev);
1226 tevent_req_set_callback(subreq, vfs_gluster_fsync_done, req);
1228 talloc_set_destructor(state, vfs_gluster_fsync_state_destructor);
1230 return req;
1233 static void vfs_gluster_fsync_do(void *private_data)
1235 struct vfs_gluster_fsync_state *state = talloc_get_type_abort(
1236 private_data, struct vfs_gluster_fsync_state);
1237 struct timespec start_time;
1238 struct timespec end_time;
1240 SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1242 PROFILE_TIMESTAMP(&start_time);
1244 do {
1245 #ifdef HAVE_GFAPI_VER_7_6
1246 state->ret = glfs_fsync(state->fd, NULL, NULL);
1247 #else
1248 state->ret = glfs_fsync(state->fd);
1249 #endif
1250 } while ((state->ret == -1) && (errno == EINTR));
1252 if (state->ret == -1) {
1253 state->vfs_aio_state.error = errno;
1256 PROFILE_TIMESTAMP(&end_time);
1258 state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1260 SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1263 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state)
1265 return -1;
1268 static void vfs_gluster_fsync_done(struct tevent_req *subreq)
1270 struct tevent_req *req = tevent_req_callback_data(
1271 subreq, struct tevent_req);
1272 struct vfs_gluster_fsync_state *state = tevent_req_data(
1273 req, struct vfs_gluster_fsync_state);
1274 int ret;
1276 ret = pthreadpool_tevent_job_recv(subreq);
1277 TALLOC_FREE(subreq);
1278 SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1279 talloc_set_destructor(state, NULL);
1280 if (ret != 0) {
1281 if (ret != EAGAIN) {
1282 tevent_req_error(req, ret);
1283 return;
1286 * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1287 * means the lower level pthreadpool failed to create a new
1288 * thread. Fallback to sync processing in that case to allow
1289 * some progress for the client.
1291 vfs_gluster_fsync_do(state);
1294 tevent_req_done(req);
1297 static int vfs_gluster_fsync_recv(struct tevent_req *req,
1298 struct vfs_aio_state *vfs_aio_state)
1300 struct vfs_gluster_fsync_state *state = tevent_req_data(
1301 req, struct vfs_gluster_fsync_state);
1303 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1304 return -1;
1307 *vfs_aio_state = state->vfs_aio_state;
1308 return state->ret;
1311 static int vfs_gluster_stat(struct vfs_handle_struct *handle,
1312 struct smb_filename *smb_fname)
1314 struct stat st;
1315 int ret;
1317 START_PROFILE(syscall_stat);
1318 ret = glfs_stat(handle->data, smb_fname->base_name, &st);
1319 if (ret == 0) {
1320 smb_stat_ex_from_stat(&smb_fname->st, &st);
1322 if (ret < 0 && errno != ENOENT) {
1323 DEBUG(0, ("glfs_stat(%s) failed: %s\n",
1324 smb_fname->base_name, strerror(errno)));
1326 END_PROFILE(syscall_stat);
1328 return ret;
1331 static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
1332 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1334 struct stat st;
1335 int ret;
1336 glfs_fd_t *glfd = NULL;
1338 START_PROFILE(syscall_fstat);
1340 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1341 if (glfd == NULL) {
1342 END_PROFILE(syscall_fstat);
1343 DBG_ERR("Failed to fetch gluster fd\n");
1344 return -1;
1347 ret = glfs_fstat(glfd, &st);
1348 if (ret == 0) {
1349 smb_stat_ex_from_stat(sbuf, &st);
1351 if (ret < 0) {
1352 DEBUG(0, ("glfs_fstat(%d) failed: %s\n",
1353 fsp->fh->fd, strerror(errno)));
1355 END_PROFILE(syscall_fstat);
1357 return ret;
1360 static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
1361 struct smb_filename *smb_fname)
1363 struct stat st;
1364 int ret;
1366 START_PROFILE(syscall_lstat);
1367 ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
1368 if (ret == 0) {
1369 smb_stat_ex_from_stat(&smb_fname->st, &st);
1371 if (ret < 0 && errno != ENOENT) {
1372 DEBUG(0, ("glfs_lstat(%s) failed: %s\n",
1373 smb_fname->base_name, strerror(errno)));
1375 END_PROFILE(syscall_lstat);
1377 return ret;
1380 static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle,
1381 files_struct *fsp,
1382 const SMB_STRUCT_STAT *sbuf)
1384 uint64_t ret;
1386 START_PROFILE(syscall_get_alloc_size);
1387 ret = sbuf->st_ex_blocks * 512;
1388 END_PROFILE(syscall_get_alloc_size);
1390 return ret;
1393 static int vfs_gluster_unlinkat(struct vfs_handle_struct *handle,
1394 struct files_struct *dirfsp,
1395 const struct smb_filename *smb_fname,
1396 int flags)
1398 int ret;
1400 START_PROFILE(syscall_unlinkat);
1401 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1402 if (flags & AT_REMOVEDIR) {
1403 ret = glfs_rmdir(handle->data, smb_fname->base_name);
1404 } else {
1405 ret = glfs_unlink(handle->data, smb_fname->base_name);
1407 END_PROFILE(syscall_unlinkat);
1409 return ret;
1412 static int vfs_gluster_chmod(struct vfs_handle_struct *handle,
1413 const struct smb_filename *smb_fname,
1414 mode_t mode)
1416 int ret;
1418 START_PROFILE(syscall_chmod);
1419 ret = glfs_chmod(handle->data, smb_fname->base_name, mode);
1420 END_PROFILE(syscall_chmod);
1422 return ret;
1425 static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
1426 files_struct *fsp, mode_t mode)
1428 int ret;
1429 glfs_fd_t *glfd = NULL;
1431 START_PROFILE(syscall_fchmod);
1433 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1434 if (glfd == NULL) {
1435 END_PROFILE(syscall_fchmod);
1436 DBG_ERR("Failed to fetch gluster fd\n");
1437 return -1;
1440 ret = glfs_fchmod(glfd, mode);
1441 END_PROFILE(syscall_fchmod);
1443 return ret;
1446 static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
1447 files_struct *fsp, uid_t uid, gid_t gid)
1449 int ret;
1450 glfs_fd_t *glfd = NULL;
1452 START_PROFILE(syscall_fchown);
1454 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1455 if (glfd == NULL) {
1456 END_PROFILE(syscall_fchown);
1457 DBG_ERR("Failed to fetch gluster fd\n");
1458 return -1;
1461 ret = glfs_fchown(glfd, uid, gid);
1462 END_PROFILE(syscall_fchown);
1464 return ret;
1467 static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
1468 const struct smb_filename *smb_fname,
1469 uid_t uid,
1470 gid_t gid)
1472 int ret;
1474 START_PROFILE(syscall_lchown);
1475 ret = glfs_lchown(handle->data, smb_fname->base_name, uid, gid);
1476 END_PROFILE(syscall_lchown);
1478 return ret;
1481 static int vfs_gluster_chdir(struct vfs_handle_struct *handle,
1482 const struct smb_filename *smb_fname)
1484 int ret;
1486 START_PROFILE(syscall_chdir);
1487 ret = glfs_chdir(handle->data, smb_fname->base_name);
1488 END_PROFILE(syscall_chdir);
1490 return ret;
1493 static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
1494 TALLOC_CTX *ctx)
1496 char *cwd;
1497 char *ret;
1498 struct smb_filename *smb_fname = NULL;
1500 START_PROFILE(syscall_getwd);
1502 cwd = SMB_CALLOC_ARRAY(char, PATH_MAX);
1503 if (cwd == NULL) {
1504 END_PROFILE(syscall_getwd);
1505 return NULL;
1508 ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1);
1509 END_PROFILE(syscall_getwd);
1511 if (ret == NULL) {
1512 SAFE_FREE(cwd);
1513 return NULL;
1515 smb_fname = synthetic_smb_fname(ctx,
1516 ret,
1517 NULL,
1518 NULL,
1520 SAFE_FREE(cwd);
1521 return smb_fname;
1524 static int vfs_gluster_ntimes(struct vfs_handle_struct *handle,
1525 const struct smb_filename *smb_fname,
1526 struct smb_file_time *ft)
1528 int ret = -1;
1529 struct timespec times[2];
1531 START_PROFILE(syscall_ntimes);
1533 if (is_omit_timespec(&ft->atime)) {
1534 times[0].tv_sec = smb_fname->st.st_ex_atime.tv_sec;
1535 times[0].tv_nsec = smb_fname->st.st_ex_atime.tv_nsec;
1536 } else {
1537 times[0].tv_sec = ft->atime.tv_sec;
1538 times[0].tv_nsec = ft->atime.tv_nsec;
1541 if (is_omit_timespec(&ft->mtime)) {
1542 times[1].tv_sec = smb_fname->st.st_ex_mtime.tv_sec;
1543 times[1].tv_nsec = smb_fname->st.st_ex_mtime.tv_nsec;
1544 } else {
1545 times[1].tv_sec = ft->mtime.tv_sec;
1546 times[1].tv_nsec = ft->mtime.tv_nsec;
1549 if ((timespec_compare(&times[0],
1550 &smb_fname->st.st_ex_atime) == 0) &&
1551 (timespec_compare(&times[1],
1552 &smb_fname->st.st_ex_mtime) == 0)) {
1553 END_PROFILE(syscall_ntimes);
1554 return 0;
1557 ret = glfs_utimens(handle->data, smb_fname->base_name, times);
1558 END_PROFILE(syscall_ntimes);
1560 return ret;
1563 static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle,
1564 files_struct *fsp, off_t offset)
1566 int ret;
1567 glfs_fd_t *glfd = NULL;
1569 START_PROFILE(syscall_ftruncate);
1571 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1572 if (glfd == NULL) {
1573 END_PROFILE(syscall_ftruncate);
1574 DBG_ERR("Failed to fetch gluster fd\n");
1575 return -1;
1578 #ifdef HAVE_GFAPI_VER_7_6
1579 ret = glfs_ftruncate(glfd, offset, NULL, NULL);
1580 #else
1581 ret = glfs_ftruncate(glfd, offset);
1582 #endif
1583 END_PROFILE(syscall_ftruncate);
1585 return ret;
1588 static int vfs_gluster_fallocate(struct vfs_handle_struct *handle,
1589 struct files_struct *fsp,
1590 uint32_t mode,
1591 off_t offset, off_t len)
1593 int ret;
1594 #ifdef HAVE_GFAPI_VER_6
1595 glfs_fd_t *glfd = NULL;
1596 int keep_size, punch_hole;
1598 START_PROFILE(syscall_fallocate);
1600 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1601 if (glfd == NULL) {
1602 END_PROFILE(syscall_fallocate);
1603 DBG_ERR("Failed to fetch gluster fd\n");
1604 return -1;
1607 keep_size = mode & VFS_FALLOCATE_FL_KEEP_SIZE;
1608 punch_hole = mode & VFS_FALLOCATE_FL_PUNCH_HOLE;
1610 mode &= ~(VFS_FALLOCATE_FL_KEEP_SIZE|VFS_FALLOCATE_FL_PUNCH_HOLE);
1611 if (mode != 0) {
1612 END_PROFILE(syscall_fallocate);
1613 errno = ENOTSUP;
1614 return -1;
1617 if (punch_hole) {
1618 ret = glfs_discard(glfd, offset, len);
1619 if (ret != 0) {
1620 DBG_DEBUG("glfs_discard failed: %s\n",
1621 strerror(errno));
1625 ret = glfs_fallocate(glfd, keep_size, offset, len);
1626 END_PROFILE(syscall_fallocate);
1627 #else
1628 errno = ENOTSUP;
1629 ret = -1;
1630 #endif
1631 return ret;
1634 static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handle,
1635 TALLOC_CTX *ctx,
1636 const struct smb_filename *smb_fname)
1638 char *result = NULL;
1639 struct smb_filename *result_fname = NULL;
1640 char *resolved_path = NULL;
1642 START_PROFILE(syscall_realpath);
1644 resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1645 if (resolved_path == NULL) {
1646 END_PROFILE(syscall_realpath);
1647 errno = ENOMEM;
1648 return NULL;
1651 result = glfs_realpath(handle->data,
1652 smb_fname->base_name,
1653 resolved_path);
1654 if (result != NULL) {
1655 result_fname = synthetic_smb_fname(ctx, result, NULL, NULL, 0);
1658 SAFE_FREE(resolved_path);
1659 END_PROFILE(syscall_realpath);
1661 return result_fname;
1664 static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
1665 files_struct *fsp, int op, off_t offset,
1666 off_t count, int type)
1668 struct flock flock = { 0, };
1669 int ret;
1670 glfs_fd_t *glfd = NULL;
1671 bool ok = false;
1673 START_PROFILE(syscall_fcntl_lock);
1675 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1676 if (glfd == NULL) {
1677 DBG_ERR("Failed to fetch gluster fd\n");
1678 ok = false;
1679 goto out;
1682 flock.l_type = type;
1683 flock.l_whence = SEEK_SET;
1684 flock.l_start = offset;
1685 flock.l_len = count;
1686 flock.l_pid = 0;
1688 ret = glfs_posix_lock(glfd, op, &flock);
1690 if (op == F_GETLK) {
1691 /* lock query, true if someone else has locked */
1692 if ((ret != -1) &&
1693 (flock.l_type != F_UNLCK) &&
1694 (flock.l_pid != 0) && (flock.l_pid != getpid())) {
1695 ok = true;
1696 goto out;
1698 /* not me */
1699 ok = false;
1700 goto out;
1703 if (ret == -1) {
1704 ok = false;
1705 goto out;
1708 ok = true;
1709 out:
1710 END_PROFILE(syscall_fcntl_lock);
1712 return ok;
1715 static int vfs_gluster_kernel_flock(struct vfs_handle_struct *handle,
1716 files_struct *fsp, uint32_t share_access,
1717 uint32_t access_mask)
1719 errno = ENOSYS;
1720 return -1;
1723 static int vfs_gluster_fcntl(vfs_handle_struct *handle,
1724 files_struct *fsp, int cmd, va_list cmd_arg)
1727 * SMB_VFS_FCNTL() is currently only called by vfs_set_blocking() to
1728 * clear O_NONBLOCK, etc for LOCK_MAND and FIFOs. Ignore it.
1730 if (cmd == F_GETFL) {
1731 return 0;
1732 } else if (cmd == F_SETFL) {
1733 va_list dup_cmd_arg;
1734 int opt;
1736 va_copy(dup_cmd_arg, cmd_arg);
1737 opt = va_arg(dup_cmd_arg, int);
1738 va_end(dup_cmd_arg);
1739 if (opt == 0) {
1740 return 0;
1742 DBG_ERR("unexpected fcntl SETFL(%d)\n", opt);
1743 goto err_out;
1745 DBG_ERR("unexpected fcntl: %d\n", cmd);
1746 err_out:
1747 errno = EINVAL;
1748 return -1;
1751 static int vfs_gluster_linux_setlease(struct vfs_handle_struct *handle,
1752 files_struct *fsp, int leasetype)
1754 errno = ENOSYS;
1755 return -1;
1758 static bool vfs_gluster_getlock(struct vfs_handle_struct *handle,
1759 files_struct *fsp, off_t *poffset,
1760 off_t *pcount, int *ptype, pid_t *ppid)
1762 struct flock flock = { 0, };
1763 int ret;
1764 glfs_fd_t *glfd = NULL;
1766 START_PROFILE(syscall_fcntl_getlock);
1768 glfd = vfs_gluster_fetch_glfd(handle, fsp);
1769 if (glfd == NULL) {
1770 END_PROFILE(syscall_fcntl_getlock);
1771 DBG_ERR("Failed to fetch gluster fd\n");
1772 return false;
1775 flock.l_type = *ptype;
1776 flock.l_whence = SEEK_SET;
1777 flock.l_start = *poffset;
1778 flock.l_len = *pcount;
1779 flock.l_pid = 0;
1781 ret = glfs_posix_lock(glfd, F_GETLK, &flock);
1783 if (ret == -1) {
1784 END_PROFILE(syscall_fcntl_getlock);
1785 return false;
1788 *ptype = flock.l_type;
1789 *poffset = flock.l_start;
1790 *pcount = flock.l_len;
1791 *ppid = flock.l_pid;
1792 END_PROFILE(syscall_fcntl_getlock);
1794 return true;
1797 static int vfs_gluster_symlinkat(struct vfs_handle_struct *handle,
1798 const char *link_target,
1799 struct files_struct *dirfsp,
1800 const struct smb_filename *new_smb_fname)
1802 int ret;
1804 START_PROFILE(syscall_symlinkat);
1805 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1806 ret = glfs_symlink(handle->data,
1807 link_target,
1808 new_smb_fname->base_name);
1809 END_PROFILE(syscall_symlinkat);
1811 return ret;
1814 static int vfs_gluster_readlinkat(struct vfs_handle_struct *handle,
1815 files_struct *dirfsp,
1816 const struct smb_filename *smb_fname,
1817 char *buf,
1818 size_t bufsiz)
1820 int ret;
1822 START_PROFILE(syscall_readlinkat);
1823 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1824 ret = glfs_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1825 END_PROFILE(syscall_readlinkat);
1827 return ret;
1830 static int vfs_gluster_linkat(struct vfs_handle_struct *handle,
1831 files_struct *srcfsp,
1832 const struct smb_filename *old_smb_fname,
1833 files_struct *dstfsp,
1834 const struct smb_filename *new_smb_fname,
1835 int flags)
1837 int ret;
1839 START_PROFILE(syscall_linkat);
1841 SMB_ASSERT(srcfsp == srcfsp->conn->cwd_fsp);
1842 SMB_ASSERT(dstfsp == dstfsp->conn->cwd_fsp);
1844 ret = glfs_link(handle->data,
1845 old_smb_fname->base_name,
1846 new_smb_fname->base_name);
1847 END_PROFILE(syscall_linkat);
1849 return ret;
1852 static int vfs_gluster_mknodat(struct vfs_handle_struct *handle,
1853 files_struct *dirfsp,
1854 const struct smb_filename *smb_fname,
1855 mode_t mode,
1856 SMB_DEV_T dev)
1858 int ret;
1860 START_PROFILE(syscall_mknodat);
1861 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1862 ret = glfs_mknod(handle->data, smb_fname->base_name, mode, dev);
1863 END_PROFILE(syscall_mknodat);
1865 return ret;
1868 static int vfs_gluster_chflags(struct vfs_handle_struct *handle,
1869 const struct smb_filename *smb_fname,
1870 unsigned int flags)
1872 errno = ENOSYS;
1873 return -1;
1876 static int vfs_gluster_get_real_filename(struct vfs_handle_struct *handle,
1877 const char *path, const char *name,
1878 TALLOC_CTX *mem_ctx, char **found_name)
1880 int ret;
1881 char key_buf[GLUSTER_NAME_MAX + 64];
1882 char val_buf[GLUSTER_NAME_MAX + 1];
1884 if (strlen(name) >= GLUSTER_NAME_MAX) {
1885 errno = ENAMETOOLONG;
1886 return -1;
1889 snprintf(key_buf, GLUSTER_NAME_MAX + 64,
1890 "glusterfs.get_real_filename:%s", name);
1892 ret = glfs_getxattr(handle->data, path, key_buf, val_buf,
1893 GLUSTER_NAME_MAX + 1);
1894 if (ret == -1) {
1895 if (errno == ENOATTR) {
1896 errno = ENOENT;
1898 return -1;
1901 *found_name = talloc_strdup(mem_ctx, val_buf);
1902 if (found_name[0] == NULL) {
1903 errno = ENOMEM;
1904 return -1;
1906 return 0;
1909 static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle,
1910 const struct smb_filename *smb_fname)
1912 return handle->conn->connectpath;
1915 /* EA Operations */
1917 static ssize_t vfs_gluster_getxattr(struct vfs_handle_struct *handle,
1918 const struct smb_filename *smb_fname,
1919 const char *name,
1920 void *value,
1921 size_t size)
1923 return glfs_getxattr(handle->data, smb_fname->base_name,
1924 name, value, size);
1927 static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
1928 files_struct *fsp, const char *name,
1929 void *value, size_t size)
1931 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1932 if (glfd == NULL) {
1933 DBG_ERR("Failed to fetch gluster fd\n");
1934 return -1;
1937 return glfs_fgetxattr(glfd, name, value, size);
1940 static ssize_t vfs_gluster_listxattr(struct vfs_handle_struct *handle,
1941 const struct smb_filename *smb_fname,
1942 char *list,
1943 size_t size)
1945 return glfs_listxattr(handle->data, smb_fname->base_name, list, size);
1948 static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
1949 files_struct *fsp, char *list,
1950 size_t size)
1952 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1953 if (glfd == NULL) {
1954 DBG_ERR("Failed to fetch gluster fd\n");
1955 return -1;
1958 return glfs_flistxattr(glfd, list, size);
1961 static int vfs_gluster_removexattr(struct vfs_handle_struct *handle,
1962 const struct smb_filename *smb_fname,
1963 const char *name)
1965 return glfs_removexattr(handle->data, smb_fname->base_name, name);
1968 static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
1969 files_struct *fsp, const char *name)
1971 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1972 if (glfd == NULL) {
1973 DBG_ERR("Failed to fetch gluster fd\n");
1974 return -1;
1977 return glfs_fremovexattr(glfd, name);
1980 static int vfs_gluster_setxattr(struct vfs_handle_struct *handle,
1981 const struct smb_filename *smb_fname,
1982 const char *name,
1983 const void *value, size_t size, int flags)
1985 return glfs_setxattr(handle->data, smb_fname->base_name, name, value, size, flags);
1988 static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
1989 files_struct *fsp, const char *name,
1990 const void *value, size_t size, int flags)
1992 glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1993 if (glfd == NULL) {
1994 DBG_ERR("Failed to fetch gluster fd\n");
1995 return -1;
1998 return glfs_fsetxattr(glfd, name, value, size, flags);
2001 /* AIO Operations */
2003 static bool vfs_gluster_aio_force(struct vfs_handle_struct *handle,
2004 files_struct *fsp)
2006 return false;
2009 static NTSTATUS vfs_gluster_create_dfs_pathat(struct vfs_handle_struct *handle,
2010 struct files_struct *dirfsp,
2011 const struct smb_filename *smb_fname,
2012 const struct referral *reflist,
2013 size_t referral_count)
2015 TALLOC_CTX *frame = talloc_stackframe();
2016 NTSTATUS status = NT_STATUS_NO_MEMORY;
2017 int ret;
2018 char *msdfs_link = NULL;
2020 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2022 /* Form the msdfs_link contents */
2023 msdfs_link = msdfs_link_string(frame,
2024 reflist,
2025 referral_count);
2026 if (msdfs_link == NULL) {
2027 goto out;
2030 ret = glfs_symlink(handle->data,
2031 msdfs_link,
2032 smb_fname->base_name);
2033 if (ret == 0) {
2034 status = NT_STATUS_OK;
2035 } else {
2036 status = map_nt_error_from_unix(errno);
2039 out:
2041 TALLOC_FREE(frame);
2042 return status;
2046 * Read and return the contents of a DFS redirect given a
2047 * pathname. A caller can pass in NULL for ppreflist and
2048 * preferral_count but still determine if this was a
2049 * DFS redirect point by getting NT_STATUS_OK back
2050 * without incurring the overhead of reading and parsing
2051 * the referral contents.
2054 static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
2055 TALLOC_CTX *mem_ctx,
2056 struct files_struct *dirfsp,
2057 const struct smb_filename *smb_fname,
2058 struct referral **ppreflist,
2059 size_t *preferral_count)
2061 NTSTATUS status = NT_STATUS_NO_MEMORY;
2062 size_t bufsize;
2063 char *link_target = NULL;
2064 int referral_len;
2065 bool ok;
2066 #if defined(HAVE_BROKEN_READLINK)
2067 char link_target_buf[PATH_MAX];
2068 #else
2069 char link_target_buf[7];
2070 #endif
2072 SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2074 if (ppreflist == NULL && preferral_count == NULL) {
2076 * We're only checking if this is a DFS
2077 * redirect. We don't need to return data.
2079 bufsize = sizeof(link_target_buf);
2080 link_target = link_target_buf;
2081 } else {
2082 bufsize = PATH_MAX;
2083 link_target = talloc_array(mem_ctx, char, bufsize);
2084 if (!link_target) {
2085 goto err;
2089 referral_len = glfs_readlink(handle->data,
2090 smb_fname->base_name,
2091 link_target,
2092 bufsize - 1);
2093 if (referral_len < 0) {
2094 if (errno == EINVAL) {
2095 DBG_INFO("%s is not a link.\n", smb_fname->base_name);
2096 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2097 } else {
2098 status = map_nt_error_from_unix(errno);
2099 DBG_ERR("Error reading "
2100 "msdfs link %s: %s\n",
2101 smb_fname->base_name,
2102 strerror(errno));
2104 goto err;
2106 link_target[referral_len] = '\0';
2108 DBG_INFO("%s -> %s\n",
2109 smb_fname->base_name,
2110 link_target);
2112 if (!strnequal(link_target, "msdfs:", 6)) {
2113 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2114 goto err;
2117 if (ppreflist == NULL && preferral_count == NULL) {
2118 /* Early return for checking if this is a DFS link. */
2119 return NT_STATUS_OK;
2122 ok = parse_msdfs_symlink(mem_ctx,
2123 lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
2124 link_target,
2125 ppreflist,
2126 preferral_count);
2128 if (ok) {
2129 status = NT_STATUS_OK;
2130 } else {
2131 status = NT_STATUS_NO_MEMORY;
2134 err:
2136 if (link_target != link_target_buf) {
2137 TALLOC_FREE(link_target);
2139 return status;
2142 static struct vfs_fn_pointers glusterfs_fns = {
2144 /* Disk Operations */
2146 .connect_fn = vfs_gluster_connect,
2147 .disconnect_fn = vfs_gluster_disconnect,
2148 .disk_free_fn = vfs_gluster_disk_free,
2149 .get_quota_fn = vfs_gluster_get_quota,
2150 .set_quota_fn = vfs_gluster_set_quota,
2151 .statvfs_fn = vfs_gluster_statvfs,
2152 .fs_capabilities_fn = vfs_gluster_fs_capabilities,
2154 .get_dfs_referrals_fn = NULL,
2156 /* Directory Operations */
2158 .opendir_fn = vfs_gluster_opendir,
2159 .fdopendir_fn = vfs_gluster_fdopendir,
2160 .readdir_fn = vfs_gluster_readdir,
2161 .seekdir_fn = vfs_gluster_seekdir,
2162 .telldir_fn = vfs_gluster_telldir,
2163 .rewind_dir_fn = vfs_gluster_rewinddir,
2164 .mkdirat_fn = vfs_gluster_mkdirat,
2165 .closedir_fn = vfs_gluster_closedir,
2167 /* File Operations */
2169 .open_fn = vfs_gluster_open,
2170 .create_file_fn = NULL,
2171 .close_fn = vfs_gluster_close,
2172 .pread_fn = vfs_gluster_pread,
2173 .pread_send_fn = vfs_gluster_pread_send,
2174 .pread_recv_fn = vfs_gluster_pread_recv,
2175 .pwrite_fn = vfs_gluster_pwrite,
2176 .pwrite_send_fn = vfs_gluster_pwrite_send,
2177 .pwrite_recv_fn = vfs_gluster_pwrite_recv,
2178 .lseek_fn = vfs_gluster_lseek,
2179 .sendfile_fn = vfs_gluster_sendfile,
2180 .recvfile_fn = vfs_gluster_recvfile,
2181 .renameat_fn = vfs_gluster_renameat,
2182 .fsync_send_fn = vfs_gluster_fsync_send,
2183 .fsync_recv_fn = vfs_gluster_fsync_recv,
2185 .stat_fn = vfs_gluster_stat,
2186 .fstat_fn = vfs_gluster_fstat,
2187 .lstat_fn = vfs_gluster_lstat,
2188 .get_alloc_size_fn = vfs_gluster_get_alloc_size,
2189 .unlinkat_fn = vfs_gluster_unlinkat,
2191 .chmod_fn = vfs_gluster_chmod,
2192 .fchmod_fn = vfs_gluster_fchmod,
2193 .fchown_fn = vfs_gluster_fchown,
2194 .lchown_fn = vfs_gluster_lchown,
2195 .chdir_fn = vfs_gluster_chdir,
2196 .getwd_fn = vfs_gluster_getwd,
2197 .ntimes_fn = vfs_gluster_ntimes,
2198 .ftruncate_fn = vfs_gluster_ftruncate,
2199 .fallocate_fn = vfs_gluster_fallocate,
2200 .lock_fn = vfs_gluster_lock,
2201 .kernel_flock_fn = vfs_gluster_kernel_flock,
2202 .fcntl_fn = vfs_gluster_fcntl,
2203 .linux_setlease_fn = vfs_gluster_linux_setlease,
2204 .getlock_fn = vfs_gluster_getlock,
2205 .symlinkat_fn = vfs_gluster_symlinkat,
2206 .readlinkat_fn = vfs_gluster_readlinkat,
2207 .linkat_fn = vfs_gluster_linkat,
2208 .mknodat_fn = vfs_gluster_mknodat,
2209 .realpath_fn = vfs_gluster_realpath,
2210 .chflags_fn = vfs_gluster_chflags,
2211 .file_id_create_fn = NULL,
2212 .streaminfo_fn = NULL,
2213 .get_real_filename_fn = vfs_gluster_get_real_filename,
2214 .connectpath_fn = vfs_gluster_connectpath,
2215 .create_dfs_pathat_fn = vfs_gluster_create_dfs_pathat,
2216 .read_dfs_pathat_fn = vfs_gluster_read_dfs_pathat,
2218 .brl_lock_windows_fn = NULL,
2219 .brl_unlock_windows_fn = NULL,
2220 .strict_lock_check_fn = NULL,
2221 .translate_name_fn = NULL,
2222 .fsctl_fn = NULL,
2224 /* NT ACL Operations */
2225 .fget_nt_acl_fn = NULL,
2226 .get_nt_acl_fn = NULL,
2227 .fset_nt_acl_fn = NULL,
2228 .audit_file_fn = NULL,
2230 /* Posix ACL Operations */
2231 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
2232 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
2233 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
2234 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
2235 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
2236 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
2237 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
2239 /* EA Operations */
2240 .getxattr_fn = vfs_gluster_getxattr,
2241 .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2242 .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2243 .fgetxattr_fn = vfs_gluster_fgetxattr,
2244 .listxattr_fn = vfs_gluster_listxattr,
2245 .flistxattr_fn = vfs_gluster_flistxattr,
2246 .removexattr_fn = vfs_gluster_removexattr,
2247 .fremovexattr_fn = vfs_gluster_fremovexattr,
2248 .setxattr_fn = vfs_gluster_setxattr,
2249 .fsetxattr_fn = vfs_gluster_fsetxattr,
2251 /* AIO Operations */
2252 .aio_force_fn = vfs_gluster_aio_force,
2254 /* Durable handle Operations */
2255 .durable_cookie_fn = NULL,
2256 .durable_disconnect_fn = NULL,
2257 .durable_reconnect_fn = NULL,
2260 static_decl_vfs;
2261 NTSTATUS vfs_glusterfs_init(TALLOC_CTX *ctx)
2263 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2264 "glusterfs", &glusterfs_fns);