235329f090d5e4c925b71fe6c53ef11bd8410f40
[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 #ifdef STAT_HAVE_NSEC
75         dst->st_ex_atime.tv_nsec = src->st_atime_nsec;
76         dst->st_ex_mtime.tv_nsec = src->st_mtime_nsec;
77         dst->st_ex_ctime.tv_nsec = src->st_ctime_nsec;
78         dst->st_ex_btime.tv_nsec = src->st_mtime_nsec;
79 #endif
80 }
81
82 /* pre-opened glfs_t */
83
84 static struct glfs_preopened {
85         char *volume;
86         char *connectpath;
87         glfs_t *fs;
88         int ref;
89         struct glfs_preopened *next, *prev;
90 } *glfs_preopened;
91
92
93 static int glfs_set_preopened(const char *volume, const char *connectpath, glfs_t *fs)
94 {
95         struct glfs_preopened *entry = NULL;
96
97         entry = talloc_zero(NULL, struct glfs_preopened);
98         if (!entry) {
99                 errno = ENOMEM;
100                 return -1;
101         }
102
103         entry->volume = talloc_strdup(entry, volume);
104         if (!entry->volume) {
105                 talloc_free(entry);
106                 errno = ENOMEM;
107                 return -1;
108         }
109
110         entry->connectpath = talloc_strdup(entry, connectpath);
111         if (entry->connectpath == NULL) {
112                 talloc_free(entry);
113                 errno = ENOMEM;
114                 return -1;
115         }
116
117         entry->fs = fs;
118         entry->ref = 1;
119
120         DLIST_ADD(glfs_preopened, entry);
121
122         return 0;
123 }
124
125 static glfs_t *glfs_find_preopened(const char *volume, const char *connectpath)
126 {
127         struct glfs_preopened *entry = NULL;
128
129         for (entry = glfs_preopened; entry; entry = entry->next) {
130                 if (strcmp(entry->volume, volume) == 0 &&
131                     strcmp(entry->connectpath, connectpath) == 0)
132                 {
133                         entry->ref++;
134                         return entry->fs;
135                 }
136         }
137
138         return NULL;
139 }
140
141 static void glfs_clear_preopened(glfs_t *fs)
142 {
143         struct glfs_preopened *entry = NULL;
144
145         for (entry = glfs_preopened; entry; entry = entry->next) {
146                 if (entry->fs == fs) {
147                         if (--entry->ref)
148                                 return;
149
150                         DLIST_REMOVE(glfs_preopened, entry);
151
152                         glfs_fini(entry->fs);
153                         talloc_free(entry);
154                         break;
155                 }
156         }
157 }
158
159 static int vfs_gluster_set_volfile_servers(glfs_t *fs,
160                                            const char *volfile_servers)
161 {
162         char *server = NULL;
163         size_t server_count = 0;
164         size_t server_success = 0;
165         int   ret = -1;
166         TALLOC_CTX *frame = talloc_stackframe();
167
168         DBG_INFO("servers list %s\n", volfile_servers);
169
170         while (next_token_talloc(frame, &volfile_servers, &server, " \t")) {
171                 char *transport = NULL;
172                 char *host = NULL;
173                 int   port = 0;
174
175                 server_count++;
176                 DBG_INFO("server %zu %s\n", server_count, server);
177
178                 /* Determine the transport type */
179                 if (strncmp(server, "unix+", 5) == 0) {
180                         port = 0;
181                         transport = talloc_strdup(frame, "unix");
182                         if (!transport) {
183                                 errno = ENOMEM;
184                                 goto out;
185                         }
186                         host = talloc_strdup(frame, server + 5);
187                         if (!host) {
188                                 errno = ENOMEM;
189                                 goto out;
190                         }
191                 } else {
192                         char *p = NULL;
193                         char *port_index = NULL;
194
195                         if (strncmp(server, "tcp+", 4) == 0) {
196                                 server += 4;
197                         }
198
199                         /* IPv6 is enclosed in []
200                          * ':' before ']' is part of IPv6
201                          * ':' after  ']' indicates port
202                          */
203                         p = server;
204                         if (server[0] == '[') {
205                                 server++;
206                                 p = index(server, ']');
207                                 if (p == NULL) {
208                                         /* Malformed IPv6 */
209                                         continue;
210                                 }
211                                 p[0] = '\0';
212                                 p++;
213                         }
214
215                         port_index = index(p, ':');
216
217                         if (port_index == NULL) {
218                                 port = 0;
219                         } else {
220                                 port = atoi(port_index + 1);
221                                 port_index[0] = '\0';
222                         }
223                         transport = talloc_strdup(frame, "tcp");
224                         if (!transport) {
225                                 errno = ENOMEM;
226                                 goto out;
227                         }
228                         host = talloc_strdup(frame, server);
229                         if (!host) {
230                                 errno = ENOMEM;
231                                 goto out;
232                         }
233                 }
234
235                 DBG_INFO("Calling set volfile server with params "
236                          "transport=%s, host=%s, port=%d\n", transport,
237                           host, port);
238
239                 ret = glfs_set_volfile_server(fs, transport, host, port);
240                 if (ret < 0) {
241                         DBG_WARNING("Failed to set volfile_server "
242                                     "transport=%s, host=%s, port=%d (%s)\n",
243                                     transport, host, port, strerror(errno));
244                 } else {
245                         server_success++;
246                 }
247         }
248
249 out:
250         if (server_count == 0) {
251                 ret = -1;
252         } else if (server_success < server_count) {
253                 DBG_WARNING("Failed to set %zu out of %zu servers parsed\n",
254                             server_count - server_success, server_count);
255                 ret = 0;
256         }
257
258         TALLOC_FREE(frame);
259         return ret;
260 }
261
262 /* Disk Operations */
263
264 static int check_for_write_behind_translator(TALLOC_CTX *mem_ctx,
265                                              glfs_t *fs,
266                                              const char *volume)
267 {
268         char *buf = NULL;
269         char **lines = NULL;
270         int numlines = 0;
271         int i;
272         char *option;
273         bool write_behind_present = false;
274         size_t newlen;
275         int ret;
276
277         ret = glfs_get_volfile(fs, NULL, 0);
278         if (ret == 0) {
279                 DBG_ERR("%s: Failed to get volfile for "
280                         "volume (%s): No volfile\n",
281                         volume,
282                         strerror(errno));
283                 return -1;
284         }
285         if (ret > 0) {
286                 DBG_ERR("%s: Invalid return %d for glfs_get_volfile for "
287                         "volume (%s): No volfile\n",
288                         volume,
289                         ret,
290                         strerror(errno));
291                 return -1;
292         }
293
294         newlen = 0 - ret;
295
296         buf = talloc_zero_array(mem_ctx, char, newlen);
297         if (buf == NULL) {
298                 return -1;
299         }
300
301         ret = glfs_get_volfile(fs, buf, newlen);
302         if (ret != newlen) {
303                 TALLOC_FREE(buf);
304                 DBG_ERR("%s: Failed to get volfile for volume (%s)\n",
305                         volume, strerror(errno));
306                 return -1;
307         }
308
309         option = talloc_asprintf(mem_ctx, "volume %s-write-behind", volume);
310         if (option == NULL) {
311                 TALLOC_FREE(buf);
312                 return -1;
313         }
314
315         /*
316          * file_lines_parse() plays horrible tricks with
317          * the passed-in talloc pointers and the hierarchy
318          * which makes freeing hard to get right.
319          *
320          * As we know mem_ctx is freed by the caller, after
321          * this point don't free on exit and let the caller
322          * handle it. This violates good Samba coding practice
323          * but we know we're not leaking here.
324          */
325
326         lines = file_lines_parse(buf,
327                                 newlen,
328                                 &numlines,
329                                 mem_ctx);
330         if (lines == NULL || numlines <= 0) {
331                 return -1;
332         }
333         /* On success, buf is now a talloc child of lines !! */
334
335         for (i=0; i < numlines; i++) {
336                 if (strequal(lines[i], option)) {
337                         write_behind_present = true;
338                         break;
339                 }
340         }
341
342         if (write_behind_present) {
343                 DBG_ERR("Write behind translator is enabled for "
344                         "volume (%s), refusing to connect! "
345                         "Please turn off the write behind translator by calling "
346                         "'gluster volume set %s performance.write-behind off' "
347                         "on the commandline. "
348                         "Check the vfs_glusterfs(8) manpage for "
349                         "further details.\n",
350                         volume, volume);
351                 return -1;
352         }
353
354         return 0;
355 }
356
357 static int vfs_gluster_connect(struct vfs_handle_struct *handle,
358                                const char *service,
359                                const char *user)
360 {
361         const struct loadparm_substitution *lp_sub =
362                 loadparm_s3_global_substitution();
363         const char *volfile_servers;
364         const char *volume;
365         char *logfile;
366         int loglevel;
367         glfs_t *fs = NULL;
368         TALLOC_CTX *tmp_ctx;
369         int ret = 0;
370         bool write_behind_pass_through_set = false;
371
372         tmp_ctx = talloc_new(NULL);
373         if (tmp_ctx == NULL) {
374                 ret = -1;
375                 goto done;
376         }
377         logfile = lp_parm_substituted_string(tmp_ctx,
378                                              lp_sub,
379                                              SNUM(handle->conn),
380                                              "glusterfs",
381                                              "logfile",
382                                              NULL);
383
384         loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
385
386         volfile_servers = lp_parm_substituted_string(tmp_ctx,
387                                                      lp_sub,
388                                                      SNUM(handle->conn),
389                                                      "glusterfs",
390                                                      "volfile_server",
391                                                      NULL);
392         if (volfile_servers == NULL) {
393                 volfile_servers = DEFAULT_VOLFILE_SERVER;
394         }
395
396         volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
397                                       NULL);
398         if (volume == NULL) {
399                 volume = service;
400         }
401
402         fs = glfs_find_preopened(volume, handle->conn->connectpath);
403         if (fs) {
404                 goto done;
405         }
406
407         fs = glfs_new(volume);
408         if (fs == NULL) {
409                 ret = -1;
410                 goto done;
411         }
412
413         ret = vfs_gluster_set_volfile_servers(fs, volfile_servers);
414         if (ret < 0) {
415                 DBG_ERR("Failed to set volfile_servers from list %s\n",
416                         volfile_servers);
417                 goto done;
418         }
419
420         ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-posix-acl",
421                                      "true");
422         if (ret < 0) {
423                 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
424                 goto done;
425         }
426
427         ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-selinux",
428                                      "true");
429         if (ret < 0) {
430                 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
431                 goto done;
432         }
433
434         ret = glfs_set_xlator_option(fs, "*-snapview-client",
435                                      "snapdir-entry-path",
436                                      handle->conn->connectpath);
437         if (ret < 0) {
438                 DEBUG(0, ("%s: Failed to set xlator option:"
439                           " snapdir-entry-path\n", volume));
440                 goto done;
441         }
442
443 #ifdef HAVE_GFAPI_VER_7_9
444         ret = glfs_set_xlator_option(fs, "*-write-behind", "pass-through",
445                                      "true");
446         if (ret < 0) {
447                 DBG_ERR("%s: Failed to set xlator option: pass-through\n",
448                         volume);
449                 goto done;
450         }
451         write_behind_pass_through_set = true;
452 #endif
453
454         ret = glfs_set_logging(fs, logfile, loglevel);
455         if (ret < 0) {
456                 DEBUG(0, ("%s: Failed to set logfile %s loglevel %d\n",
457                           volume, logfile, loglevel));
458                 goto done;
459         }
460
461         ret = glfs_init(fs);
462         if (ret < 0) {
463                 DEBUG(0, ("%s: Failed to initialize volume (%s)\n",
464                           volume, strerror(errno)));
465                 goto done;
466         }
467
468         if (!write_behind_pass_through_set) {
469                 ret = check_for_write_behind_translator(tmp_ctx, fs, volume);
470                 if (ret < 0) {
471                         goto done;
472                 }
473         }
474
475         ret = glfs_set_preopened(volume, handle->conn->connectpath, fs);
476         if (ret < 0) {
477                 DEBUG(0, ("%s: Failed to register volume (%s)\n",
478                           volume, strerror(errno)));
479                 goto done;
480         }
481
482         /*
483          * The shadow_copy2 module will fail to export subdirectories
484          * of a gluster volume unless we specify the mount point,
485          * because the detection fails if the file system is not
486          * locally mounted:
487          * https://bugzilla.samba.org/show_bug.cgi?id=13091
488          */
489         lp_do_parameter(SNUM(handle->conn), "shadow:mountpoint", "/");
490
491         /*
492          * Unless we have an async implementation of getxattrat turn this off.
493          */
494         lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false");
495
496 done:
497         if (ret < 0) {
498                 if (fs)
499                         glfs_fini(fs);
500         } else {
501                 DBG_ERR("%s: Initialized volume from servers %s\n",
502                         volume, volfile_servers);
503                 handle->data = fs;
504         }
505         talloc_free(tmp_ctx);
506         return ret;
507 }
508
509 static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
510 {
511         glfs_t *fs = NULL;
512
513         fs = handle->data;
514
515         glfs_clear_preopened(fs);
516 }
517
518 static uint64_t vfs_gluster_disk_free(struct vfs_handle_struct *handle,
519                                 const struct smb_filename *smb_fname,
520                                 uint64_t *bsize_p,
521                                 uint64_t *dfree_p,
522                                 uint64_t *dsize_p)
523 {
524         struct statvfs statvfs = { 0, };
525         int ret;
526
527         ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
528         if (ret < 0) {
529                 return -1;
530         }
531
532         if (bsize_p != NULL) {
533                 *bsize_p = (uint64_t)statvfs.f_bsize; /* Block size */
534         }
535         if (dfree_p != NULL) {
536                 *dfree_p = (uint64_t)statvfs.f_bavail; /* Available Block units */
537         }
538         if (dsize_p != NULL) {
539                 *dsize_p = (uint64_t)statvfs.f_blocks; /* Total Block units */
540         }
541
542         return (uint64_t)statvfs.f_bavail;
543 }
544
545 static int vfs_gluster_get_quota(struct vfs_handle_struct *handle,
546                                 const struct smb_filename *smb_fname,
547                                 enum SMB_QUOTA_TYPE qtype,
548                                 unid_t id,
549                                 SMB_DISK_QUOTA *qt)
550 {
551         errno = ENOSYS;
552         return -1;
553 }
554
555 static int
556 vfs_gluster_set_quota(struct vfs_handle_struct *handle,
557                       enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
558 {
559         errno = ENOSYS;
560         return -1;
561 }
562
563 static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
564                                 const struct smb_filename *smb_fname,
565                                 struct vfs_statvfs_struct *vfs_statvfs)
566 {
567         struct statvfs statvfs = { 0, };
568         int ret;
569
570         ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
571         if (ret < 0) {
572                 DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
573                           smb_fname->base_name, strerror(errno)));
574                 return -1;
575         }
576
577         ZERO_STRUCTP(vfs_statvfs);
578
579         vfs_statvfs->OptimalTransferSize = statvfs.f_frsize;
580         vfs_statvfs->BlockSize = statvfs.f_bsize;
581         vfs_statvfs->TotalBlocks = statvfs.f_blocks;
582         vfs_statvfs->BlocksAvail = statvfs.f_bfree;
583         vfs_statvfs->UserBlocksAvail = statvfs.f_bavail;
584         vfs_statvfs->TotalFileNodes = statvfs.f_files;
585         vfs_statvfs->FreeFileNodes = statvfs.f_ffree;
586         vfs_statvfs->FsIdentifier = statvfs.f_fsid;
587         vfs_statvfs->FsCapabilities =
588             FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
589
590         return ret;
591 }
592
593 static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
594                                             enum timestamp_set_resolution *p_ts_res)
595 {
596         uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
597
598 #ifdef HAVE_GFAPI_VER_6
599         caps |= FILE_SUPPORTS_SPARSE_FILES;
600 #endif
601
602 #ifdef STAT_HAVE_NSEC
603         *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
604 #endif
605
606         return caps;
607 }
608
609 static glfs_fd_t *vfs_gluster_fetch_glfd(struct vfs_handle_struct *handle,
610                                          const files_struct *fsp)
611 {
612         glfs_fd_t **glfd = (glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
613         if (glfd == NULL) {
614                 DBG_INFO("Failed to fetch fsp extension\n");
615                 return NULL;
616         }
617         if (*glfd == NULL) {
618                 DBG_INFO("Empty glfs_fd_t pointer\n");
619                 return NULL;
620         }
621
622         return *glfd;
623 }
624
625 static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle,
626                                   files_struct *fsp, const char *mask,
627                                   uint32_t attributes)
628 {
629         glfs_fd_t *glfd = NULL;
630
631         glfd = glfs_opendir(handle->data, fsp->fsp_name->base_name);
632         if (glfd == NULL) {
633                 return NULL;
634         }
635
636         return (DIR *)glfd;
637 }
638
639 static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp)
640 {
641         int ret;
642
643         START_PROFILE(syscall_closedir);
644         ret = glfs_closedir((void *)dirp);
645         END_PROFILE(syscall_closedir);
646
647         return ret;
648 }
649
650 static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle,
651                                           struct files_struct *dirfsp,
652                                           DIR *dirp)
653 {
654         static char direntbuf[512];
655         int ret;
656         struct dirent *dirent = 0;
657
658         START_PROFILE(syscall_readdir);
659
660         ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
661
662         if ((ret < 0) || (dirent == NULL)) {
663                 END_PROFILE(syscall_readdir);
664                 return NULL;
665         }
666
667         END_PROFILE(syscall_readdir);
668         return dirent;
669 }
670
671 static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
672 {
673         START_PROFILE(syscall_rewinddir);
674         glfs_seekdir((void *)dirp, 0);
675         END_PROFILE(syscall_rewinddir);
676 }
677
678 static int vfs_gluster_mkdirat(struct vfs_handle_struct *handle,
679                         struct files_struct *dirfsp,
680                         const struct smb_filename *smb_fname,
681                         mode_t mode)
682 {
683         int ret;
684
685 #ifdef HAVE_GFAPI_VER_7_11
686         glfs_fd_t *pglfd = NULL;
687
688         START_PROFILE(syscall_mkdirat);
689
690         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
691         if (pglfd == NULL) {
692                 END_PROFILE(syscall_mkdirat);
693                 DBG_ERR("Failed to fetch gluster fd\n");
694                 return -1;
695         }
696
697         ret = glfs_mkdirat(pglfd, smb_fname->base_name, mode);
698 #else
699         struct smb_filename *full_fname = NULL;
700
701         START_PROFILE(syscall_mkdirat);
702
703         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
704                                                   dirfsp,
705                                                   smb_fname);
706         if (full_fname == NULL) {
707                 END_PROFILE(syscall_mkdirat);
708                 return -1;
709         }
710
711         ret = glfs_mkdir(handle->data, full_fname->base_name, mode);
712
713         TALLOC_FREE(full_fname);
714 #endif
715
716         END_PROFILE(syscall_mkdirat);
717
718         return ret;
719 }
720
721 static int vfs_gluster_openat(struct vfs_handle_struct *handle,
722                               const struct files_struct *dirfsp,
723                               const struct smb_filename *smb_fname,
724                               files_struct *fsp,
725                               const struct vfs_open_how *how)
726 {
727         int flags = how->flags;
728         struct smb_filename *full_fname = NULL;
729         bool have_opath = false;
730         bool became_root = false;
731         glfs_fd_t *glfd = NULL;
732         glfs_fd_t *pglfd = NULL;
733         glfs_fd_t **p_tmp;
734
735         START_PROFILE(syscall_openat);
736
737         if (how->resolve != 0) {
738                 END_PROFILE(syscall_openat);
739                 errno = ENOSYS;
740                 return -1;
741         }
742
743         p_tmp = VFS_ADD_FSP_EXTENSION(handle, fsp, glfs_fd_t *, NULL);
744         if (p_tmp == NULL) {
745                 END_PROFILE(syscall_openat);
746                 errno = ENOMEM;
747                 return -1;
748         }
749
750 #ifdef O_PATH
751         have_opath = true;
752         if (fsp->fsp_flags.is_pathref) {
753                 flags |= O_PATH;
754         }
755 #endif
756
757         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
758                                                   dirfsp,
759                                                   smb_fname);
760         if (full_fname == NULL) {
761                 END_PROFILE(syscall_openat);
762                 return -1;
763         }
764
765         if (fsp->fsp_flags.is_pathref && !have_opath) {
766                 become_root();
767                 became_root = true;
768         }
769
770         if (fsp_get_pathref_fd(dirfsp) != AT_FDCWD) {
771 #ifdef HAVE_GFAPI_VER_7_11
772                 /*
773                  * Fetch Gluster fd for parent directory using dirfsp
774                  * before calling glfs_openat();
775                  */
776                 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
777                 if (pglfd == NULL) {
778                         END_PROFILE(syscall_openat);
779                         DBG_ERR("Failed to fetch gluster fd\n");
780                         return -1;
781                 }
782
783                 glfd = glfs_openat(pglfd,
784                                    smb_fname->base_name,
785                                    flags,
786                                    how->mode);
787 #else
788                 /*
789                  * Replace smb_fname with full_path constructed above.
790                  */
791                 smb_fname = full_fname;
792 #endif
793         }
794
795         if (pglfd == NULL) {
796                 /*
797                  * smb_fname can either be a full_path or the same one
798                  * as received from the caller. In the latter case we
799                  * are operating at current working directory.
800                  */
801                 if (flags & O_CREAT) {
802                         glfd = glfs_creat(handle->data,
803                                           smb_fname->base_name,
804                                           flags,
805                                           how->mode);
806                 } else {
807                         glfd = glfs_open(handle->data,
808                                          smb_fname->base_name,
809                                          flags);
810                 }
811         }
812
813         if (became_root) {
814                 unbecome_root();
815         }
816
817         TALLOC_FREE(full_fname);
818
819         fsp->fsp_flags.have_proc_fds = false;
820
821         if (glfd == NULL) {
822                 END_PROFILE(syscall_openat);
823                 /* no extension destroy_fn, so no need to save errno */
824                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
825                 return -1;
826         }
827
828         *p_tmp = glfd;
829
830         END_PROFILE(syscall_openat);
831         /* An arbitrary value for error reporting, so you know its us. */
832         return 13371337;
833 }
834
835 static int vfs_gluster_close(struct vfs_handle_struct *handle,
836                              files_struct *fsp)
837 {
838         int ret;
839         glfs_fd_t *glfd = NULL;
840
841         START_PROFILE(syscall_close);
842
843         glfd = vfs_gluster_fetch_glfd(handle, fsp);
844         if (glfd == NULL) {
845                 END_PROFILE(syscall_close);
846                 DBG_ERR("Failed to fetch gluster fd\n");
847                 return -1;
848         }
849
850         VFS_REMOVE_FSP_EXTENSION(handle, fsp);
851
852         ret = glfs_close(glfd);
853         END_PROFILE(syscall_close);
854
855         return ret;
856 }
857
858 static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
859                                  files_struct *fsp, void *data, size_t n,
860                                  off_t offset)
861 {
862         ssize_t ret;
863         glfs_fd_t *glfd = NULL;
864
865         START_PROFILE_BYTES(syscall_pread, n);
866
867         glfd = vfs_gluster_fetch_glfd(handle, fsp);
868         if (glfd == NULL) {
869                 END_PROFILE_BYTES(syscall_pread);
870                 DBG_ERR("Failed to fetch gluster fd\n");
871                 return -1;
872         }
873
874 #ifdef HAVE_GFAPI_VER_7_6
875         ret = glfs_pread(glfd, data, n, offset, 0, NULL);
876 #else
877         ret = glfs_pread(glfd, data, n, offset, 0);
878 #endif
879         END_PROFILE_BYTES(syscall_pread);
880
881         return ret;
882 }
883
884 struct vfs_gluster_pread_state {
885         ssize_t ret;
886         glfs_fd_t *fd;
887         void *buf;
888         size_t count;
889         off_t offset;
890
891         struct vfs_aio_state vfs_aio_state;
892         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
893 };
894
895 static void vfs_gluster_pread_do(void *private_data);
896 static void vfs_gluster_pread_done(struct tevent_req *subreq);
897 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state);
898
899 static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
900                                                   *handle, TALLOC_CTX *mem_ctx,
901                                                   struct tevent_context *ev,
902                                                   files_struct *fsp,
903                                                   void *data, size_t n,
904                                                   off_t offset)
905 {
906         struct vfs_gluster_pread_state *state;
907         struct tevent_req *req, *subreq;
908
909         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
910         if (glfd == NULL) {
911                 DBG_ERR("Failed to fetch gluster fd\n");
912                 return NULL;
913         }
914
915         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pread_state);
916         if (req == NULL) {
917                 return NULL;
918         }
919
920         state->ret = -1;
921         state->fd = glfd;
922         state->buf = data;
923         state->count = n;
924         state->offset = offset;
925
926         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
927                                      state->profile_bytes, n);
928         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
929
930         subreq = pthreadpool_tevent_job_send(
931                 state, ev, handle->conn->sconn->pool,
932                 vfs_gluster_pread_do, state);
933         if (tevent_req_nomem(subreq, req)) {
934                 return tevent_req_post(req, ev);
935         }
936         tevent_req_set_callback(subreq, vfs_gluster_pread_done, req);
937
938         talloc_set_destructor(state, vfs_gluster_pread_state_destructor);
939
940         return req;
941 }
942
943 static void vfs_gluster_pread_do(void *private_data)
944 {
945         struct vfs_gluster_pread_state *state = talloc_get_type_abort(
946                 private_data, struct vfs_gluster_pread_state);
947         struct timespec start_time;
948         struct timespec end_time;
949
950         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
951
952         PROFILE_TIMESTAMP(&start_time);
953
954         do {
955 #ifdef HAVE_GFAPI_VER_7_6
956                 state->ret = glfs_pread(state->fd, state->buf, state->count,
957                                         state->offset, 0, NULL);
958 #else
959                 state->ret = glfs_pread(state->fd, state->buf, state->count,
960                                         state->offset, 0);
961 #endif
962         } while ((state->ret == -1) && (errno == EINTR));
963
964         if (state->ret == -1) {
965                 state->vfs_aio_state.error = errno;
966         }
967
968         PROFILE_TIMESTAMP(&end_time);
969
970         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
971
972         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
973 }
974
975 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state)
976 {
977         return -1;
978 }
979
980 static void vfs_gluster_pread_done(struct tevent_req *subreq)
981 {
982         struct tevent_req *req = tevent_req_callback_data(
983                 subreq, struct tevent_req);
984         struct vfs_gluster_pread_state *state = tevent_req_data(
985                 req, struct vfs_gluster_pread_state);
986         int ret;
987
988         ret = pthreadpool_tevent_job_recv(subreq);
989         TALLOC_FREE(subreq);
990         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
991         talloc_set_destructor(state, NULL);
992         if (ret != 0) {
993                 if (ret != EAGAIN) {
994                         tevent_req_error(req, ret);
995                         return;
996                 }
997                 /*
998                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
999                  * means the lower level pthreadpool failed to create a new
1000                  * thread. Fallback to sync processing in that case to allow
1001                  * some progress for the client.
1002                  */
1003                 vfs_gluster_pread_do(state);
1004         }
1005
1006         tevent_req_done(req);
1007 }
1008
1009 static ssize_t vfs_gluster_pread_recv(struct tevent_req *req,
1010                                       struct vfs_aio_state *vfs_aio_state)
1011 {
1012         struct vfs_gluster_pread_state *state = tevent_req_data(
1013                 req, struct vfs_gluster_pread_state);
1014
1015         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1016                 return -1;
1017         }
1018
1019         *vfs_aio_state = state->vfs_aio_state;
1020         return state->ret;
1021 }
1022
1023 struct vfs_gluster_pwrite_state {
1024         ssize_t ret;
1025         glfs_fd_t *fd;
1026         const void *buf;
1027         size_t count;
1028         off_t offset;
1029
1030         struct vfs_aio_state vfs_aio_state;
1031         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1032 };
1033
1034 static void vfs_gluster_pwrite_do(void *private_data);
1035 static void vfs_gluster_pwrite_done(struct tevent_req *subreq);
1036 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state);
1037
1038 static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
1039                                                   *handle, TALLOC_CTX *mem_ctx,
1040                                                   struct tevent_context *ev,
1041                                                   files_struct *fsp,
1042                                                   const void *data, size_t n,
1043                                                   off_t offset)
1044 {
1045         struct tevent_req *req, *subreq;
1046         struct vfs_gluster_pwrite_state *state;
1047
1048         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1049         if (glfd == NULL) {
1050                 DBG_ERR("Failed to fetch gluster fd\n");
1051                 return NULL;
1052         }
1053
1054         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pwrite_state);
1055         if (req == NULL) {
1056                 return NULL;
1057         }
1058
1059         state->ret = -1;
1060         state->fd = glfd;
1061         state->buf = data;
1062         state->count = n;
1063         state->offset = offset;
1064
1065         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1066                                      state->profile_bytes, n);
1067         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1068
1069         subreq = pthreadpool_tevent_job_send(
1070                 state, ev, handle->conn->sconn->pool,
1071                 vfs_gluster_pwrite_do, state);
1072         if (tevent_req_nomem(subreq, req)) {
1073                 return tevent_req_post(req, ev);
1074         }
1075         tevent_req_set_callback(subreq, vfs_gluster_pwrite_done, req);
1076
1077         talloc_set_destructor(state, vfs_gluster_pwrite_state_destructor);
1078
1079         return req;
1080 }
1081
1082 static void vfs_gluster_pwrite_do(void *private_data)
1083 {
1084         struct vfs_gluster_pwrite_state *state = talloc_get_type_abort(
1085                 private_data, struct vfs_gluster_pwrite_state);
1086         struct timespec start_time;
1087         struct timespec end_time;
1088
1089         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1090
1091         PROFILE_TIMESTAMP(&start_time);
1092
1093         do {
1094 #ifdef HAVE_GFAPI_VER_7_6
1095                 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
1096                                          state->offset, 0, NULL, NULL);
1097 #else
1098                 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
1099                                          state->offset, 0);
1100 #endif
1101         } while ((state->ret == -1) && (errno == EINTR));
1102
1103         if (state->ret == -1) {
1104                 state->vfs_aio_state.error = errno;
1105         }
1106
1107         PROFILE_TIMESTAMP(&end_time);
1108
1109         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1110
1111         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1112 }
1113
1114 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state)
1115 {
1116         return -1;
1117 }
1118
1119 static void vfs_gluster_pwrite_done(struct tevent_req *subreq)
1120 {
1121         struct tevent_req *req = tevent_req_callback_data(
1122                 subreq, struct tevent_req);
1123         struct vfs_gluster_pwrite_state *state = tevent_req_data(
1124                 req, struct vfs_gluster_pwrite_state);
1125         int ret;
1126
1127         ret = pthreadpool_tevent_job_recv(subreq);
1128         TALLOC_FREE(subreq);
1129         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1130         talloc_set_destructor(state, NULL);
1131         if (ret != 0) {
1132                 if (ret != EAGAIN) {
1133                         tevent_req_error(req, ret);
1134                         return;
1135                 }
1136                 /*
1137                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1138                  * means the lower level pthreadpool failed to create a new
1139                  * thread. Fallback to sync processing in that case to allow
1140                  * some progress for the client.
1141                  */
1142                 vfs_gluster_pwrite_do(state);
1143         }
1144
1145         tevent_req_done(req);
1146 }
1147
1148 static ssize_t vfs_gluster_pwrite_recv(struct tevent_req *req,
1149                                        struct vfs_aio_state *vfs_aio_state)
1150 {
1151         struct vfs_gluster_pwrite_state *state = tevent_req_data(
1152                 req, struct vfs_gluster_pwrite_state);
1153
1154         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1155                 return -1;
1156         }
1157
1158         *vfs_aio_state = state->vfs_aio_state;
1159
1160         return state->ret;
1161 }
1162
1163 static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
1164                                   files_struct *fsp, const void *data,
1165                                   size_t n, off_t offset)
1166 {
1167         ssize_t ret;
1168         glfs_fd_t *glfd = NULL;
1169
1170         START_PROFILE_BYTES(syscall_pwrite, n);
1171
1172         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1173         if (glfd == NULL) {
1174                 END_PROFILE_BYTES(syscall_pwrite);
1175                 DBG_ERR("Failed to fetch gluster fd\n");
1176                 return -1;
1177         }
1178
1179 #ifdef HAVE_GFAPI_VER_7_6
1180         ret = glfs_pwrite(glfd, data, n, offset, 0, NULL, NULL);
1181 #else
1182         ret = glfs_pwrite(glfd, data, n, offset, 0);
1183 #endif
1184         END_PROFILE_BYTES(syscall_pwrite);
1185
1186         return ret;
1187 }
1188
1189 static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
1190                                files_struct *fsp, off_t offset, int whence)
1191 {
1192         off_t ret = 0;
1193         glfs_fd_t *glfd = NULL;
1194
1195         START_PROFILE(syscall_lseek);
1196
1197         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1198         if (glfd == NULL) {
1199                 END_PROFILE(syscall_lseek);
1200                 DBG_ERR("Failed to fetch gluster fd\n");
1201                 return -1;
1202         }
1203
1204         ret = glfs_lseek(glfd, offset, whence);
1205         END_PROFILE(syscall_lseek);
1206
1207         return ret;
1208 }
1209
1210 static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd,
1211                                     files_struct *fromfsp,
1212                                     const DATA_BLOB *hdr,
1213                                     off_t offset, size_t n)
1214 {
1215         errno = ENOTSUP;
1216         return -1;
1217 }
1218
1219 static ssize_t vfs_gluster_recvfile(struct vfs_handle_struct *handle,
1220                                     int fromfd, files_struct *tofsp,
1221                                     off_t offset, size_t n)
1222 {
1223         errno = ENOTSUP;
1224         return -1;
1225 }
1226
1227 static int vfs_gluster_renameat(struct vfs_handle_struct *handle,
1228                         files_struct *srcfsp,
1229                         const struct smb_filename *smb_fname_src,
1230                         files_struct *dstfsp,
1231                         const struct smb_filename *smb_fname_dst)
1232 {
1233         int ret;
1234
1235 #ifdef HAVE_GFAPI_VER_7_11
1236         glfs_fd_t *src_pglfd = NULL;
1237         glfs_fd_t *dst_pglfd = NULL;
1238
1239         START_PROFILE(syscall_renameat);
1240
1241         src_pglfd = vfs_gluster_fetch_glfd(handle, srcfsp);
1242         if (src_pglfd == NULL) {
1243                 END_PROFILE(syscall_renameat);
1244                 DBG_ERR("Failed to fetch gluster fd\n");
1245                 return -1;
1246         }
1247
1248         dst_pglfd = vfs_gluster_fetch_glfd(handle, dstfsp);
1249         if (dst_pglfd == NULL) {
1250                 END_PROFILE(syscall_renameat);
1251                 DBG_ERR("Failed to fetch gluster fd\n");
1252                 return -1;
1253         }
1254
1255         ret = glfs_renameat(src_pglfd, smb_fname_src->base_name,
1256                             dst_pglfd, smb_fname_dst->base_name);
1257 #else
1258         struct smb_filename *full_fname_src = NULL;
1259         struct smb_filename *full_fname_dst = NULL;
1260
1261         START_PROFILE(syscall_renameat);
1262
1263         full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
1264                                                       srcfsp,
1265                                                       smb_fname_src);
1266         if (full_fname_src == NULL) {
1267                 END_PROFILE(syscall_renameat);
1268                 errno = ENOMEM;
1269                 return -1;
1270         }
1271
1272         full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
1273                                                       dstfsp,
1274                                                       smb_fname_dst);
1275         if (full_fname_dst == NULL) {
1276                 END_PROFILE(syscall_renameat);
1277                 TALLOC_FREE(full_fname_src);
1278                 errno = ENOMEM;
1279                 return -1;
1280         }
1281         ret = glfs_rename(handle->data,
1282                           full_fname_src->base_name,
1283                           full_fname_dst->base_name);
1284
1285         TALLOC_FREE(full_fname_src);
1286         TALLOC_FREE(full_fname_dst);
1287 #endif
1288
1289         END_PROFILE(syscall_renameat);
1290
1291         return ret;
1292 }
1293
1294 struct vfs_gluster_fsync_state {
1295         ssize_t ret;
1296         glfs_fd_t *fd;
1297
1298         struct vfs_aio_state vfs_aio_state;
1299         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1300 };
1301
1302 static void vfs_gluster_fsync_do(void *private_data);
1303 static void vfs_gluster_fsync_done(struct tevent_req *subreq);
1304 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state);
1305
1306 static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
1307                                                  *handle, TALLOC_CTX *mem_ctx,
1308                                                  struct tevent_context *ev,
1309                                                  files_struct *fsp)
1310 {
1311         struct tevent_req *req, *subreq;
1312         struct vfs_gluster_fsync_state *state;
1313
1314         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1315         if (glfd == NULL) {
1316                 DBG_ERR("Failed to fetch gluster fd\n");
1317                 return NULL;
1318         }
1319
1320         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_fsync_state);
1321         if (req == NULL) {
1322                 return NULL;
1323         }
1324
1325         state->ret = -1;
1326         state->fd = glfd;
1327
1328         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1329                                      state->profile_bytes, 0);
1330         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1331
1332         subreq = pthreadpool_tevent_job_send(
1333                 state, ev, handle->conn->sconn->pool, vfs_gluster_fsync_do, state);
1334         if (tevent_req_nomem(subreq, req)) {
1335                 return tevent_req_post(req, ev);
1336         }
1337         tevent_req_set_callback(subreq, vfs_gluster_fsync_done, req);
1338
1339         talloc_set_destructor(state, vfs_gluster_fsync_state_destructor);
1340
1341         return req;
1342 }
1343
1344 static void vfs_gluster_fsync_do(void *private_data)
1345 {
1346         struct vfs_gluster_fsync_state *state = talloc_get_type_abort(
1347                 private_data, struct vfs_gluster_fsync_state);
1348         struct timespec start_time;
1349         struct timespec end_time;
1350
1351         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1352
1353         PROFILE_TIMESTAMP(&start_time);
1354
1355         do {
1356 #ifdef HAVE_GFAPI_VER_7_6
1357                 state->ret = glfs_fsync(state->fd, NULL, NULL);
1358 #else
1359                 state->ret = glfs_fsync(state->fd);
1360 #endif
1361         } while ((state->ret == -1) && (errno == EINTR));
1362
1363         if (state->ret == -1) {
1364                 state->vfs_aio_state.error = errno;
1365         }
1366
1367         PROFILE_TIMESTAMP(&end_time);
1368
1369         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1370
1371         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1372 }
1373
1374 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state)
1375 {
1376         return -1;
1377 }
1378
1379 static void vfs_gluster_fsync_done(struct tevent_req *subreq)
1380 {
1381         struct tevent_req *req = tevent_req_callback_data(
1382                 subreq, struct tevent_req);
1383         struct vfs_gluster_fsync_state *state = tevent_req_data(
1384                 req, struct vfs_gluster_fsync_state);
1385         int ret;
1386
1387         ret = pthreadpool_tevent_job_recv(subreq);
1388         TALLOC_FREE(subreq);
1389         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1390         talloc_set_destructor(state, NULL);
1391         if (ret != 0) {
1392                 if (ret != EAGAIN) {
1393                         tevent_req_error(req, ret);
1394                         return;
1395                 }
1396                 /*
1397                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1398                  * means the lower level pthreadpool failed to create a new
1399                  * thread. Fallback to sync processing in that case to allow
1400                  * some progress for the client.
1401                  */
1402                 vfs_gluster_fsync_do(state);
1403         }
1404
1405         tevent_req_done(req);
1406 }
1407
1408 static int vfs_gluster_fsync_recv(struct tevent_req *req,
1409                                   struct vfs_aio_state *vfs_aio_state)
1410 {
1411         struct vfs_gluster_fsync_state *state = tevent_req_data(
1412                 req, struct vfs_gluster_fsync_state);
1413
1414         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1415                 return -1;
1416         }
1417
1418         *vfs_aio_state = state->vfs_aio_state;
1419         return state->ret;
1420 }
1421
1422 static int vfs_gluster_stat(struct vfs_handle_struct *handle,
1423                             struct smb_filename *smb_fname)
1424 {
1425         struct stat st;
1426         int ret;
1427
1428         START_PROFILE(syscall_stat);
1429         ret = glfs_stat(handle->data, smb_fname->base_name, &st);
1430         if (ret == 0) {
1431                 smb_stat_ex_from_stat(&smb_fname->st, &st);
1432         }
1433         if (ret < 0 && errno != ENOENT) {
1434                 DEBUG(0, ("glfs_stat(%s) failed: %s\n",
1435                           smb_fname->base_name, strerror(errno)));
1436         }
1437         END_PROFILE(syscall_stat);
1438
1439         return ret;
1440 }
1441
1442 static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
1443                              files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1444 {
1445         struct stat st;
1446         int ret;
1447         glfs_fd_t *glfd = NULL;
1448
1449         START_PROFILE(syscall_fstat);
1450
1451         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1452         if (glfd == NULL) {
1453                 END_PROFILE(syscall_fstat);
1454                 DBG_ERR("Failed to fetch gluster fd\n");
1455                 return -1;
1456         }
1457
1458         ret = glfs_fstat(glfd, &st);
1459         if (ret == 0) {
1460                 smb_stat_ex_from_stat(sbuf, &st);
1461         }
1462         if (ret < 0) {
1463                 DEBUG(0, ("glfs_fstat(%d) failed: %s\n",
1464                           fsp_get_io_fd(fsp), strerror(errno)));
1465         }
1466         END_PROFILE(syscall_fstat);
1467
1468         return ret;
1469 }
1470
1471 static int vfs_gluster_fstatat(struct vfs_handle_struct *handle,
1472                                const struct files_struct *dirfsp,
1473                                const struct smb_filename *smb_fname,
1474                                SMB_STRUCT_STAT *sbuf,
1475                                int flags)
1476 {
1477         struct stat st;
1478         int ret;
1479
1480 #ifdef HAVE_GFAPI_VER_7_11
1481         glfs_fd_t *pglfd = NULL;
1482
1483         START_PROFILE(syscall_fstatat);
1484
1485         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
1486         if (pglfd == NULL) {
1487                 END_PROFILE(syscall_fstatat);
1488                 DBG_ERR("Failed to fetch gluster fd\n");
1489                 return -1;
1490         }
1491
1492         ret = glfs_fstatat(pglfd, smb_fname->base_name, &st, flags);
1493 #else
1494         struct smb_filename *full_fname = NULL;
1495
1496         START_PROFILE(syscall_fstatat);
1497
1498         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1499                                                   dirfsp,
1500                                                   smb_fname);
1501         if (full_fname == NULL) {
1502                 END_PROFILE(syscall_fstatat);
1503                 return -1;
1504         }
1505
1506         ret = glfs_stat(handle->data, full_fname->base_name, &st);
1507
1508         TALLOC_FREE(full_fname->base_name);
1509 #endif
1510
1511         if (ret == 0) {
1512                 smb_stat_ex_from_stat(sbuf, &st);
1513         }
1514
1515         END_PROFILE(syscall_fstatat);
1516
1517         return ret;
1518 }
1519
1520 static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
1521                              struct smb_filename *smb_fname)
1522 {
1523         struct stat st;
1524         int ret;
1525
1526         START_PROFILE(syscall_lstat);
1527         ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
1528         if (ret == 0) {
1529                 smb_stat_ex_from_stat(&smb_fname->st, &st);
1530         }
1531         if (ret < 0 && errno != ENOENT) {
1532                 DEBUG(0, ("glfs_lstat(%s) failed: %s\n",
1533                           smb_fname->base_name, strerror(errno)));
1534         }
1535         END_PROFILE(syscall_lstat);
1536
1537         return ret;
1538 }
1539
1540 static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle,
1541                                            files_struct *fsp,
1542                                            const SMB_STRUCT_STAT *sbuf)
1543 {
1544         uint64_t ret;
1545
1546         START_PROFILE(syscall_get_alloc_size);
1547         ret = sbuf->st_ex_blocks * 512;
1548         END_PROFILE(syscall_get_alloc_size);
1549
1550         return ret;
1551 }
1552
1553 static int vfs_gluster_unlinkat(struct vfs_handle_struct *handle,
1554                         struct files_struct *dirfsp,
1555                         const struct smb_filename *smb_fname,
1556                         int flags)
1557 {
1558         int ret;
1559
1560 #ifdef HAVE_GFAPI_VER_7_11
1561         glfs_fd_t *pglfd = NULL;
1562
1563         START_PROFILE(syscall_unlinkat);
1564
1565         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
1566         if (pglfd == NULL) {
1567                 END_PROFILE(syscall_unlinkat);
1568                 DBG_ERR("Failed to fetch gluster fd\n");
1569                 return -1;
1570         }
1571
1572         ret = glfs_unlinkat(pglfd, smb_fname->base_name, flags);
1573 #else
1574         struct smb_filename *full_fname = NULL;
1575
1576         START_PROFILE(syscall_unlinkat);
1577
1578         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1579                                                   dirfsp,
1580                                                   smb_fname);
1581         if (full_fname == NULL) {
1582                 END_PROFILE(syscall_unlinkat);
1583                 return -1;
1584         }
1585
1586         if (flags & AT_REMOVEDIR) {
1587                 ret = glfs_rmdir(handle->data, full_fname->base_name);
1588         } else {
1589                 ret = glfs_unlink(handle->data, full_fname->base_name);
1590         }
1591
1592         TALLOC_FREE(full_fname);
1593 #endif
1594
1595         END_PROFILE(syscall_unlinkat);
1596
1597         return ret;
1598 }
1599
1600 static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
1601                               files_struct *fsp, mode_t mode)
1602 {
1603         int ret;
1604         glfs_fd_t *glfd = NULL;
1605
1606         START_PROFILE(syscall_fchmod);
1607
1608         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1609         if (glfd == NULL) {
1610                 END_PROFILE(syscall_fchmod);
1611                 DBG_ERR("Failed to fetch gluster fd\n");
1612                 return -1;
1613         }
1614
1615         if (!fsp->fsp_flags.is_pathref) {
1616                 /*
1617                  * We can use an io_fd to remove xattrs.
1618                  */
1619                 ret = glfs_fchmod(glfd, mode);
1620         } else {
1621                 /*
1622                  * This is no longer a handle based call.
1623                  */
1624                 ret = glfs_chmod(handle->data, fsp->fsp_name->base_name, mode);
1625         }
1626         END_PROFILE(syscall_fchmod);
1627
1628         return ret;
1629 }
1630
1631 static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
1632                               files_struct *fsp, uid_t uid, gid_t gid)
1633 {
1634         int ret;
1635         glfs_fd_t *glfd = NULL;
1636
1637         START_PROFILE(syscall_fchown);
1638
1639         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1640         if (glfd == NULL) {
1641                 END_PROFILE(syscall_fchown);
1642                 DBG_ERR("Failed to fetch gluster fd\n");
1643                 return -1;
1644         }
1645
1646         ret = glfs_fchown(glfd, uid, gid);
1647         END_PROFILE(syscall_fchown);
1648
1649         return ret;
1650 }
1651
1652 static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
1653                         const struct smb_filename *smb_fname,
1654                         uid_t uid,
1655                         gid_t gid)
1656 {
1657         int ret;
1658
1659         START_PROFILE(syscall_lchown);
1660         ret = glfs_lchown(handle->data, smb_fname->base_name, uid, gid);
1661         END_PROFILE(syscall_lchown);
1662
1663         return ret;
1664 }
1665
1666 static int vfs_gluster_chdir(struct vfs_handle_struct *handle,
1667                         const struct smb_filename *smb_fname)
1668 {
1669         int ret;
1670
1671         START_PROFILE(syscall_chdir);
1672         ret = glfs_chdir(handle->data, smb_fname->base_name);
1673         END_PROFILE(syscall_chdir);
1674
1675         return ret;
1676 }
1677
1678 static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
1679                                 TALLOC_CTX *ctx)
1680 {
1681         char cwd[PATH_MAX] = { '\0' };
1682         char *ret;
1683         struct smb_filename *smb_fname = NULL;
1684
1685         START_PROFILE(syscall_getwd);
1686
1687         ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1);
1688         END_PROFILE(syscall_getwd);
1689
1690         if (ret == NULL) {
1691                 return NULL;
1692         }
1693         smb_fname = synthetic_smb_fname(ctx,
1694                                         ret,
1695                                         NULL,
1696                                         NULL,
1697                                         0,
1698                                         0);
1699         return smb_fname;
1700 }
1701
1702 static int vfs_gluster_fntimes(struct vfs_handle_struct *handle,
1703                                files_struct *fsp,
1704                                struct smb_file_time *ft)
1705 {
1706         int ret = -1;
1707         struct timespec times[2];
1708         glfs_fd_t *glfd = NULL;
1709
1710         START_PROFILE(syscall_fntimes);
1711
1712         if (is_omit_timespec(&ft->atime)) {
1713                 times[0].tv_sec = fsp->fsp_name->st.st_ex_atime.tv_sec;
1714                 times[0].tv_nsec = fsp->fsp_name->st.st_ex_atime.tv_nsec;
1715         } else {
1716                 times[0].tv_sec = ft->atime.tv_sec;
1717                 times[0].tv_nsec = ft->atime.tv_nsec;
1718         }
1719
1720         if (is_omit_timespec(&ft->mtime)) {
1721                 times[1].tv_sec = fsp->fsp_name->st.st_ex_mtime.tv_sec;
1722                 times[1].tv_nsec = fsp->fsp_name->st.st_ex_mtime.tv_nsec;
1723         } else {
1724                 times[1].tv_sec = ft->mtime.tv_sec;
1725                 times[1].tv_nsec = ft->mtime.tv_nsec;
1726         }
1727
1728         if ((timespec_compare(&times[0],
1729                               &fsp->fsp_name->st.st_ex_atime) == 0) &&
1730             (timespec_compare(&times[1],
1731                               &fsp->fsp_name->st.st_ex_mtime) == 0)) {
1732                 END_PROFILE(syscall_fntimes);
1733                 return 0;
1734         }
1735
1736         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1737         if (glfd == NULL) {
1738                 END_PROFILE(syscall_fntimes);
1739                 DBG_ERR("Failed to fetch gluster fd\n");
1740                 return -1;
1741         }
1742
1743         if (!fsp->fsp_flags.is_pathref) {
1744                 ret = glfs_futimens(glfd, times);
1745         } else {
1746                 ret = glfs_utimens(handle->data,
1747                                    fsp->fsp_name->base_name,
1748                                    times);
1749         }
1750         END_PROFILE(syscall_fntimes);
1751
1752         return ret;
1753 }
1754
1755 static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle,
1756                                  files_struct *fsp, off_t offset)
1757 {
1758         int ret;
1759         glfs_fd_t *glfd = NULL;
1760
1761         START_PROFILE(syscall_ftruncate);
1762
1763         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1764         if (glfd == NULL) {
1765                 END_PROFILE(syscall_ftruncate);
1766                 DBG_ERR("Failed to fetch gluster fd\n");
1767                 return -1;
1768         }
1769
1770 #ifdef HAVE_GFAPI_VER_7_6
1771         ret = glfs_ftruncate(glfd, offset, NULL, NULL);
1772 #else
1773         ret = glfs_ftruncate(glfd, offset);
1774 #endif
1775         END_PROFILE(syscall_ftruncate);
1776
1777         return ret;
1778 }
1779
1780 static int vfs_gluster_fallocate(struct vfs_handle_struct *handle,
1781                                  struct files_struct *fsp,
1782                                  uint32_t mode,
1783                                  off_t offset, off_t len)
1784 {
1785         int ret;
1786 #ifdef HAVE_GFAPI_VER_6
1787         glfs_fd_t *glfd = NULL;
1788         int keep_size, punch_hole;
1789
1790         START_PROFILE(syscall_fallocate);
1791
1792         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1793         if (glfd == NULL) {
1794                 END_PROFILE(syscall_fallocate);
1795                 DBG_ERR("Failed to fetch gluster fd\n");
1796                 return -1;
1797         }
1798
1799         keep_size = mode & VFS_FALLOCATE_FL_KEEP_SIZE;
1800         punch_hole = mode & VFS_FALLOCATE_FL_PUNCH_HOLE;
1801
1802         mode &= ~(VFS_FALLOCATE_FL_KEEP_SIZE|VFS_FALLOCATE_FL_PUNCH_HOLE);
1803         if (mode != 0) {
1804                 END_PROFILE(syscall_fallocate);
1805                 errno = ENOTSUP;
1806                 return -1;
1807         }
1808
1809         if (punch_hole) {
1810                 ret = glfs_discard(glfd, offset, len);
1811                 if (ret != 0) {
1812                         DBG_DEBUG("glfs_discard failed: %s\n",
1813                                   strerror(errno));
1814                 }
1815         }
1816
1817         ret = glfs_fallocate(glfd, keep_size, offset, len);
1818         END_PROFILE(syscall_fallocate);
1819 #else
1820         errno = ENOTSUP;
1821         ret = -1;
1822 #endif
1823         return ret;
1824 }
1825
1826 static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handle,
1827                                 TALLOC_CTX *ctx,
1828                                 const struct smb_filename *smb_fname)
1829 {
1830         char *result = NULL;
1831         struct smb_filename *result_fname = NULL;
1832         char *resolved_path = NULL;
1833
1834         START_PROFILE(syscall_realpath);
1835
1836         resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1837         if (resolved_path == NULL) {
1838                 END_PROFILE(syscall_realpath);
1839                 errno = ENOMEM;
1840                 return NULL;
1841         }
1842
1843         result = glfs_realpath(handle->data,
1844                         smb_fname->base_name,
1845                         resolved_path);
1846         if (result != NULL) {
1847                 result_fname = synthetic_smb_fname(ctx,
1848                                                    result,
1849                                                    NULL,
1850                                                    NULL,
1851                                                    0,
1852                                                    0);
1853         }
1854
1855         SAFE_FREE(resolved_path);
1856         END_PROFILE(syscall_realpath);
1857
1858         return result_fname;
1859 }
1860
1861 static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
1862                              files_struct *fsp, int op, off_t offset,
1863                              off_t count, int type)
1864 {
1865         struct flock flock = { 0, };
1866         int ret;
1867         glfs_fd_t *glfd = NULL;
1868         bool ok = false;
1869
1870         START_PROFILE(syscall_fcntl_lock);
1871
1872         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1873         if (glfd == NULL) {
1874                 DBG_ERR("Failed to fetch gluster fd\n");
1875                 ok = false;
1876                 goto out;
1877         }
1878
1879         flock.l_type = type;
1880         flock.l_whence = SEEK_SET;
1881         flock.l_start = offset;
1882         flock.l_len = count;
1883         flock.l_pid = 0;
1884
1885         ret = glfs_posix_lock(glfd, op, &flock);
1886
1887         if (op == F_GETLK) {
1888                 /* lock query, true if someone else has locked */
1889                 if ((ret != -1) &&
1890                     (flock.l_type != F_UNLCK) &&
1891                     (flock.l_pid != 0) && (flock.l_pid != getpid())) {
1892                         ok = true;
1893                         goto out;
1894                 }
1895                 /* not me */
1896                 ok = false;
1897                 goto out;
1898         }
1899
1900         if (ret == -1) {
1901                 ok = false;
1902                 goto out;
1903         }
1904
1905         ok = true;
1906 out:
1907         END_PROFILE(syscall_fcntl_lock);
1908
1909         return ok;
1910 }
1911
1912 static int vfs_gluster_filesystem_sharemode(struct vfs_handle_struct *handle,
1913                                             files_struct *fsp,
1914                                             uint32_t share_access,
1915                                             uint32_t access_mask)
1916 {
1917         errno = ENOSYS;
1918         return -1;
1919 }
1920
1921 static int vfs_gluster_fcntl(vfs_handle_struct *handle,
1922                              files_struct *fsp, int cmd, va_list cmd_arg)
1923 {
1924         /*
1925          * SMB_VFS_FCNTL() is currently only called by vfs_set_blocking() to
1926          * clear O_NONBLOCK, etc for LOCK_MAND and FIFOs. Ignore it.
1927          */
1928         if (cmd == F_GETFL) {
1929                 return 0;
1930         } else if (cmd == F_SETFL) {
1931                 va_list dup_cmd_arg;
1932                 int opt;
1933
1934                 va_copy(dup_cmd_arg, cmd_arg);
1935                 opt = va_arg(dup_cmd_arg, int);
1936                 va_end(dup_cmd_arg);
1937                 if (opt == 0) {
1938                         return 0;
1939                 }
1940                 DBG_ERR("unexpected fcntl SETFL(%d)\n", opt);
1941                 goto err_out;
1942         }
1943         DBG_ERR("unexpected fcntl: %d\n", cmd);
1944 err_out:
1945         errno = EINVAL;
1946         return -1;
1947 }
1948
1949 static int vfs_gluster_linux_setlease(struct vfs_handle_struct *handle,
1950                                       files_struct *fsp, int leasetype)
1951 {
1952         errno = ENOSYS;
1953         return -1;
1954 }
1955
1956 static bool vfs_gluster_getlock(struct vfs_handle_struct *handle,
1957                                 files_struct *fsp, off_t *poffset,
1958                                 off_t *pcount, int *ptype, pid_t *ppid)
1959 {
1960         struct flock flock = { 0, };
1961         int ret;
1962         glfs_fd_t *glfd = NULL;
1963
1964         START_PROFILE(syscall_fcntl_getlock);
1965
1966         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1967         if (glfd == NULL) {
1968                 END_PROFILE(syscall_fcntl_getlock);
1969                 DBG_ERR("Failed to fetch gluster fd\n");
1970                 return false;
1971         }
1972
1973         flock.l_type = *ptype;
1974         flock.l_whence = SEEK_SET;
1975         flock.l_start = *poffset;
1976         flock.l_len = *pcount;
1977         flock.l_pid = 0;
1978
1979         ret = glfs_posix_lock(glfd, F_GETLK, &flock);
1980
1981         if (ret == -1) {
1982                 END_PROFILE(syscall_fcntl_getlock);
1983                 return false;
1984         }
1985
1986         *ptype = flock.l_type;
1987         *poffset = flock.l_start;
1988         *pcount = flock.l_len;
1989         *ppid = flock.l_pid;
1990         END_PROFILE(syscall_fcntl_getlock);
1991
1992         return true;
1993 }
1994
1995 static int vfs_gluster_symlinkat(struct vfs_handle_struct *handle,
1996                                 const struct smb_filename *link_target,
1997                                 struct files_struct *dirfsp,
1998                                 const struct smb_filename *new_smb_fname)
1999 {
2000         int ret;
2001
2002 #ifdef HAVE_GFAPI_VER_7_11
2003         glfs_fd_t *pglfd = NULL;
2004
2005         START_PROFILE(syscall_symlinkat);
2006
2007         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2008         if (pglfd == NULL) {
2009                 END_PROFILE(syscall_symlinkat);
2010                 DBG_ERR("Failed to fetch gluster fd\n");
2011                 return -1;
2012         }
2013
2014         ret = glfs_symlinkat(link_target->base_name,
2015                              pglfd,
2016                              new_smb_fname->base_name);
2017 #else
2018         struct smb_filename *full_fname = NULL;
2019
2020         START_PROFILE(syscall_symlinkat);
2021
2022         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2023                                                   dirfsp,
2024                                                   new_smb_fname);
2025         if (full_fname == NULL) {
2026                 END_PROFILE(syscall_symlinkat);
2027                 return -1;
2028         }
2029
2030         ret = glfs_symlink(handle->data,
2031                            link_target->base_name,
2032                            full_fname->base_name);
2033
2034         TALLOC_FREE(full_fname);
2035 #endif
2036
2037         END_PROFILE(syscall_symlinkat);
2038
2039         return ret;
2040 }
2041
2042 static int vfs_gluster_readlinkat(struct vfs_handle_struct *handle,
2043                                 const struct files_struct *dirfsp,
2044                                 const struct smb_filename *smb_fname,
2045                                 char *buf,
2046                                 size_t bufsiz)
2047 {
2048         int ret;
2049
2050 #ifdef HAVE_GFAPI_VER_7_11
2051         glfs_fd_t *pglfd = NULL;
2052
2053         START_PROFILE(syscall_readlinkat);
2054
2055         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2056         if (pglfd == NULL) {
2057                 END_PROFILE(syscall_readlinkat);
2058                 DBG_ERR("Failed to fetch gluster fd\n");
2059                 return -1;
2060         }
2061
2062         ret = glfs_readlinkat(pglfd, smb_fname->base_name, buf, bufsiz);
2063 #else
2064         struct smb_filename *full_fname = NULL;
2065
2066         START_PROFILE(syscall_readlinkat);
2067
2068         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2069                                                   dirfsp,
2070                                                   smb_fname);
2071         if (full_fname == NULL) {
2072                 END_PROFILE(syscall_readlinkat);
2073                 return -1;
2074         }
2075
2076         ret = glfs_readlink(handle->data, full_fname->base_name, buf, bufsiz);
2077
2078         TALLOC_FREE(full_fname);
2079 #endif
2080
2081         END_PROFILE(syscall_readlinkat);
2082
2083         return ret;
2084 }
2085
2086 static int vfs_gluster_linkat(struct vfs_handle_struct *handle,
2087                                 files_struct *srcfsp,
2088                                 const struct smb_filename *old_smb_fname,
2089                                 files_struct *dstfsp,
2090                                 const struct smb_filename *new_smb_fname,
2091                                 int flags)
2092 {
2093         int ret;
2094
2095 #ifdef HAVE_GFAPI_VER_7_11
2096         glfs_fd_t *src_pglfd = NULL;
2097         glfs_fd_t *dst_pglfd = NULL;
2098
2099         START_PROFILE(syscall_linkat);
2100
2101         src_pglfd = vfs_gluster_fetch_glfd(handle, srcfsp);
2102         if (src_pglfd == NULL) {
2103                 END_PROFILE(syscall_linkat);
2104                 DBG_ERR("Failed to fetch gluster fd\n");
2105                 return -1;
2106         }
2107
2108         dst_pglfd = vfs_gluster_fetch_glfd(handle, dstfsp);
2109         if (dst_pglfd == NULL) {
2110                 END_PROFILE(syscall_linkat);
2111                 DBG_ERR("Failed to fetch gluster fd\n");
2112                 return -1;
2113         }
2114
2115         ret = glfs_linkat(src_pglfd,
2116                           old_smb_fname->base_name,
2117                           dst_pglfd,
2118                           new_smb_fname->base_name,
2119                           flags);
2120 #else
2121         struct smb_filename *full_fname_old = NULL;
2122         struct smb_filename *full_fname_new = NULL;
2123
2124         START_PROFILE(syscall_linkat);
2125
2126         full_fname_old = full_path_from_dirfsp_atname(talloc_tos(),
2127                                                       srcfsp,
2128                                                       old_smb_fname);
2129         if (full_fname_old == NULL) {
2130                 END_PROFILE(syscall_linkat);
2131                 return -1;
2132         }
2133
2134         full_fname_new = full_path_from_dirfsp_atname(talloc_tos(),
2135                                                       dstfsp,
2136                                                       new_smb_fname);
2137         if (full_fname_new == NULL) {
2138                 END_PROFILE(syscall_linkat);
2139                 TALLOC_FREE(full_fname_old);
2140                 return -1;
2141         }
2142
2143         ret = glfs_link(handle->data,
2144                         full_fname_old->base_name,
2145                         full_fname_new->base_name);
2146
2147         TALLOC_FREE(full_fname_old);
2148         TALLOC_FREE(full_fname_new);
2149 #endif
2150
2151         END_PROFILE(syscall_linkat);
2152
2153         return ret;
2154 }
2155
2156 static int vfs_gluster_mknodat(struct vfs_handle_struct *handle,
2157                                 files_struct *dirfsp,
2158                                 const struct smb_filename *smb_fname,
2159                                 mode_t mode,
2160                                 SMB_DEV_T dev)
2161 {
2162         int ret;
2163
2164 #ifdef HAVE_GFAPI_VER_7_11
2165         glfs_fd_t *pglfd = NULL;
2166
2167         START_PROFILE(syscall_mknodat);
2168
2169         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2170         if (pglfd == NULL) {
2171                 END_PROFILE(syscall_mknodat);
2172                 DBG_ERR("Failed to fetch gluster fd\n");
2173                 return -1;
2174         }
2175
2176         ret = glfs_mknodat(pglfd, smb_fname->base_name, mode, dev);
2177 #else
2178         struct smb_filename *full_fname = NULL;
2179
2180         START_PROFILE(syscall_mknodat);
2181
2182         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2183                                                   dirfsp,
2184                                                   smb_fname);
2185         if (full_fname == NULL) {
2186                 END_PROFILE(syscall_mknodat);
2187                 return -1;
2188         }
2189
2190         ret = glfs_mknod(handle->data, full_fname->base_name, mode, dev);
2191
2192         TALLOC_FREE(full_fname);
2193 #endif
2194
2195         END_PROFILE(syscall_mknodat);
2196
2197         return ret;
2198 }
2199
2200 static int vfs_gluster_fchflags(struct vfs_handle_struct *handle,
2201                                 struct files_struct *fsp,
2202                                 unsigned int flags)
2203 {
2204         errno = ENOSYS;
2205         return -1;
2206 }
2207
2208 static NTSTATUS vfs_gluster_get_real_filename_at(
2209         struct vfs_handle_struct *handle,
2210         struct files_struct *dirfsp,
2211         const char *name,
2212         TALLOC_CTX *mem_ctx,
2213         char **found_name)
2214 {
2215         int ret;
2216         char key_buf[GLUSTER_NAME_MAX + 64];
2217         char val_buf[GLUSTER_NAME_MAX + 1];
2218
2219         if (strlen(name) >= GLUSTER_NAME_MAX) {
2220                 return NT_STATUS_OBJECT_NAME_INVALID;
2221         }
2222
2223         snprintf(key_buf, GLUSTER_NAME_MAX + 64,
2224                  "glusterfs.get_real_filename:%s", name);
2225
2226         ret = glfs_getxattr(handle->data,
2227                             dirfsp->fsp_name->base_name,
2228                             key_buf,
2229                             val_buf,
2230                             GLUSTER_NAME_MAX + 1);
2231         if (ret == -1) {
2232                 if (errno == ENOATTR) {
2233                         errno = ENOENT;
2234                 }
2235                 return map_nt_error_from_unix(errno);
2236         }
2237
2238         *found_name = talloc_strdup(mem_ctx, val_buf);
2239         if (found_name[0] == NULL) {
2240                 return NT_STATUS_NO_MEMORY;
2241         }
2242
2243         return NT_STATUS_OK;
2244 }
2245
2246 static const char *vfs_gluster_connectpath(
2247         struct vfs_handle_struct *handle,
2248         const struct files_struct *dirfsp,
2249         const struct smb_filename *smb_fname)
2250 {
2251         return handle->conn->connectpath;
2252 }
2253
2254 /* EA Operations */
2255
2256 static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
2257                                      files_struct *fsp, const char *name,
2258                                      void *value, size_t size)
2259 {
2260         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2261         if (glfd == NULL) {
2262                 DBG_ERR("Failed to fetch gluster fd\n");
2263                 return -1;
2264         }
2265
2266         if (!fsp->fsp_flags.is_pathref) {
2267                 /*
2268                  * We can use an io_fd to retrieve xattr value.
2269                  */
2270                 return glfs_fgetxattr(glfd, name, value, size);
2271         }
2272
2273         /*
2274          * This is no longer a handle based call.
2275          */
2276         return glfs_getxattr(handle->data,
2277                              fsp->fsp_name->base_name,
2278                              name,
2279                              value,
2280                              size);
2281 }
2282
2283 static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
2284                                       files_struct *fsp, char *list,
2285                                       size_t size)
2286 {
2287         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2288         if (glfd == NULL) {
2289                 DBG_ERR("Failed to fetch gluster fd\n");
2290                 return -1;
2291         }
2292         if (!fsp->fsp_flags.is_pathref) {
2293                 /*
2294                  * We can use an io_fd to list xattrs.
2295                  */
2296                 return glfs_flistxattr(glfd, list, size);
2297         } else {
2298                 /*
2299                  * This is no longer a handle based call.
2300                  */
2301                 return glfs_listxattr(handle->data,
2302                                 fsp->fsp_name->base_name,
2303                                 list,
2304                                 size);
2305         }
2306 }
2307
2308 static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
2309                                     files_struct *fsp, const char *name)
2310 {
2311         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2312         if (glfd == NULL) {
2313                 DBG_ERR("Failed to fetch gluster fd\n");
2314                 return -1;
2315         }
2316         if (!fsp->fsp_flags.is_pathref) {
2317                 /*
2318                  * We can use an io_fd to remove xattrs.
2319                  */
2320                 return glfs_fremovexattr(glfd, name);
2321         } else {
2322                 /*
2323                  * This is no longer a handle based call.
2324                  */
2325                 return glfs_removexattr(handle->data,
2326                                 fsp->fsp_name->base_name,
2327                                 name);
2328         }
2329 }
2330
2331 static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
2332                                  files_struct *fsp, const char *name,
2333                                  const void *value, size_t size, int flags)
2334 {
2335         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
2336         if (glfd == NULL) {
2337                 DBG_ERR("Failed to fetch gluster fd\n");
2338                 return -1;
2339         }
2340
2341         if (!fsp->fsp_flags.is_pathref) {
2342                 /*
2343                  * We can use an io_fd to set xattrs.
2344                  */
2345                 return glfs_fsetxattr(glfd, name, value, size, flags);
2346         } else {
2347                 /*
2348                  * This is no longer a handle based call.
2349                  */
2350                 return glfs_setxattr(handle->data,
2351                                 fsp->fsp_name->base_name,
2352                                 name,
2353                                 value,
2354                                 size,
2355                                 flags);
2356         }
2357 }
2358
2359 /* AIO Operations */
2360
2361 static bool vfs_gluster_aio_force(struct vfs_handle_struct *handle,
2362                                   files_struct *fsp)
2363 {
2364         return false;
2365 }
2366
2367 static NTSTATUS vfs_gluster_create_dfs_pathat(struct vfs_handle_struct *handle,
2368                                 struct files_struct *dirfsp,
2369                                 const struct smb_filename *smb_fname,
2370                                 const struct referral *reflist,
2371                                 size_t referral_count)
2372 {
2373         TALLOC_CTX *frame = talloc_stackframe();
2374         NTSTATUS status = NT_STATUS_NO_MEMORY;
2375         int ret;
2376         char *msdfs_link = NULL;
2377 #ifdef HAVE_GFAPI_VER_7_11
2378         glfs_fd_t *pglfd = NULL;
2379 #else
2380         struct smb_filename *full_fname = NULL;
2381 #endif
2382
2383         /* Form the msdfs_link contents */
2384         msdfs_link = msdfs_link_string(frame,
2385                                         reflist,
2386                                         referral_count);
2387         if (msdfs_link == NULL) {
2388                 goto out;
2389         }
2390
2391 #ifdef HAVE_GFAPI_VER_7_11
2392         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2393         if (pglfd == NULL) {
2394                 DBG_ERR("Failed to fetch gluster fd\n");
2395                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2396                 goto out;
2397         }
2398
2399         ret = glfs_symlinkat(msdfs_link, pglfd, smb_fname->base_name);
2400 #else
2401         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2402                                                   dirfsp,
2403                                                   smb_fname);
2404         if (full_fname == NULL) {
2405                 goto out;
2406         }
2407
2408         ret = glfs_symlink(handle->data, msdfs_link, full_fname->base_name);
2409
2410         TALLOC_FREE(full_fname);
2411 #endif
2412         if (ret == 0) {
2413                 status = NT_STATUS_OK;
2414         } else {
2415                 status = map_nt_error_from_unix(errno);
2416         }
2417
2418   out:
2419
2420         TALLOC_FREE(frame);
2421         return status;
2422 }
2423
2424 /*
2425  * Read and return the contents of a DFS redirect given a
2426  * pathname. A caller can pass in NULL for ppreflist and
2427  * preferral_count but still determine if this was a
2428  * DFS redirect point by getting NT_STATUS_OK back
2429  * without incurring the overhead of reading and parsing
2430  * the referral contents.
2431  */
2432
2433 static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
2434                                 TALLOC_CTX *mem_ctx,
2435                                 struct files_struct *dirfsp,
2436                                 struct smb_filename *smb_fname,
2437                                 struct referral **ppreflist,
2438                                 size_t *preferral_count)
2439 {
2440         NTSTATUS status = NT_STATUS_NO_MEMORY;
2441         size_t bufsize;
2442         char *link_target = NULL;
2443         int referral_len;
2444         bool ok;
2445 #if defined(HAVE_BROKEN_READLINK)
2446         char link_target_buf[PATH_MAX];
2447 #else
2448         char link_target_buf[7];
2449 #endif
2450         struct stat st;
2451         struct smb_filename *full_fname = NULL;
2452         int ret;
2453 #ifdef HAVE_GFAPI_VER_7_11
2454         glfs_fd_t *pglfd = NULL;
2455 #endif
2456
2457         if (is_named_stream(smb_fname)) {
2458                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2459                 goto err;
2460         }
2461
2462         if (ppreflist == NULL && preferral_count == NULL) {
2463                 /*
2464                  * We're only checking if this is a DFS
2465                  * redirect. We don't need to return data.
2466                  */
2467                 bufsize = sizeof(link_target_buf);
2468                 link_target = link_target_buf;
2469         } else {
2470                 bufsize = PATH_MAX;
2471                 link_target = talloc_array(mem_ctx, char, bufsize);
2472                 if (!link_target) {
2473                         goto err;
2474                 }
2475         }
2476
2477         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2478                                                   dirfsp,
2479                                                   smb_fname);
2480         if (full_fname == NULL) {
2481                 status = NT_STATUS_NO_MEMORY;
2482                 goto err;
2483         }
2484
2485         ret = glfs_lstat(handle->data, full_fname->base_name, &st);
2486         if (ret < 0) {
2487                 status = map_nt_error_from_unix(errno);
2488                 goto err;
2489         }
2490
2491 #ifdef HAVE_GFAPI_VER_7_11
2492         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
2493         if (pglfd == NULL) {
2494                 DBG_ERR("Failed to fetch gluster fd\n");
2495                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2496         }
2497
2498         referral_len = glfs_readlinkat(pglfd,
2499                                        smb_fname->base_name,
2500                                        link_target,
2501                                        bufsize - 1);
2502 #else
2503         referral_len = glfs_readlink(handle->data,
2504                                 full_fname->base_name,
2505                                 link_target,
2506                                 bufsize - 1);
2507 #endif
2508         if (referral_len < 0) {
2509                 if (errno == EINVAL) {
2510                         DBG_INFO("%s is not a link.\n", full_fname->base_name);
2511                         status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2512                 } else {
2513                         status = map_nt_error_from_unix(errno);
2514                         DBG_ERR("Error reading "
2515                                 "msdfs link %s: %s\n",
2516                                 full_fname->base_name,
2517                                 strerror(errno));
2518                 }
2519                 goto err;
2520         }
2521         link_target[referral_len] = '\0';
2522
2523         DBG_INFO("%s -> %s\n",
2524                         full_fname->base_name,
2525                         link_target);
2526
2527         if (!strnequal(link_target, "msdfs:", 6)) {
2528                 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2529                 goto err;
2530         }
2531
2532         if (ppreflist == NULL && preferral_count == NULL) {
2533                 /* Early return for checking if this is a DFS link. */
2534                 TALLOC_FREE(full_fname);
2535                 smb_stat_ex_from_stat(&smb_fname->st, &st);
2536                 return NT_STATUS_OK;
2537         }
2538
2539         ok = parse_msdfs_symlink(mem_ctx,
2540                         lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
2541                         link_target,
2542                         ppreflist,
2543                         preferral_count);
2544
2545         if (ok) {
2546                 smb_stat_ex_from_stat(&smb_fname->st, &st);
2547                 status = NT_STATUS_OK;
2548         } else {
2549                 status = NT_STATUS_NO_MEMORY;
2550         }
2551
2552   err:
2553
2554         if (link_target != link_target_buf) {
2555                 TALLOC_FREE(link_target);
2556         }
2557         TALLOC_FREE(full_fname);
2558         return status;
2559 }
2560
2561 static struct vfs_fn_pointers glusterfs_fns = {
2562
2563         /* Disk Operations */
2564
2565         .connect_fn = vfs_gluster_connect,
2566         .disconnect_fn = vfs_gluster_disconnect,
2567         .disk_free_fn = vfs_gluster_disk_free,
2568         .get_quota_fn = vfs_gluster_get_quota,
2569         .set_quota_fn = vfs_gluster_set_quota,
2570         .statvfs_fn = vfs_gluster_statvfs,
2571         .fs_capabilities_fn = vfs_gluster_fs_capabilities,
2572
2573         .get_dfs_referrals_fn = NULL,
2574
2575         /* Directory Operations */
2576
2577         .fdopendir_fn = vfs_gluster_fdopendir,
2578         .readdir_fn = vfs_gluster_readdir,
2579         .rewind_dir_fn = vfs_gluster_rewinddir,
2580         .mkdirat_fn = vfs_gluster_mkdirat,
2581         .closedir_fn = vfs_gluster_closedir,
2582
2583         /* File Operations */
2584
2585         .openat_fn = vfs_gluster_openat,
2586         .create_file_fn = NULL,
2587         .close_fn = vfs_gluster_close,
2588         .pread_fn = vfs_gluster_pread,
2589         .pread_send_fn = vfs_gluster_pread_send,
2590         .pread_recv_fn = vfs_gluster_pread_recv,
2591         .pwrite_fn = vfs_gluster_pwrite,
2592         .pwrite_send_fn = vfs_gluster_pwrite_send,
2593         .pwrite_recv_fn = vfs_gluster_pwrite_recv,
2594         .lseek_fn = vfs_gluster_lseek,
2595         .sendfile_fn = vfs_gluster_sendfile,
2596         .recvfile_fn = vfs_gluster_recvfile,
2597         .renameat_fn = vfs_gluster_renameat,
2598         .fsync_send_fn = vfs_gluster_fsync_send,
2599         .fsync_recv_fn = vfs_gluster_fsync_recv,
2600
2601         .stat_fn = vfs_gluster_stat,
2602         .fstat_fn = vfs_gluster_fstat,
2603         .fstatat_fn = vfs_gluster_fstatat,
2604         .lstat_fn = vfs_gluster_lstat,
2605         .get_alloc_size_fn = vfs_gluster_get_alloc_size,
2606         .unlinkat_fn = vfs_gluster_unlinkat,
2607
2608         .fchmod_fn = vfs_gluster_fchmod,
2609         .fchown_fn = vfs_gluster_fchown,
2610         .lchown_fn = vfs_gluster_lchown,
2611         .chdir_fn = vfs_gluster_chdir,
2612         .getwd_fn = vfs_gluster_getwd,
2613         .fntimes_fn = vfs_gluster_fntimes,
2614         .ftruncate_fn = vfs_gluster_ftruncate,
2615         .fallocate_fn = vfs_gluster_fallocate,
2616         .lock_fn = vfs_gluster_lock,
2617         .filesystem_sharemode_fn = vfs_gluster_filesystem_sharemode,
2618         .fcntl_fn = vfs_gluster_fcntl,
2619         .linux_setlease_fn = vfs_gluster_linux_setlease,
2620         .getlock_fn = vfs_gluster_getlock,
2621         .symlinkat_fn = vfs_gluster_symlinkat,
2622         .readlinkat_fn = vfs_gluster_readlinkat,
2623         .linkat_fn = vfs_gluster_linkat,
2624         .mknodat_fn = vfs_gluster_mknodat,
2625         .realpath_fn = vfs_gluster_realpath,
2626         .fchflags_fn = vfs_gluster_fchflags,
2627         .file_id_create_fn = NULL,
2628         .fstreaminfo_fn = NULL,
2629         .get_real_filename_at_fn = vfs_gluster_get_real_filename_at,
2630         .connectpath_fn = vfs_gluster_connectpath,
2631         .create_dfs_pathat_fn = vfs_gluster_create_dfs_pathat,
2632         .read_dfs_pathat_fn = vfs_gluster_read_dfs_pathat,
2633
2634         .brl_lock_windows_fn = NULL,
2635         .brl_unlock_windows_fn = NULL,
2636         .strict_lock_check_fn = NULL,
2637         .translate_name_fn = NULL,
2638         .fsctl_fn = NULL,
2639
2640         /* NT ACL Operations */
2641         .fget_nt_acl_fn = NULL,
2642         .fset_nt_acl_fn = NULL,
2643         .audit_file_fn = NULL,
2644
2645         /* Posix ACL Operations */
2646         .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
2647         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
2648         .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
2649         .sys_acl_delete_def_fd_fn = posixacl_xattr_acl_delete_def_fd,
2650
2651         /* EA Operations */
2652         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2653         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2654         .fgetxattr_fn = vfs_gluster_fgetxattr,
2655         .flistxattr_fn = vfs_gluster_flistxattr,
2656         .fremovexattr_fn = vfs_gluster_fremovexattr,
2657         .fsetxattr_fn = vfs_gluster_fsetxattr,
2658
2659         /* AIO Operations */
2660         .aio_force_fn = vfs_gluster_aio_force,
2661
2662         /* Durable handle Operations */
2663         .durable_cookie_fn = NULL,
2664         .durable_disconnect_fn = NULL,
2665         .durable_reconnect_fn = NULL,
2666 };
2667
2668 static_decl_vfs;
2669 NTSTATUS vfs_glusterfs_init(TALLOC_CTX *ctx)
2670 {
2671         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2672                                 "glusterfs", &glusterfs_fns);
2673 }