smbd: use async dos_mode_at_send in smbd_smb2_query_directory_send()
[samba.git] / source3 / modules / vfs_gpfs.c
index 47bbb9d70fc0f333ca479c81ce6b0a6e4d5f0337..982dc19e785fb58a1e97cccfd3e6b5771afdcc77 100644 (file)
@@ -22,7 +22,6 @@
 
 #include "includes.h"
 #include "smbd/smbd.h"
-#include "librpc/gen_ndr/ndr_xattr.h"
 #include "include/smbprofile.h"
 #include "modules/non_posix_acls.h"
 #include "libcli/security/security.h"
@@ -40,6 +39,7 @@
 #endif
 
 struct gpfs_config_data {
+       struct smbacl4_vfs_params nfs4_params;
        bool sharemodes;
        bool leases;
        bool hsm;
@@ -86,8 +86,8 @@ static bool set_gpfs_sharemode(files_struct *fsp, uint32_t access_mask,
                return True;
        }
 
-       allow |= (access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA|
-                                DELETE_ACCESS)) ? GPFS_SHARE_WRITE : 0;
+       allow |= (access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) ?
+               GPFS_SHARE_WRITE : 0;
        allow |= (access_mask & (FILE_READ_DATA|FILE_EXECUTE)) ?
                GPFS_SHARE_READ : 0;
 
@@ -99,6 +99,15 @@ static bool set_gpfs_sharemode(files_struct *fsp, uint32_t access_mask,
                        0 : GPFS_DENY_WRITE;
                deny |= (share_access & (FILE_SHARE_READ)) ?
                        0 : GPFS_DENY_READ;
+
+               /*
+                * GPFS_DENY_DELETE can only be set together with either
+                * GPFS_DENY_WRITE or GPFS_DENY_READ.
+                */
+               if (deny & (GPFS_DENY_WRITE|GPFS_DENY_READ)) {
+                       deny |= (share_access & (FILE_SHARE_DELETE)) ?
+                               0 : GPFS_DENY_DELETE;
+               }
        }
        DEBUG(10, ("am=%x, allow=%d, sa=%x, deny=%d\n",
                   access_mask, allow, share_access, deny));
@@ -234,8 +243,10 @@ static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
                                      char **found_name)
 {
        int result;
-       char *full_path;
-       char real_pathname[PATH_MAX+1];
+       char *full_path = NULL;
+       char *to_free = NULL;
+       char real_pathname[PATH_MAX+1], tmpbuf[PATH_MAX];
+       size_t full_path_len;
        int buflen;
        bool mangled;
        struct gpfs_config_data *config;
@@ -255,8 +266,9 @@ static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
                                                      mem_ctx, found_name);
        }
 
-       full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name);
-       if (full_path == NULL) {
+       full_path_len = full_path_tos(path, name, tmpbuf, sizeof(tmpbuf),
+                                     &full_path, &to_free);
+       if (full_path_len == -1) {
                errno = ENOMEM;
                return -1;
        }
@@ -266,7 +278,7 @@ static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
        result = gpfswrap_get_realfilename_path(full_path, real_pathname,
                                                &buflen);
 
-       TALLOC_FREE(full_path);
+       TALLOC_FREE(to_free);
 
        if ((result == -1) && (errno == ENOSYS)) {
                return SMB_VFS_NEXT_GET_REAL_FILENAME(
@@ -359,6 +371,21 @@ static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
        }
 }
 
+static int gpfs_getacl_with_capability(const char *fname, int flags, void *buf)
+{
+       int ret, saved_errno;
+
+       set_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+       ret = gpfswrap_getacl(discard_const_p(char, fname), flags, buf);
+       saved_errno = errno;
+
+       drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+       errno = saved_errno;
+       return ret;
+}
+
 /*
  * get the ACL from GPFS, allocated on the specified mem_ctx
  * internally retries when initial buffer was too small
@@ -379,6 +406,7 @@ static void *vfs_gpfs_getacl(TALLOC_CTX *mem_ctx,
        int ret, flags;
        unsigned int *len;
        size_t struct_size;
+       bool use_capability = false;
 
 again:
 
@@ -407,8 +435,18 @@ again:
        /* set the length of the buffer as input value */
        *len = size;
 
-       errno = 0;
-       ret = gpfswrap_getacl(discard_const_p(char, fname), flags, aclbuf);
+       if (use_capability) {
+               ret = gpfs_getacl_with_capability(fname, flags, aclbuf);
+       } else {
+               ret = gpfswrap_getacl(discard_const_p(char, fname),
+                                     flags, aclbuf);
+               if ((ret != 0) && (errno == EACCES)) {
+                       DBG_DEBUG("Retry with DAC capability for %s\n", fname);
+                       use_capability = true;
+                       ret = gpfs_getacl_with_capability(fname, flags, aclbuf);
+               }
+       }
+
        if ((ret != 0) && (errno == ENOSPC)) {
                /*
                 * get the size needed to accommodate the complete buffer
@@ -564,8 +602,9 @@ static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
        result = gpfs_get_nfs4_acl(frame, fsp->fsp_name->base_name, &pacl);
 
        if (result == 0) {
-               status = smb_fget_nt_acl_nfs4(fsp, security_info, mem_ctx,
-                                             ppdesc, pacl);
+               status = smb_fget_nt_acl_nfs4(fsp, &config->nfs4_params,
+                                             security_info,
+                                             mem_ctx, ppdesc, pacl);
                TALLOC_FREE(frame);
                return status;
        }
@@ -585,9 +624,10 @@ static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
 }
 
 static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
-       const char *name,
-       uint32_t security_info,
-       TALLOC_CTX *mem_ctx, struct security_descriptor **ppdesc)
+                                  const struct smb_filename *smb_fname,
+                                  uint32_t security_info,
+                                  TALLOC_CTX *mem_ctx,
+                                  struct security_descriptor **ppdesc)
 {
        struct SMB4ACL_T *pacl = NULL;
        int     result;
@@ -602,25 +642,28 @@ static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
                                return NT_STATUS_INTERNAL_ERROR);
 
        if (!config->acl) {
-               status = SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info,
+               status = SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname,
+                                                security_info,
                                                 mem_ctx, ppdesc);
                TALLOC_FREE(frame);
                return status;
        }
 
-       result = gpfs_get_nfs4_acl(frame, name, &pacl);
+       result = gpfs_get_nfs4_acl(frame, smb_fname->base_name, &pacl);
 
        if (result == 0) {
-               status = smb_get_nt_acl_nfs4(handle->conn, name, security_info,
-                                          mem_ctx, ppdesc, pacl);
+               status = smb_get_nt_acl_nfs4(handle->conn, smb_fname,
+                                            &config->nfs4_params,
+                                            security_info, mem_ctx, ppdesc,
+                                            pacl);
                TALLOC_FREE(frame);
                return status;
        }
 
        if (result > 0) {
                DEBUG(10, ("retrying with posix acl...\n"));
-               status =  posix_get_nt_acl(handle->conn, name, security_info,
-                                          mem_ctx, ppdesc);
+               status = posix_get_nt_acl(handle->conn, smb_fname,
+                                         security_info, mem_ctx, ppdesc);
                TALLOC_FREE(frame);
                return status;
        }
@@ -773,6 +816,8 @@ static NTSTATUS gpfsacl_set_nt_acl_internal(vfs_handle_struct *handle, files_str
        }
 
        if (acl->acl_version == GPFS_ACL_VERSION_NFS4) {
+               struct gpfs_config_data *config;
+
                if (lp_parm_bool(fsp->conn->params->service, "gpfs",
                                 "refuse_dacl_protected", false)
                    && (psd->type&SEC_DESC_DACL_PROTECTED)) {
@@ -781,8 +826,12 @@ static NTSTATUS gpfsacl_set_nt_acl_internal(vfs_handle_struct *handle, files_str
                        return NT_STATUS_NOT_SUPPORTED;
                }
 
+               SMB_VFS_HANDLE_GET_DATA(handle, config,
+                                       struct gpfs_config_data,
+                                       return NT_STATUS_INTERNAL_ERROR);
+
                result = smb_set_nt_acl_nfs4(handle,
-                       fsp, security_info_sent, psd,
+                       fsp, &config->nfs4_params, security_info_sent, psd,
                        gpfsacl_process_smbacl);
        } else { /* assume POSIX ACL - by default... */
                result = set_nt_acl(fsp, security_info_sent, psd);
@@ -924,7 +973,7 @@ static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type,
 }
 
 static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
-                                         const char *path_p,
+                                         const struct smb_filename *smb_fname,
                                          SMB_ACL_TYPE_T type,
                                          TALLOC_CTX *mem_ctx)
 {
@@ -936,7 +985,7 @@ static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
                                return NULL);
 
        if (!config->acl) {
-               return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p,
+               return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, smb_fname,
                                                     type, mem_ctx);
        }
 
