s3: VFS: vfs_glusterfs. Implement linkat().
[samba.git] / source3 / modules / vfs_glusterfs.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Wrap GlusterFS GFAPI calls in vfs functions.
5
6    Copyright (c) 2013 Anand Avati <avati@redhat.com>
7
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.
12
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.
17
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/>.
20 */
21
22 /**
23  * @file   vfs_glusterfs.c
24  * @author Anand Avati <avati@redhat.com>
25  * @date   May 2013
26  * @brief  Samba VFS module for glusterfs
27  *
28  * @todo
29  *   - sendfile/recvfile support
30  *
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.
35  *
36  */
37
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
49 #define DEFAULT_VOLFILE_SERVER "localhost"
50 #define GLUSTER_NAME_MAX 255
51
52 static int read_fd = -1;
53 static int write_fd = -1;
54 static struct tevent_fd *aio_read_event = NULL;
55
56 /**
57  * Helper to convert struct stat to struct stat_ex.
58  */
59 static void smb_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src)
60 {
61         ZERO_STRUCTP(dst);
62
63         dst->st_ex_dev = src->st_dev;
64         dst->st_ex_ino = src->st_ino;
65         dst->st_ex_mode = src->st_mode;
66         dst->st_ex_nlink = src->st_nlink;
67         dst->st_ex_uid = src->st_uid;
68         dst->st_ex_gid = src->st_gid;
69         dst->st_ex_rdev = src->st_rdev;
70         dst->st_ex_size = src->st_size;
71         dst->st_ex_atime.tv_sec = src->st_atime;
72         dst->st_ex_mtime.tv_sec = src->st_mtime;
73         dst->st_ex_ctime.tv_sec = src->st_ctime;
74         dst->st_ex_btime.tv_sec = src->st_mtime;
75         dst->st_ex_blksize = src->st_blksize;
76         dst->st_ex_blocks = src->st_blocks;
77         dst->st_ex_file_id = dst->st_ex_ino;
78         dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_FILE_ID;
79 #ifdef STAT_HAVE_NSEC
80         dst->st_ex_atime.tv_nsec = src->st_atime_nsec;
81         dst->st_ex_mtime.tv_nsec = src->st_mtime_nsec;
82         dst->st_ex_ctime.tv_nsec = src->st_ctime_nsec;
83         dst->st_ex_btime.tv_nsec = src->st_mtime_nsec;
84 #endif
85         dst->st_ex_itime = dst->st_ex_btime;
86         dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_ITIME;
87 }
88
89 /* pre-opened glfs_t */
90
91 static struct glfs_preopened {
92         char *volume;
93         char *connectpath;
94         glfs_t *fs;
95         int ref;
96         struct glfs_preopened *next, *prev;
97 } *glfs_preopened;
98
99
100 static int glfs_set_preopened(const char *volume, const char *connectpath, glfs_t *fs)
101 {
102         struct glfs_preopened *entry = NULL;
103
104         entry = talloc_zero(NULL, struct glfs_preopened);
105         if (!entry) {
106                 errno = ENOMEM;
107                 return -1;
108         }
109
110         entry->volume = talloc_strdup(entry, volume);
111         if (!entry->volume) {
112                 talloc_free(entry);
113                 errno = ENOMEM;
114                 return -1;
115         }
116
117         entry->connectpath = talloc_strdup(entry, connectpath);
118         if (entry->connectpath == NULL) {
119                 talloc_free(entry);
120                 errno = ENOMEM;
121                 return -1;
122         }
123
124         entry->fs = fs;
125         entry->ref = 1;
126
127         DLIST_ADD(glfs_preopened, entry);
128
129         return 0;
130 }
131
132 static glfs_t *glfs_find_preopened(const char *volume, const char *connectpath)
133 {
134         struct glfs_preopened *entry = NULL;
135
136         for (entry = glfs_preopened; entry; entry = entry->next) {
137                 if (strcmp(entry->volume, volume) == 0 &&
138                     strcmp(entry->connectpath, connectpath) == 0)
139                 {
140                         entry->ref++;
141                         return entry->fs;
142                 }
143         }
144
145         return NULL;
146 }
147
148 static void glfs_clear_preopened(glfs_t *fs)
149 {
150         struct glfs_preopened *entry = NULL;
151
152         for (entry = glfs_preopened; entry; entry = entry->next) {
153                 if (entry->fs == fs) {
154                         if (--entry->ref)
155                                 return;
156
157                         DLIST_REMOVE(glfs_preopened, entry);
158
159                         glfs_fini(entry->fs);
160                         talloc_free(entry);
161                 }
162         }
163 }
164
165 static int vfs_gluster_set_volfile_servers(glfs_t *fs,
166                                            const char *volfile_servers)
167 {
168         char *server = NULL;
169         size_t server_count = 0;
170         size_t server_success = 0;
171         int   ret = -1;
172         TALLOC_CTX *frame = talloc_stackframe();
173
174         DBG_INFO("servers list %s\n", volfile_servers);
175
176         while (next_token_talloc(frame, &volfile_servers, &server, " \t")) {
177                 char *transport = NULL;
178                 char *host = NULL;
179                 int   port = 0;
180
181                 server_count++;
182                 DBG_INFO("server %zu %s\n", server_count, server);
183
184                 /* Determine the transport type */
185                 if (strncmp(server, "unix+", 5) == 0) {
186                         port = 0;
187                         transport = talloc_strdup(frame, "unix");
188                         if (!transport) {
189                                 errno = ENOMEM;
190                                 goto out;
191                         }
192                         host = talloc_strdup(frame, server + 5);
193                         if (!host) {
194                                 errno = ENOMEM;
195                                 goto out;
196                         }
197                 } else {
198                         char *p = NULL;
199                         char *port_index = NULL;
200
201                         if (strncmp(server, "tcp+", 4) == 0) {
202                                 server += 4;
203                         }
204
205                         /* IPv6 is enclosed in []
206                          * ':' before ']' is part of IPv6
207                          * ':' after  ']' indicates port
208                          */
209                         p = server;
210                         if (server[0] == '[') {
211                                 server++;
212                                 p = index(server, ']');
213                                 if (p == NULL) {
214                                         /* Malformed IPv6 */
215                                         continue;
216                                 }
217                                 p[0] = '\0';
218                                 p++;
219                         }
220
221                         port_index = index(p, ':');
222
223                         if (port_index == NULL) {
224                                 port = 0;
225                         } else {
226                                 port = atoi(port_index + 1);
227                                 port_index[0] = '\0';
228                         }
229                         transport = talloc_strdup(frame, "tcp");
230                         if (!transport) {
231                                 errno = ENOMEM;
232                                 goto out;
233                         }
234                         host = talloc_strdup(frame, server);
235                         if (!host) {
236                                 errno = ENOMEM;
237                                 goto out;
238                         }
239                 }
240
241                 DBG_INFO("Calling set volfile server with params "
242                          "transport=%s, host=%s, port=%d\n", transport,
243                           host, port);
244
245                 ret = glfs_set_volfile_server(fs, transport, host, port);
246                 if (ret < 0) {
247                         DBG_WARNING("Failed to set volfile_server "
248                                     "transport=%s, host=%s, port=%d (%s)\n",
249                                     transport, host, port, strerror(errno));
250                 } else {
251                         server_success++;
252                 }
253         }
254
255 out:
256         if (server_count == 0) {
257                 ret = -1;
258         } else if (server_success < server_count) {
259                 DBG_WARNING("Failed to set %zu out of %zu servers parsed\n",
260                             server_count - server_success, server_count);
261                 ret = 0;
262         }
263
264         TALLOC_FREE(frame);
265         return ret;
266 }
267
268 /* Disk Operations */
269
270 static int vfs_gluster_connect(struct vfs_handle_struct *handle,
271                                const char *service,
272                                const char *user)
273 {
274         const char *volfile_servers;
275         const char *volume;
276         char *logfile;
277         int loglevel;
278         glfs_t *fs = NULL;
279         TALLOC_CTX *tmp_ctx;
280         int ret = 0;
281
282         tmp_ctx = talloc_new(NULL);
283         if (tmp_ctx == NULL) {
284                 ret = -1;
285                 goto done;
286         }
287         logfile = lp_parm_talloc_string(tmp_ctx, SNUM(handle->conn), "glusterfs",
288                                        "logfile", NULL);
289
290         loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
291
292         volfile_servers = lp_parm_talloc_string(tmp_ctx, SNUM(handle->conn),
293                                                "glusterfs", "volfile_server",
294                                                NULL);
295         if (volfile_servers == NULL) {
296                 volfile_servers = DEFAULT_VOLFILE_SERVER;
297         }
298
299         volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
300                                       NULL);
301         if (volume == NULL) {
302                 volume = service;
303         }
304
305         fs = glfs_find_preopened(volume, handle->conn->connectpath);
306         if (fs) {
307                 goto done;
308         }
309
310         fs = glfs_new(volume);
311         if (fs == NULL) {
312                 ret = -1;
313                 goto done;
314         }
315
316         ret = vfs_gluster_set_volfile_servers(fs, volfile_servers);
317         if (ret < 0) {
318                 DBG_ERR("Failed to set volfile_servers from list %s\n",
319                         volfile_servers);
320                 goto done;
321         }
322
323         ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-posix-acl",
324                                      "true");
325         if (ret < 0) {
326                 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
327                 goto done;
328         }
329
330
331         ret = glfs_set_xlator_option(fs, "*-snapview-client",
332                                      "snapdir-entry-path",
333                                      handle->conn->connectpath);
334         if (ret < 0) {
335                 DEBUG(0, ("%s: Failed to set xlator option:"
336                           " snapdir-entry-path\n", volume));
337                 goto done;
338         }
339
340         ret = glfs_set_logging(fs, logfile, loglevel);
341         if (ret < 0) {
342                 DEBUG(0, ("%s: Failed to set logfile %s loglevel %d\n",
343                           volume, logfile, loglevel));
344                 goto done;
345         }
346
347         ret = glfs_init(fs);
348         if (ret < 0) {
349                 DEBUG(0, ("%s: Failed to initialize volume (%s)\n",
350                           volume, strerror(errno)));
351                 goto done;
352         }
353
354         ret = glfs_set_preopened(volume, handle->conn->connectpath, fs);
355         if (ret < 0) {
356                 DEBUG(0, ("%s: Failed to register volume (%s)\n",
357                           volume, strerror(errno)));
358                 goto done;
359         }
360
361         /*
362          * The shadow_copy2 module will fail to export subdirectories
363          * of a gluster volume unless we specify the mount point,
364          * because the detection fails if the file system is not
365          * locally mounted:
366          * https://bugzilla.samba.org/show_bug.cgi?id=13091
367          */
368         lp_do_parameter(SNUM(handle->conn), "shadow:mountpoint", "/");
369
370         /*
371          * Unless we have an async implementation of getxattrat turn this off.
372          */
373         lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false");
374
375 done:
376         if (ret < 0) {
377                 if (fs)
378                         glfs_fini(fs);
379         } else {
380                 DBG_ERR("%s: Initialized volume from servers %s\n",
381                         volume, volfile_servers);
382                 handle->data = fs;
383         }
384         talloc_free(tmp_ctx);
385         return ret;
386 }
387
388 static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
389 {
390         glfs_t *fs = NULL;
391
392         fs = handle->data;
393
394         glfs_clear_preopened(fs);
395 }
396
397 static uint64_t vfs_gluster_disk_free(struct vfs_handle_struct *handle,
398                                 const struct smb_filename *smb_fname,
399                                 uint64_t *bsize_p,
400                                 uint64_t *dfree_p,
401                                 uint64_t *dsize_p)
402 {
403         struct statvfs statvfs = { 0, };
404         int ret;
405
406         ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
407         if (ret < 0) {
408                 return -1;
409         }
410
411         if (bsize_p != NULL) {
412                 *bsize_p = (uint64_t)statvfs.f_bsize; /* Block size */
413         }
414         if (dfree_p != NULL) {
415                 *dfree_p = (uint64_t)statvfs.f_bavail; /* Available Block units */
416         }
417         if (dsize_p != NULL) {
418                 *dsize_p = (uint64_t)statvfs.f_blocks; /* Total Block units */
419         }
420
421         return (uint64_t)statvfs.f_bavail;
422 }
423
424 static int vfs_gluster_get_quota(struct vfs_handle_struct *handle,
425                                 const struct smb_filename *smb_fname,
426                                 enum SMB_QUOTA_TYPE qtype,
427                                 unid_t id,
428                                 SMB_DISK_QUOTA *qt)
429 {
430         errno = ENOSYS;
431         return -1;
432 }
433
434 static int
435 vfs_gluster_set_quota(struct vfs_handle_struct *handle,
436                       enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
437 {
438         errno = ENOSYS;
439         return -1;
440 }
441
442 static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
443                                 const struct smb_filename *smb_fname,
444                                 struct vfs_statvfs_struct *vfs_statvfs)
445 {
446         struct statvfs statvfs = { 0, };
447         int ret;
448
449         ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
450         if (ret < 0) {
451                 DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
452                           smb_fname->base_name, strerror(errno)));
453                 return -1;
454         }
455
456         ZERO_STRUCTP(vfs_statvfs);
457
458         vfs_statvfs->OptimalTransferSize = statvfs.f_frsize;
459         vfs_statvfs->BlockSize = statvfs.f_bsize;
460         vfs_statvfs->TotalBlocks = statvfs.f_blocks;
461         vfs_statvfs->BlocksAvail = statvfs.f_bfree;
462         vfs_statvfs->UserBlocksAvail = statvfs.f_bavail;
463         vfs_statvfs->TotalFileNodes = statvfs.f_files;
464         vfs_statvfs->FreeFileNodes = statvfs.f_ffree;
465         vfs_statvfs->FsIdentifier = statvfs.f_fsid;
466         vfs_statvfs->FsCapabilities =
467             FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
468
469         return ret;
470 }
471
472 static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
473                                             enum timestamp_set_resolution *p_ts_res)
474 {
475         uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
476
477 #ifdef HAVE_GFAPI_VER_6
478         caps |= FILE_SUPPORTS_SPARSE_FILES;
479 #endif
480
481 #ifdef STAT_HAVE_NSEC
482         *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
483 #endif
484
485         return caps;
486 }
487
488 static DIR *vfs_gluster_opendir(struct vfs_handle_struct *handle,
489                                 const struct smb_filename *smb_fname,
490                                 const char *mask,
491                                 uint32_t attributes)
492 {
493         glfs_fd_t *fd;
494
495         START_PROFILE(syscall_opendir);
496
497         fd = glfs_opendir(handle->data, smb_fname->base_name);
498         if (fd == NULL) {
499                 DEBUG(0, ("glfs_opendir(%s) failed: %s\n",
500                           smb_fname->base_name, strerror(errno)));
501         }
502
503         END_PROFILE(syscall_opendir);
504
505         return (DIR *) fd;
506 }
507
508 static glfs_fd_t *vfs_gluster_fetch_glfd(struct vfs_handle_struct *handle,
509                                          files_struct *fsp)
510 {
511         glfs_fd_t **glfd = (glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
512         if (glfd == NULL) {
513                 DBG_INFO("Failed to fetch fsp extension\n");
514                 return NULL;
515         }
516         if (*glfd == NULL) {
517                 DBG_INFO("Empty glfs_fd_t pointer\n");
518                 return NULL;
519         }
520
521         return *glfd;
522 }
523
524 static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle,
525                                   files_struct *fsp, const char *mask,
526                                   uint32_t attributes)
527 {
528         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
529         if (glfd == NULL) {
530                 DBG_ERR("Failed to fetch gluster fd\n");
531                 return NULL;
532         }
533
534         return (DIR *)glfd;
535 }
536
537 static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp)
538 {
539         int ret;
540
541         START_PROFILE(syscall_closedir);
542         ret = glfs_closedir((void *)dirp);
543         END_PROFILE(syscall_closedir);
544
545         return ret;
546 }
547
548 static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle,
549                                           DIR *dirp, SMB_STRUCT_STAT *sbuf)
550 {
551         static char direntbuf[512];
552         int ret;
553         struct stat stat;
554         struct dirent *dirent = 0;
555
556         START_PROFILE(syscall_readdir);
557         if (sbuf != NULL) {
558                 ret = glfs_readdirplus_r((void *)dirp, &stat, (void *)direntbuf,
559                                          &dirent);
560         } else {
561                 ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
562         }
563
564         if ((ret < 0) || (dirent == NULL)) {
565                 END_PROFILE(syscall_readdir);
566                 return NULL;
567         }
568
569         if (sbuf != NULL) {
570                 smb_stat_ex_from_stat(sbuf, &stat);
571         }
572
573         END_PROFILE(syscall_readdir);
574         return dirent;
575 }
576
577 static long vfs_gluster_telldir(struct vfs_handle_struct *handle, DIR *dirp)
578 {
579         long ret;
580
581         START_PROFILE(syscall_telldir);
582         ret = glfs_telldir((void *)dirp);
583         END_PROFILE(syscall_telldir);
584
585         return ret;
586 }
587
588 static void vfs_gluster_seekdir(struct vfs_handle_struct *handle, DIR *dirp,
589                                 long offset)
590 {
591         START_PROFILE(syscall_seekdir);
592         glfs_seekdir((void *)dirp, offset);
593         END_PROFILE(syscall_seekdir);
594 }
595
596 static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
597 {
598         START_PROFILE(syscall_rewinddir);
599         glfs_seekdir((void *)dirp, 0);
600         END_PROFILE(syscall_rewinddir);
601 }
602
603 static int vfs_gluster_mkdir(struct vfs_handle_struct *handle,
604                              const struct smb_filename *smb_fname,
605                              mode_t mode)
606 {
607         int ret;
608
609         START_PROFILE(syscall_mkdir);
610         ret = glfs_mkdir(handle->data, smb_fname->base_name, mode);
611         END_PROFILE(syscall_mkdir);
612
613         return ret;
614 }
615
616 static int vfs_gluster_rmdir(struct vfs_handle_struct *handle,
617                         const struct smb_filename *smb_fname)
618 {
619         int ret;
620
621         START_PROFILE(syscall_rmdir);
622         ret = glfs_rmdir(handle->data, smb_fname->base_name);
623         END_PROFILE(syscall_rmdir);
624
625         return ret;
626 }
627
628 static int vfs_gluster_open(struct vfs_handle_struct *handle,
629                             struct smb_filename *smb_fname, files_struct *fsp,
630                             int flags, mode_t mode)
631 {
632         glfs_fd_t *glfd;
633         glfs_fd_t **p_tmp;
634
635         START_PROFILE(syscall_open);
636
637         p_tmp = VFS_ADD_FSP_EXTENSION(handle, fsp, glfs_fd_t *, NULL);
638         if (p_tmp == NULL) {
639                 END_PROFILE(syscall_open);
640                 errno = ENOMEM;
641                 return -1;
642         }
643
644         if (flags & O_DIRECTORY) {
645                 glfd = glfs_opendir(handle->data, smb_fname->base_name);
646         } else if (flags & O_CREAT) {
647                 glfd = glfs_creat(handle->data, smb_fname->base_name, flags,
648                                   mode);
649         } else {
650                 glfd = glfs_open(handle->data, smb_fname->base_name, flags);
651         }
652
653         if (glfd == NULL) {
654                 END_PROFILE(syscall_open);
655                 /* no extension destroy_fn, so no need to save errno */
656                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
657                 return -1;
658         }
659
660         *p_tmp = glfd;
661
662         END_PROFILE(syscall_open);
663         /* An arbitrary value for error reporting, so you know its us. */
664         return 13371337;
665 }
666
667 static int vfs_gluster_close(struct vfs_handle_struct *handle,
668                              files_struct *fsp)
669 {
670         int ret;
671         glfs_fd_t *glfd = NULL;
672
673         START_PROFILE(syscall_close);
674
675         glfd = vfs_gluster_fetch_glfd(handle, fsp);
676         if (glfd == NULL) {
677                 END_PROFILE(syscall_close);
678                 DBG_ERR("Failed to fetch gluster fd\n");
679                 return -1;
680         }
681
682         VFS_REMOVE_FSP_EXTENSION(handle, fsp);
683
684         ret = glfs_close(glfd);
685         END_PROFILE(syscall_close);
686
687         return ret;
688 }
689
690 static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
691                                  files_struct *fsp, void *data, size_t n,
692                                  off_t offset)
693 {
694         ssize_t ret;
695         glfs_fd_t *glfd = NULL;
696
697         START_PROFILE_BYTES(syscall_pread, n);
698
699         glfd = vfs_gluster_fetch_glfd(handle, fsp);
700         if (glfd == NULL) {
701                 END_PROFILE_BYTES(syscall_pread);
702                 DBG_ERR("Failed to fetch gluster fd\n");
703                 return -1;
704         }
705
706 #ifdef HAVE_GFAPI_VER_7_6
707         ret = glfs_pread(glfd, data, n, offset, 0, NULL);
708 #else
709         ret = glfs_pread(glfd, data, n, offset, 0);
710 #endif
711         END_PROFILE_BYTES(syscall_pread);
712
713         return ret;
714 }
715
716 struct glusterfs_aio_state;
717
718 struct glusterfs_aio_wrapper {
719         struct glusterfs_aio_state *state;
720 };
721
722 struct glusterfs_aio_state {
723         ssize_t ret;
724         struct tevent_req *req;
725         bool cancelled;
726         struct vfs_aio_state vfs_aio_state;
727         struct timespec start;
728         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
729 };
730
731 static int aio_wrapper_destructor(struct glusterfs_aio_wrapper *wrap)
732 {
733         if (wrap->state != NULL) {
734                 wrap->state->cancelled = true;
735         }
736
737         return 0;
738 }
739
740 /*
741  * This function is the callback that will be called on glusterfs
742  * threads once the async IO submitted is complete. To notify
743  * Samba of the completion we use a pipe based queue.
744  */
745 #ifdef HAVE_GFAPI_VER_7_6
746 static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret,
747                                struct glfs_stat *prestat,
748                                struct glfs_stat *poststat,
749                                void *data)
750 #else
751 static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret, void *data)
752 #endif
753 {
754         struct glusterfs_aio_state *state = NULL;
755         int sts = 0;
756         struct timespec end;
757
758         state = (struct glusterfs_aio_state *)data;
759
760         PROFILE_TIMESTAMP(&end);
761
762         if (ret < 0) {
763                 state->ret = -1;
764                 state->vfs_aio_state.error = errno;
765         } else {
766                 state->ret = ret;
767         }
768         state->vfs_aio_state.duration = nsec_time_diff(&end, &state->start);
769
770         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
771
772         /*
773          * Write the state pointer to glusterfs_aio_state to the
774          * pipe, so we can call tevent_req_done() from the main thread,
775          * because tevent_req_done() is not designed to be executed in
776          * the multithread environment, so tevent_req_done() must be
777          * executed from the smbd main thread.
778          *
779          * write(2) on pipes with sizes under _POSIX_PIPE_BUF
780          * in size is atomic, without this, the use op pipes in this
781          * code would not work.
782          *
783          * sys_write is a thin enough wrapper around write(2)
784          * that we can trust it here.
785          */
786
787         sts = sys_write(write_fd, &state, sizeof(struct glusterfs_aio_state *));
788         if (sts < 0) {
789                 DEBUG(0,("\nWrite to pipe failed (%s)", strerror(errno)));
790         }
791
792         return;
793 }
794
795 /*
796  * Read each req off the pipe and process it.
797  */
798 static void aio_tevent_fd_done(struct tevent_context *event_ctx,
799                                 struct tevent_fd *fde,
800                                 uint16_t flags, void *data)
801 {
802         struct tevent_req *req = NULL;
803         struct glusterfs_aio_state *state = NULL;
804         int sts = 0;
805
806         /*
807          * read(2) on pipes is atomic if the needed data is available
808          * in the pipe, per SUS and POSIX.  Because we always write
809          * to the pipe in sizeof(struct tevent_req *) chunks, we can
810          * always read in those chunks, atomically.
811          *
812          * sys_read is a thin enough wrapper around read(2) that we
813          * can trust it here.
814          */
815
816         sts = sys_read(read_fd, &state, sizeof(struct glusterfs_aio_state *));
817
818         if (sts < 0) {
819                 DEBUG(0,("\nRead from pipe failed (%s)", strerror(errno)));
820         }
821
822         /* if we've cancelled the op, there is no req, so just clean up. */
823         if (state->cancelled == true) {
824                 TALLOC_FREE(state);
825                 return;
826         }
827
828         req = state->req;
829
830         if (req) {
831                 tevent_req_done(req);
832         }
833         return;
834 }
835
836 static bool init_gluster_aio(struct vfs_handle_struct *handle)
837 {
838         int fds[2];
839         int ret = -1;
840
841         if (read_fd != -1) {
842                 /*
843                  * Already initialized.
844                  */
845                 return true;
846         }
847
848         ret = pipe(fds);
849         if (ret == -1) {
850                 goto fail;
851         }
852
853         read_fd = fds[0];
854         write_fd = fds[1];
855
856         aio_read_event = tevent_add_fd(handle->conn->sconn->ev_ctx,
857                                         NULL,
858                                         read_fd,
859                                         TEVENT_FD_READ,
860                                         aio_tevent_fd_done,
861                                         NULL);
862         if (aio_read_event == NULL) {
863                 goto fail;
864         }
865
866         return true;
867 fail:
868         TALLOC_FREE(aio_read_event);
869         if (read_fd != -1) {
870                 close(read_fd);
871                 close(write_fd);
872                 read_fd = -1;
873                 write_fd = -1;
874         }
875         return false;
876 }
877
878 static struct glusterfs_aio_state *aio_state_create(TALLOC_CTX *mem_ctx)
879 {
880         struct tevent_req *req = NULL;
881         struct glusterfs_aio_state *state = NULL;
882         struct glusterfs_aio_wrapper *wrapper = NULL;
883
884         req = tevent_req_create(mem_ctx, &wrapper, struct glusterfs_aio_wrapper);
885
886         if (req == NULL) {
887                 return NULL;
888         }
889
890         state = talloc_zero(NULL, struct glusterfs_aio_state);
891
892         if (state == NULL) {
893                 TALLOC_FREE(req);
894                 return NULL;
895         }
896
897         talloc_set_destructor(wrapper, aio_wrapper_destructor);
898         state->cancelled = false;
899         state->req = req;
900
901         wrapper->state = state;
902
903         return state;
904 }
905
906 static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
907                                                   *handle, TALLOC_CTX *mem_ctx,
908                                                   struct tevent_context *ev,
909                                                   files_struct *fsp,
910                                                   void *data, size_t n,
911                                                   off_t offset)
912 {
913         struct glusterfs_aio_state *state = NULL;
914         struct tevent_req *req = NULL;
915         int ret = 0;
916         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
917
918         if (glfd == NULL) {
919                 DBG_ERR("Failed to fetch gluster fd\n");
920                 return NULL;
921         }
922
923         state = aio_state_create(mem_ctx);
924
925         if (state == NULL) {
926                 return NULL;
927         }
928
929         req = state->req;
930
931         if (!init_gluster_aio(handle)) {
932                 tevent_req_error(req, EIO);
933                 return tevent_req_post(req, ev);
934         }
935
936         /*
937          * aio_glusterfs_done and aio_tevent_fd_done()
938          * use the raw tevent context. We need to use
939          * tevent_req_defer_callback() in order to
940          * use the event context we're started with.
941          */
942         tevent_req_defer_callback(req, ev);
943
944         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
945                                      state->profile_bytes, n);
946         PROFILE_TIMESTAMP(&state->start);
947         ret = glfs_pread_async(glfd, data, n, offset, 0, aio_glusterfs_done,
948                                 state);
949         if (ret < 0) {
950                 tevent_req_error(req, -ret);
951                 return tevent_req_post(req, ev);
952         }
953
954         return req;
955 }
956
957 static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
958                                                   *handle, TALLOC_CTX *mem_ctx,
959                                                   struct tevent_context *ev,
960                                                   files_struct *fsp,
961                                                   const void *data, size_t n,
962                                                   off_t offset)
963 {
964         struct glusterfs_aio_state *state = NULL;
965         struct tevent_req *req = NULL;
966         int ret = 0;
967         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
968
969         if (glfd == NULL) {
970                 DBG_ERR("Failed to fetch gluster fd\n");
971                 return NULL;
972         }
973
974         state = aio_state_create(mem_ctx);
975
976         if (state == NULL) {
977                 return NULL;
978         }
979
980         req = state->req;
981
982         if (!init_gluster_aio(handle)) {
983                 tevent_req_error(req, EIO);
984                 return tevent_req_post(req, ev);
985         }
986
987         /*
988          * aio_glusterfs_done and aio_tevent_fd_done()
989          * use the raw tevent context. We need to use
990          * tevent_req_defer_callback() in order to
991          * use the event context we're started with.
992          */
993         tevent_req_defer_callback(req, ev);
994
995         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
996                                      state->profile_bytes, n);
997         PROFILE_TIMESTAMP(&state->start);
998         ret = glfs_pwrite_async(glfd, data, n, offset, 0, aio_glusterfs_done,
999                                 state);
1000         if (ret < 0) {
1001                 tevent_req_error(req, -ret);
1002                 return tevent_req_post(req, ev);
1003         }
1004
1005         return req;
1006 }
1007
1008 static ssize_t vfs_gluster_recv(struct tevent_req *req,
1009                                 struct vfs_aio_state *vfs_aio_state)
1010 {
1011         struct glusterfs_aio_wrapper *wrapper = NULL;
1012         int ret = 0;
1013
1014         wrapper = tevent_req_data(req, struct glusterfs_aio_wrapper);
1015
1016         if (wrapper == NULL) {
1017                 return -1;
1018         }
1019
1020         if (wrapper->state == NULL) {
1021                 return -1;
1022         }
1023
1024         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1025                 return -1;
1026         }
1027
1028         *vfs_aio_state = wrapper->state->vfs_aio_state;
1029         ret = wrapper->state->ret;
1030
1031         /* Clean up the state, it is in a NULL context. */
1032
1033         TALLOC_FREE(wrapper->state);
1034
1035         return ret;
1036 }
1037
1038 static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
1039                                   files_struct *fsp, const void *data,
1040                                   size_t n, off_t offset)
1041 {
1042         ssize_t ret;
1043         glfs_fd_t *glfd = NULL;
1044
1045         START_PROFILE_BYTES(syscall_pwrite, n);
1046
1047         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1048         if (glfd == NULL) {
1049                 END_PROFILE_BYTES(syscall_pwrite);
1050                 DBG_ERR("Failed to fetch gluster fd\n");
1051                 return -1;
1052         }
1053
1054 #ifdef HAVE_GFAPI_VER_7_6
1055         ret = glfs_pwrite(glfd, data, n, offset, 0, NULL, NULL);
1056 #else
1057         ret = glfs_pwrite(glfd, data, n, offset, 0);
1058 #endif
1059         END_PROFILE_BYTES(syscall_pwrite);
1060
1061         return ret;
1062 }
1063
1064 static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
1065                                files_struct *fsp, off_t offset, int whence)
1066 {
1067         off_t ret = 0;
1068         glfs_fd_t *glfd = NULL;
1069
1070         START_PROFILE(syscall_lseek);
1071
1072         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1073         if (glfd == NULL) {
1074                 END_PROFILE(syscall_lseek);
1075                 DBG_ERR("Failed to fetch gluster fd\n");
1076                 return -1;
1077         }
1078
1079         ret = glfs_lseek(glfd, offset, whence);
1080         END_PROFILE(syscall_lseek);
1081
1082         return ret;
1083 }
1084
1085 static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd,
1086                                     files_struct *fromfsp,
1087                                     const DATA_BLOB *hdr,
1088                                     off_t offset, size_t n)
1089 {
1090         errno = ENOTSUP;
1091         return -1;
1092 }
1093
1094 static ssize_t vfs_gluster_recvfile(struct vfs_handle_struct *handle,
1095                                     int fromfd, files_struct *tofsp,
1096                                     off_t offset, size_t n)
1097 {
1098         errno = ENOTSUP;
1099         return -1;
1100 }
1101
1102 static int vfs_gluster_renameat(struct vfs_handle_struct *handle,
1103                         files_struct *srcfsp,
1104                         const struct smb_filename *smb_fname_src,
1105                         files_struct *dstfsp,
1106                         const struct smb_filename *smb_fname_dst)
1107 {
1108         int ret;
1109
1110         START_PROFILE(syscall_renameat);
1111         ret = glfs_rename(handle->data, smb_fname_src->base_name,
1112                           smb_fname_dst->base_name);
1113         END_PROFILE(syscall_renameat);
1114
1115         return ret;
1116 }
1117
1118 static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
1119                                                  *handle, TALLOC_CTX *mem_ctx,
1120                                                  struct tevent_context *ev,
1121                                                  files_struct *fsp)
1122 {
1123         struct tevent_req *req = NULL;
1124         struct glusterfs_aio_state *state = NULL;
1125         int ret = 0;
1126         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1127
1128         if (glfd == NULL) {
1129                 DBG_ERR("Failed to fetch gluster fd\n");
1130                 return NULL;
1131         }
1132
1133         state = aio_state_create(mem_ctx);
1134
1135         if (state == NULL) {
1136                 return NULL;
1137         }
1138
1139         req = state->req;
1140
1141         if (!init_gluster_aio(handle)) {
1142                 tevent_req_error(req, EIO);
1143                 return tevent_req_post(req, ev);
1144         }
1145
1146         /*
1147          * aio_glusterfs_done and aio_tevent_fd_done()
1148          * use the raw tevent context. We need to use
1149          * tevent_req_defer_callback() in order to
1150          * use the event context we're started with.
1151          */
1152         tevent_req_defer_callback(req, ev);
1153
1154         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1155                                      state->profile_bytes, 0);
1156         PROFILE_TIMESTAMP(&state->start);
1157         ret = glfs_fsync_async(glfd, aio_glusterfs_done, state);
1158         if (ret < 0) {
1159                 tevent_req_error(req, -ret);
1160                 return tevent_req_post(req, ev);
1161         }
1162         return req;
1163 }
1164
1165 static int vfs_gluster_fsync_recv(struct tevent_req *req,
1166                                   struct vfs_aio_state *vfs_aio_state)
1167 {
1168         /*
1169          * Use implicit conversion ssize_t->int
1170          */
1171         return vfs_gluster_recv(req, vfs_aio_state);
1172 }
1173
1174 static int vfs_gluster_stat(struct vfs_handle_struct *handle,
1175                             struct smb_filename *smb_fname)
1176 {
1177         struct stat st;
1178         int ret;
1179
1180         START_PROFILE(syscall_stat);
1181         ret = glfs_stat(handle->data, smb_fname->base_name, &st);
1182         if (ret == 0) {
1183                 smb_stat_ex_from_stat(&smb_fname->st, &st);
1184         }
1185         if (ret < 0 && errno != ENOENT) {
1186                 DEBUG(0, ("glfs_stat(%s) failed: %s\n",
1187                           smb_fname->base_name, strerror(errno)));
1188         }
1189         END_PROFILE(syscall_stat);
1190
1191         return ret;
1192 }
1193
1194 static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
1195                              files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1196 {
1197         struct stat st;
1198         int ret;
1199         glfs_fd_t *glfd = NULL;
1200
1201         START_PROFILE(syscall_fstat);
1202
1203         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1204         if (glfd == NULL) {
1205                 END_PROFILE(syscall_fstat);
1206                 DBG_ERR("Failed to fetch gluster fd\n");
1207                 return -1;
1208         }
1209
1210         ret = glfs_fstat(glfd, &st);
1211         if (ret == 0) {
1212                 smb_stat_ex_from_stat(sbuf, &st);
1213         }
1214         if (ret < 0) {
1215                 DEBUG(0, ("glfs_fstat(%d) failed: %s\n",
1216                           fsp->fh->fd, strerror(errno)));
1217         }
1218         END_PROFILE(syscall_fstat);
1219
1220         return ret;
1221 }
1222
1223 static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
1224                              struct smb_filename *smb_fname)
1225 {
1226         struct stat st;
1227         int ret;
1228
1229         START_PROFILE(syscall_lstat);
1230         ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
1231         if (ret == 0) {
1232                 smb_stat_ex_from_stat(&smb_fname->st, &st);
1233         }
1234         if (ret < 0 && errno != ENOENT) {
1235                 DEBUG(0, ("glfs_lstat(%s) failed: %s\n",
1236                           smb_fname->base_name, strerror(errno)));
1237         }
1238         END_PROFILE(syscall_lstat);
1239
1240         return ret;
1241 }
1242
1243 static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle,
1244                                            files_struct *fsp,
1245                                            const SMB_STRUCT_STAT *sbuf)
1246 {
1247         uint64_t ret;
1248
1249         START_PROFILE(syscall_get_alloc_size);
1250         ret = sbuf->st_ex_blocks * 512;
1251         END_PROFILE(syscall_get_alloc_size);
1252
1253         return ret;
1254 }
1255
1256 static int vfs_gluster_unlink(struct vfs_handle_struct *handle,
1257                               const struct smb_filename *smb_fname)
1258 {
1259         int ret;
1260
1261         START_PROFILE(syscall_unlink);
1262         ret = glfs_unlink(handle->data, smb_fname->base_name);
1263         END_PROFILE(syscall_unlink);
1264
1265         return ret;
1266 }
1267
1268 static int vfs_gluster_chmod(struct vfs_handle_struct *handle,
1269                                 const struct smb_filename *smb_fname,
1270                                 mode_t mode)
1271 {
1272         int ret;
1273
1274         START_PROFILE(syscall_chmod);
1275         ret = glfs_chmod(handle->data, smb_fname->base_name, mode);
1276         END_PROFILE(syscall_chmod);
1277
1278         return ret;
1279 }
1280
1281 static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
1282                               files_struct *fsp, mode_t mode)
1283 {
1284         int ret;
1285         glfs_fd_t *glfd = NULL;
1286
1287         START_PROFILE(syscall_fchmod);
1288
1289         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1290         if (glfd == NULL) {
1291                 END_PROFILE(syscall_fchmod);
1292                 DBG_ERR("Failed to fetch gluster fd\n");
1293                 return -1;
1294         }
1295
1296         ret = glfs_fchmod(glfd, mode);
1297         END_PROFILE(syscall_fchmod);
1298
1299         return ret;
1300 }
1301
1302 static int vfs_gluster_chown(struct vfs_handle_struct *handle,
1303                         const struct smb_filename *smb_fname,
1304                         uid_t uid,
1305                         gid_t gid)
1306 {
1307         int ret;
1308
1309         START_PROFILE(syscall_chown);
1310         ret = glfs_chown(handle->data, smb_fname->base_name, uid, gid);
1311         END_PROFILE(syscall_chown);
1312
1313         return ret;
1314 }
1315
1316 static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
1317                               files_struct *fsp, uid_t uid, gid_t gid)
1318 {
1319         int ret;
1320         glfs_fd_t *glfd = NULL;
1321
1322         START_PROFILE(syscall_fchown);
1323
1324         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1325         if (glfd == NULL) {
1326                 END_PROFILE(syscall_fchown);
1327                 DBG_ERR("Failed to fetch gluster fd\n");
1328                 return -1;
1329         }
1330
1331         ret = glfs_fchown(glfd, uid, gid);
1332         END_PROFILE(syscall_fchown);
1333
1334         return ret;
1335 }
1336
1337 static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
1338                         const struct smb_filename *smb_fname,
1339                         uid_t uid,
1340                         gid_t gid)
1341 {
1342         int ret;
1343
1344         START_PROFILE(syscall_lchown);
1345         ret = glfs_lchown(handle->data, smb_fname->base_name, uid, gid);
1346         END_PROFILE(syscall_lchown);
1347
1348         return ret;
1349 }
1350
1351 static int vfs_gluster_chdir(struct vfs_handle_struct *handle,
1352                         const struct smb_filename *smb_fname)
1353 {
1354         int ret;
1355
1356         START_PROFILE(syscall_chdir);
1357         ret = glfs_chdir(handle->data, smb_fname->base_name);
1358         END_PROFILE(syscall_chdir);
1359
1360         return ret;
1361 }
1362
1363 static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
1364                                 TALLOC_CTX *ctx)
1365 {
1366         char *cwd;
1367         char *ret;
1368         struct smb_filename *smb_fname = NULL;
1369
1370         START_PROFILE(syscall_getwd);
1371
1372         cwd = SMB_CALLOC_ARRAY(char, PATH_MAX);
1373         if (cwd == NULL) {
1374                 END_PROFILE(syscall_getwd);
1375                 return NULL;
1376         }
1377
1378         ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1);
1379         END_PROFILE(syscall_getwd);
1380
1381         if (ret == NULL) {
1382                 SAFE_FREE(cwd);
1383                 return NULL;
1384         }
1385         smb_fname = synthetic_smb_fname(ctx,
1386                                         ret,
1387                                         NULL,
1388                                         NULL,
1389                                         0);
1390         SAFE_FREE(cwd);
1391         return smb_fname;
1392 }
1393
1394 static int vfs_gluster_ntimes(struct vfs_handle_struct *handle,
1395                               const struct smb_filename *smb_fname,
1396                               struct smb_file_time *ft)
1397 {
1398         int ret = -1;
1399         struct timespec times[2];
1400
1401         START_PROFILE(syscall_ntimes);
1402
1403         if (null_timespec(ft->atime)) {
1404                 times[0].tv_sec = smb_fname->st.st_ex_atime.tv_sec;
1405                 times[0].tv_nsec = smb_fname->st.st_ex_atime.tv_nsec;
1406         } else {
1407                 times[0].tv_sec = ft->atime.tv_sec;
1408                 times[0].tv_nsec = ft->atime.tv_nsec;
1409         }
1410
1411         if (null_timespec(ft->mtime)) {
1412                 times[1].tv_sec = smb_fname->st.st_ex_mtime.tv_sec;
1413                 times[1].tv_nsec = smb_fname->st.st_ex_mtime.tv_nsec;
1414         } else {
1415                 times[1].tv_sec = ft->mtime.tv_sec;
1416                 times[1].tv_nsec = ft->mtime.tv_nsec;
1417         }
1418
1419         if ((timespec_compare(&times[0],
1420                               &smb_fname->st.st_ex_atime) == 0) &&
1421             (timespec_compare(&times[1],
1422                               &smb_fname->st.st_ex_mtime) == 0)) {
1423                 END_PROFILE(syscall_ntimes);
1424                 return 0;
1425         }
1426
1427         ret = glfs_utimens(handle->data, smb_fname->base_name, times);
1428         END_PROFILE(syscall_ntimes);
1429
1430         return ret;
1431 }
1432
1433 static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle,
1434                                  files_struct *fsp, off_t offset)
1435 {
1436         int ret;
1437         glfs_fd_t *glfd = NULL;
1438
1439         START_PROFILE(syscall_ftruncate);
1440
1441         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1442         if (glfd == NULL) {
1443                 END_PROFILE(syscall_ftruncate);
1444                 DBG_ERR("Failed to fetch gluster fd\n");
1445                 return -1;
1446         }
1447
1448 #ifdef HAVE_GFAPI_VER_7_6
1449         ret = glfs_ftruncate(glfd, offset, NULL, NULL);
1450 #else
1451         ret = glfs_ftruncate(glfd, offset);
1452 #endif
1453         END_PROFILE(syscall_ftruncate);
1454
1455         return ret;
1456 }
1457
1458 static int vfs_gluster_fallocate(struct vfs_handle_struct *handle,
1459                                  struct files_struct *fsp,
1460                                  uint32_t mode,
1461                                  off_t offset, off_t len)
1462 {
1463         int ret;
1464 #ifdef HAVE_GFAPI_VER_6
1465         glfs_fd_t *glfd = NULL;
1466         int keep_size, punch_hole;
1467
1468         START_PROFILE(syscall_fallocate);
1469
1470         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1471         if (glfd == NULL) {
1472                 END_PROFILE(syscall_fallocate);
1473                 DBG_ERR("Failed to fetch gluster fd\n");
1474                 return -1;
1475         }
1476
1477         keep_size = mode & VFS_FALLOCATE_FL_KEEP_SIZE;
1478         punch_hole = mode & VFS_FALLOCATE_FL_PUNCH_HOLE;
1479
1480         mode &= ~(VFS_FALLOCATE_FL_KEEP_SIZE|VFS_FALLOCATE_FL_PUNCH_HOLE);
1481         if (mode != 0) {
1482                 END_PROFILE(syscall_fallocate);
1483                 errno = ENOTSUP;
1484                 return -1;
1485         }
1486
1487         if (punch_hole) {
1488                 ret = glfs_discard(glfd, offset, len);
1489         }
1490
1491         ret = glfs_fallocate(glfd, keep_size, offset, len);
1492         END_PROFILE(syscall_fallocate);
1493 #else
1494         errno = ENOTSUP;
1495         ret = -1;
1496 #endif
1497         return ret;
1498 }
1499
1500 static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handle,
1501                                 TALLOC_CTX *ctx,
1502                                 const struct smb_filename *smb_fname)
1503 {
1504         char *result = NULL;
1505         struct smb_filename *result_fname = NULL;
1506         char *resolved_path = NULL;
1507
1508         START_PROFILE(syscall_realpath);
1509
1510         resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1511         if (resolved_path == NULL) {
1512                 END_PROFILE(syscall_realpath);
1513                 errno = ENOMEM;
1514                 return NULL;
1515         }
1516
1517         result = glfs_realpath(handle->data,
1518                         smb_fname->base_name,
1519                         resolved_path);
1520         if (result != NULL) {
1521                 result_fname = synthetic_smb_fname(ctx, result, NULL, NULL, 0);
1522         }
1523
1524         SAFE_FREE(resolved_path);
1525         END_PROFILE(syscall_realpath);
1526
1527         return result_fname;
1528 }
1529
1530 static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
1531                              files_struct *fsp, int op, off_t offset,
1532                              off_t count, int type)
1533 {
1534         struct flock flock = { 0, };
1535         int ret;
1536         glfs_fd_t *glfd = NULL;
1537         bool ok = false;
1538
1539         START_PROFILE(syscall_fcntl_lock);
1540
1541         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1542         if (glfd == NULL) {
1543                 DBG_ERR("Failed to fetch gluster fd\n");
1544                 ok = false;
1545                 goto out;
1546         }
1547
1548         flock.l_type = type;
1549         flock.l_whence = SEEK_SET;
1550         flock.l_start = offset;
1551         flock.l_len = count;
1552         flock.l_pid = 0;
1553
1554         ret = glfs_posix_lock(glfd, op, &flock);
1555
1556         if (op == F_GETLK) {
1557                 /* lock query, true if someone else has locked */
1558                 if ((ret != -1) &&
1559                     (flock.l_type != F_UNLCK) &&
1560                     (flock.l_pid != 0) && (flock.l_pid != getpid())) {
1561                         ok = true;
1562                         goto out;
1563                 }
1564                 /* not me */
1565                 ok = false;
1566                 goto out;
1567         }
1568
1569         if (ret == -1) {
1570                 ok = false;
1571                 goto out;
1572         }
1573
1574         ok = true;
1575 out:
1576         END_PROFILE(syscall_fcntl_lock);
1577
1578         return ok;
1579 }
1580
1581 static int vfs_gluster_kernel_flock(struct vfs_handle_struct *handle,
1582                                     files_struct *fsp, uint32_t share_mode,
1583                                     uint32_t access_mask)
1584 {
1585         errno = ENOSYS;
1586         return -1;
1587 }
1588
1589 static int vfs_gluster_linux_setlease(struct vfs_handle_struct *handle,
1590                                       files_struct *fsp, int leasetype)
1591 {
1592         errno = ENOSYS;
1593         return -1;
1594 }
1595
1596 static bool vfs_gluster_getlock(struct vfs_handle_struct *handle,
1597                                 files_struct *fsp, off_t *poffset,
1598                                 off_t *pcount, int *ptype, pid_t *ppid)
1599 {
1600         struct flock flock = { 0, };
1601         int ret;
1602         glfs_fd_t *glfd = NULL;
1603
1604         START_PROFILE(syscall_fcntl_getlock);
1605
1606         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1607         if (glfd == NULL) {
1608                 END_PROFILE(syscall_fcntl_getlock);
1609                 DBG_ERR("Failed to fetch gluster fd\n");
1610                 return false;
1611         }
1612
1613         flock.l_type = *ptype;
1614         flock.l_whence = SEEK_SET;
1615         flock.l_start = *poffset;
1616         flock.l_len = *pcount;
1617         flock.l_pid = 0;
1618
1619         ret = glfs_posix_lock(glfd, F_GETLK, &flock);
1620
1621         if (ret == -1) {
1622                 END_PROFILE(syscall_fcntl_getlock);
1623                 return false;
1624         }
1625
1626         *ptype = flock.l_type;
1627         *poffset = flock.l_start;
1628         *pcount = flock.l_len;
1629         *ppid = flock.l_pid;
1630         END_PROFILE(syscall_fcntl_getlock);
1631
1632         return true;
1633 }
1634
1635 static int vfs_gluster_symlink(struct vfs_handle_struct *handle,
1636                                 const char *link_target,
1637                                 const struct smb_filename *new_smb_fname)
1638 {
1639         int ret;
1640
1641         START_PROFILE(syscall_symlink);
1642         ret = glfs_symlink(handle->data,
1643                         link_target,
1644                         new_smb_fname->base_name);
1645         END_PROFILE(syscall_symlink);
1646
1647         return ret;
1648 }
1649
1650 static int vfs_gluster_readlink(struct vfs_handle_struct *handle,
1651                                 const struct smb_filename *smb_fname,
1652                                 char *buf,
1653                                 size_t bufsiz)
1654 {
1655         int ret;
1656
1657         START_PROFILE(syscall_readlink);
1658         ret = glfs_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1659         END_PROFILE(syscall_readlink);
1660
1661         return ret;
1662 }
1663
1664 static int vfs_gluster_link(struct vfs_handle_struct *handle,
1665                                 const struct smb_filename *old_smb_fname,
1666                                 const struct smb_filename *new_smb_fname)
1667 {
1668         int ret;
1669
1670         START_PROFILE(syscall_link);
1671         ret = glfs_link(handle->data,
1672                         old_smb_fname->base_name,
1673                         new_smb_fname->base_name);
1674         END_PROFILE(syscall_link);
1675
1676         return ret;
1677 }
1678
1679 static int vfs_gluster_linkat(struct vfs_handle_struct *handle,
1680                                 files_struct *srcfsp,
1681                                 const struct smb_filename *old_smb_fname,
1682                                 files_struct *dstfsp,
1683                                 const struct smb_filename *new_smb_fname,
1684                                 int flags)
1685 {
1686         int ret;
1687
1688         START_PROFILE(syscall_linkat);
1689
1690         SMB_ASSERT(srcfsp == srcfsp->conn->cwd_fsp);
1691         SMB_ASSERT(dstfsp == dstfsp->conn->cwd_fsp);
1692
1693         ret = glfs_link(handle->data,
1694                         old_smb_fname->base_name,
1695                         new_smb_fname->base_name);
1696         END_PROFILE(syscall_linkat);
1697
1698         return ret;
1699 }
1700
1701 static int vfs_gluster_mknod(struct vfs_handle_struct *handle,
1702                                 const struct smb_filename *smb_fname,
1703                                 mode_t mode,
1704                                 SMB_DEV_T dev)
1705 {
1706         int ret;
1707
1708         START_PROFILE(syscall_mknod);
1709         ret = glfs_mknod(handle->data, smb_fname->base_name, mode, dev);
1710         END_PROFILE(syscall_mknod);
1711
1712         return ret;
1713 }
1714
1715 static int vfs_gluster_chflags(struct vfs_handle_struct *handle,
1716                                 const struct smb_filename *smb_fname,
1717                                 unsigned int flags)
1718 {
1719         errno = ENOSYS;
1720         return -1;
1721 }
1722
1723 static int vfs_gluster_get_real_filename(struct vfs_handle_struct *handle,
1724                                          const char *path, const char *name,
1725                                          TALLOC_CTX *mem_ctx, char **found_name)
1726 {
1727         int ret;
1728         char key_buf[GLUSTER_NAME_MAX + 64];
1729         char val_buf[GLUSTER_NAME_MAX + 1];
1730
1731         if (strlen(name) >= GLUSTER_NAME_MAX) {
1732                 errno = ENAMETOOLONG;
1733                 return -1;
1734         }
1735
1736         snprintf(key_buf, GLUSTER_NAME_MAX + 64,
1737                  "glusterfs.get_real_filename:%s", name);
1738
1739         ret = glfs_getxattr(handle->data, path, key_buf, val_buf,
1740                             GLUSTER_NAME_MAX + 1);
1741         if (ret == -1) {
1742                 if (errno == ENOATTR) {
1743                         errno = ENOENT;
1744                 }
1745                 return -1;
1746         }
1747
1748         *found_name = talloc_strdup(mem_ctx, val_buf);
1749         if (found_name[0] == NULL) {
1750                 errno = ENOMEM;
1751                 return -1;
1752         }
1753         return 0;
1754 }
1755
1756 static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle,
1757                                 const struct smb_filename *smb_fname)
1758 {
1759         return handle->conn->connectpath;
1760 }
1761
1762 /* EA Operations */
1763
1764 static ssize_t vfs_gluster_getxattr(struct vfs_handle_struct *handle,
1765                                 const struct smb_filename *smb_fname,
1766                                 const char *name,
1767                                 void *value,
1768                                 size_t size)
1769 {
1770         return glfs_getxattr(handle->data, smb_fname->base_name,
1771                              name, value, size);
1772 }
1773
1774 static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
1775                                      files_struct *fsp, const char *name,
1776                                      void *value, size_t size)
1777 {
1778         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1779         if (glfd == NULL) {
1780                 DBG_ERR("Failed to fetch gluster fd\n");
1781                 return -1;
1782         }
1783
1784         return glfs_fgetxattr(glfd, name, value, size);
1785 }
1786
1787 static ssize_t vfs_gluster_listxattr(struct vfs_handle_struct *handle,
1788                                 const struct smb_filename *smb_fname,
1789                                 char *list,
1790                                 size_t size)
1791 {
1792         return glfs_listxattr(handle->data, smb_fname->base_name, list, size);
1793 }
1794
1795 static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
1796                                       files_struct *fsp, char *list,
1797                                       size_t size)
1798 {
1799         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1800         if (glfd == NULL) {
1801                 DBG_ERR("Failed to fetch gluster fd\n");
1802                 return -1;
1803         }
1804
1805         return glfs_flistxattr(glfd, list, size);
1806 }
1807
1808 static int vfs_gluster_removexattr(struct vfs_handle_struct *handle,
1809                                 const struct smb_filename *smb_fname,
1810                                 const char *name)
1811 {
1812         return glfs_removexattr(handle->data, smb_fname->base_name, name);
1813 }
1814
1815 static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
1816                                     files_struct *fsp, const char *name)
1817 {
1818         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1819         if (glfd == NULL) {
1820                 DBG_ERR("Failed to fetch gluster fd\n");
1821                 return -1;
1822         }
1823
1824         return glfs_fremovexattr(glfd, name);
1825 }
1826
1827 static int vfs_gluster_setxattr(struct vfs_handle_struct *handle,
1828                                 const struct smb_filename *smb_fname,
1829                                 const char *name,
1830                                 const void *value, size_t size, int flags)
1831 {
1832         return glfs_setxattr(handle->data, smb_fname->base_name, name, value, size, flags);
1833 }
1834
1835 static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
1836                                  files_struct *fsp, const char *name,
1837                                  const void *value, size_t size, int flags)
1838 {
1839         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1840         if (glfd == NULL) {
1841                 DBG_ERR("Failed to fetch gluster fd\n");
1842                 return -1;
1843         }
1844
1845         return glfs_fsetxattr(glfd, name, value, size, flags);
1846 }
1847
1848 /* AIO Operations */
1849
1850 static bool vfs_gluster_aio_force(struct vfs_handle_struct *handle,
1851                                   files_struct *fsp)
1852 {
1853         return false;
1854 }
1855
1856 static struct vfs_fn_pointers glusterfs_fns = {
1857
1858         /* Disk Operations */
1859
1860         .connect_fn = vfs_gluster_connect,
1861         .disconnect_fn = vfs_gluster_disconnect,
1862         .disk_free_fn = vfs_gluster_disk_free,
1863         .get_quota_fn = vfs_gluster_get_quota,
1864         .set_quota_fn = vfs_gluster_set_quota,
1865         .statvfs_fn = vfs_gluster_statvfs,
1866         .fs_capabilities_fn = vfs_gluster_fs_capabilities,
1867
1868         .get_dfs_referrals_fn = NULL,
1869
1870         /* Directory Operations */
1871
1872         .opendir_fn = vfs_gluster_opendir,
1873         .fdopendir_fn = vfs_gluster_fdopendir,
1874         .readdir_fn = vfs_gluster_readdir,
1875         .seekdir_fn = vfs_gluster_seekdir,
1876         .telldir_fn = vfs_gluster_telldir,
1877         .rewind_dir_fn = vfs_gluster_rewinddir,
1878         .mkdir_fn = vfs_gluster_mkdir,
1879         .rmdir_fn = vfs_gluster_rmdir,
1880         .closedir_fn = vfs_gluster_closedir,
1881
1882         /* File Operations */
1883
1884         .open_fn = vfs_gluster_open,
1885         .create_file_fn = NULL,
1886         .close_fn = vfs_gluster_close,
1887         .pread_fn = vfs_gluster_pread,
1888         .pread_send_fn = vfs_gluster_pread_send,
1889         .pread_recv_fn = vfs_gluster_recv,
1890         .pwrite_fn = vfs_gluster_pwrite,
1891         .pwrite_send_fn = vfs_gluster_pwrite_send,
1892         .pwrite_recv_fn = vfs_gluster_recv,
1893         .lseek_fn = vfs_gluster_lseek,
1894         .sendfile_fn = vfs_gluster_sendfile,
1895         .recvfile_fn = vfs_gluster_recvfile,
1896         .renameat_fn = vfs_gluster_renameat,
1897         .fsync_send_fn = vfs_gluster_fsync_send,
1898         .fsync_recv_fn = vfs_gluster_fsync_recv,
1899
1900         .stat_fn = vfs_gluster_stat,
1901         .fstat_fn = vfs_gluster_fstat,
1902         .lstat_fn = vfs_gluster_lstat,
1903         .get_alloc_size_fn = vfs_gluster_get_alloc_size,
1904         .unlink_fn = vfs_gluster_unlink,
1905
1906         .chmod_fn = vfs_gluster_chmod,
1907         .fchmod_fn = vfs_gluster_fchmod,
1908         .chown_fn = vfs_gluster_chown,
1909         .fchown_fn = vfs_gluster_fchown,
1910         .lchown_fn = vfs_gluster_lchown,
1911         .chdir_fn = vfs_gluster_chdir,
1912         .getwd_fn = vfs_gluster_getwd,
1913         .ntimes_fn = vfs_gluster_ntimes,
1914         .ftruncate_fn = vfs_gluster_ftruncate,
1915         .fallocate_fn = vfs_gluster_fallocate,
1916         .lock_fn = vfs_gluster_lock,
1917         .kernel_flock_fn = vfs_gluster_kernel_flock,
1918         .linux_setlease_fn = vfs_gluster_linux_setlease,
1919         .getlock_fn = vfs_gluster_getlock,
1920         .symlink_fn = vfs_gluster_symlink,
1921         .readlink_fn = vfs_gluster_readlink,
1922         .link_fn = vfs_gluster_link,
1923         .linkat_fn = vfs_gluster_linkat,
1924         .mknod_fn = vfs_gluster_mknod,
1925         .realpath_fn = vfs_gluster_realpath,
1926         .chflags_fn = vfs_gluster_chflags,
1927         .file_id_create_fn = NULL,
1928         .streaminfo_fn = NULL,
1929         .get_real_filename_fn = vfs_gluster_get_real_filename,
1930         .connectpath_fn = vfs_gluster_connectpath,
1931
1932         .brl_lock_windows_fn = NULL,
1933         .brl_unlock_windows_fn = NULL,
1934         .strict_lock_check_fn = NULL,
1935         .translate_name_fn = NULL,
1936         .fsctl_fn = NULL,
1937
1938         /* NT ACL Operations */
1939         .fget_nt_acl_fn = NULL,
1940         .get_nt_acl_fn = NULL,
1941         .fset_nt_acl_fn = NULL,
1942         .audit_file_fn = NULL,
1943
1944         /* Posix ACL Operations */
1945         .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1946         .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1947         .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1948         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1949         .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1950         .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1951         .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1952
1953         /* EA Operations */
1954         .getxattr_fn = vfs_gluster_getxattr,
1955         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1956         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1957         .fgetxattr_fn = vfs_gluster_fgetxattr,
1958         .listxattr_fn = vfs_gluster_listxattr,
1959         .flistxattr_fn = vfs_gluster_flistxattr,
1960         .removexattr_fn = vfs_gluster_removexattr,
1961         .fremovexattr_fn = vfs_gluster_fremovexattr,
1962         .setxattr_fn = vfs_gluster_setxattr,
1963         .fsetxattr_fn = vfs_gluster_fsetxattr,
1964
1965         /* AIO Operations */
1966         .aio_force_fn = vfs_gluster_aio_force,
1967
1968         /* Durable handle Operations */
1969         .durable_cookie_fn = NULL,
1970         .durable_disconnect_fn = NULL,
1971         .durable_reconnect_fn = NULL,
1972 };
1973
1974 static_decl_vfs;
1975 NTSTATUS vfs_glusterfs_init(TALLOC_CTX *ctx)
1976 {
1977         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1978                                 "glusterfs", &glusterfs_fns);
1979 }