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