@@ -952,7 +1001,7 @@ static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
                smb_panic("exiting");
        }
 
-       return gpfsacl_get_posix_acl(path_p, gpfs_type, mem_ctx);
+       return gpfsacl_get_posix_acl(smb_fname->base_name, gpfs_type, mem_ctx);
 }
 
 static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
@@ -974,7 +1023,7 @@ static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
 }
 
 static int gpfsacl_sys_acl_blob_get_file(vfs_handle_struct *handle,
-                                     const char *path_p,
+                                     const struct smb_filename *smb_fname,
                                      TALLOC_CTX *mem_ctx,
                                      char **blob_description,
                                      DATA_BLOB *blob)
@@ -983,13 +1032,14 @@ static int gpfsacl_sys_acl_blob_get_file(vfs_handle_struct *handle,
        struct gpfs_opaque_acl *acl = NULL;
        DATA_BLOB aclblob;
        int result;
+       const char *path_p = smb_fname->base_name;
 
        SMB_VFS_HANDLE_GET_DATA(handle, config,
                                struct gpfs_config_data,
                                return -1);
 
        if (!config->acl) {
-               return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FILE(handle, path_p,
+               return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FILE(handle, smb_fname,
                                                          mem_ctx,
                                                          blob_description,
                                                          blob);
@@ -1031,7 +1081,7 @@ static int gpfsacl_sys_acl_blob_get_file(vfs_handle_struct *handle,
                        return -1;
                }
 
-               result = non_posix_sys_acl_blob_get_file_helper(handle, path_p,
+               result = non_posix_sys_acl_blob_get_file_helper(handle, smb_fname,
                                                                aclblob,
                                                                mem_ctx, blob);
 
@@ -1040,7 +1090,7 @@ static int gpfsacl_sys_acl_blob_get_file(vfs_handle_struct *handle,
        }
 
        /* fall back to POSIX ACL */
-       return posix_sys_acl_blob_get_file(handle, path_p, mem_ctx,
+       return posix_sys_acl_blob_get_file(handle, smb_fname, mem_ctx,
                                           blob_description, blob);
 }
 
@@ -1195,7 +1245,7 @@ static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl,
 }
 
 static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
-                                   const char *name,
+                                   const struct smb_filename *smb_fname,
                                    SMB_ACL_TYPE_T type,
                                    SMB_ACL_T theacl)
 {
@@ -1208,7 +1258,8 @@ static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
                                return -1);
 
        if (!config->acl) {
-               return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name, type, theacl);
+               return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, smb_fname,
+                               type, theacl);
        }
 
        gpfs_acl = smb2gpfs_acl(theacl, type);
@@ -1216,7 +1267,7 @@ static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
                return -1;
        }
 
-       result = gpfswrap_putacl(discard_const_p(char, name),
+       result = gpfswrap_putacl(discard_const_p(char, smb_fname->base_name),
                                 GPFS_PUTACL_STRUCT|GPFS_ACL_SAMBA, gpfs_acl);
 
        SAFE_FREE(gpfs_acl);
@@ -1237,12 +1288,12 @@ static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
                return SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl);
        }
 
