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