s3:utils: let smbstatus report anonymous signing/encryption explicitly
[samba.git] / source3 / modules / vfs_glusterfs.c
index 59b7654611295294a0c247b885a79dbc65156a50..00b4cdd4698da6f06f4f751fbd1fd1a1c2016795 100644 (file)
@@ -41,6 +41,7 @@
 #include <glusterfs/api/glfs.h>
 #include "lib/util/dlinklist.h"
 #include "lib/util/tevent_unix.h"
+#include "lib/util/util_file.h"
 #include "smbd/globals.h"
 #include "lib/util/sys_rw.h"
 #include "smbprofile.h"
@@ -71,16 +72,12 @@ static void smb_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src)
        dst->st_ex_btime.tv_sec = src->st_mtime;
        dst->st_ex_blksize = src->st_blksize;
        dst->st_ex_blocks = src->st_blocks;
-       dst->st_ex_file_id = dst->st_ex_ino;
-       dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_FILE_ID;
 #ifdef STAT_HAVE_NSEC
        dst->st_ex_atime.tv_nsec = src->st_atime_nsec;
        dst->st_ex_mtime.tv_nsec = src->st_mtime_nsec;
        dst->st_ex_ctime.tv_nsec = src->st_ctime_nsec;
        dst->st_ex_btime.tv_nsec = src->st_mtime_nsec;
 #endif
-       dst->st_ex_itime = dst->st_ex_btime;
-       dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_ITIME;
 }
 
 /* pre-opened glfs_t */
@@ -155,6 +152,7 @@ static void glfs_clear_preopened(glfs_t *fs)
 
                        glfs_fini(entry->fs);
                        talloc_free(entry);
+                       break;
                }
        }
 }