-       return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name->base_name,
+       return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name,
                                        SMB_ACL_TYPE_ACCESS, theacl);
 }
 
 static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
-                                          const char *path)
+                               const struct smb_filename *smb_fname)
 {
        struct gpfs_config_data *config;
 
@@ -1251,7 +1302,7 @@ static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
                                return -1);
 
        if (!config->acl) {
-               return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, path);
+               return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, smb_fname);
        }
 
        errno = ENOTSUP;
@@ -1377,7 +1428,7 @@ static int gpfsacl_emu_chmod(vfs_handle_struct *handle,
 
        /* don't add complementary DENY ACEs here */
        fake_fsp.fsp_name = synthetic_smb_fname(
-               frame, path, NULL, NULL);
+               frame, path, NULL, NULL, 0);
        if (fake_fsp.fsp_name == NULL) {
                errno = ENOMEM;
                TALLOC_FREE(frame);
@@ -1393,29 +1444,35 @@ static int gpfsacl_emu_chmod(vfs_handle_struct *handle,
        return 0; /* ok for [f]chmod */
 }
 
-static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
+static int vfs_gpfs_chmod(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       mode_t mode)
 {
        struct smb_filename *smb_fname_cpath;
        int rc;
 
-       smb_fname_cpath = synthetic_smb_fname(talloc_tos(), path, NULL, NULL);
+       smb_fname_cpath = cp_smb_filename(talloc_tos(), smb_fname);
        if (smb_fname_cpath == NULL) {
                errno = ENOMEM;
                return -1;
        }
 
        if (SMB_VFS_NEXT_STAT(handle, smb_fname_cpath) != 0) {
+               TALLOC_FREE(smb_fname_cpath);
                return -1;
        }
 
        /* avoid chmod() if possible, to preserve acls */
        if ((smb_fname_cpath->st.st_ex_mode & ~S_IFMT) == mode) {
+               TALLOC_FREE(smb_fname_cpath);
                return 0;
        }
 
-       rc = gpfsacl_emu_chmod(handle, path, mode);
+       rc = gpfsacl_emu_chmod(handle, smb_fname->base_name, mode);
        if (rc == 1)
-               return SMB_VFS_NEXT_CHMOD(handle, path, mode);
+               return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
+
+       TALLOC_FREE(smb_fname_cpath);
        return rc;
 }
 
@@ -1440,167 +1497,278 @@ static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t
                 return rc;
 }
 
-static int gpfs_set_xattr(struct vfs_handle_struct *handle,  const char *path,
-                           const char *name, const void *value, size_t size,  int flags){
-       struct xattr_DOSATTRIB dosattrib;
-        enum ndr_err_code ndr_err;
-        DATA_BLOB blob;
-        unsigned int dosmode=0;
-        struct gpfs_winattr attrs;
-        int ret = 0;
+static uint32_t vfs_gpfs_winattrs_to_dosmode(unsigned int winattrs)
+{
+       uint32_t dosmode = 0;
+
+       if (winattrs & GPFS_WINATTR_ARCHIVE){
+               dosmode |= FILE_ATTRIBUTE_ARCHIVE;
+       }
+       if (winattrs & GPFS_WINATTR_HIDDEN){
+               dosmode |= FILE_ATTRIBUTE_HIDDEN;
+       }
+       if (winattrs & GPFS_WINATTR_SYSTEM){
+               dosmode |= FILE_ATTRIBUTE_SYSTEM;
+       }
+       if (winattrs & GPFS_WINATTR_READONLY){
+               dosmode |= FILE_ATTRIBUTE_READONLY;
+       }
+       if (winattrs & GPFS_WINATTR_SPARSE_FILE) {
+               dosmode |= FILE_ATTRIBUTE_SPARSE;
+       }
+       if (winattrs & GPFS_WINATTR_OFFLINE) {
+               dosmode |= FILE_ATTRIBUTE_OFFLINE;
+       }
+
+       return dosmode;
+}
+
+static unsigned int vfs_gpfs_dosmode_to_winattrs(uint32_t dosmode)
+{
+       unsigned int winattrs = 0;
+
+       if (dosmode & FILE_ATTRIBUTE_ARCHIVE){
+               winattrs |= GPFS_WINATTR_ARCHIVE;
+       }
+       if (dosmode & FILE_ATTRIBUTE_HIDDEN){
+               winattrs |= GPFS_WINATTR_HIDDEN;
+       }
+       if (dosmode & FILE_ATTRIBUTE_SYSTEM){
+               winattrs |= GPFS_WINATTR_SYSTEM;
+       }
+       if (dosmode & FILE_ATTRIBUTE_READONLY){
+               winattrs |= GPFS_WINATTR_READONLY;
+       }
+       if (dosmode & FILE_ATTRIBUTE_SPARSE) {
+               winattrs |= GPFS_WINATTR_SPARSE_FILE;
+       }
+       if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
+               winattrs |= GPFS_WINATTR_OFFLINE;
+       }
+
+       return winattrs;
+}
+
+static int get_dos_attr_with_capability(struct smb_filename *smb_fname,
+                                       struct gpfs_winattr *attr)
+{
+       int saved_errno = 0;
+       int ret;
+
+       /*
+        * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to an
+        * Existing File" FILE_LIST_DIRECTORY on a directory implies
+        * FILE_READ_ATTRIBUTES for directory entries. Being able to stat() a
+        * file implies FILE_LIST_DIRECTORY for the directory containing the
+        * file.
+        */
+
+       if (!VALID_STAT(smb_fname->st)) {
+               /*
+                * Safety net: dos_mode() already checks this, but as we set
+                * DAC_OVERRIDE_CAPABILITY based on this, add an additional
+                * layer of defense.
+                */
+               DBG_ERR("Rejecting DAC override, invalid stat [%s]\n",
+                       smb_fname_str_dbg(smb_fname));
+               errno = EACCES;
+               return -1;
+       }
+
+       set_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+       ret = gpfswrap_get_winattrs_path(smb_fname->base_name, attr);
+       if (ret == -1) {
+               saved_errno = errno;
+       }
+
+       drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
+       return ret;
+}
+
+static NTSTATUS vfs_gpfs_get_dos_attributes(struct vfs_handle_struct *handle,
+                                           struct smb_filename *smb_fname,
+                                           uint32_t *dosmode)
+{
        struct gpfs_config_data *config;
+       struct gpfs_winattr attrs = { };
+       int ret;
 
        SMB_VFS_HANDLE_GET_DATA(handle, config,
                                struct gpfs_config_data,
-                               return -1);
+                               return NT_STATUS_INTERNAL_ERROR);
 
        if (!config->winattr) {
-               DEBUG(10, ("gpfs_set_xattr:name is %s -> next\n",name));
-               return SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags);
+               return SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle,
+                                                      smb_fname, dosmode);
        }
 
