vfs_glusterfs: Enable caching of selinux xattr by default
[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 #include "lib/pthreadpool/pthreadpool_tevent.h"
49
50 #define DEFAULT_VOLFILE_SERVER "localhost"
51 #define GLUSTER_NAME_MAX 255
52
53 /**
54  * Helper to convert struct stat to struct stat_ex.
55  */
56 static void smb_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src)
57 {
58         ZERO_STRUCTP(dst);
59
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;
84 }
85
86 /* pre-opened glfs_t */
87
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;
95
96
97 static int glfs_set_preopened(const char *volume, const char *connectpath, glfs_t *fs)
98 {
99         struct glfs_preopened *entry = NULL;
100
101         entry = talloc_zero(NULL, struct glfs_preopened);
102         if (!entry) {
103                 errno = ENOMEM;
104                 return -1;
105         }
106
107         entry->volume = talloc_strdup(entry, volume);
108         if (!entry->volume) {
109                 talloc_free(entry);
110                 errno = ENOMEM;
111                 return -1;
112         }
113
114         entry->connectpath = talloc_strdup(entry, connectpath);
115         if (entry->connectpath == NULL) {
116                 talloc_free(entry);
117                 errno = ENOMEM;
118                 return -1;
119         }
120
121         entry->fs = fs;
122         entry->ref = 1;
123
124         DLIST_ADD(glfs_preopened, entry);
125
126         return 0;
127 }
128
129 static glfs_t *glfs_find_preopened(const char *volume, const char *connectpath)
130 {
131         struct glfs_preopened *entry = NULL;
132
133         for (entry = glfs_preopened; entry; entry = entry->next) {
134                 if (strcmp(entry->volume, volume) == 0 &&
135                     strcmp(entry->connectpath, connectpath) == 0)
136                 {
137                         entry->ref++;
138                         return entry->fs;
139                 }
140         }
141
142         return NULL;
143 }
144
145 static void glfs_clear_preopened(glfs_t *fs)
146 {
147         struct glfs_preopened *entry = NULL;
148
149         for (entry = glfs_preopened; entry; entry = entry->next) {
150                 if (entry->fs == fs) {
151                         if (--entry->ref)
152                                 return;
153
154                         DLIST_REMOVE(glfs_preopened, entry);
155
156                         glfs_fini(entry->fs);
157                         talloc_free(entry);
158                 }
159         }
160 }
161
162 static int vfs_gluster_set_volfile_servers(glfs_t *fs,
163                                            const char *volfile_servers)
164 {
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();
170
171         DBG_INFO("servers list %s\n", volfile_servers);
172
173         while (next_token_talloc(frame, &volfile_servers, &server, " \t")) {
174                 char *transport = NULL;
175                 char *host = NULL;
176                 int   port = 0;
177
178                 server_count++;
179                 DBG_INFO("server %zu %s\n", server_count, server);
180
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;
188                         }
189                         host = talloc_strdup(frame, server + 5);
190                         if (!host) {
191                                 errno = ENOMEM;
192                                 goto out;
193                         }
194                 } else {
195                         char *p = NULL;
196                         char *port_index = NULL;
197
198                         if (strncmp(server, "tcp+", 4) == 0) {
199                                 server += 4;
200                         }
201
202                         /* IPv6 is enclosed in []
203                          * ':' before ']' is part of IPv6
204                          * ':' after  ']' indicates port
205                          */
206                         p = server;
207                         if (server[0] == '[') {
208                                 server++;
209                                 p = index(server, ']');
210                                 if (p == NULL) {
211                                         /* Malformed IPv6 */
212                                         continue;
213                                 }
214                                 p[0] = '\0';
215                                 p++;
216                         }
217
218                         port_index = index(p, ':');
219
220                         if (port_index == NULL) {
221                                 port = 0;
222                         } else {
223                                 port = atoi(port_index + 1);
224                                 port_index[0] = '\0';
225                         }
226                         transport = talloc_strdup(frame, "tcp");
227                         if (!transport) {
228                                 errno = ENOMEM;
229                                 goto out;
230                         }
231                         host = talloc_strdup(frame, server);
232                         if (!host) {
233                                 errno = ENOMEM;
234                                 goto out;
235                         }
236                 }
237
238                 DBG_INFO("Calling set volfile server with params "
239                          "transport=%s, host=%s, port=%d\n", transport,
240                           host, port);
241
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++;
249                 }
250         }
251
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;
259         }
260
261         TALLOC_FREE(frame);
262         return ret;
263 }
264
265 /* Disk Operations */
266
267 static int vfs_gluster_connect(struct vfs_handle_struct *handle,
268                                const char *service,
269                                const char *user)
270 {
271         const struct loadparm_substitution *lp_sub =
272                 loadparm_s3_global_substitution();
273         const char *volfile_servers;
274         const char *volume;
275         char *logfile;
276         int loglevel;
277         glfs_t *fs = NULL;
278         TALLOC_CTX *tmp_ctx;
279         int ret = 0;
280
281         tmp_ctx = talloc_new(NULL);
282         if (tmp_ctx == NULL) {
283                 ret = -1;
284                 goto done;
285         }
286         logfile = lp_parm_substituted_string(tmp_ctx,
287                                              lp_sub,
288                                              SNUM(handle->conn),
289                                              "glusterfs",
290                                              "logfile",
291                                              NULL);
292
293         loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
294
295         volfile_servers = lp_parm_substituted_string(tmp_ctx,
296                                                      lp_sub,
297                                                      SNUM(handle->conn),
298                                                      "glusterfs",
299                                                      "volfile_server",
300                                                      NULL);
301         if (volfile_servers == NULL) {
302                 volfile_servers = DEFAULT_VOLFILE_SERVER;
303         }
304
305         volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
306                                       NULL);
307         if (volume == NULL) {
308                 volume = service;
309         }
310
311         fs = glfs_find_preopened(volume, handle->conn->connectpath);
312         if (fs) {
313                 goto done;
314         }
315
316         fs = glfs_new(volume);
317         if (fs == NULL) {
318                 ret = -1;
319                 goto done;
320         }
321
322         ret = vfs_gluster_set_volfile_servers(fs, volfile_servers);
323         if (ret < 0) {
324                 DBG_ERR("Failed to set volfile_servers from list %s\n",
325                         volfile_servers);
326                 goto done;
327         }
328
329         ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-posix-acl",
330                                      "true");
331         if (ret < 0) {
332                 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
333                 goto done;
334         }
335
336         ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-selinux",
337                                      "true");
338         if (ret < 0) {
339                 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
340                 goto done;
341         }
342
343         ret = glfs_set_xlator_option(fs, "*-snapview-client",
344                                      "snapdir-entry-path",
345                                      handle->conn->connectpath);
346         if (ret < 0) {
347                 DEBUG(0, ("%s: Failed to set xlator option:"
348                           " snapdir-entry-path\n", volume));
349                 goto done;
350         }
351
352         ret = glfs_set_logging(fs, logfile, loglevel);
353         if (ret < 0) {
354                 DEBUG(0, ("%s: Failed to set logfile %s loglevel %d\n",
355                           volume, logfile, loglevel));
356                 goto done;
357         }
358
359         ret = glfs_init(fs);
360         if (ret < 0) {
361                 DEBUG(0, ("%s: Failed to initialize volume (%s)\n",
362                           volume, strerror(errno)));
363                 goto done;
364         }
365
366         ret = glfs_set_preopened(volume, handle->conn->connectpath, fs);
367         if (ret < 0) {
368                 DEBUG(0, ("%s: Failed to register volume (%s)\n",
369                           volume, strerror(errno)));
370                 goto done;
371         }
372
373         /*
374          * The shadow_copy2 module will fail to export subdirectories
375          * of a gluster volume unless we specify the mount point,
376          * because the detection fails if the file system is not
377          * locally mounted:
378          * https://bugzilla.samba.org/show_bug.cgi?id=13091
379          */
380         lp_do_parameter(SNUM(handle->conn), "shadow:mountpoint", "/");
381
382         /*
383          * Unless we have an async implementation of getxattrat turn this off.
384          */
385         lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false");
386
387 done:
388         if (ret < 0) {
389                 if (fs)
390                         glfs_fini(fs);
391         } else {
392                 DBG_ERR("%s: Initialized volume from servers %s\n",
393                         volume, volfile_servers);
394                 handle->data = fs;
395         }
396         talloc_free(tmp_ctx);
397         return ret;
398 }
399
400 static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
401 {
402         glfs_t *fs = NULL;
403
404         fs = handle->data;
405
406         glfs_clear_preopened(fs);
407 }
408
409 static uint64_t vfs_gluster_disk_free(struct vfs_handle_struct *handle,
410                                 const struct smb_filename *smb_fname,
411                                 uint64_t *bsize_p,
412                                 uint64_t *dfree_p,
413                                 uint64_t *dsize_p)
414 {
415         struct statvfs statvfs = { 0, };
416         int ret;
417
418         ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
419         if (ret < 0) {
420                 return -1;
421         }
422
423         if (bsize_p != NULL) {
424                 *bsize_p = (uint64_t)statvfs.f_bsize; /* Block size */
425         }
426         if (dfree_p != NULL) {
427                 *dfree_p = (uint64_t)statvfs.f_bavail; /* Available Block units */
428         }
429         if (dsize_p != NULL) {
430                 *dsize_p = (uint64_t)statvfs.f_blocks; /* Total Block units */
431         }
432
433         return (uint64_t)statvfs.f_bavail;
434 }
435
436 static int vfs_gluster_get_quota(struct vfs_handle_struct *handle,
437                                 const struct smb_filename *smb_fname,
438                                 enum SMB_QUOTA_TYPE qtype,
439                                 unid_t id,
440                                 SMB_DISK_QUOTA *qt)
441 {
442         errno = ENOSYS;
443         return -1;
444 }
445
446 static int
447 vfs_gluster_set_quota(struct vfs_handle_struct *handle,
448                       enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
449 {
450         errno = ENOSYS;
451         return -1;
452 }
453
454 static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
455                                 const struct smb_filename *smb_fname,
456                                 struct vfs_statvfs_struct *vfs_statvfs)
457 {
458         struct statvfs statvfs = { 0, };
459         int ret;
460
461         ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
462         if (ret < 0) {
463                 DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
464                           smb_fname->base_name, strerror(errno)));
465                 return -1;
466         }
467
468         ZERO_STRUCTP(vfs_statvfs);
469
470         vfs_statvfs->OptimalTransferSize = statvfs.f_frsize;
471         vfs_statvfs->BlockSize = statvfs.f_bsize;
472         vfs_statvfs->TotalBlocks = statvfs.f_blocks;
473         vfs_statvfs->BlocksAvail = statvfs.f_bfree;
474         vfs_statvfs->UserBlocksAvail = statvfs.f_bavail;
475         vfs_statvfs->TotalFileNodes = statvfs.f_files;
476         vfs_statvfs->FreeFileNodes = statvfs.f_ffree;
477         vfs_statvfs->FsIdentifier = statvfs.f_fsid;
478         vfs_statvfs->FsCapabilities =
479             FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
480
481         return ret;
482 }
483
484 static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
485                                             enum timestamp_set_resolution *p_ts_res)
486 {
487         uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
488
489 #ifdef HAVE_GFAPI_VER_6
490         caps |= FILE_SUPPORTS_SPARSE_FILES;
491 #endif
492
493 #ifdef STAT_HAVE_NSEC
494         *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
495 #endif
496
497         return caps;
498 }
499
500 static glfs_fd_t *vfs_gluster_fetch_glfd(struct vfs_handle_struct *handle,
501                                          files_struct *fsp)
502 {
503         glfs_fd_t **glfd = (glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
504         if (glfd == NULL) {
505                 DBG_INFO("Failed to fetch fsp extension\n");
506                 return NULL;
507         }
508         if (*glfd == NULL) {
509                 DBG_INFO("Empty glfs_fd_t pointer\n");
510                 return NULL;
511         }
512
513         return *glfd;
514 }
515
516 static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle,
517                                   files_struct *fsp, const char *mask,
518                                   uint32_t attributes)
519 {
520         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
521         if (glfd == NULL) {
522                 DBG_ERR("Failed to fetch gluster fd\n");
523                 return NULL;
524         }
525
526         return (DIR *)glfd;
527 }
528
529 static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp)
530 {
531         int ret;
532
533         START_PROFILE(syscall_closedir);
534         ret = glfs_closedir((void *)dirp);
535         END_PROFILE(syscall_closedir);
536
537         return ret;
538 }
539
540 static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle,
541                                           DIR *dirp, SMB_STRUCT_STAT *sbuf)
542 {
543         static char direntbuf[512];
544         int ret;
545         struct stat stat;
546         struct dirent *dirent = 0;
547
548         START_PROFILE(syscall_readdir);
549         if (sbuf != NULL) {
550                 ret = glfs_readdirplus_r((void *)dirp, &stat, (void *)direntbuf,
551                                          &dirent);
552         } else {
553                 ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
554         }
555
556         if ((ret < 0) || (dirent == NULL)) {
557                 END_PROFILE(syscall_readdir);
558                 return NULL;
559         }
560
561         if (sbuf != NULL) {
562                 SET_STAT_INVALID(*sbuf);
563                 if (!S_ISLNK(stat.st_mode)) {
564                         smb_stat_ex_from_stat(sbuf, &stat);
565                 }
566         }
567
568         END_PROFILE(syscall_readdir);
569         return dirent;
570 }
571
572 static long vfs_gluster_telldir(struct vfs_handle_struct *handle, DIR *dirp)
573 {
574         long ret;
575
576         START_PROFILE(syscall_telldir);
577         ret = glfs_telldir((void *)dirp);
578         END_PROFILE(syscall_telldir);
579
580         return ret;
581 }
582
583 static void vfs_gluster_seekdir(struct vfs_handle_struct *handle, DIR *dirp,
584                                 long offset)
585 {
586         START_PROFILE(syscall_seekdir);
587         glfs_seekdir((void *)dirp, offset);
588         END_PROFILE(syscall_seekdir);
589 }
590
591 static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
592 {
593         START_PROFILE(syscall_rewinddir);
594         glfs_seekdir((void *)dirp, 0);
595         END_PROFILE(syscall_rewinddir);
596 }
597
598 static int vfs_gluster_mkdirat(struct vfs_handle_struct *handle,
599                         struct files_struct *dirfsp,
600                         const struct smb_filename *smb_fname,
601                         mode_t mode)
602 {
603         int ret;
604
605         START_PROFILE(syscall_mkdirat);
606         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
607         ret = glfs_mkdir(handle->data, smb_fname->base_name, mode);
608         END_PROFILE(syscall_mkdirat);
609
610         return ret;
611 }
612
613 static int vfs_gluster_openat(struct vfs_handle_struct *handle,
614                               const struct files_struct *dirfsp,
615                               const struct smb_filename *smb_fname,
616                               files_struct *fsp,
617                               int flags,
618                               mode_t mode)
619 {
620         glfs_fd_t *glfd;
621         glfs_fd_t **p_tmp;
622
623         START_PROFILE(syscall_openat);
624
625         /*
626          * Looks like glfs API doesn't have openat().
627          */
628         SMB_ASSERT(dirfsp->fh->fd == AT_FDCWD);
629
630         p_tmp = VFS_ADD_FSP_EXTENSION(handle, fsp, glfs_fd_t *, NULL);
631         if (p_tmp == NULL) {
632                 END_PROFILE(syscall_openat);
633                 errno = ENOMEM;
634                 return -1;
635         }
636
637         if (flags & O_DIRECTORY) {
638                 glfd = glfs_opendir(handle->data, smb_fname->base_name);
639         } else if (flags & O_CREAT) {
640                 glfd = glfs_creat(handle->data, smb_fname->base_name, flags,
641                                   mode);
642         } else {
643                 glfd = glfs_open(handle->data, smb_fname->base_name, flags);
644         }
645
646         if (glfd == NULL) {
647                 END_PROFILE(syscall_openat);
648                 /* no extension destroy_fn, so no need to save errno */
649                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
650                 return -1;
651         }
652
653         *p_tmp = glfd;
654
655         END_PROFILE(syscall_openat);
656         /* An arbitrary value for error reporting, so you know its us. */
657         return 13371337;
658 }
659
660 static int vfs_gluster_close(struct vfs_handle_struct *handle,
661                              files_struct *fsp)
662 {
663         int ret;
664         glfs_fd_t *glfd = NULL;
665
666         START_PROFILE(syscall_close);
667
668         glfd = vfs_gluster_fetch_glfd(handle, fsp);
669         if (glfd == NULL) {
670                 END_PROFILE(syscall_close);
671                 DBG_ERR("Failed to fetch gluster fd\n");
672                 return -1;
673         }
674
675         VFS_REMOVE_FSP_EXTENSION(handle, fsp);
676
677         ret = glfs_close(glfd);
678         END_PROFILE(syscall_close);
679
680         return ret;
681 }
682
683 static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
684                                  files_struct *fsp, void *data, size_t n,
685                                  off_t offset)
686 {
687         ssize_t ret;
688         glfs_fd_t *glfd = NULL;
689
690         START_PROFILE_BYTES(syscall_pread, n);
691
692         glfd = vfs_gluster_fetch_glfd(handle, fsp);
693         if (glfd == NULL) {
694                 END_PROFILE_BYTES(syscall_pread);
695                 DBG_ERR("Failed to fetch gluster fd\n");
696                 return -1;
697         }
698
699 #ifdef HAVE_GFAPI_VER_7_6
700         ret = glfs_pread(glfd, data, n, offset, 0, NULL);
701 #else
702         ret = glfs_pread(glfd, data, n, offset, 0);
703 #endif
704         END_PROFILE_BYTES(syscall_pread);
705
706         return ret;
707 }
708
709 struct vfs_gluster_pread_state {
710         ssize_t ret;
711         glfs_fd_t *fd;
712         void *buf;
713         size_t count;
714         off_t offset;
715
716         struct vfs_aio_state vfs_aio_state;
717         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
718 };
719
720 static void vfs_gluster_pread_do(void *private_data);
721 static void vfs_gluster_pread_done(struct tevent_req *subreq);
722 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state);
723
724 static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
725                                                   *handle, TALLOC_CTX *mem_ctx,
726                                                   struct tevent_context *ev,
727                                                   files_struct *fsp,
728                                                   void *data, size_t n,
729                                                   off_t offset)
730 {
731         struct vfs_gluster_pread_state *state;
732         struct tevent_req *req, *subreq;
733
734         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
735         if (glfd == NULL) {
736                 DBG_ERR("Failed to fetch gluster fd\n");
737                 return NULL;
738         }
739
740         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pread_state);
741         if (req == NULL) {
742                 return NULL;
743         }
744
745         state->ret = -1;
746         state->fd = glfd;
747         state->buf = data;
748         state->count = n;
749         state->offset = offset;
750
751         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
752                                      state->profile_bytes, n);
753         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
754
755         subreq = pthreadpool_tevent_job_send(
756                 state, ev, handle->conn->sconn->pool,
757                 vfs_gluster_pread_do, state);
758         if (tevent_req_nomem(subreq, req)) {
759                 return tevent_req_post(req, ev);
760         }
761         tevent_req_set_callback(subreq, vfs_gluster_pread_done, req);
762
763         talloc_set_destructor(state, vfs_gluster_pread_state_destructor);
764
765         return req;
766 }
767
768 static void vfs_gluster_pread_do(void *private_data)
769 {
770         struct vfs_gluster_pread_state *state = talloc_get_type_abort(
771                 private_data, struct vfs_gluster_pread_state);
772         struct timespec start_time;
773         struct timespec end_time;
774
775         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
776
777         PROFILE_TIMESTAMP(&start_time);
778
779         do {
780 #ifdef HAVE_GFAPI_VER_7_6
781                 state->ret = glfs_pread(state->fd, state->buf, state->count,
782                                         state->offset, 0, NULL);
783 #else
784                 state->ret = glfs_pread(state->fd, state->buf, state->count,
785                                         state->offset, 0);
786 #endif
787         } while ((state->ret == -1) && (errno == EINTR));
788
789         if (state->ret == -1) {
790                 state->vfs_aio_state.error = errno;
791         }
792
793         PROFILE_TIMESTAMP(&end_time);
794
795         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
796
797         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
798 }
799
800 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state)
801 {
802         return -1;
803 }
804
805 static void vfs_gluster_pread_done(struct tevent_req *subreq)
806 {
807         struct tevent_req *req = tevent_req_callback_data(
808                 subreq, struct tevent_req);
809         struct vfs_gluster_pread_state *state = tevent_req_data(
810                 req, struct vfs_gluster_pread_state);
811         int ret;
812
813         ret = pthreadpool_tevent_job_recv(subreq);
814         TALLOC_FREE(subreq);
815         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
816         talloc_set_destructor(state, NULL);
817         if (ret != 0) {
818                 if (ret != EAGAIN) {
819                         tevent_req_error(req, ret);
820                         return;
821                 }
822                 /*
823                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
824                  * means the lower level pthreadpool failed to create a new
825                  * thread. Fallback to sync processing in that case to allow
826                  * some progress for the client.
827                  */
828                 vfs_gluster_pread_do(state);
829         }
830
831         tevent_req_done(req);
832 }
833
834 static ssize_t vfs_gluster_pread_recv(struct tevent_req *req,
835                                       struct vfs_aio_state *vfs_aio_state)
836 {
837         struct vfs_gluster_pread_state *state = tevent_req_data(
838                 req, struct vfs_gluster_pread_state);
839
840         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
841                 return -1;
842         }
843
844         *vfs_aio_state = state->vfs_aio_state;
845         return state->ret;
846 }
847
848 struct vfs_gluster_pwrite_state {
849         ssize_t ret;
850         glfs_fd_t *fd;
851         const void *buf;
852         size_t count;
853         off_t offset;
854
855         struct vfs_aio_state vfs_aio_state;
856         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
857 };
858
859 static void vfs_gluster_pwrite_do(void *private_data);
860 static void vfs_gluster_pwrite_done(struct tevent_req *subreq);
861 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state);
862
863 static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
864                                                   *handle, TALLOC_CTX *mem_ctx,
865                                                   struct tevent_context *ev,
866                                                   files_struct *fsp,
867                                                   const void *data, size_t n,
868                                                   off_t offset)
869 {
870         struct tevent_req *req, *subreq;
871         struct vfs_gluster_pwrite_state *state;
872
873         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
874         if (glfd == NULL) {
875                 DBG_ERR("Failed to fetch gluster fd\n");
876                 return NULL;
877         }
878
879         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pwrite_state);
880         if (req == NULL) {
881                 return NULL;
882         }
883
884         state->ret = -1;
885         state->fd = glfd;
886         state->buf = data;
887         state->count = n;
888         state->offset = offset;
889
890         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
891                                      state->profile_bytes, n);
892         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
893
894         subreq = pthreadpool_tevent_job_send(
895                 state, ev, handle->conn->sconn->pool,
896                 vfs_gluster_pwrite_do, state);
897         if (tevent_req_nomem(subreq, req)) {
898                 return tevent_req_post(req, ev);
899         }
900         tevent_req_set_callback(subreq, vfs_gluster_pwrite_done, req);
901
902         talloc_set_destructor(state, vfs_gluster_pwrite_state_destructor);
903
904         return req;
905 }
906
907 static void vfs_gluster_pwrite_do(void *private_data)
908 {
909         struct vfs_gluster_pwrite_state *state = talloc_get_type_abort(
910                 private_data, struct vfs_gluster_pwrite_state);
911         struct timespec start_time;
912         struct timespec end_time;
913
914         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
915
916         PROFILE_TIMESTAMP(&start_time);
917
918         do {
919 #ifdef HAVE_GFAPI_VER_7_6
920                 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
921                                          state->offset, 0, NULL, NULL);
922 #else
923                 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
924                                          state->offset, 0);
925 #endif
926         } while ((state->ret == -1) && (errno == EINTR));
927
928         if (state->ret == -1) {
929                 state->vfs_aio_state.error = errno;
930         }
931
932         PROFILE_TIMESTAMP(&end_time);
933
934         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
935
936         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
937 }
938
939 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state)
940 {
941         return -1;
942 }
943
944 static void vfs_gluster_pwrite_done(struct tevent_req *subreq)
945 {
946         struct tevent_req *req = tevent_req_callback_data(
947                 subreq, struct tevent_req);
948         struct vfs_gluster_pwrite_state *state = tevent_req_data(
949                 req, struct vfs_gluster_pwrite_state);
950         int ret;
951
952         ret = pthreadpool_tevent_job_recv(subreq);
953         TALLOC_FREE(subreq);
954         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
955         talloc_set_destructor(state, NULL);
956         if (ret != 0) {
957                 if (ret != EAGAIN) {
958                         tevent_req_error(req, ret);
959                         return;
960                 }
961                 /*
962                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
963                  * means the lower level pthreadpool failed to create a new
964                  * thread. Fallback to sync processing in that case to allow
965                  * some progress for the client.
966                  */
967                 vfs_gluster_pwrite_do(state);
968         }
969
970         tevent_req_done(req);
971 }
972
973 static ssize_t vfs_gluster_pwrite_recv(struct tevent_req *req,
974                                        struct vfs_aio_state *vfs_aio_state)
975 {
976         struct vfs_gluster_pwrite_state *state = tevent_req_data(
977                 req, struct vfs_gluster_pwrite_state);
978
979         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
980                 return -1;
981         }
982
983         *vfs_aio_state = state->vfs_aio_state;
984
985         return state->ret;
986 }
987
988 static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
989                                   files_struct *fsp, const void *data,
990                                   size_t n, off_t offset)
991 {
992         ssize_t ret;
993         glfs_fd_t *glfd = NULL;
994
995         START_PROFILE_BYTES(syscall_pwrite, n);
996
997         glfd = vfs_gluster_fetch_glfd(handle, fsp);
998         if (glfd == NULL) {
999                 END_PROFILE_BYTES(syscall_pwrite);
1000                 DBG_ERR("Failed to fetch gluster fd\n");
1001                 return -1;
1002         }
1003
1004 #ifdef HAVE_GFAPI_VER_7_6
1005         ret = glfs_pwrite(glfd, data, n, offset, 0, NULL, NULL);
1006 #else
1007         ret = glfs_pwrite(glfd, data, n, offset, 0);
1008 #endif
1009         END_PROFILE_BYTES(syscall_pwrite);
1010
1011         return ret;
1012 }
1013
1014 static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
1015                                files_struct *fsp, off_t offset, int whence)
1016 {
1017         off_t ret = 0;
1018         glfs_fd_t *glfd = NULL;
1019
1020         START_PROFILE(syscall_lseek);
1021
1022         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1023         if (glfd == NULL) {
1024                 END_PROFILE(syscall_lseek);
1025                 DBG_ERR("Failed to fetch gluster fd\n");
1026                 return -1;
1027         }
1028
1029         ret = glfs_lseek(glfd, offset, whence);
1030         END_PROFILE(syscall_lseek);
1031
1032         return ret;
1033 }
1034
1035 static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd,
1036                                     files_struct *fromfsp,
1037                                     const DATA_BLOB *hdr,
1038                                     off_t offset, size_t n)
1039 {
1040         errno = ENOTSUP;
1041         return -1;
1042 }
1043
1044 static ssize_t vfs_gluster_recvfile(struct vfs_handle_struct *handle,
1045                                     int fromfd, files_struct *tofsp,
1046                                     off_t offset, size_t n)
1047 {
1048         errno = ENOTSUP;
1049         return -1;
1050 }
1051
1052 static int vfs_gluster_renameat(struct vfs_handle_struct *handle,
1053                         files_struct *srcfsp,
1054                         const struct smb_filename *smb_fname_src,
1055                         files_struct *dstfsp,
1056                         const struct smb_filename *smb_fname_dst)
1057 {
1058         int ret;
1059
1060         START_PROFILE(syscall_renameat);
1061         ret = glfs_rename(handle->data, smb_fname_src->base_name,
1062                           smb_fname_dst->base_name);
1063         END_PROFILE(syscall_renameat);
1064
1065         return ret;
1066 }
1067
1068 struct vfs_gluster_fsync_state {
1069         ssize_t ret;
1070         glfs_fd_t *fd;
1071
1072         struct vfs_aio_state vfs_aio_state;
1073         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1074 };
1075
1076 static void vfs_gluster_fsync_do(void *private_data);
1077 static void vfs_gluster_fsync_done(struct tevent_req *subreq);
1078 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state);
1079
1080 static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
1081                                                  *handle, TALLOC_CTX *mem_ctx,
1082                                                  struct tevent_context *ev,
1083                                                  files_struct *fsp)
1084 {
1085         struct tevent_req *req, *subreq;
1086         struct vfs_gluster_fsync_state *state;
1087
1088         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1089         if (glfd == NULL) {
1090                 DBG_ERR("Failed to fetch gluster fd\n");
1091                 return NULL;
1092         }
1093
1094         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_fsync_state);
1095         if (req == NULL) {
1096                 return NULL;
1097         }
1098
1099         state->ret = -1;
1100         state->fd = glfd;
1101
1102         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1103                                      state->profile_bytes, 0);
1104         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1105
1106         subreq = pthreadpool_tevent_job_send(
1107                 state, ev, handle->conn->sconn->pool, vfs_gluster_fsync_do, state);
1108         if (tevent_req_nomem(subreq, req)) {
1109                 return tevent_req_post(req, ev);
1110         }
1111         tevent_req_set_callback(subreq, vfs_gluster_fsync_done, req);
1112
1113         talloc_set_destructor(state, vfs_gluster_fsync_state_destructor);
1114
1115         return req;
1116 }
1117
1118 static void vfs_gluster_fsync_do(void *private_data)
1119 {
1120         struct vfs_gluster_fsync_state *state = talloc_get_type_abort(
1121                 private_data, struct vfs_gluster_fsync_state);
1122         struct timespec start_time;
1123         struct timespec end_time;
1124
1125         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1126
1127         PROFILE_TIMESTAMP(&start_time);
1128
1129         do {
1130 #ifdef HAVE_GFAPI_VER_7_6
1131                 state->ret = glfs_fsync(state->fd, NULL, NULL);
1132 #else
1133                 state->ret = glfs_fsync(state->fd);
1134 #endif
1135         } while ((state->ret == -1) && (errno == EINTR));
1136
1137         if (state->ret == -1) {
1138                 state->vfs_aio_state.error = errno;
1139         }
1140
1141         PROFILE_TIMESTAMP(&end_time);
1142
1143         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1144
1145         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1146 }
1147
1148 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state)
1149 {
1150         return -1;
1151 }
1152
1153 static void vfs_gluster_fsync_done(struct tevent_req *subreq)
1154 {
1155         struct tevent_req *req = tevent_req_callback_data(
1156                 subreq, struct tevent_req);
1157         struct vfs_gluster_fsync_state *state = tevent_req_data(
1158                 req, struct vfs_gluster_fsync_state);
1159         int ret;
1160
1161         ret = pthreadpool_tevent_job_recv(subreq);
1162         TALLOC_FREE(subreq);
1163         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1164         talloc_set_destructor(state, NULL);
1165         if (ret != 0) {
1166                 if (ret != EAGAIN) {
1167                         tevent_req_error(req, ret);
1168                         return;
1169                 }
1170                 /*
1171                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1172                  * means the lower level pthreadpool failed to create a new
1173                  * thread. Fallback to sync processing in that case to allow
1174                  * some progress for the client.
1175                  */
1176                 vfs_gluster_fsync_do(state);
1177         }
1178
1179         tevent_req_done(req);
1180 }
1181
1182 static int vfs_gluster_fsync_recv(struct tevent_req *req,
1183                                   struct vfs_aio_state *vfs_aio_state)
1184 {
1185         struct vfs_gluster_fsync_state *state = tevent_req_data(
1186                 req, struct vfs_gluster_fsync_state);
1187
1188         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1189                 return -1;
1190         }
1191
1192         *vfs_aio_state = state->vfs_aio_state;
1193         return state->ret;
1194 }
1195
1196 static int vfs_gluster_stat(struct vfs_handle_struct *handle,
1197                             struct smb_filename *smb_fname)
1198 {
1199         struct stat st;
1200         int ret;
1201
1202         START_PROFILE(syscall_stat);
1203         ret = glfs_stat(handle->data, smb_fname->base_name, &st);
1204         if (ret == 0) {
1205                 smb_stat_ex_from_stat(&smb_fname->st, &st);
1206         }
1207         if (ret < 0 && errno != ENOENT) {
1208                 DEBUG(0, ("glfs_stat(%s) failed: %s\n",
1209                           smb_fname->base_name, strerror(errno)));
1210         }
1211         END_PROFILE(syscall_stat);
1212
1213         return ret;
1214 }
1215
1216 static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
1217                              files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1218 {
1219         struct stat st;
1220         int ret;
1221         glfs_fd_t *glfd = NULL;
1222
1223         START_PROFILE(syscall_fstat);
1224
1225         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1226         if (glfd == NULL) {
1227                 END_PROFILE(syscall_fstat);
1228                 DBG_ERR("Failed to fetch gluster fd\n");
1229                 return -1;
1230         }
1231
1232         ret = glfs_fstat(glfd, &st);
1233         if (ret == 0) {
1234                 smb_stat_ex_from_stat(sbuf, &st);
1235         }
1236         if (ret < 0) {
1237                 DEBUG(0, ("glfs_fstat(%d) failed: %s\n",
1238                           fsp->fh->fd, strerror(errno)));
1239         }
1240         END_PROFILE(syscall_fstat);
1241
1242         return ret;
1243 }
1244
1245 static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
1246                              struct smb_filename *smb_fname)
1247 {
1248         struct stat st;
1249         int ret;
1250
1251         START_PROFILE(syscall_lstat);
1252         ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
1253         if (ret == 0) {
1254                 smb_stat_ex_from_stat(&smb_fname->st, &st);
1255         }
1256         if (ret < 0 && errno != ENOENT) {
1257                 DEBUG(0, ("glfs_lstat(%s) failed: %s\n",
1258                           smb_fname->base_name, strerror(errno)));
1259         }
1260         END_PROFILE(syscall_lstat);
1261
1262         return ret;
1263 }
1264
1265 static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle,
1266                                            files_struct *fsp,
1267                                            const SMB_STRUCT_STAT *sbuf)
1268 {
1269         uint64_t ret;
1270
1271         START_PROFILE(syscall_get_alloc_size);
1272         ret = sbuf->st_ex_blocks * 512;
1273         END_PROFILE(syscall_get_alloc_size);
1274
1275         return ret;
1276 }
1277
1278 static int vfs_gluster_unlinkat(struct vfs_handle_struct *handle,
1279                         struct files_struct *dirfsp,
1280                         const struct smb_filename *smb_fname,
1281                         int flags)
1282 {
1283         int ret;
1284
1285         START_PROFILE(syscall_unlinkat);
1286         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1287         if (flags & AT_REMOVEDIR) {
1288                 ret = glfs_rmdir(handle->data, smb_fname->base_name);
1289         } else {
1290                 ret = glfs_unlink(handle->data, smb_fname->base_name);
1291         }
1292         END_PROFILE(syscall_unlinkat);
1293
1294         return ret;
1295 }
1296
1297 static int vfs_gluster_chmod(struct vfs_handle_struct *handle,
1298                                 const struct smb_filename *smb_fname,
1299                                 mode_t mode)
1300 {
1301         int ret;
1302
1303         START_PROFILE(syscall_chmod);
1304         ret = glfs_chmod(handle->data, smb_fname->base_name, mode);
1305         END_PROFILE(syscall_chmod);
1306
1307         return ret;
1308 }
1309
1310 static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
1311                               files_struct *fsp, mode_t mode)
1312 {
1313         int ret;
1314         glfs_fd_t *glfd = NULL;
1315
1316         START_PROFILE(syscall_fchmod);
1317
1318         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1319         if (glfd == NULL) {
1320                 END_PROFILE(syscall_fchmod);
1321                 DBG_ERR("Failed to fetch gluster fd\n");
1322                 return -1;
1323         }
1324
1325         ret = glfs_fchmod(glfd, mode);
1326         END_PROFILE(syscall_fchmod);
1327
1328         return ret;
1329 }
1330
1331 static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
1332                               files_struct *fsp, uid_t uid, gid_t gid)
1333 {
1334         int ret;
1335         glfs_fd_t *glfd = NULL;
1336
1337         START_PROFILE(syscall_fchown);
1338
1339         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1340         if (glfd == NULL) {
1341                 END_PROFILE(syscall_fchown);
1342                 DBG_ERR("Failed to fetch gluster fd\n");
1343                 return -1;
1344         }
1345
1346         ret = glfs_fchown(glfd, uid, gid);
1347         END_PROFILE(syscall_fchown);
1348
1349         return ret;
1350 }
1351
1352 static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
1353                         const struct smb_filename *smb_fname,
1354                         uid_t uid,
1355                         gid_t gid)
1356 {
1357         int ret;
1358
1359         START_PROFILE(syscall_lchown);
1360         ret = glfs_lchown(handle->data, smb_fname->base_name, uid, gid);
1361         END_PROFILE(syscall_lchown);
1362
1363         return ret;
1364 }
1365
1366 static int vfs_gluster_chdir(struct vfs_handle_struct *handle,
1367                         const struct smb_filename *smb_fname)
1368 {
1369         int ret;
1370
1371         START_PROFILE(syscall_chdir);
1372         ret = glfs_chdir(handle->data, smb_fname->base_name);
1373         END_PROFILE(syscall_chdir);
1374
1375         return ret;
1376 }
1377
1378 static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
1379                                 TALLOC_CTX *ctx)
1380 {
1381         char *cwd;
1382         char *ret;
1383         struct smb_filename *smb_fname = NULL;
1384
1385         START_PROFILE(syscall_getwd);
1386
1387         cwd = SMB_CALLOC_ARRAY(char, PATH_MAX);
1388         if (cwd == NULL) {
1389                 END_PROFILE(syscall_getwd);
1390                 return NULL;
1391         }
1392
1393         ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1);
1394         END_PROFILE(syscall_getwd);
1395
1396         if (ret == NULL) {
1397                 SAFE_FREE(cwd);
1398                 return NULL;
1399         }
1400         smb_fname = synthetic_smb_fname(ctx,
1401                                         ret,
1402                                         NULL,
1403                                         NULL,
1404                                         0,
1405                                         0);
1406         SAFE_FREE(cwd);
1407         return smb_fname;
1408 }
1409
1410 static int vfs_gluster_ntimes(struct vfs_handle_struct *handle,
1411                               const struct smb_filename *smb_fname,
1412                               struct smb_file_time *ft)
1413 {
1414         int ret = -1;
1415         struct timespec times[2];
1416
1417         START_PROFILE(syscall_ntimes);
1418
1419         if (is_omit_timespec(&ft->atime)) {
1420                 times[0].tv_sec = smb_fname->st.st_ex_atime.tv_sec;
1421                 times[0].tv_nsec = smb_fname->st.st_ex_atime.tv_nsec;
1422         } else {
1423                 times[0].tv_sec = ft->atime.tv_sec;
1424                 times[0].tv_nsec = ft->atime.tv_nsec;
1425         }
1426
1427         if (is_omit_timespec(&ft->mtime)) {
1428                 times[1].tv_sec = smb_fname->st.st_ex_mtime.tv_sec;
1429                 times[1].tv_nsec = smb_fname->st.st_ex_mtime.tv_nsec;
1430         } else {
1431                 times[1].tv_sec = ft->mtime.tv_sec;
1432                 times[1].tv_nsec = ft->mtime.tv_nsec;
1433         }
1434
1435         if ((timespec_compare(&times[0],
1436                               &smb_fname->st.st_ex_atime) == 0) &&
1437             (timespec_compare(&times[1],
1438                               &smb_fname->st.st_ex_mtime) == 0)) {
1439                 END_PROFILE(syscall_ntimes);
1440                 return 0;
1441         }
1442
1443         ret = glfs_utimens(handle->data, smb_fname->base_name, times);
1444         END_PROFILE(syscall_ntimes);
1445
1446         return ret;
1447 }
1448
1449 static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle,
1450                                  files_struct *fsp, off_t offset)
1451 {
1452         int ret;
1453         glfs_fd_t *glfd = NULL;
1454
1455         START_PROFILE(syscall_ftruncate);
1456
1457         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1458         if (glfd == NULL) {
1459                 END_PROFILE(syscall_ftruncate);
1460                 DBG_ERR("Failed to fetch gluster fd\n");
1461                 return -1;
1462         }
1463
1464 #ifdef HAVE_GFAPI_VER_7_6
1465         ret = glfs_ftruncate(glfd, offset, NULL, NULL);
1466 #else
1467         ret = glfs_ftruncate(glfd, offset);
1468 #endif
1469         END_PROFILE(syscall_ftruncate);
1470
1471         return ret;
1472 }
1473
1474 static int vfs_gluster_fallocate(struct vfs_handle_struct *handle,
1475                                  struct files_struct *fsp,
1476                                  uint32_t mode,
1477                                  off_t offset, off_t len)
1478 {
1479         int ret;
1480 #ifdef HAVE_GFAPI_VER_6
1481         glfs_fd_t *glfd = NULL;
1482         int keep_size, punch_hole;
1483
1484         START_PROFILE(syscall_fallocate);
1485
1486         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1487         if (glfd == NULL) {
1488                 END_PROFILE(syscall_fallocate);
1489                 DBG_ERR("Failed to fetch gluster fd\n");
1490                 return -1;
1491         }
1492
1493         keep_size = mode & VFS_FALLOCATE_FL_KEEP_SIZE;
1494         punch_hole = mode & VFS_FALLOCATE_FL_PUNCH_HOLE;
1495
1496         mode &= ~(VFS_FALLOCATE_FL_KEEP_SIZE|VFS_FALLOCATE_FL_PUNCH_HOLE);
1497         if (mode != 0) {
1498                 END_PROFILE(syscall_fallocate);
1499                 errno = ENOTSUP;
1500                 return -1;
1501         }
1502
1503         if (punch_hole) {
1504                 ret = glfs_discard(glfd, offset, len);
1505                 if (ret != 0) {
1506                         DBG_DEBUG("glfs_discard failed: %s\n",
1507                                   strerror(errno));
1508                 }
1509         }
1510
1511         ret = glfs_fallocate(glfd, keep_size, offset, len);
1512         END_PROFILE(syscall_fallocate);
1513 #else
1514         errno = ENOTSUP;
1515         ret = -1;
1516 #endif
1517         return ret;
1518 }
1519
1520 static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handle,
1521                                 TALLOC_CTX *ctx,
1522                                 const struct smb_filename *smb_fname)
1523 {
1524         char *result = NULL;
1525         struct smb_filename *result_fname = NULL;
1526         char *resolved_path = NULL;
1527
1528         START_PROFILE(syscall_realpath);
1529
1530         resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1531         if (resolved_path == NULL) {
1532                 END_PROFILE(syscall_realpath);
1533                 errno = ENOMEM;
1534                 return NULL;
1535         }
1536
1537         result = glfs_realpath(handle->data,
1538                         smb_fname->base_name,
1539                         resolved_path);
1540         if (result != NULL) {
1541                 result_fname = synthetic_smb_fname(ctx,
1542                                                    result,
1543                                                    NULL,
1544                                                    NULL,
1545                                                    0,
1546                                                    0);
1547         }
1548
1549         SAFE_FREE(resolved_path);
1550         END_PROFILE(syscall_realpath);
1551
1552         return result_fname;
1553 }
1554
1555 static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
1556                              files_struct *fsp, int op, off_t offset,
1557                              off_t count, int type)
1558 {
1559         struct flock flock = { 0, };
1560         int ret;
1561         glfs_fd_t *glfd = NULL;
1562         bool ok = false;
1563
1564         START_PROFILE(syscall_fcntl_lock);
1565
1566         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1567         if (glfd == NULL) {
1568                 DBG_ERR("Failed to fetch gluster fd\n");
1569                 ok = false;
1570                 goto out;
1571         }
1572
1573         flock.l_type = type;
1574         flock.l_whence = SEEK_SET;
1575         flock.l_start = offset;
1576         flock.l_len = count;
1577         flock.l_pid = 0;
1578
1579         ret = glfs_posix_lock(glfd, op, &flock);
1580
1581         if (op == F_GETLK) {
1582                 /* lock query, true if someone else has locked */
1583                 if ((ret != -1) &&
1584                     (flock.l_type != F_UNLCK) &&
1585                     (flock.l_pid != 0) && (flock.l_pid != getpid())) {
1586                         ok = true;
1587                         goto out;
1588                 }
1589                 /* not me */
1590                 ok = false;
1591                 goto out;
1592         }
1593
1594         if (ret == -1) {
1595                 ok = false;
1596                 goto out;
1597         }
1598
1599         ok = true;
1600 out:
1601         END_PROFILE(syscall_fcntl_lock);
1602
1603         return ok;
1604 }
1605
1606 static int vfs_gluster_kernel_flock(struct vfs_handle_struct *handle,
1607                                     files_struct *fsp, uint32_t share_access,
1608                                     uint32_t access_mask)
1609 {
1610         errno = ENOSYS;
1611         return -1;
1612 }
1613
1614 static int vfs_gluster_fcntl(vfs_handle_struct *handle,
1615                              files_struct *fsp, int cmd, va_list cmd_arg)
1616 {
1617         /*
1618          * SMB_VFS_FCNTL() is currently only called by vfs_set_blocking() to
1619          * clear O_NONBLOCK, etc for LOCK_MAND and FIFOs. Ignore it.
1620          */
1621         if (cmd == F_GETFL) {
1622                 return 0;
1623         } else if (cmd == F_SETFL) {
1624                 va_list dup_cmd_arg;
1625                 int opt;
1626
1627                 va_copy(dup_cmd_arg, cmd_arg);
1628                 opt = va_arg(dup_cmd_arg, int);
1629                 va_end(dup_cmd_arg);
1630                 if (opt == 0) {
1631                         return 0;
1632                 }
1633                 DBG_ERR("unexpected fcntl SETFL(%d)\n", opt);
1634                 goto err_out;
1635         }
1636         DBG_ERR("unexpected fcntl: %d\n", cmd);
1637 err_out:
1638         errno = EINVAL;
1639         return -1;
1640 }
1641
1642 static int vfs_gluster_linux_setlease(struct vfs_handle_struct *handle,
1643                                       files_struct *fsp, int leasetype)
1644 {
1645         errno = ENOSYS;
1646         return -1;
1647 }
1648
1649 static bool vfs_gluster_getlock(struct vfs_handle_struct *handle,
1650                                 files_struct *fsp, off_t *poffset,
1651                                 off_t *pcount, int *ptype, pid_t *ppid)
1652 {
1653         struct flock flock = { 0, };
1654         int ret;
1655         glfs_fd_t *glfd = NULL;
1656
1657         START_PROFILE(syscall_fcntl_getlock);
1658
1659         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1660         if (glfd == NULL) {
1661                 END_PROFILE(syscall_fcntl_getlock);
1662                 DBG_ERR("Failed to fetch gluster fd\n");
1663                 return false;
1664         }
1665
1666         flock.l_type = *ptype;
1667         flock.l_whence = SEEK_SET;
1668         flock.l_start = *poffset;
1669         flock.l_len = *pcount;
1670         flock.l_pid = 0;
1671
1672         ret = glfs_posix_lock(glfd, F_GETLK, &flock);
1673
1674         if (ret == -1) {
1675                 END_PROFILE(syscall_fcntl_getlock);
1676                 return false;
1677         }
1678
1679         *ptype = flock.l_type;
1680         *poffset = flock.l_start;
1681         *pcount = flock.l_len;
1682         *ppid = flock.l_pid;
1683         END_PROFILE(syscall_fcntl_getlock);
1684
1685         return true;
1686 }
1687
1688 static int vfs_gluster_symlinkat(struct vfs_handle_struct *handle,
1689                                 const struct smb_filename *link_target,
1690                                 struct files_struct *dirfsp,
1691                                 const struct smb_filename *new_smb_fname)
1692 {
1693         int ret;
1694
1695         START_PROFILE(syscall_symlinkat);
1696         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1697         ret = glfs_symlink(handle->data,
1698                         link_target->base_name,
1699                         new_smb_fname->base_name);
1700         END_PROFILE(syscall_symlinkat);
1701
1702         return ret;
1703 }
1704
1705 static int vfs_gluster_readlinkat(struct vfs_handle_struct *handle,
1706                                 files_struct *dirfsp,
1707                                 const struct smb_filename *smb_fname,
1708                                 char *buf,
1709                                 size_t bufsiz)
1710 {
1711         int ret;
1712
1713         START_PROFILE(syscall_readlinkat);
1714         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1715         ret = glfs_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1716         END_PROFILE(syscall_readlinkat);
1717
1718         return ret;
1719 }
1720
1721 static int vfs_gluster_linkat(struct vfs_handle_struct *handle,
1722                                 files_struct *srcfsp,
1723                                 const struct smb_filename *old_smb_fname,
1724                                 files_struct *dstfsp,
1725                                 const struct smb_filename *new_smb_fname,
1726                                 int flags)
1727 {
1728         int ret;
1729
1730         START_PROFILE(syscall_linkat);
1731
1732         SMB_ASSERT(srcfsp == srcfsp->conn->cwd_fsp);
1733         SMB_ASSERT(dstfsp == dstfsp->conn->cwd_fsp);
1734
1735         ret = glfs_link(handle->data,
1736                         old_smb_fname->base_name,
1737                         new_smb_fname->base_name);
1738         END_PROFILE(syscall_linkat);
1739
1740         return ret;
1741 }
1742
1743 static int vfs_gluster_mknodat(struct vfs_handle_struct *handle,
1744                                 files_struct *dirfsp,
1745                                 const struct smb_filename *smb_fname,
1746                                 mode_t mode,
1747                                 SMB_DEV_T dev)
1748 {
1749         int ret;
1750
1751         START_PROFILE(syscall_mknodat);
1752         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1753         ret = glfs_mknod(handle->data, smb_fname->base_name, mode, dev);
1754         END_PROFILE(syscall_mknodat);
1755
1756         return ret;
1757 }
1758
1759 static int vfs_gluster_chflags(struct vfs_handle_struct *handle,
1760                                 const struct smb_filename *smb_fname,
1761                                 unsigned int flags)
1762 {
1763         errno = ENOSYS;
1764         return -1;
1765 }
1766
1767 static int vfs_gluster_get_real_filename(struct vfs_handle_struct *handle,
1768                                          const struct smb_filename *path,
1769                                          const char *name,
1770                                          TALLOC_CTX *mem_ctx,
1771                                          char **found_name)
1772 {
1773         int ret;
1774         char key_buf[GLUSTER_NAME_MAX + 64];
1775         char val_buf[GLUSTER_NAME_MAX + 1];
1776
1777         if (strlen(name) >= GLUSTER_NAME_MAX) {
1778                 errno = ENAMETOOLONG;
1779                 return -1;
1780         }
1781
1782         snprintf(key_buf, GLUSTER_NAME_MAX + 64,
1783                  "glusterfs.get_real_filename:%s", name);
1784
1785         ret = glfs_getxattr(handle->data, path->base_name, key_buf, val_buf,
1786                             GLUSTER_NAME_MAX + 1);
1787         if (ret == -1) {
1788                 if (errno == ENOATTR) {
1789                         errno = ENOENT;
1790                 }
1791                 return -1;
1792         }
1793
1794         *found_name = talloc_strdup(mem_ctx, val_buf);
1795         if (found_name[0] == NULL) {
1796                 errno = ENOMEM;
1797                 return -1;
1798         }
1799         return 0;
1800 }
1801
1802 static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle,
1803                                 const struct smb_filename *smb_fname)
1804 {
1805         return handle->conn->connectpath;
1806 }
1807
1808 /* EA Operations */
1809
1810 static ssize_t vfs_gluster_getxattr(struct vfs_handle_struct *handle,
1811                                 const struct smb_filename *smb_fname,
1812                                 const char *name,
1813                                 void *value,
1814                                 size_t size)
1815 {
1816         return glfs_getxattr(handle->data, smb_fname->base_name,
1817                              name, value, size);
1818 }
1819
1820 static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
1821                                      files_struct *fsp, const char *name,
1822                                      void *value, size_t size)
1823 {
1824         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1825         if (glfd == NULL) {
1826                 DBG_ERR("Failed to fetch gluster fd\n");
1827                 return -1;
1828         }
1829
1830         return glfs_fgetxattr(glfd, name, value, size);
1831 }
1832
1833 static ssize_t vfs_gluster_listxattr(struct vfs_handle_struct *handle,
1834                                 const struct smb_filename *smb_fname,
1835                                 char *list,
1836                                 size_t size)
1837 {
1838         return glfs_listxattr(handle->data, smb_fname->base_name, list, size);
1839 }
1840
1841 static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
1842                                       files_struct *fsp, char *list,
1843                                       size_t size)
1844 {
1845         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1846         if (glfd == NULL) {
1847                 DBG_ERR("Failed to fetch gluster fd\n");
1848                 return -1;
1849         }
1850
1851         return glfs_flistxattr(glfd, list, size);
1852 }
1853
1854 static int vfs_gluster_removexattr(struct vfs_handle_struct *handle,
1855                                 const struct smb_filename *smb_fname,
1856                                 const char *name)
1857 {
1858         return glfs_removexattr(handle->data, smb_fname->base_name, name);
1859 }
1860
1861 static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
1862                                     files_struct *fsp, const char *name)
1863 {
1864         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1865         if (glfd == NULL) {
1866                 DBG_ERR("Failed to fetch gluster fd\n");
1867                 return -1;
1868         }
1869
1870         return glfs_fremovexattr(glfd, name);
1871 }
1872
1873 static int vfs_gluster_setxattr(struct vfs_handle_struct *handle,
1874                                 const struct smb_filename *smb_fname,
1875                                 const char *name,
1876                                 const void *value, size_t size, int flags)
1877 {
1878         return glfs_setxattr(handle->data, smb_fname->base_name, name, value, size, flags);
1879 }
1880
1881 static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
1882                                  files_struct *fsp, const char *name,
1883                                  const void *value, size_t size, int flags)
1884 {
1885         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1886         if (glfd == NULL) {
1887                 DBG_ERR("Failed to fetch gluster fd\n");
1888                 return -1;
1889         }
1890
1891         return glfs_fsetxattr(glfd, name, value, size, flags);
1892 }
1893
1894 /* AIO Operations */
1895
1896 static bool vfs_gluster_aio_force(struct vfs_handle_struct *handle,
1897                                   files_struct *fsp)
1898 {
1899         return false;
1900 }
1901
1902 static NTSTATUS vfs_gluster_create_dfs_pathat(struct vfs_handle_struct *handle,
1903                                 struct files_struct *dirfsp,
1904                                 const struct smb_filename *smb_fname,
1905                                 const struct referral *reflist,
1906                                 size_t referral_count)
1907 {
1908         TALLOC_CTX *frame = talloc_stackframe();
1909         NTSTATUS status = NT_STATUS_NO_MEMORY;
1910         int ret;
1911         char *msdfs_link = NULL;
1912
1913         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1914
1915         /* Form the msdfs_link contents */
1916         msdfs_link = msdfs_link_string(frame,
1917                                         reflist,
1918                                         referral_count);
1919         if (msdfs_link == NULL) {
1920                 goto out;
1921         }
1922
1923         ret = glfs_symlink(handle->data,
1924                         msdfs_link,
1925                         smb_fname->base_name);
1926         if (ret == 0) {
1927                 status = NT_STATUS_OK;
1928         } else {
1929                 status = map_nt_error_from_unix(errno);
1930         }
1931
1932   out:
1933
1934         TALLOC_FREE(frame);
1935         return status;
1936 }
1937
1938 /*
1939  * Read and return the contents of a DFS redirect given a
1940  * pathname. A caller can pass in NULL for ppreflist and
1941  * preferral_count but still determine if this was a
1942  * DFS redirect point by getting NT_STATUS_OK back
1943  * without incurring the overhead of reading and parsing
1944  * the referral contents.
1945  */
1946
1947 static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
1948                                 TALLOC_CTX *mem_ctx,
1949                                 struct files_struct *dirfsp,
1950                                 struct smb_filename *smb_fname,
1951                                 struct referral **ppreflist,
1952                                 size_t *preferral_count)
1953 {
1954         NTSTATUS status = NT_STATUS_NO_MEMORY;
1955         size_t bufsize;
1956         char *link_target = NULL;
1957         int referral_len;
1958         bool ok;
1959 #if defined(HAVE_BROKEN_READLINK)
1960         char link_target_buf[PATH_MAX];
1961 #else
1962         char link_target_buf[7];
1963 #endif
1964         struct stat st;
1965         int ret;
1966
1967         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1968
1969         if (is_named_stream(smb_fname)) {
1970                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1971                 goto err;
1972         }
1973
1974         if (ppreflist == NULL && preferral_count == NULL) {
1975                 /*
1976                  * We're only checking if this is a DFS
1977                  * redirect. We don't need to return data.
1978                  */
1979                 bufsize = sizeof(link_target_buf);
1980                 link_target = link_target_buf;
1981         } else {
1982                 bufsize = PATH_MAX;
1983                 link_target = talloc_array(mem_ctx, char, bufsize);
1984                 if (!link_target) {
1985                         goto err;
1986                 }
1987         }
1988
1989         ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
1990         if (ret < 0) {
1991                 status = map_nt_error_from_unix(errno);
1992                 goto err;
1993         }
1994
1995         referral_len = glfs_readlink(handle->data,
1996                                 smb_fname->base_name,
1997                                 link_target,
1998                                 bufsize - 1);
1999         if (referral_len < 0) {
2000                 if (errno == EINVAL) {
2001                         DBG_INFO("%s is not a link.\n", smb_fname->base_name);
2002                         status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2003                 } else {
2004                         status = map_nt_error_from_unix(errno);
2005                         DBG_ERR("Error reading "
2006                                 "msdfs link %s: %s\n",
2007                                 smb_fname->base_name,
2008                                 strerror(errno));
2009                 }
2010                 goto err;
2011         }
2012         link_target[referral_len] = '\0';
2013
2014         DBG_INFO("%s -> %s\n",
2015                         smb_fname->base_name,
2016                         link_target);
2017
2018         if (!strnequal(link_target, "msdfs:", 6)) {
2019                 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2020                 goto err;
2021         }
2022
2023         if (ppreflist == NULL && preferral_count == NULL) {
2024                 /* Early return for checking if this is a DFS link. */
2025                 smb_stat_ex_from_stat(&smb_fname->st, &st);
2026                 return NT_STATUS_OK;
2027         }
2028
2029         ok = parse_msdfs_symlink(mem_ctx,
2030                         lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
2031                         link_target,
2032                         ppreflist,
2033                         preferral_count);
2034
2035         if (ok) {
2036                 smb_stat_ex_from_stat(&smb_fname->st, &st);
2037                 status = NT_STATUS_OK;
2038         } else {
2039                 status = NT_STATUS_NO_MEMORY;
2040         }
2041
2042   err:
2043
2044         if (link_target != link_target_buf) {
2045                 TALLOC_FREE(link_target);
2046         }
2047         return status;
2048 }
2049
2050 static struct vfs_fn_pointers glusterfs_fns = {
2051
2052         /* Disk Operations */
2053
2054         .connect_fn = vfs_gluster_connect,
2055         .disconnect_fn = vfs_gluster_disconnect,
2056         .disk_free_fn = vfs_gluster_disk_free,
2057         .get_quota_fn = vfs_gluster_get_quota,
2058         .set_quota_fn = vfs_gluster_set_quota,
2059         .statvfs_fn = vfs_gluster_statvfs,
2060         .fs_capabilities_fn = vfs_gluster_fs_capabilities,
2061
2062         .get_dfs_referrals_fn = NULL,
2063
2064         /* Directory Operations */
2065
2066         .fdopendir_fn = vfs_gluster_fdopendir,
2067         .readdir_fn = vfs_gluster_readdir,
2068         .seekdir_fn = vfs_gluster_seekdir,
2069         .telldir_fn = vfs_gluster_telldir,
2070         .rewind_dir_fn = vfs_gluster_rewinddir,
2071         .mkdirat_fn = vfs_gluster_mkdirat,
2072         .closedir_fn = vfs_gluster_closedir,
2073
2074         /* File Operations */
2075
2076         .openat_fn = vfs_gluster_openat,
2077         .create_file_fn = NULL,
2078         .close_fn = vfs_gluster_close,
2079         .pread_fn = vfs_gluster_pread,
2080         .pread_send_fn = vfs_gluster_pread_send,
2081         .pread_recv_fn = vfs_gluster_pread_recv,
2082         .pwrite_fn = vfs_gluster_pwrite,
2083         .pwrite_send_fn = vfs_gluster_pwrite_send,
2084         .pwrite_recv_fn = vfs_gluster_pwrite_recv,
2085         .lseek_fn = vfs_gluster_lseek,
2086         .sendfile_fn = vfs_gluster_sendfile,
2087         .recvfile_fn = vfs_gluster_recvfile,
2088         .renameat_fn = vfs_gluster_renameat,
2089         .fsync_send_fn = vfs_gluster_fsync_send,
2090         .fsync_recv_fn = vfs_gluster_fsync_recv,
2091
2092         .stat_fn = vfs_gluster_stat,
2093         .fstat_fn = vfs_gluster_fstat,
2094         .lstat_fn = vfs_gluster_lstat,
2095         .get_alloc_size_fn = vfs_gluster_get_alloc_size,
2096         .unlinkat_fn = vfs_gluster_unlinkat,
2097
2098         .chmod_fn = vfs_gluster_chmod,
2099         .fchmod_fn = vfs_gluster_fchmod,
2100         .fchown_fn = vfs_gluster_fchown,
2101         .lchown_fn = vfs_gluster_lchown,
2102         .chdir_fn = vfs_gluster_chdir,
2103         .getwd_fn = vfs_gluster_getwd,
2104         .ntimes_fn = vfs_gluster_ntimes,
2105         .ftruncate_fn = vfs_gluster_ftruncate,
2106         .fallocate_fn = vfs_gluster_fallocate,
2107         .lock_fn = vfs_gluster_lock,
2108         .kernel_flock_fn = vfs_gluster_kernel_flock,
2109         .fcntl_fn = vfs_gluster_fcntl,
2110         .linux_setlease_fn = vfs_gluster_linux_setlease,
2111         .getlock_fn = vfs_gluster_getlock,
2112         .symlinkat_fn = vfs_gluster_symlinkat,
2113         .readlinkat_fn = vfs_gluster_readlinkat,
2114         .linkat_fn = vfs_gluster_linkat,
2115         .mknodat_fn = vfs_gluster_mknodat,
2116         .realpath_fn = vfs_gluster_realpath,
2117         .chflags_fn = vfs_gluster_chflags,
2118         .file_id_create_fn = NULL,
2119         .streaminfo_fn = NULL,
2120         .get_real_filename_fn = vfs_gluster_get_real_filename,
2121         .connectpath_fn = vfs_gluster_connectpath,
2122         .create_dfs_pathat_fn = vfs_gluster_create_dfs_pathat,
2123         .read_dfs_pathat_fn = vfs_gluster_read_dfs_pathat,
2124
2125         .brl_lock_windows_fn = NULL,
2126         .brl_unlock_windows_fn = NULL,
2127         .strict_lock_check_fn = NULL,
2128         .translate_name_fn = NULL,
2129         .fsctl_fn = NULL,
2130
2131         /* NT ACL Operations */
2132         .fget_nt_acl_fn = NULL,
2133         .get_nt_acl_at_fn = NULL,
2134         .fset_nt_acl_fn = NULL,
2135         .audit_file_fn = NULL,
2136
2137         /* Posix ACL Operations */
2138         .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
2139         .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
2140         .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
2141         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
2142         .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
2143         .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
2144         .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
2145
2146         /* EA Operations */
2147         .getxattr_fn = vfs_gluster_getxattr,
2148         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2149         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2150         .fgetxattr_fn = vfs_gluster_fgetxattr,
2151         .listxattr_fn = vfs_gluster_listxattr,
2152         .flistxattr_fn = vfs_gluster_flistxattr,
2153         .removexattr_fn = vfs_gluster_removexattr,
2154         .fremovexattr_fn = vfs_gluster_fremovexattr,
2155         .setxattr_fn = vfs_gluster_setxattr,
2156         .fsetxattr_fn = vfs_gluster_fsetxattr,
2157
2158         /* AIO Operations */
2159         .aio_force_fn = vfs_gluster_aio_force,
2160
2161         /* Durable handle Operations */
2162         .durable_cookie_fn = NULL,
2163         .durable_disconnect_fn = NULL,
2164         .durable_reconnect_fn = NULL,
2165 };
2166
2167 static_decl_vfs;
2168 NTSTATUS vfs_glusterfs_init(TALLOC_CTX *ctx)
2169 {
2170         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2171                                 "glusterfs", &glusterfs_fns);
2172 }