@@ -317,7 +315,7 @@ static int check_for_write_behind_translator(TALLOC_CTX *mem_ctx,
 
        /*
         * file_lines_parse() plays horrible tricks with
-        * the passed-in talloc pointers and the hierarcy
+        * the passed-in talloc pointers and the hierarchy
         * which makes freeing hard to get right.
         *
         * As we know mem_ctx is freed by the caller, after
@@ -610,7 +608,7 @@ static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
 }
 
 static glfs_fd_t *vfs_gluster_fetch_glfd(struct vfs_handle_struct *handle,
-                                        files_struct *fsp)
+                                        const files_struct *fsp)
 {
        glfs_fd_t **glfd = (glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
        if (glfd == NULL) {
@@ -629,9 +627,10 @@ static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle,
                                  files_struct *fsp, const char *mask,
                                  uint32_t attributes)
 {
-       glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
+       glfs_fd_t *glfd = NULL;
+
+       glfd = glfs_opendir(handle->data, fsp->fsp_name->base_name);
        if (glfd == NULL) {
-               DBG_ERR("Failed to fetch gluster fd\n");
                return NULL;
        }
 
@@ -651,57 +650,25 @@ static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp)
 
 static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle,
                                          struct files_struct *dirfsp,
-                                         DIR *dirp,
-                                         SMB_STRUCT_STAT *sbuf)
+                                         DIR *dirp)
 {
        static char direntbuf[512];
        int ret;
-       struct stat stat;
        struct dirent *dirent = 0;
 
        START_PROFILE(syscall_readdir);
-       if (sbuf != NULL) {
-               ret = glfs_readdirplus_r((void *)dirp, &stat, (void *)direntbuf,
-                                        &dirent);
-       } else {
-               ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
-       }
+
+       ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
 
        if ((ret < 0) || (dirent == NULL)) {
                END_PROFILE(syscall_readdir);
                return NULL;
        }
 
-       if (sbuf != NULL) {
-               SET_STAT_INVALID(*sbuf);
-               if (!S_ISLNK(stat.st_mode)) {
-                       smb_stat_ex_from_stat(sbuf, &stat);
-               }
-       }
-
        END_PROFILE(syscall_readdir);
        return dirent;
 }
 
-static long vfs_gluster_telldir(struct vfs_handle_struct *handle, DIR *dirp)
-{
-       long ret;
-
-       START_PROFILE(syscall_telldir);
-       ret = glfs_telldir((void *)dirp);
-       END_PROFILE(syscall_telldir);
-
-       return ret;
-}
-
-static void vfs_gluster_seekdir(struct vfs_handle_struct *handle, DIR *dirp,
-                               long offset)
-{
-       START_PROFILE(syscall_seekdir);
-       glfs_seekdir((void *)dirp, offset);
-       END_PROFILE(syscall_seekdir);
-}
-
 static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
 {
        START_PROFILE(syscall_rewinddir);
@@ -714,9 +681,24 @@ static int vfs_gluster_mkdirat(struct vfs_handle_struct *handle,
                        const struct smb_filename *smb_fname,
                        mode_t mode)
 {
-       struct smb_filename *full_fname = NULL;
        int ret;
 
+#ifdef HAVE_GFAPI_VER_7_11
+       glfs_fd_t *pglfd = NULL;
+
+       START_PROFILE(syscall_mkdirat);
+
+       pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
+       if (pglfd == NULL) {
+               END_PROFILE(syscall_mkdirat);
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return -1;
+       }
+
+       ret = glfs_mkdirat(pglfd, smb_fname->base_name, mode);
+#else
+       struct smb_filename *full_fname = NULL;
+
        START_PROFILE(syscall_mkdirat);
 
        full_fname = full_path_from_dirfsp_atname(talloc_tos(),
@@ -730,6 +712,7 @@ static int vfs_gluster_mkdirat(struct vfs_handle_struct *handle,
        ret = glfs_mkdir(handle->data, full_fname->base_name, mode);
 
        TALLOC_FREE(full_fname);
+#endif
 
        END_PROFILE(syscall_mkdirat);
 
@@ -740,63 +723,103 @@ static int vfs_gluster_openat(struct vfs_handle_struct *handle,
                              const struct files_struct *dirfsp,
                              const struct smb_filename *smb_fname,
                              files_struct *fsp,
-                             int flags,
-                             mode_t mode)
+                             const struct vfs_open_how *how)
 {
-       struct smb_filename *name = NULL;
+       int flags = how->flags;
+       struct smb_filename *full_fname = NULL;
+       bool have_opath = false;
        bool became_root = false;
-       glfs_fd_t *glfd;
+       glfs_fd_t *glfd = NULL;
+       glfs_fd_t *pglfd = NULL;
        glfs_fd_t **p_tmp;
 
        START_PROFILE(syscall_openat);
 
-       /*
-        * Looks like glfs API doesn't have openat().
-        */
-       if (fsp_get_pathref_fd(dirfsp) != AT_FDCWD) {
-               name = full_path_from_dirfsp_atname(talloc_tos(),
-                                                   dirfsp,
-                                                   smb_fname);
-               if (name == NULL) {
-                       return -1;
-               }
-               smb_fname = name;
+       if (how->resolve != 0) {
+               END_PROFILE(syscall_openat);
+               errno = ENOSYS;
+               return -1;
        }
 
        p_tmp = VFS_ADD_FSP_EXTENSION(handle, fsp, glfs_fd_t *, NULL);
        if (p_tmp == NULL) {
-               TALLOC_FREE(name);
                END_PROFILE(syscall_openat);
                errno = ENOMEM;
                return -1;
        }
 
+#ifdef O_PATH
+       have_opath = true;
        if (fsp->fsp_flags.is_pathref) {
-               /*
-                * ceph doesn't support O_PATH so we have to fallback to
-                * become_root().
-                */
+               flags |= O_PATH;
+       }
+#endif
+
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 smb_fname);
+       if (full_fname == NULL) {
+               END_PROFILE(syscall_openat);
+               return -1;
+       }
+
+       if (fsp->fsp_flags.is_pathref && !have_opath) {
                become_root();
                became_root = true;
        }
 
-       if (flags & O_DIRECTORY) {
-               glfd = glfs_opendir(handle->data, smb_fname->base_name);
-       } else if (flags & O_CREAT) {
-               glfd = glfs_creat(handle->data, smb_fname->base_name, flags,
-                                 mode);
-       } else {
-               glfd = glfs_open(handle->data, smb_fname->base_name, flags);
+       if (fsp_get_pathref_fd(dirfsp) != AT_FDCWD) {
+#ifdef HAVE_GFAPI_VER_7_11
+               /*
+                * Fetch Gluster fd for parent directory using dirfsp
+                * before calling glfs_openat();
+                */
+               pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
+               if (pglfd == NULL) {
+                       END_PROFILE(syscall_openat);
+                       DBG_ERR("Failed to fetch gluster fd\n");
+                       return -1;
+               }
+
+               glfd = glfs_openat(pglfd,
+                                  smb_fname->base_name,
+                                  flags,
+                                  how->mode);
+#else
+               /*
+                * Replace smb_fname with full_path constructed above.
+                */
+               smb_fname = full_fname;
+#endif
+       }
+
+       if (pglfd == NULL) {
+               /*
+                * smb_fname can either be a full_path or the same one
+                * as received from the caller. In the latter case we
+                * are operating at current working directory.
+                */
+               if (flags & O_CREAT) {
+                       glfd = glfs_creat(handle->data,
+                                         smb_fname->base_name,
+                                         flags,
+                                         how->mode);
+               } else {
+                       glfd = glfs_open(handle->data,
+                                        smb_fname->base_name,
+                                        flags);
+               }
        }
 
        if (became_root) {
                unbecome_root();
        }
 
+       TALLOC_FREE(full_fname);
+
        fsp->fsp_flags.have_proc_fds = false;
 
        if (glfd == NULL) {
-               TALLOC_FREE(name);
                END_PROFILE(syscall_openat);
                /* no extension destroy_fn, so no need to save errno */
                VFS_REMOVE_FSP_EXTENSION(handle, fsp);
@@ -805,7 +828,6 @@ static int vfs_gluster_openat(struct vfs_handle_struct *handle,
 
        *p_tmp = glfd;
 
-       TALLOC_FREE(name);
        END_PROFILE(syscall_openat);
        /* An arbitrary value for error reporting, so you know its us. */
        return 13371337;
@@ -1211,9 +1233,60 @@ static int vfs_gluster_renameat(struct vfs_handle_struct *handle,
 {
        int ret;
 
+#ifdef HAVE_GFAPI_VER_7_11
+       glfs_fd_t *src_pglfd = NULL;
+       glfs_fd_t *dst_pglfd = NULL;
+
+       START_PROFILE(syscall_renameat);
+
+       src_pglfd = vfs_gluster_fetch_glfd(handle, srcfsp);
+       if (src_pglfd == NULL) {
+               END_PROFILE(syscall_renameat);
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return -1;
+       }
+
+       dst_pglfd = vfs_gluster_fetch_glfd(handle, dstfsp);
+       if (dst_pglfd == NULL) {
+               END_PROFILE(syscall_renameat);
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return -1;
+       }
+
+       ret = glfs_renameat(src_pglfd, smb_fname_src->base_name,
+                           dst_pglfd, smb_fname_dst->base_name);
+#else
+       struct smb_filename *full_fname_src = NULL;
+       struct smb_filename *full_fname_dst = NULL;
+
        START_PROFILE(syscall_renameat);
-       ret = glfs_rename(handle->data, smb_fname_src->base_name,
-                         smb_fname_dst->base_name);
+
+       full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
+                                                     srcfsp,
+                                                     smb_fname_src);
+       if (full_fname_src == NULL) {
+               END_PROFILE(syscall_renameat);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
+                                                     dstfsp,
+                                                     smb_fname_dst);
+       if (full_fname_dst == NULL) {
+               END_PROFILE(syscall_renameat);
+               TALLOC_FREE(full_fname_src);
+               errno = ENOMEM;
+               return -1;
+       }
+       ret = glfs_rename(handle->data,
+                         full_fname_src->base_name,
+                         full_fname_dst->base_name);
+
+       TALLOC_FREE(full_fname_src);
+       TALLOC_FREE(full_fname_dst);
+#endif
+
        END_PROFILE(syscall_renameat);
 
        return ret;
@@ -1396,6 +1469,55 @@ static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
        return ret;
 }
 
+static int vfs_gluster_fstatat(struct vfs_handle_struct *handle,
+                              const struct files_struct *dirfsp,
+                              const struct smb_filename *smb_fname,
+                              SMB_STRUCT_STAT *sbuf,
+                              int flags)
+{
+       struct stat st;
+       int ret;
+
+#ifdef HAVE_GFAPI_VER_7_11
+       glfs_fd_t *pglfd = NULL;
+
+       START_PROFILE(syscall_fstatat);
+
+       pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
+       if (pglfd == NULL) {
+               END_PROFILE(syscall_fstatat);
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return -1;
+       }
+
+       ret = glfs_fstatat(pglfd, smb_fname->base_name, &st, flags);
+#else
+       struct smb_filename *full_fname = NULL;
+
+       START_PROFILE(syscall_fstatat);
+
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 smb_fname);
+       if (full_fname == NULL) {
+               END_PROFILE(syscall_fstatat);
+               return -1;
+       }
+
+       ret = glfs_stat(handle->data, full_fname->base_name, &st);
+
+       TALLOC_FREE(full_fname->base_name);
+#endif
+
+       if (ret == 0) {
+               smb_stat_ex_from_stat(sbuf, &st);
+       }
+
+       END_PROFILE(syscall_fstatat);
+
+       return ret;
+}
+
 static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
                             struct smb_filename *smb_fname)
 {
@@ -1436,27 +1558,42 @@ static int vfs_gluster_unlinkat(struct vfs_handle_struct *handle,
 {
        int ret;
 
+#ifdef HAVE_GFAPI_VER_7_11
+       glfs_fd_t *pglfd = NULL;
+
+       START_PROFILE(syscall_unlinkat);
+
+       pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
+       if (pglfd == NULL) {
+               END_PROFILE(syscall_unlinkat);
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return -1;
+       }
+
+       ret = glfs_unlinkat(pglfd, smb_fname->base_name, flags);
+#else
+       struct smb_filename *full_fname = NULL;
+
        START_PROFILE(syscall_unlinkat);
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
+
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 smb_fname);
+       if (full_fname == NULL) {
+               END_PROFILE(syscall_unlinkat);
+               return -1;
+       }
+
        if (flags & AT_REMOVEDIR) {
-               ret = glfs_rmdir(handle->data, smb_fname->base_name);
+               ret = glfs_rmdir(handle->data, full_fname->base_name);
        } else {
-               ret = glfs_unlink(handle->data, smb_fname->base_name);
+               ret = glfs_unlink(handle->data, full_fname->base_name);
        }
-       END_PROFILE(syscall_unlinkat);
 
-       return ret;
-}
-
-static int vfs_gluster_chmod(struct vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               mode_t mode)
-{
-       int ret;
+       TALLOC_FREE(full_fname);
+#endif
 
-       START_PROFILE(syscall_chmod);
-       ret = glfs_chmod(handle->data, smb_fname->base_name, mode);
-       END_PROFILE(syscall_chmod);
+       END_PROFILE(syscall_unlinkat);
 
        return ret;
 }
@@ -1476,7 +1613,17 @@ static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
                return -1;
        }
 
-       ret = glfs_fchmod(glfd, mode);
+       if (!fsp->fsp_flags.is_pathref) {
+               /*
+                * We can use an io_fd to remove xattrs.
+                */
+               ret = glfs_fchmod(glfd, mode);
+       } else {
+               /*
+                * This is no longer a handle based call.
+                */
+               ret = glfs_chmod(handle->data, fsp->fsp_name->base_name, mode);
+       }
        END_PROFILE(syscall_fchmod);
 
        return ret;
@@ -1532,23 +1679,16 @@ static int vfs_gluster_chdir(struct vfs_handle_struct *handle,
 static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
                                TALLOC_CTX *ctx)
 {
-       char *cwd;
+       char cwd[PATH_MAX] = { '\0' };
        char *ret;
        struct smb_filename *smb_fname = NULL;
 
        START_PROFILE(syscall_getwd);
 
-       cwd = SMB_CALLOC_ARRAY(char, PATH_MAX);
-       if (cwd == NULL) {
-               END_PROFILE(syscall_getwd);
-               return NULL;
-       }
-
        ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1);
        END_PROFILE(syscall_getwd);
 
        if (ret == NULL) {
-               SAFE_FREE(cwd);
                return NULL;
        }
        smb_fname = synthetic_smb_fname(ctx,
@@ -1557,45 +1697,58 @@ static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
                                        NULL,
                                        0,
                                        0);
-       SAFE_FREE(cwd);
        return smb_fname;
 }
 
-static int vfs_gluster_ntimes(struct vfs_handle_struct *handle,
-                             const struct smb_filename *smb_fname,
-                             struct smb_file_time *ft)
+static int vfs_gluster_fntimes(struct vfs_handle_struct *handle,
+                              files_struct *fsp,
+                              struct smb_file_time *ft)
 {
        int ret = -1;
        struct timespec times[2];
+       glfs_fd_t *glfd = NULL;
 
-       START_PROFILE(syscall_ntimes);
+       START_PROFILE(syscall_fntimes);
 
        if (is_omit_timespec(&ft->atime)) {
-               times[0].tv_sec = smb_fname->st.st_ex_atime.tv_sec;
-               times[0].tv_nsec = smb_fname->st.st_ex_atime.tv_nsec;
+               times[0].tv_sec = fsp->fsp_name->st.st_ex_atime.tv_sec;
+               times[0].tv_nsec = fsp->fsp_name->st.st_ex_atime.tv_nsec;
        } else {
                times[0].tv_sec = ft->atime.tv_sec;
                times[0].tv_nsec = ft->atime.tv_nsec;
        }
 
        if (is_omit_timespec(&ft->mtime)) {
-               times[1].tv_sec = smb_fname->st.st_ex_mtime.tv_sec;
-               times[1].tv_nsec = smb_fname->st.st_ex_mtime.tv_nsec;
+               times[1].tv_sec = fsp->fsp_name->st.st_ex_mtime.tv_sec;
+               times[1].tv_nsec = fsp->fsp_name->st.st_ex_mtime.tv_nsec;
        } else {
                times[1].tv_sec = ft->mtime.tv_sec;
                times[1].tv_nsec = ft->mtime.tv_nsec;
        }
 
        if ((timespec_compare(&times[0],
-                             &smb_fname->st.st_ex_atime) == 0) &&
+                             &fsp->fsp_name->st.st_ex_atime) == 0) &&
            (timespec_compare(&times[1],
-                             &smb_fname->st.st_ex_mtime) == 0)) {
-               END_PROFILE(syscall_ntimes);
+                             &fsp->fsp_name->st.st_ex_mtime) == 0)) {
+               END_PROFILE(syscall_fntimes);
                return 0;
        }
 