-        DEBUG(10, ("gpfs_set_xattr: %s \n",path));
+       ret = gpfswrap_get_winattrs_path(smb_fname->base_name, &attrs);
+       if (ret == -1 && errno == ENOSYS) {
+               return SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle, smb_fname,
+                                                      dosmode);
+       }
+       if (ret == -1 && errno == EACCES) {
+               ret = get_dos_attr_with_capability(smb_fname, &attrs);
+       }
 
-        /* Only handle DOS Attributes */
-        if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
-               DEBUG(5, ("gpfs_set_xattr:name is %s\n",name));
-               return SMB_VFS_NEXT_SETXATTR(handle,path,name,value,size,flags);
-        }
+       if (ret == -1 && errno == EBADF) {
+               /*
+                * Returned for directory listings in gpfs root for
+                * .. entry which steps out of gpfs.
+                */
+               DBG_DEBUG("Getting winattrs for %s returned EBADF.\n",
+                         smb_fname->base_name);
+               return map_nt_error_from_unix(errno);
+       } else if (ret == -1) {
+               DBG_WARNING("Getting winattrs failed for %s: %s\n",
+                           smb_fname->base_name, strerror(errno));
+               return map_nt_error_from_unix(errno);
+       }
 
-       blob.data = discard_const_p(uint8_t, value);
-       blob.length = size;
+       *dosmode |= vfs_gpfs_winattrs_to_dosmode(attrs.winAttrs);
+       smb_fname->st.st_ex_calculated_birthtime = false;
+       smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
+       smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
 
-       ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
-                       (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
+       return NT_STATUS_OK;
+}
 
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               DEBUG(1, ("gpfs_set_xattr: bad ndr decode "
-                         "from EA on file %s: Error = %s\n",
-                         path, ndr_errstr(ndr_err)));
-               return false;
-       }
+static NTSTATUS vfs_gpfs_fget_dos_attributes(struct vfs_handle_struct *handle,
+                                            struct files_struct *fsp,
+                                            uint32_t *dosmode)
+{
+       struct gpfs_config_data *config;
+       struct gpfs_winattr attrs = { };
+       int ret;
 
-       if (dosattrib.version != 3) {
-               DEBUG(1, ("gpfs_set_xattr: expected dosattrib version 3, got "
-                         "%d\n", (int)dosattrib.version));
-               return false;
+       SMB_VFS_HANDLE_GET_DATA(handle, config,
+                               struct gpfs_config_data,
+                               return NT_STATUS_INTERNAL_ERROR);
+
+       if (!config->winattr) {
+               return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
        }
-       if (!(dosattrib.info.info3.valid_flags & XATTR_DOSINFO_ATTRIB)) {
-               DEBUG(10, ("gpfs_set_xattr: XATTR_DOSINFO_ATTRIB not "
-                          "valid, ignoring\n"));
-               return true;
+
+       ret = gpfswrap_get_winattrs(fsp->fh->fd, &attrs);
+       if (ret == -1 && errno == ENOSYS) {
+               return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
        }
 
-       dosmode = dosattrib.info.info3.attrib;
+       if (ret == -1 && errno == EACCES) {
+               int saved_errno = 0;
 
-        attrs.winAttrs = 0;
-        /*Just map RD_ONLY, ARCHIVE, SYSTEM HIDDEN and SPARSE. Ignore the others*/
-        if (dosmode & FILE_ATTRIBUTE_ARCHIVE){
-                attrs.winAttrs |= GPFS_WINATTR_ARCHIVE;
-        }
-        if (dosmode & FILE_ATTRIBUTE_HIDDEN){
-                        attrs.winAttrs |= GPFS_WINATTR_HIDDEN;
-                }
-        if (dosmode & FILE_ATTRIBUTE_SYSTEM){
-                        attrs.winAttrs |= GPFS_WINATTR_SYSTEM;
-                }
-        if (dosmode & FILE_ATTRIBUTE_READONLY){
-                        attrs.winAttrs |= GPFS_WINATTR_READONLY;
-        }
-        if (dosmode & FILE_ATTRIBUTE_SPARSE) {
-               attrs.winAttrs |= GPFS_WINATTR_SPARSE_FILE;
-       }
+               /*
+                * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
+                * an Existing File" FILE_LIST_DIRECTORY on a directory implies
+                * FILE_READ_ATTRIBUTES for directory entries. Being able to
+                * open a file implies FILE_LIST_DIRECTORY.
+                */
 
+               set_effective_capability(DAC_OVERRIDE_CAPABILITY);
 
-       ret = gpfswrap_set_winattrs_path(discard_const_p(char, path),
-                                        GPFS_WINATTR_SET_ATTRS, &attrs);
-        if ( ret == -1){
-               if (errno == ENOSYS) {
-                       return SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
-                                                    size, flags);
+               ret = gpfswrap_get_winattrs(fsp->fh->fd, &attrs);
+               if (ret == -1) {
+                       saved_errno = errno;
                }
 
-                DEBUG(1, ("gpfs_set_xattr:Set GPFS attributes failed %d\n",ret));
-                return -1;
-        }
+               drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
 
-        DEBUG(10, ("gpfs_set_xattr:Set attributes: 0x%x\n",attrs.winAttrs));
-        return 0;
+               if (saved_errno != 0) {
+                       errno = saved_errno;
+               }
+       }
+
+       if (ret == -1) {
+               DBG_WARNING("Getting winattrs failed for %s: %s\n",
+                           fsp->fsp_name->base_name, strerror(errno));
+               return map_nt_error_from_unix(errno);
+       }
+
+       *dosmode |= vfs_gpfs_winattrs_to_dosmode(attrs.winAttrs);
+       fsp->fsp_name->st.st_ex_calculated_birthtime = false;
+       fsp->fsp_name->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
+       fsp->fsp_name->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
+
+       return NT_STATUS_OK;
 }
 
-static ssize_t gpfs_get_xattr(struct vfs_handle_struct *handle,  const char *path,
-                              const char *name, void *value, size_t size){
-        char *attrstr = value;
-        unsigned int dosmode = 0;
-        struct gpfs_winattr attrs;
-        int ret = 0;
+static NTSTATUS vfs_gpfs_set_dos_attributes(struct vfs_handle_struct *handle,
+                                          const struct smb_filename *smb_fname,
+                                          uint32_t dosmode)
+{
        struct gpfs_config_data *config;
+       struct gpfs_winattr attrs = { };
+       int ret;
 
        SMB_VFS_HANDLE_GET_DATA(handle, config,
                                struct gpfs_config_data,
-                               return -1);
+                               return NT_STATUS_INTERNAL_ERROR);
 
        if (!config->winattr) {
-               DEBUG(10, ("gpfs_get_xattr:name is %s -> next\n",name));
-               return SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size);
+               return SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle,
+                                                      smb_fname, dosmode);
+       }
+
+       attrs.winAttrs = vfs_gpfs_dosmode_to_winattrs(dosmode);
+       ret = gpfswrap_set_winattrs_path(smb_fname->base_name,
+                                        GPFS_WINATTR_SET_ATTRS, &attrs);
+
+       if (ret == -1 && errno == ENOSYS) {
+               return SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle,
+                                                      smb_fname, dosmode);
        }
 
