smbd: use fsp_get_pathref_fd() for *at related directory handles
[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                                           DIR *dirp, SMB_STRUCT_STAT *sbuf)
654 {
655         static char direntbuf[512];
656         int ret;
657         struct stat stat;
658         struct dirent *dirent = 0;
659
660         START_PROFILE(syscall_readdir);
661         if (sbuf != NULL) {
662                 ret = glfs_readdirplus_r((void *)dirp, &stat, (void *)direntbuf,
663                                          &dirent);
664         } else {
665                 ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
666         }
667
668         if ((ret < 0) || (dirent == NULL)) {
669                 END_PROFILE(syscall_readdir);
670                 return NULL;
671         }
672
673         if (sbuf != NULL) {
674                 SET_STAT_INVALID(*sbuf);
675                 if (!S_ISLNK(stat.st_mode)) {
676                         smb_stat_ex_from_stat(sbuf, &stat);
677                 }
678         }
679
680         END_PROFILE(syscall_readdir);
681         return dirent;
682 }
683
684 static long vfs_gluster_telldir(struct vfs_handle_struct *handle, DIR *dirp)
685 {
686         long ret;
687
688         START_PROFILE(syscall_telldir);
689         ret = glfs_telldir((void *)dirp);
690         END_PROFILE(syscall_telldir);
691
692         return ret;
693 }
694
695 static void vfs_gluster_seekdir(struct vfs_handle_struct *handle, DIR *dirp,
696                                 long offset)
697 {
698         START_PROFILE(syscall_seekdir);
699         glfs_seekdir((void *)dirp, offset);
700         END_PROFILE(syscall_seekdir);
701 }
702
703 static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
704 {
705         START_PROFILE(syscall_rewinddir);
706         glfs_seekdir((void *)dirp, 0);
707         END_PROFILE(syscall_rewinddir);
708 }
709
710 static int vfs_gluster_mkdirat(struct vfs_handle_struct *handle,
711                         struct files_struct *dirfsp,
712                         const struct smb_filename *smb_fname,
713                         mode_t mode)
714 {
715         int ret;
716
717         START_PROFILE(syscall_mkdirat);
718         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
719         ret = glfs_mkdir(handle->data, smb_fname->base_name, mode);
720         END_PROFILE(syscall_mkdirat);
721
722         return ret;
723 }
724
725 static int vfs_gluster_openat(struct vfs_handle_struct *handle,
726                               const struct files_struct *dirfsp,
727                               const struct smb_filename *smb_fname,
728                               files_struct *fsp,
729                               int flags,
730                               mode_t mode)
731 {
732         glfs_fd_t *glfd;
733         glfs_fd_t **p_tmp;
734
735         START_PROFILE(syscall_openat);
736
737         /*
738          * Looks like glfs API doesn't have openat().
739          */
740         SMB_ASSERT(fsp_get_pathref_fd(dirfsp) == AT_FDCWD);
741
742         p_tmp = VFS_ADD_FSP_EXTENSION(handle, fsp, glfs_fd_t *, NULL);
743         if (p_tmp == NULL) {
744                 END_PROFILE(syscall_openat);
745                 errno = ENOMEM;
746                 return -1;
747         }
748
749         if (flags & O_DIRECTORY) {
750                 glfd = glfs_opendir(handle->data, smb_fname->base_name);
751         } else if (flags & O_CREAT) {
752                 glfd = glfs_creat(handle->data, smb_fname->base_name, flags,
753                                   mode);
754         } else {
755                 glfd = glfs_open(handle->data, smb_fname->base_name, flags);
756         }
757
758         if (glfd == NULL) {
759                 END_PROFILE(syscall_openat);
760                 /* no extension destroy_fn, so no need to save errno */
761                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
762                 return -1;
763         }
764
765         *p_tmp = glfd;
766
767         END_PROFILE(syscall_openat);
768         /* An arbitrary value for error reporting, so you know its us. */
769         return 13371337;
770 }
771
772 static int vfs_gluster_close(struct vfs_handle_struct *handle,
773                              files_struct *fsp)
774 {
775         int ret;
776         glfs_fd_t *glfd = NULL;
777
778         START_PROFILE(syscall_close);
779
780         glfd = vfs_gluster_fetch_glfd(handle, fsp);
781         if (glfd == NULL) {
782                 END_PROFILE(syscall_close);
783                 DBG_ERR("Failed to fetch gluster fd\n");
784                 return -1;
785         }
786
787         VFS_REMOVE_FSP_EXTENSION(handle, fsp);
788
789         ret = glfs_close(glfd);
790         END_PROFILE(syscall_close);
791
792         return ret;
793 }
794
795 static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
796                                  files_struct *fsp, void *data, size_t n,
797                                  off_t offset)
798 {
799         ssize_t ret;
800         glfs_fd_t *glfd = NULL;
801
802         START_PROFILE_BYTES(syscall_pread, n);
803
804         glfd = vfs_gluster_fetch_glfd(handle, fsp);
805         if (glfd == NULL) {
806                 END_PROFILE_BYTES(syscall_pread);
807                 DBG_ERR("Failed to fetch gluster fd\n");
808                 return -1;
809         }
810
811 #ifdef HAVE_GFAPI_VER_7_6
812         ret = glfs_pread(glfd, data, n, offset, 0, NULL);
813 #else
814         ret = glfs_pread(glfd, data, n, offset, 0);
815 #endif
816         END_PROFILE_BYTES(syscall_pread);
817
818         return ret;
819 }
820
821 struct vfs_gluster_pread_state {
822         ssize_t ret;
823         glfs_fd_t *fd;
824         void *buf;
825         size_t count;
826         off_t offset;
827
828         struct vfs_aio_state vfs_aio_state;
829         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
830 };
831
832 static void vfs_gluster_pread_do(void *private_data);
833 static void vfs_gluster_pread_done(struct tevent_req *subreq);
834 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state);
835
836 static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
837                                                   *handle, TALLOC_CTX *mem_ctx,
838                                                   struct tevent_context *ev,
839                                                   files_struct *fsp,
840                                                   void *data, size_t n,
841                                                   off_t offset)
842 {
843         struct vfs_gluster_pread_state *state;
844         struct tevent_req *req, *subreq;
845
846         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
847         if (glfd == NULL) {
848                 DBG_ERR("Failed to fetch gluster fd\n");
849                 return NULL;
850         }
851
852         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pread_state);
853         if (req == NULL) {
854                 return NULL;
855         }
856
857         state->ret = -1;
858         state->fd = glfd;
859         state->buf = data;
860         state->count = n;
861         state->offset = offset;
862
863         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
864                                      state->profile_bytes, n);
865         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
866
867         subreq = pthreadpool_tevent_job_send(
868                 state, ev, handle->conn->sconn->pool,
869                 vfs_gluster_pread_do, state);
870         if (tevent_req_nomem(subreq, req)) {
871                 return tevent_req_post(req, ev);
872         }
873         tevent_req_set_callback(subreq, vfs_gluster_pread_done, req);
874
875         talloc_set_destructor(state, vfs_gluster_pread_state_destructor);
876
877         return req;
878 }
879
880 static void vfs_gluster_pread_do(void *private_data)
881 {
882         struct vfs_gluster_pread_state *state = talloc_get_type_abort(
883                 private_data, struct vfs_gluster_pread_state);
884         struct timespec start_time;
885         struct timespec end_time;
886
887         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
888
889         PROFILE_TIMESTAMP(&start_time);
890
891         do {
892 #ifdef HAVE_GFAPI_VER_7_6
893                 state->ret = glfs_pread(state->fd, state->buf, state->count,
894                                         state->offset, 0, NULL);
895 #else
896                 state->ret = glfs_pread(state->fd, state->buf, state->count,
897                                         state->offset, 0);
898 #endif
899         } while ((state->ret == -1) && (errno == EINTR));
900
901         if (state->ret == -1) {
902                 state->vfs_aio_state.error = errno;
903         }
904
905         PROFILE_TIMESTAMP(&end_time);
906
907         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
908
909         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
910 }
911
912 static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state)
913 {
914         return -1;
915 }
916
917 static void vfs_gluster_pread_done(struct tevent_req *subreq)
918 {
919         struct tevent_req *req = tevent_req_callback_data(
920                 subreq, struct tevent_req);
921         struct vfs_gluster_pread_state *state = tevent_req_data(
922                 req, struct vfs_gluster_pread_state);
923         int ret;
924
925         ret = pthreadpool_tevent_job_recv(subreq);
926         TALLOC_FREE(subreq);
927         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
928         talloc_set_destructor(state, NULL);
929         if (ret != 0) {
930                 if (ret != EAGAIN) {
931                         tevent_req_error(req, ret);
932                         return;
933                 }
934                 /*
935                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
936                  * means the lower level pthreadpool failed to create a new
937                  * thread. Fallback to sync processing in that case to allow
938                  * some progress for the client.
939                  */
940                 vfs_gluster_pread_do(state);
941         }
942
943         tevent_req_done(req);
944 }
945
946 static ssize_t vfs_gluster_pread_recv(struct tevent_req *req,
947                                       struct vfs_aio_state *vfs_aio_state)
948 {
949         struct vfs_gluster_pread_state *state = tevent_req_data(
950                 req, struct vfs_gluster_pread_state);
951
952         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
953                 return -1;
954         }
955
956         *vfs_aio_state = state->vfs_aio_state;
957         return state->ret;
958 }
959
960 struct vfs_gluster_pwrite_state {
961         ssize_t ret;
962         glfs_fd_t *fd;
963         const void *buf;
964         size_t count;
965         off_t offset;
966
967         struct vfs_aio_state vfs_aio_state;
968         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
969 };
970
971 static void vfs_gluster_pwrite_do(void *private_data);
972 static void vfs_gluster_pwrite_done(struct tevent_req *subreq);
973 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state);
974
975 static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
976                                                   *handle, TALLOC_CTX *mem_ctx,
977                                                   struct tevent_context *ev,
978                                                   files_struct *fsp,
979                                                   const void *data, size_t n,
980                                                   off_t offset)
981 {
982         struct tevent_req *req, *subreq;
983         struct vfs_gluster_pwrite_state *state;
984
985         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
986         if (glfd == NULL) {
987                 DBG_ERR("Failed to fetch gluster fd\n");
988                 return NULL;
989         }
990
991         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pwrite_state);
992         if (req == NULL) {
993                 return NULL;
994         }
995
996         state->ret = -1;
997         state->fd = glfd;
998         state->buf = data;
999         state->count = n;
1000         state->offset = offset;
1001
1002         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
1003                                      state->profile_bytes, n);
1004         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1005
1006         subreq = pthreadpool_tevent_job_send(
1007                 state, ev, handle->conn->sconn->pool,
1008                 vfs_gluster_pwrite_do, state);
1009         if (tevent_req_nomem(subreq, req)) {
1010                 return tevent_req_post(req, ev);
1011         }
1012         tevent_req_set_callback(subreq, vfs_gluster_pwrite_done, req);
1013
1014         talloc_set_destructor(state, vfs_gluster_pwrite_state_destructor);
1015
1016         return req;
1017 }
1018
1019 static void vfs_gluster_pwrite_do(void *private_data)
1020 {
1021         struct vfs_gluster_pwrite_state *state = talloc_get_type_abort(
1022                 private_data, struct vfs_gluster_pwrite_state);
1023         struct timespec start_time;
1024         struct timespec end_time;
1025
1026         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1027
1028         PROFILE_TIMESTAMP(&start_time);
1029
1030         do {
1031 #ifdef HAVE_GFAPI_VER_7_6
1032                 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
1033                                          state->offset, 0, NULL, NULL);
1034 #else
1035                 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
1036                                          state->offset, 0);
1037 #endif
1038         } while ((state->ret == -1) && (errno == EINTR));
1039
1040         if (state->ret == -1) {
1041                 state->vfs_aio_state.error = errno;
1042         }
1043
1044         PROFILE_TIMESTAMP(&end_time);
1045
1046         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1047
1048         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1049 }
1050
1051 static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state)
1052 {
1053         return -1;
1054 }
1055
1056 static void vfs_gluster_pwrite_done(struct tevent_req *subreq)
1057 {
1058         struct tevent_req *req = tevent_req_callback_data(
1059                 subreq, struct tevent_req);
1060         struct vfs_gluster_pwrite_state *state = tevent_req_data(
1061                 req, struct vfs_gluster_pwrite_state);
1062         int ret;
1063
1064         ret = pthreadpool_tevent_job_recv(subreq);
1065         TALLOC_FREE(subreq);
1066         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1067         talloc_set_destructor(state, NULL);
1068         if (ret != 0) {
1069                 if (ret != EAGAIN) {
1070                         tevent_req_error(req, ret);
1071                         return;
1072                 }
1073                 /*
1074                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1075                  * means the lower level pthreadpool failed to create a new
1076                  * thread. Fallback to sync processing in that case to allow
1077                  * some progress for the client.
1078                  */
1079                 vfs_gluster_pwrite_do(state);
1080         }
1081
1082         tevent_req_done(req);
1083 }
1084
1085 static ssize_t vfs_gluster_pwrite_recv(struct tevent_req *req,
1086                                        struct vfs_aio_state *vfs_aio_state)
1087 {
1088         struct vfs_gluster_pwrite_state *state = tevent_req_data(
1089                 req, struct vfs_gluster_pwrite_state);
1090
1091         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1092                 return -1;
1093         }
1094
1095         *vfs_aio_state = state->vfs_aio_state;
1096
1097         return state->ret;
1098 }
1099
1100 static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
1101                                   files_struct *fsp, const void *data,
1102                                   size_t n, off_t offset)
1103 {
1104         ssize_t ret;
1105         glfs_fd_t *glfd = NULL;
1106
1107         START_PROFILE_BYTES(syscall_pwrite, n);
1108
1109         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1110         if (glfd == NULL) {
1111                 END_PROFILE_BYTES(syscall_pwrite);
1112                 DBG_ERR("Failed to fetch gluster fd\n");
1113                 return -1;
1114         }
1115
1116 #ifdef HAVE_GFAPI_VER_7_6
1117         ret = glfs_pwrite(glfd, data, n, offset, 0, NULL, NULL);
1118 #else
1119         ret = glfs_pwrite(glfd, data, n, offset, 0);
1120 #endif
1121         END_PROFILE_BYTES(syscall_pwrite);
1122
1123         return ret;
1124 }
1125
1126 static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
1127                                files_struct *fsp, off_t offset, int whence)
1128 {
1129         off_t ret = 0;
1130         glfs_fd_t *glfd = NULL;
1131
1132         START_PROFILE(syscall_lseek);
1133
1134         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1135         if (glfd == NULL) {
1136                 END_PROFILE(syscall_lseek);
1137                 DBG_ERR("Failed to fetch gluster fd\n");
1138                 return -1;
1139         }
1140
1141         ret = glfs_lseek(glfd, offset, whence);
1142         END_PROFILE(syscall_lseek);
1143
1144         return ret;
1145 }
1146
1147 static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd,
1148                                     files_struct *fromfsp,
1149                                     const DATA_BLOB *hdr,
1150                                     off_t offset, size_t n)
1151 {
1152         errno = ENOTSUP;
1153         return -1;
1154 }
1155
1156 static ssize_t vfs_gluster_recvfile(struct vfs_handle_struct *handle,
1157                                     int fromfd, files_struct *tofsp,
1158                                     off_t offset, size_t n)
1159 {
1160         errno = ENOTSUP;
1161         return -1;
1162 }
1163
1164 static int vfs_gluster_renameat(struct vfs_handle_struct *handle,
1165                         files_struct *srcfsp,
1166                         const struct smb_filename *smb_fname_src,
1167                         files_struct *dstfsp,
1168                         const struct smb_filename *smb_fname_dst)
1169 {
1170         int ret;
1171
1172         START_PROFILE(syscall_renameat);
1173         ret = glfs_rename(handle->data, smb_fname_src->base_name,
1174                           smb_fname_dst->base_name);
1175         END_PROFILE(syscall_renameat);
1176
1177         return ret;
1178 }
1179
1180 struct vfs_gluster_fsync_state {
1181         ssize_t ret;
1182         glfs_fd_t *fd;
1183
1184         struct vfs_aio_state vfs_aio_state;
1185         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
1186 };
1187
1188 static void vfs_gluster_fsync_do(void *private_data);
1189 static void vfs_gluster_fsync_done(struct tevent_req *subreq);
1190 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state);
1191
1192 static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
1193                                                  *handle, TALLOC_CTX *mem_ctx,
1194                                                  struct tevent_context *ev,
1195                                                  files_struct *fsp)
1196 {
1197         struct tevent_req *req, *subreq;
1198         struct vfs_gluster_fsync_state *state;
1199
1200         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1201         if (glfd == NULL) {
1202                 DBG_ERR("Failed to fetch gluster fd\n");
1203                 return NULL;
1204         }
1205
1206         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_fsync_state);
1207         if (req == NULL) {
1208                 return NULL;
1209         }
1210
1211         state->ret = -1;
1212         state->fd = glfd;
1213
1214         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
1215                                      state->profile_bytes, 0);
1216         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1217
1218         subreq = pthreadpool_tevent_job_send(
1219                 state, ev, handle->conn->sconn->pool, vfs_gluster_fsync_do, state);
1220         if (tevent_req_nomem(subreq, req)) {
1221                 return tevent_req_post(req, ev);
1222         }
1223         tevent_req_set_callback(subreq, vfs_gluster_fsync_done, req);
1224
1225         talloc_set_destructor(state, vfs_gluster_fsync_state_destructor);
1226
1227         return req;
1228 }
1229
1230 static void vfs_gluster_fsync_do(void *private_data)
1231 {
1232         struct vfs_gluster_fsync_state *state = talloc_get_type_abort(
1233                 private_data, struct vfs_gluster_fsync_state);
1234         struct timespec start_time;
1235         struct timespec end_time;
1236
1237         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
1238
1239         PROFILE_TIMESTAMP(&start_time);
1240
1241         do {
1242 #ifdef HAVE_GFAPI_VER_7_6
1243                 state->ret = glfs_fsync(state->fd, NULL, NULL);
1244 #else
1245                 state->ret = glfs_fsync(state->fd);
1246 #endif
1247         } while ((state->ret == -1) && (errno == EINTR));
1248
1249         if (state->ret == -1) {
1250                 state->vfs_aio_state.error = errno;
1251         }
1252
1253         PROFILE_TIMESTAMP(&end_time);
1254
1255         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
1256
1257         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
1258 }
1259
1260 static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state)
1261 {
1262         return -1;
1263 }
1264
1265 static void vfs_gluster_fsync_done(struct tevent_req *subreq)
1266 {
1267         struct tevent_req *req = tevent_req_callback_data(
1268                 subreq, struct tevent_req);
1269         struct vfs_gluster_fsync_state *state = tevent_req_data(
1270                 req, struct vfs_gluster_fsync_state);
1271         int ret;
1272
1273         ret = pthreadpool_tevent_job_recv(subreq);
1274         TALLOC_FREE(subreq);
1275         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
1276         talloc_set_destructor(state, NULL);
1277         if (ret != 0) {
1278                 if (ret != EAGAIN) {
1279                         tevent_req_error(req, ret);
1280                         return;
1281                 }
1282                 /*
1283                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
1284                  * means the lower level pthreadpool failed to create a new
1285                  * thread. Fallback to sync processing in that case to allow
1286                  * some progress for the client.
1287                  */
1288                 vfs_gluster_fsync_do(state);
1289         }
1290
1291         tevent_req_done(req);
1292 }
1293
1294 static int vfs_gluster_fsync_recv(struct tevent_req *req,
1295                                   struct vfs_aio_state *vfs_aio_state)
1296 {
1297         struct vfs_gluster_fsync_state *state = tevent_req_data(
1298                 req, struct vfs_gluster_fsync_state);
1299
1300         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1301                 return -1;
1302         }
1303
1304         *vfs_aio_state = state->vfs_aio_state;
1305         return state->ret;
1306 }
1307
1308 static int vfs_gluster_stat(struct vfs_handle_struct *handle,
1309                             struct smb_filename *smb_fname)
1310 {
1311         struct stat st;
1312         int ret;
1313
1314         START_PROFILE(syscall_stat);
1315         ret = glfs_stat(handle->data, smb_fname->base_name, &st);
1316         if (ret == 0) {
1317                 smb_stat_ex_from_stat(&smb_fname->st, &st);
1318         }
1319         if (ret < 0 && errno != ENOENT) {
1320                 DEBUG(0, ("glfs_stat(%s) failed: %s\n",
1321                           smb_fname->base_name, strerror(errno)));
1322         }
1323         END_PROFILE(syscall_stat);
1324
1325         return ret;
1326 }
1327
1328 static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
1329                              files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1330 {
1331         struct stat st;
1332         int ret;
1333         glfs_fd_t *glfd = NULL;
1334
1335         START_PROFILE(syscall_fstat);
1336
1337         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1338         if (glfd == NULL) {
1339                 END_PROFILE(syscall_fstat);
1340                 DBG_ERR("Failed to fetch gluster fd\n");
1341                 return -1;
1342         }
1343
1344         ret = glfs_fstat(glfd, &st);
1345         if (ret == 0) {
1346                 smb_stat_ex_from_stat(sbuf, &st);
1347         }
1348         if (ret < 0) {
1349                 DEBUG(0, ("glfs_fstat(%d) failed: %s\n",
1350                           fsp_get_io_fd(fsp), strerror(errno)));
1351         }
1352         END_PROFILE(syscall_fstat);
1353
1354         return ret;
1355 }
1356
1357 static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
1358                              struct smb_filename *smb_fname)
1359 {
1360         struct stat st;
1361         int ret;
1362
1363         START_PROFILE(syscall_lstat);
1364         ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
1365         if (ret == 0) {
1366                 smb_stat_ex_from_stat(&smb_fname->st, &st);
1367         }
1368         if (ret < 0 && errno != ENOENT) {
1369                 DEBUG(0, ("glfs_lstat(%s) failed: %s\n",
1370                           smb_fname->base_name, strerror(errno)));
1371         }
1372         END_PROFILE(syscall_lstat);
1373
1374         return ret;
1375 }
1376
1377 static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle,
1378                                            files_struct *fsp,
1379                                            const SMB_STRUCT_STAT *sbuf)
1380 {
1381         uint64_t ret;
1382
1383         START_PROFILE(syscall_get_alloc_size);
1384         ret = sbuf->st_ex_blocks * 512;
1385         END_PROFILE(syscall_get_alloc_size);
1386
1387         return ret;
1388 }
1389
1390 static int vfs_gluster_unlinkat(struct vfs_handle_struct *handle,
1391                         struct files_struct *dirfsp,
1392                         const struct smb_filename *smb_fname,
1393                         int flags)
1394 {
1395         int ret;
1396
1397         START_PROFILE(syscall_unlinkat);
1398         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1399         if (flags & AT_REMOVEDIR) {
1400                 ret = glfs_rmdir(handle->data, smb_fname->base_name);
1401         } else {
1402                 ret = glfs_unlink(handle->data, smb_fname->base_name);
1403         }
1404         END_PROFILE(syscall_unlinkat);
1405
1406         return ret;
1407 }
1408
1409 static int vfs_gluster_chmod(struct vfs_handle_struct *handle,
1410                                 const struct smb_filename *smb_fname,
1411                                 mode_t mode)
1412 {
1413         int ret;
1414
1415         START_PROFILE(syscall_chmod);
1416         ret = glfs_chmod(handle->data, smb_fname->base_name, mode);
1417         END_PROFILE(syscall_chmod);
1418
1419         return ret;
1420 }
1421
1422 static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
1423                               files_struct *fsp, mode_t mode)
1424 {
1425         int ret;
1426         glfs_fd_t *glfd = NULL;
1427
1428         START_PROFILE(syscall_fchmod);
1429
1430         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1431         if (glfd == NULL) {
1432                 END_PROFILE(syscall_fchmod);
1433                 DBG_ERR("Failed to fetch gluster fd\n");
1434                 return -1;
1435         }
1436
1437         ret = glfs_fchmod(glfd, mode);
1438         END_PROFILE(syscall_fchmod);
1439
1440         return ret;
1441 }
1442
1443 static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
1444                               files_struct *fsp, uid_t uid, gid_t gid)
1445 {
1446         int ret;
1447         glfs_fd_t *glfd = NULL;
1448
1449         START_PROFILE(syscall_fchown);
1450
1451         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1452         if (glfd == NULL) {
1453                 END_PROFILE(syscall_fchown);
1454                 DBG_ERR("Failed to fetch gluster fd\n");
1455                 return -1;
1456         }
1457
1458         ret = glfs_fchown(glfd, uid, gid);
1459         END_PROFILE(syscall_fchown);
1460
1461         return ret;
1462 }
1463
1464 static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
1465                         const struct smb_filename *smb_fname,
1466                         uid_t uid,
1467                         gid_t gid)
1468 {
1469         int ret;
1470
1471         START_PROFILE(syscall_lchown);
1472         ret = glfs_lchown(handle->data, smb_fname->base_name, uid, gid);
1473         END_PROFILE(syscall_lchown);
1474
1475         return ret;
1476 }
1477
1478 static int vfs_gluster_chdir(struct vfs_handle_struct *handle,
1479                         const struct smb_filename *smb_fname)
1480 {
1481         int ret;
1482
1483         START_PROFILE(syscall_chdir);
1484         ret = glfs_chdir(handle->data, smb_fname->base_name);
1485         END_PROFILE(syscall_chdir);
1486
1487         return ret;
1488 }
1489
1490 static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
1491                                 TALLOC_CTX *ctx)
1492 {
1493         char *cwd;
1494         char *ret;
1495         struct smb_filename *smb_fname = NULL;
1496
1497         START_PROFILE(syscall_getwd);
1498
1499         cwd = SMB_CALLOC_ARRAY(char, PATH_MAX);
1500         if (cwd == NULL) {
1501                 END_PROFILE(syscall_getwd);
1502                 return NULL;
1503         }
1504
1505         ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1);
1506         END_PROFILE(syscall_getwd);
1507
1508         if (ret == NULL) {
1509                 SAFE_FREE(cwd);
1510                 return NULL;
1511         }
1512         smb_fname = synthetic_smb_fname(ctx,
1513                                         ret,
1514                                         NULL,
1515                                         NULL,
1516                                         0,
1517                                         0);
1518         SAFE_FREE(cwd);
1519         return smb_fname;
1520 }
1521
1522 static int vfs_gluster_ntimes(struct vfs_handle_struct *handle,
1523                               const struct smb_filename *smb_fname,
1524                               struct smb_file_time *ft)
1525 {
1526         int ret = -1;
1527         struct timespec times[2];
1528
1529         START_PROFILE(syscall_ntimes);
1530
1531         if (is_omit_timespec(&ft->atime)) {
1532                 times[0].tv_sec = smb_fname->st.st_ex_atime.tv_sec;
1533                 times[0].tv_nsec = smb_fname->st.st_ex_atime.tv_nsec;
1534         } else {
1535                 times[0].tv_sec = ft->atime.tv_sec;
1536                 times[0].tv_nsec = ft->atime.tv_nsec;
1537         }
1538
1539         if (is_omit_timespec(&ft->mtime)) {
1540                 times[1].tv_sec = smb_fname->st.st_ex_mtime.tv_sec;
1541                 times[1].tv_nsec = smb_fname->st.st_ex_mtime.tv_nsec;
1542         } else {
1543                 times[1].tv_sec = ft->mtime.tv_sec;
1544                 times[1].tv_nsec = ft->mtime.tv_nsec;
1545         }
1546
1547         if ((timespec_compare(&times[0],
1548                               &smb_fname->st.st_ex_atime) == 0) &&
1549             (timespec_compare(&times[1],
1550                               &smb_fname->st.st_ex_mtime) == 0)) {
1551                 END_PROFILE(syscall_ntimes);
1552                 return 0;
1553         }
1554
1555         ret = glfs_utimens(handle->data, smb_fname->base_name, times);
1556         END_PROFILE(syscall_ntimes);
1557
1558         return ret;
1559 }
1560
1561 static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle,
1562                                  files_struct *fsp, off_t offset)
1563 {
1564         int ret;
1565         glfs_fd_t *glfd = NULL;
1566
1567         START_PROFILE(syscall_ftruncate);
1568
1569         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1570         if (glfd == NULL) {
1571                 END_PROFILE(syscall_ftruncate);
1572                 DBG_ERR("Failed to fetch gluster fd\n");
1573                 return -1;
1574         }
1575
1576 #ifdef HAVE_GFAPI_VER_7_6
1577         ret = glfs_ftruncate(glfd, offset, NULL, NULL);
1578 #else
1579         ret = glfs_ftruncate(glfd, offset);
1580 #endif
1581         END_PROFILE(syscall_ftruncate);
1582
1583         return ret;
1584 }
1585
1586 static int vfs_gluster_fallocate(struct vfs_handle_struct *handle,
1587                                  struct files_struct *fsp,
1588                                  uint32_t mode,
1589                                  off_t offset, off_t len)
1590 {
1591         int ret;
1592 #ifdef HAVE_GFAPI_VER_6
1593         glfs_fd_t *glfd = NULL;
1594         int keep_size, punch_hole;
1595
1596         START_PROFILE(syscall_fallocate);
1597
1598         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1599         if (glfd == NULL) {
1600                 END_PROFILE(syscall_fallocate);
1601                 DBG_ERR("Failed to fetch gluster fd\n");
1602                 return -1;
1603         }
1604
1605         keep_size = mode & VFS_FALLOCATE_FL_KEEP_SIZE;
1606         punch_hole = mode & VFS_FALLOCATE_FL_PUNCH_HOLE;
1607
1608         mode &= ~(VFS_FALLOCATE_FL_KEEP_SIZE|VFS_FALLOCATE_FL_PUNCH_HOLE);
1609         if (mode != 0) {
1610                 END_PROFILE(syscall_fallocate);
1611                 errno = ENOTSUP;
1612                 return -1;
1613         }
1614
1615         if (punch_hole) {
1616                 ret = glfs_discard(glfd, offset, len);
1617                 if (ret != 0) {
1618                         DBG_DEBUG("glfs_discard failed: %s\n",
1619                                   strerror(errno));
1620                 }
1621         }
1622
1623         ret = glfs_fallocate(glfd, keep_size, offset, len);
1624         END_PROFILE(syscall_fallocate);
1625 #else
1626         errno = ENOTSUP;
1627         ret = -1;
1628 #endif
1629         return ret;
1630 }
1631
1632 static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handle,
1633                                 TALLOC_CTX *ctx,
1634                                 const struct smb_filename *smb_fname)
1635 {
1636         char *result = NULL;
1637         struct smb_filename *result_fname = NULL;
1638         char *resolved_path = NULL;
1639
1640         START_PROFILE(syscall_realpath);
1641
1642         resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1643         if (resolved_path == NULL) {
1644                 END_PROFILE(syscall_realpath);
1645                 errno = ENOMEM;
1646                 return NULL;
1647         }
1648
1649         result = glfs_realpath(handle->data,
1650                         smb_fname->base_name,
1651                         resolved_path);
1652         if (result != NULL) {
1653                 result_fname = synthetic_smb_fname(ctx,
1654                                                    result,
1655                                                    NULL,
1656                                                    NULL,
1657                                                    0,
1658                                                    0);
1659         }
1660
1661         SAFE_FREE(resolved_path);
1662         END_PROFILE(syscall_realpath);
1663
1664         return result_fname;
1665 }
1666
1667 static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
1668                              files_struct *fsp, int op, off_t offset,
1669                              off_t count, int type)
1670 {
1671         struct flock flock = { 0, };
1672         int ret;
1673         glfs_fd_t *glfd = NULL;
1674         bool ok = false;
1675
1676         START_PROFILE(syscall_fcntl_lock);
1677
1678         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1679         if (glfd == NULL) {
1680                 DBG_ERR("Failed to fetch gluster fd\n");
1681                 ok = false;
1682                 goto out;
1683         }
1684
1685         flock.l_type = type;
1686         flock.l_whence = SEEK_SET;
1687         flock.l_start = offset;
1688         flock.l_len = count;
1689         flock.l_pid = 0;
1690
1691         ret = glfs_posix_lock(glfd, op, &flock);
1692
1693         if (op == F_GETLK) {
1694                 /* lock query, true if someone else has locked */
1695                 if ((ret != -1) &&
1696                     (flock.l_type != F_UNLCK) &&
1697                     (flock.l_pid != 0) && (flock.l_pid != getpid())) {
1698                         ok = true;
1699                         goto out;
1700                 }
1701                 /* not me */
1702                 ok = false;
1703                 goto out;
1704         }
1705
1706         if (ret == -1) {
1707                 ok = false;
1708                 goto out;
1709         }
1710
1711         ok = true;
1712 out:
1713         END_PROFILE(syscall_fcntl_lock);
1714
1715         return ok;
1716 }
1717
1718 static int vfs_gluster_kernel_flock(struct vfs_handle_struct *handle,
1719                                     files_struct *fsp, uint32_t share_access,
1720                                     uint32_t access_mask)
1721 {
1722         errno = ENOSYS;
1723         return -1;
1724 }
1725
1726 static int vfs_gluster_fcntl(vfs_handle_struct *handle,
1727                              files_struct *fsp, int cmd, va_list cmd_arg)
1728 {
1729         /*
1730          * SMB_VFS_FCNTL() is currently only called by vfs_set_blocking() to
1731          * clear O_NONBLOCK, etc for LOCK_MAND and FIFOs. Ignore it.
1732          */
1733         if (cmd == F_GETFL) {
1734                 return 0;
1735         } else if (cmd == F_SETFL) {
1736                 va_list dup_cmd_arg;
1737                 int opt;
1738
1739                 va_copy(dup_cmd_arg, cmd_arg);
1740                 opt = va_arg(dup_cmd_arg, int);
1741                 va_end(dup_cmd_arg);
1742                 if (opt == 0) {
1743                         return 0;
1744                 }
1745                 DBG_ERR("unexpected fcntl SETFL(%d)\n", opt);
1746                 goto err_out;
1747         }
1748         DBG_ERR("unexpected fcntl: %d\n", cmd);
1749 err_out:
1750         errno = EINVAL;
1751         return -1;
1752 }
1753
1754 static int vfs_gluster_linux_setlease(struct vfs_handle_struct *handle,
1755                                       files_struct *fsp, int leasetype)
1756 {
1757         errno = ENOSYS;
1758         return -1;
1759 }
1760
1761 static bool vfs_gluster_getlock(struct vfs_handle_struct *handle,
1762                                 files_struct *fsp, off_t *poffset,
1763                                 off_t *pcount, int *ptype, pid_t *ppid)
1764 {
1765         struct flock flock = { 0, };
1766         int ret;
1767         glfs_fd_t *glfd = NULL;
1768
1769         START_PROFILE(syscall_fcntl_getlock);
1770
1771         glfd = vfs_gluster_fetch_glfd(handle, fsp);
1772         if (glfd == NULL) {
1773                 END_PROFILE(syscall_fcntl_getlock);
1774                 DBG_ERR("Failed to fetch gluster fd\n");
1775                 return false;
1776         }
1777
1778         flock.l_type = *ptype;
1779         flock.l_whence = SEEK_SET;
1780         flock.l_start = *poffset;
1781         flock.l_len = *pcount;
1782         flock.l_pid = 0;
1783
1784         ret = glfs_posix_lock(glfd, F_GETLK, &flock);
1785
1786         if (ret == -1) {
1787                 END_PROFILE(syscall_fcntl_getlock);
1788                 return false;
1789         }
1790
1791         *ptype = flock.l_type;
1792         *poffset = flock.l_start;
1793         *pcount = flock.l_len;
1794         *ppid = flock.l_pid;
1795         END_PROFILE(syscall_fcntl_getlock);
1796
1797         return true;
1798 }
1799
1800 static int vfs_gluster_symlinkat(struct vfs_handle_struct *handle,
1801                                 const struct smb_filename *link_target,
1802                                 struct files_struct *dirfsp,
1803                                 const struct smb_filename *new_smb_fname)
1804 {
1805         int ret;
1806
1807         START_PROFILE(syscall_symlinkat);
1808         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1809         ret = glfs_symlink(handle->data,
1810                         link_target->base_name,
1811                         new_smb_fname->base_name);
1812         END_PROFILE(syscall_symlinkat);
1813
1814         return ret;
1815 }
1816
1817 static int vfs_gluster_readlinkat(struct vfs_handle_struct *handle,
1818                                 const struct files_struct *dirfsp,
1819                                 const struct smb_filename *smb_fname,
1820                                 char *buf,
1821                                 size_t bufsiz)
1822 {
1823         int ret;
1824
1825         START_PROFILE(syscall_readlinkat);
1826         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1827         ret = glfs_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1828         END_PROFILE(syscall_readlinkat);
1829
1830         return ret;
1831 }
1832
1833 static int vfs_gluster_linkat(struct vfs_handle_struct *handle,
1834                                 files_struct *srcfsp,
1835                                 const struct smb_filename *old_smb_fname,
1836                                 files_struct *dstfsp,
1837                                 const struct smb_filename *new_smb_fname,
1838                                 int flags)
1839 {
1840         int ret;
1841
1842         START_PROFILE(syscall_linkat);
1843
1844         SMB_ASSERT(srcfsp == srcfsp->conn->cwd_fsp);
1845         SMB_ASSERT(dstfsp == dstfsp->conn->cwd_fsp);
1846
1847         ret = glfs_link(handle->data,
1848                         old_smb_fname->base_name,
1849                         new_smb_fname->base_name);
1850         END_PROFILE(syscall_linkat);
1851
1852         return ret;
1853 }
1854
1855 static int vfs_gluster_mknodat(struct vfs_handle_struct *handle,
1856                                 files_struct *dirfsp,
1857                                 const struct smb_filename *smb_fname,
1858                                 mode_t mode,
1859                                 SMB_DEV_T dev)
1860 {
1861         int ret;
1862
1863         START_PROFILE(syscall_mknodat);
1864         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
1865         ret = glfs_mknod(handle->data, smb_fname->base_name, mode, dev);
1866         END_PROFILE(syscall_mknodat);
1867
1868         return ret;
1869 }
1870
1871 static int vfs_gluster_chflags(struct vfs_handle_struct *handle,
1872                                 const struct smb_filename *smb_fname,
1873                                 unsigned int flags)
1874 {
1875         errno = ENOSYS;
1876         return -1;
1877 }
1878
1879 static int vfs_gluster_get_real_filename(struct vfs_handle_struct *handle,
1880                                          const struct smb_filename *path,
1881                                          const char *name,
1882                                          TALLOC_CTX *mem_ctx,
1883                                          char **found_name)
1884 {
1885         int ret;
1886         char key_buf[GLUSTER_NAME_MAX + 64];
1887         char val_buf[GLUSTER_NAME_MAX + 1];
1888
1889         if (strlen(name) >= GLUSTER_NAME_MAX) {
1890                 errno = ENAMETOOLONG;
1891                 return -1;
1892         }
1893
1894         snprintf(key_buf, GLUSTER_NAME_MAX + 64,
1895                  "glusterfs.get_real_filename:%s", name);
1896
1897         ret = glfs_getxattr(handle->data, path->base_name, key_buf, val_buf,
1898                             GLUSTER_NAME_MAX + 1);
1899         if (ret == -1) {
1900                 if (errno == ENOATTR) {
1901                         errno = ENOENT;
1902                 }
1903                 return -1;
1904         }
1905
1906         *found_name = talloc_strdup(mem_ctx, val_buf);
1907         if (found_name[0] == NULL) {
1908                 errno = ENOMEM;
1909                 return -1;
1910         }
1911         return 0;
1912 }
1913
1914 static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle,
1915                                 const struct smb_filename *smb_fname)
1916 {
1917         return handle->conn->connectpath;
1918 }
1919
1920 /* EA Operations */
1921
1922 static ssize_t vfs_gluster_getxattr(struct vfs_handle_struct *handle,
1923                                 const struct smb_filename *smb_fname,
1924                                 const char *name,
1925                                 void *value,
1926                                 size_t size)
1927 {
1928         return glfs_getxattr(handle->data, smb_fname->base_name,
1929                              name, value, size);
1930 }
1931
1932 static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
1933                                      files_struct *fsp, const char *name,
1934                                      void *value, size_t size)
1935 {
1936         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1937         if (glfd == NULL) {
1938                 DBG_ERR("Failed to fetch gluster fd\n");
1939                 return -1;
1940         }
1941
1942         return glfs_fgetxattr(glfd, name, value, size);
1943 }
1944
1945 static ssize_t vfs_gluster_listxattr(struct vfs_handle_struct *handle,
1946                                 const struct smb_filename *smb_fname,
1947                                 char *list,
1948                                 size_t size)
1949 {
1950         return glfs_listxattr(handle->data, smb_fname->base_name, list, size);
1951 }
1952
1953 static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
1954                                       files_struct *fsp, char *list,
1955                                       size_t size)
1956 {
1957         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1958         if (glfd == NULL) {
1959                 DBG_ERR("Failed to fetch gluster fd\n");
1960                 return -1;
1961         }
1962
1963         return glfs_flistxattr(glfd, list, size);
1964 }
1965
1966 static int vfs_gluster_removexattr(struct vfs_handle_struct *handle,
1967                                 const struct smb_filename *smb_fname,
1968                                 const char *name)
1969 {
1970         return glfs_removexattr(handle->data, smb_fname->base_name, name);
1971 }
1972
1973 static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
1974                                     files_struct *fsp, const char *name)
1975 {
1976         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1977         if (glfd == NULL) {
1978                 DBG_ERR("Failed to fetch gluster fd\n");
1979                 return -1;
1980         }
1981
1982         return glfs_fremovexattr(glfd, name);
1983 }
1984
1985 static int vfs_gluster_setxattr(struct vfs_handle_struct *handle,
1986                                 const struct smb_filename *smb_fname,
1987                                 const char *name,
1988                                 const void *value, size_t size, int flags)
1989 {
1990         return glfs_setxattr(handle->data, smb_fname->base_name, name, value, size, flags);
1991 }
1992
1993 static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
1994                                  files_struct *fsp, const char *name,
1995                                  const void *value, size_t size, int flags)
1996 {
1997         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
1998         if (glfd == NULL) {
1999                 DBG_ERR("Failed to fetch gluster fd\n");
2000                 return -1;
2001         }
2002
2003         return glfs_fsetxattr(glfd, name, value, size, flags);
2004 }
2005
2006 /* AIO Operations */
2007
2008 static bool vfs_gluster_aio_force(struct vfs_handle_struct *handle,
2009                                   files_struct *fsp)
2010 {
2011         return false;
2012 }
2013
2014 static NTSTATUS vfs_gluster_create_dfs_pathat(struct vfs_handle_struct *handle,
2015                                 struct files_struct *dirfsp,
2016                                 const struct smb_filename *smb_fname,
2017                                 const struct referral *reflist,
2018                                 size_t referral_count)
2019 {
2020         TALLOC_CTX *frame = talloc_stackframe();
2021         NTSTATUS status = NT_STATUS_NO_MEMORY;
2022         int ret;
2023         char *msdfs_link = NULL;
2024
2025         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2026
2027         /* Form the msdfs_link contents */
2028         msdfs_link = msdfs_link_string(frame,
2029                                         reflist,
2030                                         referral_count);
2031         if (msdfs_link == NULL) {
2032                 goto out;
2033         }
2034
2035         ret = glfs_symlink(handle->data,
2036                         msdfs_link,
2037                         smb_fname->base_name);
2038         if (ret == 0) {
2039                 status = NT_STATUS_OK;
2040         } else {
2041                 status = map_nt_error_from_unix(errno);
2042         }
2043
2044   out:
2045
2046         TALLOC_FREE(frame);
2047         return status;
2048 }
2049
2050 /*
2051  * Read and return the contents of a DFS redirect given a
2052  * pathname. A caller can pass in NULL for ppreflist and
2053  * preferral_count but still determine if this was a
2054  * DFS redirect point by getting NT_STATUS_OK back
2055  * without incurring the overhead of reading and parsing
2056  * the referral contents.
2057  */
2058
2059 static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
2060                                 TALLOC_CTX *mem_ctx,
2061                                 struct files_struct *dirfsp,
2062                                 struct smb_filename *smb_fname,
2063                                 struct referral **ppreflist,
2064                                 size_t *preferral_count)
2065 {
2066         NTSTATUS status = NT_STATUS_NO_MEMORY;
2067         size_t bufsize;
2068         char *link_target = NULL;
2069         int referral_len;
2070         bool ok;
2071 #if defined(HAVE_BROKEN_READLINK)
2072         char link_target_buf[PATH_MAX];
2073 #else
2074         char link_target_buf[7];
2075 #endif
2076         struct stat st;
2077         int ret;
2078
2079         SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
2080
2081         if (is_named_stream(smb_fname)) {
2082                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2083                 goto err;
2084         }
2085
2086         if (ppreflist == NULL && preferral_count == NULL) {
2087                 /*
2088                  * We're only checking if this is a DFS
2089                  * redirect. We don't need to return data.
2090                  */
2091                 bufsize = sizeof(link_target_buf);
2092                 link_target = link_target_buf;
2093         } else {
2094                 bufsize = PATH_MAX;
2095                 link_target = talloc_array(mem_ctx, char, bufsize);
2096                 if (!link_target) {
2097                         goto err;
2098                 }
2099         }
2100
2101         ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
2102         if (ret < 0) {
2103                 status = map_nt_error_from_unix(errno);
2104                 goto err;
2105         }
2106
2107         referral_len = glfs_readlink(handle->data,
2108                                 smb_fname->base_name,
2109                                 link_target,
2110                                 bufsize - 1);
2111         if (referral_len < 0) {
2112                 if (errno == EINVAL) {
2113                         DBG_INFO("%s is not a link.\n", smb_fname->base_name);
2114                         status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2115                 } else {
2116                         status = map_nt_error_from_unix(errno);
2117                         DBG_ERR("Error reading "
2118                                 "msdfs link %s: %s\n",
2119                                 smb_fname->base_name,
2120                                 strerror(errno));
2121                 }
2122                 goto err;
2123         }
2124         link_target[referral_len] = '\0';
2125
2126         DBG_INFO("%s -> %s\n",
2127                         smb_fname->base_name,
2128                         link_target);
2129
2130         if (!strnequal(link_target, "msdfs:", 6)) {
2131                 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
2132                 goto err;
2133         }
2134
2135         if (ppreflist == NULL && preferral_count == NULL) {
2136                 /* Early return for checking if this is a DFS link. */
2137                 smb_stat_ex_from_stat(&smb_fname->st, &st);
2138                 return NT_STATUS_OK;
2139         }
2140
2141         ok = parse_msdfs_symlink(mem_ctx,
2142                         lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
2143                         link_target,
2144                         ppreflist,
2145                         preferral_count);
2146
2147         if (ok) {
2148                 smb_stat_ex_from_stat(&smb_fname->st, &st);
2149                 status = NT_STATUS_OK;
2150         } else {
2151                 status = NT_STATUS_NO_MEMORY;
2152         }
2153
2154   err:
2155
2156         if (link_target != link_target_buf) {
2157                 TALLOC_FREE(link_target);
2158         }
2159         return status;
2160 }
2161
2162 static struct vfs_fn_pointers glusterfs_fns = {
2163
2164         /* Disk Operations */
2165
2166         .connect_fn = vfs_gluster_connect,
2167         .disconnect_fn = vfs_gluster_disconnect,
2168         .disk_free_fn = vfs_gluster_disk_free,
2169         .get_quota_fn = vfs_gluster_get_quota,
2170         .set_quota_fn = vfs_gluster_set_quota,
2171         .statvfs_fn = vfs_gluster_statvfs,
2172         .fs_capabilities_fn = vfs_gluster_fs_capabilities,
2173
2174         .get_dfs_referrals_fn = NULL,
2175
2176         /* Directory Operations */
2177
2178         .fdopendir_fn = vfs_gluster_fdopendir,
2179         .readdir_fn = vfs_gluster_readdir,
2180         .seekdir_fn = vfs_gluster_seekdir,
2181         .telldir_fn = vfs_gluster_telldir,
2182         .rewind_dir_fn = vfs_gluster_rewinddir,
2183         .mkdirat_fn = vfs_gluster_mkdirat,
2184         .closedir_fn = vfs_gluster_closedir,
2185
2186         /* File Operations */
2187
2188         .openat_fn = vfs_gluster_openat,
2189         .create_file_fn = NULL,
2190         .close_fn = vfs_gluster_close,
2191         .pread_fn = vfs_gluster_pread,
2192         .pread_send_fn = vfs_gluster_pread_send,
2193         .pread_recv_fn = vfs_gluster_pread_recv,
2194         .pwrite_fn = vfs_gluster_pwrite,
2195         .pwrite_send_fn = vfs_gluster_pwrite_send,
2196         .pwrite_recv_fn = vfs_gluster_pwrite_recv,
2197         .lseek_fn = vfs_gluster_lseek,
2198         .sendfile_fn = vfs_gluster_sendfile,
2199         .recvfile_fn = vfs_gluster_recvfile,
2200         .renameat_fn = vfs_gluster_renameat,
2201         .fsync_send_fn = vfs_gluster_fsync_send,
2202         .fsync_recv_fn = vfs_gluster_fsync_recv,
2203
2204         .stat_fn = vfs_gluster_stat,
2205         .fstat_fn = vfs_gluster_fstat,
2206         .lstat_fn = vfs_gluster_lstat,
2207         .get_alloc_size_fn = vfs_gluster_get_alloc_size,
2208         .unlinkat_fn = vfs_gluster_unlinkat,
2209
2210         .chmod_fn = vfs_gluster_chmod,
2211         .fchmod_fn = vfs_gluster_fchmod,
2212         .fchown_fn = vfs_gluster_fchown,
2213         .lchown_fn = vfs_gluster_lchown,
2214         .chdir_fn = vfs_gluster_chdir,
2215         .getwd_fn = vfs_gluster_getwd,
2216         .ntimes_fn = vfs_gluster_ntimes,
2217         .ftruncate_fn = vfs_gluster_ftruncate,
2218         .fallocate_fn = vfs_gluster_fallocate,
2219         .lock_fn = vfs_gluster_lock,
2220         .kernel_flock_fn = vfs_gluster_kernel_flock,
2221         .fcntl_fn = vfs_gluster_fcntl,
2222         .linux_setlease_fn = vfs_gluster_linux_setlease,
2223         .getlock_fn = vfs_gluster_getlock,
2224         .symlinkat_fn = vfs_gluster_symlinkat,
2225         .readlinkat_fn = vfs_gluster_readlinkat,
2226         .linkat_fn = vfs_gluster_linkat,
2227         .mknodat_fn = vfs_gluster_mknodat,
2228         .realpath_fn = vfs_gluster_realpath,
2229         .chflags_fn = vfs_gluster_chflags,
2230         .file_id_create_fn = NULL,
2231         .streaminfo_fn = NULL,
2232         .get_real_filename_fn = vfs_gluster_get_real_filename,
2233         .connectpath_fn = vfs_gluster_connectpath,
2234         .create_dfs_pathat_fn = vfs_gluster_create_dfs_pathat,
2235         .read_dfs_pathat_fn = vfs_gluster_read_dfs_pathat,
2236
2237         .brl_lock_windows_fn = NULL,
2238         .brl_unlock_windows_fn = NULL,
2239         .strict_lock_check_fn = NULL,
2240         .translate_name_fn = NULL,
2241         .fsctl_fn = NULL,
2242
2243         /* NT ACL Operations */
2244         .fget_nt_acl_fn = NULL,
2245         .get_nt_acl_at_fn = NULL,
2246         .fset_nt_acl_fn = NULL,
2247         .audit_file_fn = NULL,
2248
2249         /* Posix ACL Operations */
2250         .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
2251         .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
2252         .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
2253         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
2254         .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
2255         .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
2256         .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
2257
2258         /* EA Operations */
2259         .getxattr_fn = vfs_gluster_getxattr,
2260         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2261         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2262         .fgetxattr_fn = vfs_gluster_fgetxattr,
2263         .listxattr_fn = vfs_gluster_listxattr,
2264         .flistxattr_fn = vfs_gluster_flistxattr,
2265         .removexattr_fn = vfs_gluster_removexattr,
2266         .fremovexattr_fn = vfs_gluster_fremovexattr,
2267         .setxattr_fn = vfs_gluster_setxattr,
2268         .fsetxattr_fn = vfs_gluster_fsetxattr,
2269
2270         /* AIO Operations */
2271         .aio_force_fn = vfs_gluster_aio_force,
2272
2273         /* Durable handle Operations */
2274         .durable_cookie_fn = NULL,
2275         .durable_disconnect_fn = NULL,
2276         .durable_reconnect_fn = NULL,
2277 };
2278
2279 static_decl_vfs;
2280 NTSTATUS vfs_glusterfs_init(TALLOC_CTX *ctx)
2281 {
2282         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2283                                 "glusterfs", &glusterfs_fns);
2284 }