-       ret = glfs_utimens(handle->data, smb_fname->base_name, times);
-       END_PROFILE(syscall_ntimes);
+       glfd = vfs_gluster_fetch_glfd(handle, fsp);
+       if (glfd == NULL) {
+               END_PROFILE(syscall_fntimes);
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return -1;
+       }
+
+       if (!fsp->fsp_flags.is_pathref) {
+               ret = glfs_futimens(glfd, times);
+       } else {
+               ret = glfs_utimens(handle->data,
+                                  fsp->fsp_name->base_name,
+                                  times);
+       }
+       END_PROFILE(syscall_fntimes);
 
        return ret;
 }
@@ -1757,9 +1910,10 @@ out:
        return ok;
 }
 
-static int vfs_gluster_kernel_flock(struct vfs_handle_struct *handle,
-                                   files_struct *fsp, uint32_t share_access,
-                                   uint32_t access_mask)
+static int vfs_gluster_filesystem_sharemode(struct vfs_handle_struct *handle,
+                                           files_struct *fsp,
+                                           uint32_t share_access,
+                                           uint32_t access_mask)
 {
        errno = ENOSYS;
        return -1;
@@ -1846,11 +2000,41 @@ static int vfs_gluster_symlinkat(struct vfs_handle_struct *handle,
 {
        int ret;
 
+#ifdef HAVE_GFAPI_VER_7_11
+       glfs_fd_t *pglfd = NULL;
+
+       START_PROFILE(syscall_symlinkat);
+
+       pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
+       if (pglfd == NULL) {
+               END_PROFILE(syscall_symlinkat);
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return -1;
+       }
+
+       ret = glfs_symlinkat(link_target->base_name,
+                            pglfd,
+                            new_smb_fname->base_name);
+#else
+       struct smb_filename *full_fname = NULL;
+
        START_PROFILE(syscall_symlinkat);
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
+
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 new_smb_fname);
+       if (full_fname == NULL) {
+               END_PROFILE(syscall_symlinkat);
+               return -1;
+       }
+
        ret = glfs_symlink(handle->data,
-                       link_target->base_name,
-                       new_smb_fname->base_name);
+                          link_target->base_name,
+                          full_fname->base_name);
+
+       TALLOC_FREE(full_fname);
+#endif
+
        END_PROFILE(syscall_symlinkat);
 
        return ret;
@@ -1864,9 +2048,37 @@ static int vfs_gluster_readlinkat(struct vfs_handle_struct *handle,
 {
        int ret;
 
+#ifdef HAVE_GFAPI_VER_7_11
+       glfs_fd_t *pglfd = NULL;
+
        START_PROFILE(syscall_readlinkat);
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-       ret = glfs_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
+
+       pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
+       if (pglfd == NULL) {
+               END_PROFILE(syscall_readlinkat);
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return -1;
+       }
+
+       ret = glfs_readlinkat(pglfd, smb_fname->base_name, buf, bufsiz);
+#else
+       struct smb_filename *full_fname = NULL;
+
+       START_PROFILE(syscall_readlinkat);
+
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 smb_fname);
+       if (full_fname == NULL) {
+               END_PROFILE(syscall_readlinkat);
+               return -1;
+       }
+
+       ret = glfs_readlink(handle->data, full_fname->base_name, buf, bufsiz);
+
+       TALLOC_FREE(full_fname);
+#endif
+
        END_PROFILE(syscall_readlinkat);
 
        return ret;
@@ -1881,14 +2093,62 @@ static int vfs_gluster_linkat(struct vfs_handle_struct *handle,
 {
        int ret;
 
+#ifdef HAVE_GFAPI_VER_7_11
+       glfs_fd_t *src_pglfd = NULL;
+       glfs_fd_t *dst_pglfd = NULL;
+
+       START_PROFILE(syscall_linkat);
+
+       src_pglfd = vfs_gluster_fetch_glfd(handle, srcfsp);
+       if (src_pglfd == NULL) {
+               END_PROFILE(syscall_linkat);
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return -1;
+       }
+
+       dst_pglfd = vfs_gluster_fetch_glfd(handle, dstfsp);
+       if (dst_pglfd == NULL) {
+               END_PROFILE(syscall_linkat);
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return -1;
+       }
+
+       ret = glfs_linkat(src_pglfd,
+                         old_smb_fname->base_name,
+                         dst_pglfd,
+                         new_smb_fname->base_name,
+                         flags);
+#else
+       struct smb_filename *full_fname_old = NULL;
+       struct smb_filename *full_fname_new = NULL;
+
        START_PROFILE(syscall_linkat);
 
-       SMB_ASSERT(srcfsp == srcfsp->conn->cwd_fsp);
-       SMB_ASSERT(dstfsp == dstfsp->conn->cwd_fsp);
+       full_fname_old = full_path_from_dirfsp_atname(talloc_tos(),
+                                                     srcfsp,
+                                                     old_smb_fname);
+       if (full_fname_old == NULL) {
+               END_PROFILE(syscall_linkat);
+               return -1;
+       }
+
+       full_fname_new = full_path_from_dirfsp_atname(talloc_tos(),
+                                                     dstfsp,
+                                                     new_smb_fname);
+       if (full_fname_new == NULL) {
+               END_PROFILE(syscall_linkat);
+               TALLOC_FREE(full_fname_old);
+               return -1;
+       }
 
        ret = glfs_link(handle->data,
-                       old_smb_fname->base_name,
-                       new_smb_fname->base_name);
+                       full_fname_old->base_name,
+                       full_fname_new->base_name);
+
+       TALLOC_FREE(full_fname_old);
+       TALLOC_FREE(full_fname_new);
+#endif
+
        END_PROFILE(syscall_linkat);
 
        return ret;
@@ -1900,14 +2160,29 @@ static int vfs_gluster_mknodat(struct vfs_handle_struct *handle,
                                mode_t mode,
                                SMB_DEV_T dev)
 {
-       struct smb_filename *full_fname = NULL;
        int ret;
 
+#ifdef HAVE_GFAPI_VER_7_11
+       glfs_fd_t *pglfd = NULL;
+
+       START_PROFILE(syscall_mknodat);
+
+       pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
+       if (pglfd == NULL) {
+               END_PROFILE(syscall_mknodat);
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return -1;
+       }
+
+       ret = glfs_mknodat(pglfd, smb_fname->base_name, mode, dev);
+#else
+       struct smb_filename *full_fname = NULL;
+
        START_PROFILE(syscall_mknodat);
 
        full_fname = full_path_from_dirfsp_atname(talloc_tos(),
-                                               dirfsp,
-                                               smb_fname);
+                                                 dirfsp,
+                                                 smb_fname);
        if (full_fname == NULL) {
                END_PROFILE(syscall_mknodat);
                return -1;
@@ -1916,73 +2191,69 @@ static int vfs_gluster_mknodat(struct vfs_handle_struct *handle,
        ret = glfs_mknod(handle->data, full_fname->base_name, mode, dev);
 
        TALLOC_FREE(full_fname);
+#endif
 
        END_PROFILE(syscall_mknodat);
 
        return ret;
 }
 
-static int vfs_gluster_chflags(struct vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
+static int vfs_gluster_fchflags(struct vfs_handle_struct *handle,
+                               struct files_struct *fsp,
                                unsigned int flags)
 {
        errno = ENOSYS;
        return -1;
 }
 
-static int vfs_gluster_get_real_filename(struct vfs_handle_struct *handle,
-                                        const struct smb_filename *path,
-                                        const char *name,
-                                        TALLOC_CTX *mem_ctx,
-                                        char **found_name)
+static NTSTATUS vfs_gluster_get_real_filename_at(
+       struct vfs_handle_struct *handle,
+       struct files_struct *dirfsp,
+       const char *name,
+       TALLOC_CTX *mem_ctx,
+       char **found_name)
 {
        int ret;
        char key_buf[GLUSTER_NAME_MAX + 64];
        char val_buf[GLUSTER_NAME_MAX + 1];
 
        if (strlen(name) >= GLUSTER_NAME_MAX) {
-               errno = ENAMETOOLONG;
-               return -1;
+               return NT_STATUS_OBJECT_NAME_INVALID;
        }
 
        snprintf(key_buf, GLUSTER_NAME_MAX + 64,
                 "glusterfs.get_real_filename:%s", name);
 
-       ret = glfs_getxattr(handle->data, path->base_name, key_buf, val_buf,
+       ret = glfs_getxattr(handle->data,
+                           dirfsp->fsp_name->base_name,
+                           key_buf,
+                           val_buf,
                            GLUSTER_NAME_MAX + 1);
        if (ret == -1) {
                if (errno == ENOATTR) {
                        errno = ENOENT;
                }
-               return -1;
+               return map_nt_error_from_unix(errno);
        }
 
        *found_name = talloc_strdup(mem_ctx, val_buf);
        if (found_name[0] == NULL) {
-               errno = ENOMEM;
-               return -1;
+               return NT_STATUS_NO_MEMORY;
        }
-       return 0;
+
+       return NT_STATUS_OK;
 }
 
-static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname)
+static const char *vfs_gluster_connectpath(
+       struct vfs_handle_struct *handle,
+       const struct files_struct *dirfsp,
+       const struct smb_filename *smb_fname)
 {
        return handle->conn->connectpath;
 }
 
 /* EA Operations */
 
-static ssize_t vfs_gluster_getxattr(struct vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               const char *name,
-                               void *value,
-                               size_t size)
-{
-       return glfs_getxattr(handle->data, smb_fname->base_name,
-                            name, value, size);
-}
-
 static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
                                     files_struct *fsp, const char *name,
                                     void *value, size_t size)
@@ -1993,15 +2264,21 @@ static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
                return -1;
        }
 
-       return glfs_fgetxattr(glfd, name, value, size);
-}
+       if (!fsp->fsp_flags.is_pathref) {
+               /*
+                * We can use an io_fd to retrieve xattr value.
+                */
+               return glfs_fgetxattr(glfd, name, value, size);
+       }
 
-static ssize_t vfs_gluster_listxattr(struct vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               char *list,
-                               size_t size)
-{
-       return glfs_listxattr(handle->data, smb_fname->base_name, list, size);
+       /*
+        * This is no longer a handle based call.
+        */
+       return glfs_getxattr(handle->data,
+                            fsp->fsp_name->base_name,
+                            name,
+                            value,
+                            size);
 }
 
 static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
@@ -2013,15 +2290,20 @@ static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
                DBG_ERR("Failed to fetch gluster fd\n");
                return -1;
        }
-
-       return glfs_flistxattr(glfd, list, size);
-}
-
-static int vfs_gluster_removexattr(struct vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               const char *name)
-{
-       return glfs_removexattr(handle->data, smb_fname->base_name, name);
+       if (!fsp->fsp_flags.is_pathref) {
+               /*
+                * We can use an io_fd to list xattrs.
+                */
+               return glfs_flistxattr(glfd, list, size);
+       } else {
+               /*
+                * This is no longer a handle based call.
+                */
+               return glfs_listxattr(handle->data,
+                               fsp->fsp_name->base_name,
+                               list,
+                               size);
+       }
 }
 
 static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