-        DEBUG(10, ("gpfs_get_xattr: %s \n",path));
+       if (ret == -1) {
+               DBG_WARNING("Setting winattrs failed for %s: %s\n",
+                           smb_fname->base_name, strerror(errno));
+               return map_nt_error_from_unix(errno);
+       }
 
-        /* Only handle DOS Attributes */
-        if (strcmp(name,SAMBA_XATTR_DOS_ATTRIB) != 0){
-               DEBUG(5, ("gpfs_get_xattr:name is %s\n",name));
-                return SMB_VFS_NEXT_GETXATTR(handle,path,name,value,size);
-        }
+       return NT_STATUS_OK;
+}
 
-       ret = gpfswrap_get_winattrs_path(discard_const_p(char, path), &attrs);
-        if ( ret == -1){
-               int dbg_lvl;
+static NTSTATUS vfs_gpfs_fset_dos_attributes(struct vfs_handle_struct *handle,
+                                            struct files_struct *fsp,
+                                            uint32_t dosmode)
+{
+       struct gpfs_config_data *config;
+       struct gpfs_winattr attrs = { };
+       int ret;
 
-               if (errno == ENOSYS) {
-                       return SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
-                                                    size);
-               }
+       SMB_VFS_HANDLE_GET_DATA(handle, config,
+                               struct gpfs_config_data,
+                               return NT_STATUS_INTERNAL_ERROR);
 
-               if (errno != EPERM && errno != EACCES) {
-                       dbg_lvl = 1;
-               } else {
-                       dbg_lvl = 5;
-               }
-               DEBUG(dbg_lvl, ("gpfs_get_xattr: Get GPFS attributes failed: "
-                             "%d (%s)\n", ret, strerror(errno)));
-                return -1;
-        }
+       if (!config->winattr) {
+               return SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
+       }
 
-        DEBUG(10, ("gpfs_get_xattr:Got attributes: 0x%x\n",attrs.winAttrs));
+       attrs.winAttrs = vfs_gpfs_dosmode_to_winattrs(dosmode);
+       ret = gpfswrap_set_winattrs(fsp->fh->fd,
+                                   GPFS_WINATTR_SET_ATTRS, &attrs);
 
-        /*Just map RD_ONLY, ARCHIVE, SYSTEM, HIDDEN and SPARSE. Ignore the others*/
-        if (attrs.winAttrs & GPFS_WINATTR_ARCHIVE){
-                dosmode |= FILE_ATTRIBUTE_ARCHIVE;
-        }
-        if (attrs.winAttrs & GPFS_WINATTR_HIDDEN){
-                dosmode |= FILE_ATTRIBUTE_HIDDEN;
-        }
-        if (attrs.winAttrs & GPFS_WINATTR_SYSTEM){
-                dosmode |= FILE_ATTRIBUTE_SYSTEM;
-        }
-        if (attrs.winAttrs & GPFS_WINATTR_READONLY){
-                dosmode |= FILE_ATTRIBUTE_READONLY;
-        }
-        if (attrs.winAttrs & GPFS_WINATTR_SPARSE_FILE) {
-               dosmode |= FILE_ATTRIBUTE_SPARSE;
+       if (ret == -1 && errno == ENOSYS) {
+               return SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
+       }
+
+       if (ret == -1) {
+               DBG_WARNING("Setting winattrs failed for %s: %s\n",
+                           fsp->fsp_name->base_name, strerror(errno));
+               return map_nt_error_from_unix(errno);
        }
 
-        snprintf(attrstr, size, "0x%2.2x",
-                (unsigned int)(dosmode & SAMBA_ATTRIBUTES_MASK));
-        DEBUG(10, ("gpfs_get_xattr: returning %s\n",attrstr));
-        return 4;
+       return NT_STATUS_OK;
 }
 
