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