@@ -2032,16 +2314,19 @@ static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
                DBG_ERR("Failed to fetch gluster fd\n");
                return -1;
        }
-
-       return glfs_fremovexattr(glfd, name);
-}
-
-static int vfs_gluster_setxattr(struct vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               const char *name,
-                               const void *value, size_t size, int flags)
-{
-       return glfs_setxattr(handle->data, smb_fname->base_name, name, value, size, flags);
+       if (!fsp->fsp_flags.is_pathref) {
+               /*
+                * We can use an io_fd to remove xattrs.
+                */
+               return glfs_fremovexattr(glfd, name);
+       } else {
+               /*
+                * This is no longer a handle based call.
+                */
+               return glfs_removexattr(handle->data,
+                               fsp->fsp_name->base_name,
+                               name);
+       }
 }
 
 static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
@@ -2054,7 +2339,22 @@ static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
                return -1;
        }
 
-       return glfs_fsetxattr(glfd, name, value, size, flags);
+       if (!fsp->fsp_flags.is_pathref) {
+               /*
+                * We can use an io_fd to set xattrs.
+                */
+               return glfs_fsetxattr(glfd, name, value, size, flags);
+       } else {
+               /*
+                * This is no longer a handle based call.
+                */
+               return glfs_setxattr(handle->data,
+                               fsp->fsp_name->base_name,
+                               name,
+                               value,
+                               size,
+                               flags);
+       }
 }
 
 /* AIO Operations */