-#if defined(HAVE_FSTATAT)
 static int stat_with_capability(struct vfs_handle_struct *handle,
                                struct smb_filename *smb_fname, int flag)
 {
+#if defined(HAVE_FSTATAT)
        int fd = -1;
        bool b;
        char *dir_name;
@@ -1634,15 +1802,14 @@ static int stat_with_capability(struct vfs_handle_struct *handle,
        }
 
        return ret;
-}
+#else
+       return -1;
 #endif
+}
 
 static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
                         struct smb_filename *smb_fname)
 {
-       struct gpfs_winattr attrs;
-       char *fname = NULL;
-       NTSTATUS status;
        int ret;
        struct gpfs_config_data *config;
 
@@ -1651,73 +1818,17 @@ static int vfs_gpfs_stat(struct vfs_handle_struct *handle,
                                return -1);
 
        ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
-#if defined(HAVE_FSTATAT)
        if (ret == -1 && errno == EACCES) {
                DEBUG(10, ("Trying stat with capability for %s\n",
                           smb_fname->base_name));
                ret = stat_with_capability(handle, smb_fname, 0);
        }
-#endif
-       if (ret == -1) {
-               return -1;
-       }
-
-       if (!config->winattr) {
-               return 0;
-       }
-
-       status = get_full_smb_filename(talloc_tos(), smb_fname, &fname);
-       if (!NT_STATUS_IS_OK(status)) {
-               errno = map_errno_from_nt_status(status);
-               return -1;
-       }
-       ret = gpfswrap_get_winattrs_path(discard_const_p(char, fname), &attrs);
-       TALLOC_FREE(fname);
-       if (ret == 0) {
-               smb_fname->st.st_ex_calculated_birthtime = false;
-               smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
-               smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
-       }
-       return 0;
-}
-
-static int vfs_gpfs_fstat(struct vfs_handle_struct *handle,
-                         struct files_struct *fsp, SMB_STRUCT_STAT *sbuf)
-{
-       struct gpfs_winattr attrs;
-       int ret;
-       struct gpfs_config_data *config;
-
-       SMB_VFS_HANDLE_GET_DATA(handle, config,
-                               struct gpfs_config_data,
-                               return -1);
-
-       ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
-       if (ret == -1) {
-               return -1;
-       }
-       if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) {
-               return 0;
-       }
-       if (!config->winattr) {
-               return 0;
-       }
-
-       ret = gpfswrap_get_winattrs(fsp->fh->fd, &attrs);
-       if (ret == 0) {
-               sbuf->st_ex_calculated_birthtime = false;
-               sbuf->st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
-               sbuf->st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
-       }
-       return 0;
+       return ret;
 }
 
 static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
                          struct smb_filename *smb_fname)
 {
-       struct gpfs_winattr attrs;
-       char *path = NULL;
-       NTSTATUS status;
        int ret;
        struct gpfs_config_data *config;
 
@@ -1726,35 +1837,13 @@ static int vfs_gpfs_lstat(struct vfs_handle_struct *handle,
                                return -1);
 
        ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
-#if defined(HAVE_FSTATAT)
        if (ret == -1 && errno == EACCES) {
                DEBUG(10, ("Trying lstat with capability for %s\n",
                           smb_fname->base_name));
                ret = stat_with_capability(handle, smb_fname,
                                           AT_SYMLINK_NOFOLLOW);
        }
-#endif
-
-       if (ret == -1) {
-               return -1;
-       }
-       if (!config->winattr) {
-               return 0;
-       }
-
-       status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
-       if (!NT_STATUS_IS_OK(status)) {
-               errno = map_errno_from_nt_status(status);
-               return -1;
-       }
-       ret = gpfswrap_get_winattrs_path(discard_const_p(char, path), &attrs);
-       TALLOC_FREE(path);
-       if (ret == 0) {
-               smb_fname->st.st_ex_calculated_birthtime = false;
-               smb_fname->st.st_ex_btime.tv_sec = attrs.creationTime.tv_sec;
-               smb_fname->st.st_ex_btime.tv_nsec = attrs.creationTime.tv_nsec;
-       }
-       return 0;
+       return ret;
 }
 
 static void timespec_to_gpfs_time(struct timespec ts, gpfs_timestruc_t *gt,
@@ -1802,23 +1891,15 @@ static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
 
         struct gpfs_winattr attrs;
         int ret;
-        char *path = NULL;
-        NTSTATUS status;
        struct gpfs_config_data *config;
 
        SMB_VFS_HANDLE_GET_DATA(handle, config,
                                struct gpfs_config_data,
                                return -1);
 
-       status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
-       if (!NT_STATUS_IS_OK(status)) {
-               errno = map_errno_from_nt_status(status);
-               return -1;
-       }
-
        /* Try to use gpfs_set_times if it is enabled and available */
        if (config->settimes) {
-               ret = smbd_gpfs_set_times_path(path, ft);
+               ret = smbd_gpfs_set_times_path(smb_fname->base_name, ft);
 
                if (ret == 0 || (ret == -1 && errno != ENOSYS)) {
                        return ret;
@@ -1851,7 +1932,7 @@ static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
         attrs.creationTime.tv_sec = ft->create_time.tv_sec;
         attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
 
-       ret = gpfswrap_set_winattrs_path(discard_const_p(char, path),
+       ret = gpfswrap_set_winattrs_path(smb_fname->base_name,
                                         GPFS_WINATTR_SET_CREATION_TIME,
                                         &attrs);
         if(ret == -1 && errno != ENOSYS){
@@ -1925,8 +2006,6 @@ static bool vfs_gpfs_is_offline(struct vfs_handle_struct *handle,
                                SMB_STRUCT_STAT *sbuf)
 {
        struct gpfs_winattr attrs;
-       char *path = NULL;
-       NTSTATUS status;
        struct gpfs_config_data *config;
        int ret;
 
@@ -1935,29 +2014,21 @@ static bool vfs_gpfs_is_offline(struct vfs_handle_struct *handle,
                                return -1);
 
        if (!config->winattr) {
-               return SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
-       }
-
-       status = get_full_smb_filename(talloc_tos(), fname, &path);
-       if (!NT_STATUS_IS_OK(status)) {
-               errno = map_errno_from_nt_status(status);
-               return -1;
+               return false;
        }
 
-       ret = gpfswrap_get_winattrs_path(path, &attrs);
+       ret = gpfswrap_get_winattrs_path(fname->base_name, &attrs);
        if (ret == -1) {
-               TALLOC_FREE(path);
                return false;
        }
 
        if ((attrs.winAttrs & GPFS_WINATTR_OFFLINE) != 0) {
-               DEBUG(10, ("%s is offline\n", path));
-               TALLOC_FREE(path);
+               DBG_DEBUG("%s is offline\n", fname->base_name);
                return true;
        }
-       DEBUG(10, ("%s is online\n", path));
-       TALLOC_FREE(path);
-       return SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
+
+       DBG_DEBUG("%s is online\n", fname->base_name);
+       return false;
 }
 
 static bool vfs_gpfs_fsp_is_offline(struct vfs_handle_struct *handle,
@@ -2023,6 +2094,12 @@ static int vfs_gpfs_connect(struct vfs_handle_struct *handle,
                return ret;
        }
 
+       ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
+       if (ret < 0) {
+               TALLOC_FREE(config);
+               return ret;
+       }
+
        config->sharemodes = lp_parm_bool(SNUM(handle->conn), "gpfs",
                                        "sharemodes", true);
 
@@ -2086,6 +2163,12 @@ static int vfs_gpfs_connect(struct vfs_handle_struct *handle,
                }
        }
 
+       /*
+        * Unless we have an async implementation of get_dos_attributes turn
+        * this off.
+        */
+       lp_do_parameter(SNUM(handle->conn), "smbd:async dosmode", "false");
+
        return 0;
 }
 
@@ -2154,9 +2237,11 @@ static void vfs_gpfs_disk_free_quota(struct gpfs_quotaInfo qi, time_t cur_time,
        }
 }
 
-static uint64_t vfs_gpfs_disk_free(vfs_handle_struct *handle, const char *path,
-                                  uint64_t *bsize,
-                                  uint64_t *dfree, uint64_t *dsize)
+static uint64_t vfs_gpfs_disk_free(vfs_handle_struct *handle,
+                               const struct smb_filename *smb_fname,
+                               uint64_t *bsize,
+                               uint64_t *dfree,
+                               uint64_t *dsize)
 {
        struct security_unix_token *utok;
        struct gpfs_quotaInfo qi_user = { 0 }, qi_group = { 0 };
@@ -2167,14 +2252,14 @@ static uint64_t vfs_gpfs_disk_free(vfs_handle_struct *handle, const char *path,
        SMB_VFS_HANDLE_GET_DATA(handle, config, struct gpfs_config_data,
                                return (uint64_t)-1);
        if (!config->dfreequota) {
-               return SMB_VFS_NEXT_DISK_FREE(handle, path,
+               return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
                                              bsize, dfree, dsize);
        }
 
-       err = sys_fsusage(path, dfree, dsize);
+       err = sys_fsusage(smb_fname->base_name, dfree, dsize);
        if (err) {
                DEBUG (0, ("Could not get fs usage, errno %d\n", errno));
-               return SMB_VFS_NEXT_DISK_FREE(handle, path,
+               return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
                                              bsize, dfree, dsize);
        }
 
@@ -2186,15 +2271,17 @@ static uint64_t vfs_gpfs_disk_free(vfs_handle_struct *handle, const char *path,
 
        utok = handle->conn->session_info->unix_token;
 
-       err = get_gpfs_quota(path, GPFS_USRQUOTA, utok->uid, &qi_user);
+       err = get_gpfs_quota(smb_fname->base_name,
+                       GPFS_USRQUOTA, utok->uid, &qi_user);
        if (err) {
-               return SMB_VFS_NEXT_DISK_FREE(handle, path,
+               return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
                                              bsize, dfree, dsize);
        }
 
-       err = get_gpfs_quota(path, GPFS_GRPQUOTA, utok->gid, &qi_group);
+       err = get_gpfs_quota(smb_fname->base_name,
+                       GPFS_GRPQUOTA, utok->gid, &qi_group);
        if (err) {
-               return SMB_VFS_NEXT_DISK_FREE(handle, path,
+               return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
                                              bsize, dfree, dsize);
        }
 
@@ -2207,6 +2294,33 @@ static uint64_t vfs_gpfs_disk_free(vfs_handle_struct *handle, const char *path,
        return *dfree / 2;
 }
 
+static int vfs_gpfs_get_quota(vfs_handle_struct *handle,
+                               const struct smb_filename *smb_fname,
+                               enum SMB_QUOTA_TYPE qtype,
+                               unid_t id,
+                               SMB_DISK_QUOTA *dq)
+{
+       switch(qtype) {
+               /*
+                * User/group quota are being used for disk-free
+                * determination, which in this module is done directly
+                * by the disk-free function. It's important that this
+                * module does not return wrong quota values by mistake,
+                * which would modify the correct values set by disk-free.
+                * User/group quota are also being used for processing
+                * NT_TRANSACT_GET_USER_QUOTA in smb1 protocol, which is
+                * currently not supported by this module.
+                */
+               case SMB_USER_QUOTA_TYPE:
+               case SMB_GROUP_QUOTA_TYPE:
+                       errno = ENOSYS;
+                       return -1;
+               default:
+                       return SMB_VFS_NEXT_GET_QUOTA(handle, smb_fname,
+                                       qtype, id, dq);
+       }
+}
+
 static uint32_t vfs_gpfs_capabilities(struct vfs_handle_struct *handle,
                                      enum timestamp_set_resolution *p_ts_res)
 {
@@ -2290,8 +2404,8 @@ static ssize_t vfs_gpfs_pread(vfs_handle_struct *handle, files_struct *fsp,
 struct vfs_gpfs_pread_state {
        struct files_struct *fsp;
        ssize_t ret;
-       int err;
        bool was_offline;
+       struct vfs_aio_state vfs_aio_state;
 };
 
 static void vfs_gpfs_pread_done(struct tevent_req *subreq);
@@ -2328,21 +2442,22 @@ static void vfs_gpfs_pread_done(struct tevent_req *subreq)
        struct vfs_gpfs_pread_state *state = tevent_req_data(
                req, struct vfs_gpfs_pread_state);
 
-       state->ret = SMB_VFS_PREAD_RECV(subreq, &state->err);
+       state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
        TALLOC_FREE(subreq);
        tevent_req_done(req);
 }
 
-static ssize_t vfs_gpfs_pread_recv(struct tevent_req *req, int *err)
+static ssize_t vfs_gpfs_pread_recv(struct tevent_req *req,
+                                  struct vfs_aio_state *vfs_aio_state)
 {
        struct vfs_gpfs_pread_state *state = tevent_req_data(
                req, struct vfs_gpfs_pread_state);
        struct files_struct *fsp = state->fsp;
 
-       if (tevent_req_is_unix_error(req, err)) {
+       if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
                return -1;
        }
-       *err = state->err;
+       *vfs_aio_state = state->vfs_aio_state;
 
        if ((state->ret != -1) && state->was_offline) {
                DEBUG(10, ("sending notify\n"));
@@ -2376,8 +2491,8 @@ static ssize_t vfs_gpfs_pwrite(vfs_handle_struct *handle, files_struct *fsp,
 struct vfs_gpfs_pwrite_state {
        struct files_struct *fsp;
        ssize_t ret;
-       int err;
        bool was_offline;
+       struct vfs_aio_state vfs_aio_state;
 };
 
 static void vfs_gpfs_pwrite_done(struct tevent_req *subreq);
@@ -2415,21 +2530,22 @@ static void vfs_gpfs_pwrite_done(struct tevent_req *subreq)
        struct vfs_gpfs_pwrite_state *state = tevent_req_data(
                req, struct vfs_gpfs_pwrite_state);
 
-       state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->err);
+       state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
        TALLOC_FREE(subreq);
        tevent_req_done(req);
 }
 
-static ssize_t vfs_gpfs_pwrite_recv(struct tevent_req *req, int *err)
+static ssize_t vfs_gpfs_pwrite_recv(struct tevent_req *req,
+                                   struct vfs_aio_state *vfs_aio_state)
 {
        struct vfs_gpfs_pwrite_state *state = tevent_req_data(
                req, struct vfs_gpfs_pwrite_state);
        struct files_struct *fsp = state->fsp;
 
-       if (tevent_req_is_unix_error(req, err)) {
+       if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
                return -1;
        }
-       *err = state->err;
+       *vfs_aio_state = state->vfs_aio_state;
 
        if ((state->ret != -1) && state->was_offline) {
                DEBUG(10, ("sending notify\n"));
@@ -2445,10 +2561,17 @@ static ssize_t vfs_gpfs_pwrite_recv(struct tevent_req *req, int *err)
 static struct vfs_fn_pointers vfs_gpfs_fns = {
        .connect_fn = vfs_gpfs_connect,
        .disk_free_fn = vfs_gpfs_disk_free,
+       .get_quota_fn = vfs_gpfs_get_quota,
        .fs_capabilities_fn = vfs_gpfs_capabilities,
        .kernel_flock_fn = vfs_gpfs_kernel_flock,
        .linux_setlease_fn = vfs_gpfs_setlease,
        .get_real_filename_fn = vfs_gpfs_get_real_filename,
+       .get_dos_attributes_fn = vfs_gpfs_get_dos_attributes,
+       .get_dos_attributes_send_fn = vfs_not_implemented_get_dos_attributes_send,
+       .get_dos_attributes_recv_fn = vfs_not_implemented_get_dos_attributes_recv,
+       .fget_dos_attributes_fn = vfs_gpfs_fget_dos_attributes,
+       .set_dos_attributes_fn = vfs_gpfs_set_dos_attributes,
+       .fset_dos_attributes_fn = vfs_gpfs_fset_dos_attributes,
        .fget_nt_acl_fn = gpfsacl_fget_nt_acl,
        .get_nt_acl_fn = gpfsacl_get_nt_acl,
        .fset_nt_acl_fn = gpfsacl_fset_nt_acl,
@@ -2462,13 +2585,9 @@ static struct vfs_fn_pointers vfs_gpfs_fns = {
        .chmod_fn = vfs_gpfs_chmod,
        .fchmod_fn = vfs_gpfs_fchmod,
        .close_fn = vfs_gpfs_close,
-       .setxattr_fn = gpfs_set_xattr,
-       .getxattr_fn = gpfs_get_xattr,
        .stat_fn = vfs_gpfs_stat,
-       .fstat_fn = vfs_gpfs_fstat,
        .lstat_fn = vfs_gpfs_lstat,
        .ntimes_fn = vfs_gpfs_ntimes,
-       .is_offline_fn = vfs_gpfs_is_offline,
        .aio_force_fn = vfs_gpfs_aio_force,
        .sendfile_fn = vfs_gpfs_sendfile,
        .fallocate_fn = vfs_gpfs_fallocate,
@@ -2482,8 +2601,8 @@ static struct vfs_fn_pointers vfs_gpfs_fns = {
        .ftruncate_fn = vfs_gpfs_ftruncate
 };
 
-NTSTATUS vfs_gpfs_init(void);
-NTSTATUS vfs_gpfs_init(void)
+static_decl_vfs;
+NTSTATUS vfs_gpfs_init(TALLOC_CTX *ctx)
 {
        int ret;