@@ -2075,8 +2375,11 @@ static NTSTATUS vfs_gluster_create_dfs_pathat(struct vfs_handle_struct *handle,
        NTSTATUS status = NT_STATUS_NO_MEMORY;
        int ret;
        char *msdfs_link = NULL;
-
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
+#ifdef HAVE_GFAPI_VER_7_11
+       glfs_fd_t *pglfd = NULL;
+#else
+       struct smb_filename *full_fname = NULL;
+#endif
 
        /* Form the msdfs_link contents */
        msdfs_link = msdfs_link_string(frame,
@@ -2086,9 +2389,27 @@ static NTSTATUS vfs_gluster_create_dfs_pathat(struct vfs_handle_struct *handle,
                goto out;
        }
 
-       ret = glfs_symlink(handle->data,
-                       msdfs_link,
-                       smb_fname->base_name);
+#ifdef HAVE_GFAPI_VER_7_11
+       pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
+       if (pglfd == NULL) {
+               DBG_ERR("Failed to fetch gluster fd\n");
+               status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               goto out;
+       }
+
+       ret = glfs_symlinkat(msdfs_link, pglfd, smb_fname->base_name);
+#else
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 smb_fname);
+       if (full_fname == NULL) {
+               goto out;
+       }
+
+       ret = glfs_symlink(handle->data, msdfs_link, full_fname->base_name);
+
+       TALLOC_FREE(full_fname);
+#endif
        if (ret == 0) {
                status = NT_STATUS_OK;
        } else {
@@ -2128,9 +2449,11 @@ static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
        char link_target_buf[7];
 #endif
        struct stat st;
+       struct smb_filename *full_fname = NULL;
        int ret;
-
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
+#ifdef HAVE_GFAPI_VER_7_11
+       glfs_fd_t *pglfd = NULL;
+#endif
 
        if (is_named_stream(smb_fname)) {
                status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
@@ -2152,25 +2475,46 @@ static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
                }
        }
 
-       ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 smb_fname);
+       if (full_fname == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto err;
+        }
+
+       ret = glfs_lstat(handle->data, full_fname->base_name, &st);
        if (ret < 0) {
                status = map_nt_error_from_unix(errno);
                goto err;
        }
 
+#ifdef HAVE_GFAPI_VER_7_11
+       pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
+       if (pglfd == NULL) {
+               DBG_ERR("Failed to fetch gluster fd\n");
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       referral_len = glfs_readlinkat(pglfd,
+                                      smb_fname->base_name,
+                                      link_target,
+                                      bufsize - 1);
+#else
        referral_len = glfs_readlink(handle->data,
-                               smb_fname->base_name,
+                               full_fname->base_name,
                                link_target,
                                bufsize - 1);
+#endif
        if (referral_len < 0) {
                if (errno == EINVAL) {
-                       DBG_INFO("%s is not a link.\n", smb_fname->base_name);
+                       DBG_INFO("%s is not a link.\n", full_fname->base_name);
                        status = NT_STATUS_OBJECT_TYPE_MISMATCH;
                } else {
                        status = map_nt_error_from_unix(errno);
                        DBG_ERR("Error reading "
                                "msdfs link %s: %s\n",
-                               smb_fname->base_name,
+                               full_fname->base_name,
                                strerror(errno));
                }
                goto err;
@@ -2178,7 +2522,7 @@ static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
        link_target[referral_len] = '\0';
 
        DBG_INFO("%s -> %s\n",
-                       smb_fname->base_name,
+                       full_fname->base_name,
                        link_target);
 
        if (!strnequal(link_target, "msdfs:", 6)) {
@@ -2188,6 +2532,7 @@ static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
 
        if (ppreflist == NULL && preferral_count == NULL) {
                /* Early return for checking if this is a DFS link. */
+               TALLOC_FREE(full_fname);
                smb_stat_ex_from_stat(&smb_fname->st, &st);
                return NT_STATUS_OK;
        }
@@ -2210,6 +2555,7 @@ static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
        if (link_target != link_target_buf) {
                TALLOC_FREE(link_target);
        }
+       TALLOC_FREE(full_fname);
        return status;
 }
 
@@ -2231,8 +2577,6 @@ static struct vfs_fn_pointers glusterfs_fns = {
 
        .fdopendir_fn = vfs_gluster_fdopendir,
        .readdir_fn = vfs_gluster_readdir,
-       .seekdir_fn = vfs_gluster_seekdir,
-       .telldir_fn = vfs_gluster_telldir,
        .rewind_dir_fn = vfs_gluster_rewinddir,
        .mkdirat_fn = vfs_gluster_mkdirat,
        .closedir_fn = vfs_gluster_closedir,
@@ -2257,21 +2601,21 @@ static struct vfs_fn_pointers glusterfs_fns = {
 
        .stat_fn = vfs_gluster_stat,
        .fstat_fn = vfs_gluster_fstat,
+       .fstatat_fn = vfs_gluster_fstatat,
        .lstat_fn = vfs_gluster_lstat,
        .get_alloc_size_fn = vfs_gluster_get_alloc_size,
        .unlinkat_fn = vfs_gluster_unlinkat,
 
-       .chmod_fn = vfs_gluster_chmod,
        .fchmod_fn = vfs_gluster_fchmod,
        .fchown_fn = vfs_gluster_fchown,
        .lchown_fn = vfs_gluster_lchown,
        .chdir_fn = vfs_gluster_chdir,
        .getwd_fn = vfs_gluster_getwd,
-       .ntimes_fn = vfs_gluster_ntimes,
+       .fntimes_fn = vfs_gluster_fntimes,
        .ftruncate_fn = vfs_gluster_ftruncate,
        .fallocate_fn = vfs_gluster_fallocate,
        .lock_fn = vfs_gluster_lock,
-       .kernel_flock_fn = vfs_gluster_kernel_flock,
+       .filesystem_sharemode_fn = vfs_gluster_filesystem_sharemode,
        .fcntl_fn = vfs_gluster_fcntl,
        .linux_setlease_fn = vfs_gluster_linux_setlease,
        .getlock_fn = vfs_gluster_getlock,
@@ -2280,10 +2624,10 @@ static struct vfs_fn_pointers glusterfs_fns = {
        .linkat_fn = vfs_gluster_linkat,
        .mknodat_fn = vfs_gluster_mknodat,
        .realpath_fn = vfs_gluster_realpath,
-       .chflags_fn = vfs_gluster_chflags,
+       .fchflags_fn = vfs_gluster_fchflags,
        .file_id_create_fn = NULL,
-       .streaminfo_fn = NULL,
-       .get_real_filename_fn = vfs_gluster_get_real_filename,
+       .fstreaminfo_fn = NULL,
+       .get_real_filename_at_fn = vfs_gluster_get_real_filename_at,
        .connectpath_fn = vfs_gluster_connectpath,
        .create_dfs_pathat_fn = vfs_gluster_create_dfs_pathat,
        .read_dfs_pathat_fn = vfs_gluster_read_dfs_pathat,
@@ -2296,28 +2640,21 @@ static struct vfs_fn_pointers glusterfs_fns = {
 
        /* NT ACL Operations */
        .fget_nt_acl_fn = NULL,
-       .get_nt_acl_at_fn = NULL,
        .fset_nt_acl_fn = NULL,
        .audit_file_fn = NULL,
 
        /* Posix ACL Operations */
-       .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
        .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
-       .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
        .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
        .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
-       .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
+       .sys_acl_delete_def_fd_fn = posixacl_xattr_acl_delete_def_fd,
 
        /* EA Operations */
-       .getxattr_fn = vfs_gluster_getxattr,
        .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
        .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
        .fgetxattr_fn = vfs_gluster_fgetxattr,
-       .listxattr_fn = vfs_gluster_listxattr,
        .flistxattr_fn = vfs_gluster_flistxattr,
-       .removexattr_fn = vfs_gluster_removexattr,
        .fremovexattr_fn = vfs_gluster_fremovexattr,
-       .setxattr_fn = vfs_gluster_setxattr,
        .fsetxattr_fn = vfs_gluster_fsetxattr,
 
        /* AIO Operations */