lib: modules: Change XXX_init interface from XXX_init(void) to XXX_init(TALLOC_CTX *)
[nivanova/samba-autobuild/.git] / source3 / modules / vfs_ceph.c
index e402ff114130063349e8180dc860a7e57cfcc91d..d819fe18dc35fee26451c4ccf762d05cdb5b51a5 100644 (file)
 #include <sys/statvfs.h>
 #include "cephfs/libcephfs.h"
 #include "smbprofile.h"
+#include "modules/posixacl_xattr.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
 
+#ifndef LIBCEPHFS_VERSION
+#define LIBCEPHFS_VERSION(maj, min, extra) ((maj << 16) + (min << 8) + extra)
+#define LIBCEPHFS_VERSION_CODE LIBCEPHFS_VERSION(0, 0, 0)
+#endif
+
 /*
  * Use %llu whenever we have a 64bit unsigned int, and cast to (long long unsigned)
  */
@@ -79,8 +85,9 @@ static int cephwrap_connect(struct vfs_handle_struct *handle,  const char *servi
 {
        int ret;
        char buf[256];
-
-       const char * conf_file;
+       int snum = SNUM(handle->conn);
+       const char *conf_file;
+       const char *user_id;
 
        if (cmount) {
                handle->data = cmount; /* We have been here before */
@@ -88,36 +95,34 @@ static int cephwrap_connect(struct vfs_handle_struct *handle,  const char *servi
                return 0;
        }
 
-       conf_file = lp_parm_const_string(SNUM(handle->conn), "ceph", "config_file", NULL);
+       /* if config_file and/or user_id are NULL, ceph will use defaults */
+       conf_file = lp_parm_const_string(snum, "ceph", "config_file", NULL);
+       user_id = lp_parm_const_string(snum, "ceph", "user_id", NULL);
 
-       DEBUG(2, ( "[CEPH] calling: ceph_create\n" ));
-       ret = ceph_create(&cmount, NULL);
-       if (ret)
+       DBG_DEBUG("[CEPH] calling: ceph_create\n");
+       ret = ceph_create(&cmount, user_id);
+       if (ret) {
                goto err_out;
-
-       if (conf_file) {
-               /* Override the config file */
-               DEBUG(2, ( "[CEPH] calling: ceph_conf_read_file\n" ));
-               ret = ceph_conf_read_file(cmount, conf_file);
-       } else {
-
-               DEBUG(2, ( "[CEPH] calling: ceph_conf_read_file with %s\n", conf_file));
-               ret = ceph_conf_read_file(cmount, NULL);
        }
 
-       if (ret)
-               goto err_out;
+       DBG_DEBUG("[CEPH] calling: ceph_conf_read_file with %s\n",
+                 (conf_file == NULL ? "default path" : conf_file));
+       ret = ceph_conf_read_file(cmount, conf_file);
+       if (ret) {
+               goto err_cm_release;
+       }
 
-       DEBUG(2, ( "[CEPH] calling: ceph_conf_get\n" ));
+       DBG_DEBUG("[CEPH] calling: ceph_conf_get\n");
        ret = ceph_conf_get(cmount, "log file", buf, sizeof(buf));
-       if (ret < 0)
-               goto err_out;
+       if (ret < 0) {
+               goto err_cm_release;
+       }
 
-       DEBUG(2, ("[CEPH] calling: ceph_mount\n"));
+       DBG_DEBUG("[CEPH] calling: ceph_mount\n");
        ret = ceph_mount(cmount, NULL);
-       if (ret < 0)
-               goto err_out;
-
+       if (ret < 0) {
+               goto err_cm_release;
+       }
 
        /*
         * encode mount context/state into our vfs/connection holding structure
@@ -128,36 +133,50 @@ static int cephwrap_connect(struct vfs_handle_struct *handle,  const char *servi
 
        return 0;
 
+err_cm_release:
+       ceph_release(cmount);
+       cmount = NULL;
 err_out:
        /*
         * Handle the error correctly. Ceph returns -errno.
         */
-       DEBUG(2, ("[CEPH] Error return: %s\n", strerror(-ret)));
+       DBG_DEBUG("[CEPH] Error return: %s\n", strerror(-ret));
        WRAP_RETURN(ret);
 }
 
 static void cephwrap_disconnect(struct vfs_handle_struct *handle)
 {
+       int ret;
+
        if (!cmount) {
-               DEBUG(0, ("[CEPH] Error, ceph not mounted\n"));
+               DBG_ERR("[CEPH] Error, ceph not mounted\n");
                return;
        }
 
        /* Should we unmount/shutdown? Only if the last disconnect? */
        if (--cmount_cnt) {
-               DEBUG(10, ("[CEPH] Not shuting down CEPH because still more connections\n"));
+               DBG_DEBUG("[CEPH] Not shuting down CEPH because still more connections\n");
                return;
        }
 
-       ceph_shutdown(cmount);
+       ret = ceph_unmount(cmount);
+       if (ret < 0) {
+               DBG_ERR("[CEPH] failed to unmount: %s\n", strerror(-ret));
+       }
+
+       ret = ceph_release(cmount);
+       if (ret < 0) {
+               DBG_ERR("[CEPH] failed to release: %s\n", strerror(-ret));
+       }
 
        cmount = NULL;  /* Make it safe */
 }
 
 /* Disk operations */
 
-static uint64_t cephwrap_disk_free(struct vfs_handle_struct *handle,  const char *path, bool small_query, uint64_t *bsize,
-                              uint64_t *dfree, uint64_t *dsize)
+static uint64_t cephwrap_disk_free(struct vfs_handle_struct *handle,
+                                  const char *path, uint64_t *bsize,
+                                  uint64_t *dfree, uint64_t *dsize)
 {
        struct statvfs statvfs_buf;
        int ret;
@@ -167,18 +186,20 @@ static uint64_t cephwrap_disk_free(struct vfs_handle_struct *handle,  const char
                 * Provide all the correct values.
                 */
                *bsize = statvfs_buf.f_bsize;
-               *dfree = statvfs_buf.f_bsize * statvfs_buf.f_bavail;
-               *dsize = statvfs_buf.f_bsize * statvfs_buf.f_blocks;
-               DEBUG(10, ("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
-                       llu(*bsize), llu(*dfree), llu(*dsize)));
+               *dfree = statvfs_buf.f_bavail;
+               *dsize = statvfs_buf.f_blocks;
+               DBG_DEBUG("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
+                       llu(*bsize), llu(*dfree), llu(*dsize));
                return *dfree;
        } else {
-               DEBUG(10, ("[CEPH] ceph_statfs returned %d\n", ret));
+               DBG_DEBUG("[CEPH] ceph_statfs returned %d\n", ret);
                WRAP_RETURN(ret);
        }
 }
 
-static int cephwrap_get_quota(struct vfs_handle_struct *handle,  enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
+static int cephwrap_get_quota(struct vfs_handle_struct *handle,
+                             const char *path, enum SMB_QUOTA_TYPE qtype,
+                             unid_t id, SMB_DISK_QUOTA *qt)
 {
        /* libceph: Ceph does not implement this */
 #if 0
@@ -235,40 +256,42 @@ static int cephwrap_statvfs(struct vfs_handle_struct *handle,  const char *path,
                statbuf->TotalFileNodes = statvfs_buf.f_files;
                statbuf->FreeFileNodes = statvfs_buf.f_ffree;
                statbuf->FsIdentifier = statvfs_buf.f_fsid;
-               DEBUG(10, ("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
+               DBG_DEBUG("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
                        (long int)statvfs_buf.f_bsize, (long int)statvfs_buf.f_blocks,
-                       (long int)statvfs_buf.f_bfree, (long int)statvfs_buf.f_bavail));
+                       (long int)statvfs_buf.f_bfree, (long int)statvfs_buf.f_bavail);
        }
        return ret;
 }
 
 /* Directory operations */
 
-static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,  const char *fname, const char *mask, uint32 attr)
+static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,
+                            const struct smb_filename *smb_fname,
+                            const char *mask, uint32_t attr)
 {
        int ret = 0;
        struct ceph_dir_result *result;
-       DEBUG(10, ("[CEPH] opendir(%p, %s)\n", handle, fname));
+       DBG_DEBUG("[CEPH] opendir(%p, %s)\n", handle, smb_fname->base_name);
 
        /* Returns NULL if it does not exist or there are problems ? */
-       ret = ceph_opendir(handle->data, fname, &result);
+       ret = ceph_opendir(handle->data, smb_fname->base_name, &result);
        if (ret < 0) {
                result = NULL;
                errno = -ret; /* We return result which is NULL in this case */
        }
 
-       DEBUG(10, ("[CEPH] opendir(...) = %d\n", ret));
+       DBG_DEBUG("[CEPH] opendir(...) = %d\n", ret);
        return (DIR *) result;
 }
 
 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
                               struct files_struct *fsp,
                               const char *mask,
-                              uint32 attributes)
+                              uint32_t attributes)
 {
        int ret = 0;
        struct ceph_dir_result *result;
-       DEBUG(10, ("[CEPH] fdopendir(%p, %p)\n", handle, fsp));
+       DBG_DEBUG("[CEPH] fdopendir(%p, %p)\n", handle, fsp);
 
        ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
        if (ret < 0) {
@@ -276,7 +299,7 @@ static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
                errno = -ret; /* We return result which is NULL in this case */
        }
 
-       DEBUG(10, ("[CEPH] fdopendir(...) = %d\n", ret));
+       DBG_DEBUG("[CEPH] fdopendir(...) = %d\n", ret);
        return (DIR *) result;
 }
 
@@ -286,9 +309,9 @@ static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
 {
        struct dirent *result;
 
-       DEBUG(10, ("[CEPH] readdir(%p, %p)\n", handle, dirp));
+       DBG_DEBUG("[CEPH] readdir(%p, %p)\n", handle, dirp);
        result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
-       DEBUG(10, ("[CEPH] readdir(...) = %p\n", result));
+       DBG_DEBUG("[CEPH] readdir(...) = %p\n", result);
 
        /* Default Posix readdir() does not give us stat info.
         * Set to invalid to indicate we didn't return this info. */
@@ -299,32 +322,35 @@ static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
 
 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
 {
-       DEBUG(10, ("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset));
+       DBG_DEBUG("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset);
        ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
 }
 
 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
 {
        long ret;
-       DEBUG(10, ("[CEPH] telldir(%p, %p)\n", handle, dirp));
+       DBG_DEBUG("[CEPH] telldir(%p, %p)\n", handle, dirp);
        ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
-       DEBUG(10, ("[CEPH] telldir(...) = %ld\n", ret));
+       DBG_DEBUG("[CEPH] telldir(...) = %ld\n", ret);
        WRAP_RETURN(ret);
 }
 
 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
 {
-       DEBUG(10, ("[CEPH] rewinddir(%p, %p)\n", handle, dirp));
+       DBG_DEBUG("[CEPH] rewinddir(%p, %p)\n", handle, dirp);
        ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
 }
 
-static int cephwrap_mkdir(struct vfs_handle_struct *handle,  const char *path, mode_t mode)
+static int cephwrap_mkdir(struct vfs_handle_struct *handle,
+                         const struct smb_filename *smb_fname,
+                         mode_t mode)
 {
        int result;
        bool has_dacl = False;
        char *parent = NULL;
+       const char *path = smb_fname->base_name;
 
-       DEBUG(10, ("[CEPH] mkdir(%p, %s)\n", handle, path));
+       DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
 
        if (lp_inherit_acls(SNUM(handle->conn))
            && parent_dirname(talloc_tos(), path, &parent, NULL)
@@ -349,20 +375,23 @@ static int cephwrap_mkdir(struct vfs_handle_struct *handle,  const char *path, m
                 * mess up any inherited ACL bits that were set. JRA.
                 */
                int saved_errno = errno; /* We may get ENOSYS */
-               if ((SMB_VFS_CHMOD_ACL(handle->conn, path, mode) == -1) && (errno == ENOSYS))
+               if ((SMB_VFS_CHMOD_ACL(handle->conn, smb_fname, mode) == -1) &&
+                               (errno == ENOSYS)) {
                        errno = saved_errno;
+               }
        }
 
        return result;
 }
 
-static int cephwrap_rmdir(struct vfs_handle_struct *handle,  const char *path)
+static int cephwrap_rmdir(struct vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname)
 {
        int result;
 
-       DEBUG(10, ("[CEPH] rmdir(%p, %s)\n", handle, path));
-       result = ceph_rmdir(handle->data, path);
-       DEBUG(10, ("[CEPH] rmdir(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name);
+       result = ceph_rmdir(handle->data, smb_fname->base_name);
+       DBG_DEBUG("[CEPH] rmdir(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
@@ -370,9 +399,9 @@ static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
 {
        int result;
 
-       DEBUG(10, ("[CEPH] closedir(%p, %p)\n", handle, dirp));
+       DBG_DEBUG("[CEPH] closedir(%p, %p)\n", handle, dirp);
        result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
-       DEBUG(10, ("[CEPH] closedir(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] closedir(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
@@ -383,7 +412,8 @@ static int cephwrap_open(struct vfs_handle_struct *handle,
                        files_struct *fsp, int flags, mode_t mode)
 {
        int result = -ENOENT;
-       DEBUG(10, ("[CEPH] open(%p, %s, %p, %d, %d)\n", handle, smb_fname_str_dbg(smb_fname), fsp, flags, mode));
+       DBG_DEBUG("[CEPH] open(%p, %s, %p, %d, %d)\n", handle,
+                 smb_fname_str_dbg(smb_fname), fsp, flags, mode);
 
        if (smb_fname->stream_name) {
                goto out;
@@ -391,7 +421,7 @@ static int cephwrap_open(struct vfs_handle_struct *handle,
 
        result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
 out:
-       DEBUG(10, ("[CEPH] open(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] open(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
@@ -399,9 +429,9 @@ static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
 {
        int result;
 
-       DEBUG(10, ("[CEPH] close(%p, %p)\n", handle, fsp));
+       DBG_DEBUG("[CEPH] close(%p, %p)\n", handle, fsp);
        result = ceph_close(handle->data, fsp->fh->fd);
-       DEBUG(10, ("[CEPH] close(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] close(...) = %d\n", result);
 
        WRAP_RETURN(result);
 }
@@ -410,11 +440,11 @@ static ssize_t cephwrap_read(struct vfs_handle_struct *handle, files_struct *fsp
 {
        ssize_t result;
 
-       DEBUG(10, ("[CEPH] read(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n)));
+       DBG_DEBUG("[CEPH] read(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
 
        /* Using -1 for the offset means read/write rather than pread/pwrite */
        result = ceph_read(handle->data, fsp->fh->fd, data, n, -1);
-       DEBUG(10, ("[CEPH] read(...) = %llu\n", llu(result)));
+       DBG_DEBUG("[CEPH] read(...) = %llu\n", llu(result));
        WRAP_RETURN(result);
 }
 
@@ -423,10 +453,10 @@ static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fs
 {
        ssize_t result;
 
-       DEBUG(10, ("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset)));
+       DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
 
        result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
-       DEBUG(10, ("[CEPH] pread(...) = %llu\n", llu(result)));
+       DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
        WRAP_RETURN(result);
 }
 
@@ -435,11 +465,11 @@ static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fs
 {
        ssize_t result;
 
-       DEBUG(10, ("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n)));
+       DBG_DEBUG("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
 
        result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
 
-       DEBUG(10, ("[CEPH] write(...) = %llu\n", llu(result)));
+       DBG_DEBUG("[CEPH] write(...) = %llu\n", llu(result));
        if (result < 0) {
                WRAP_RETURN(result);
        }
@@ -452,9 +482,9 @@ static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *f
 {
        ssize_t result;
 
-       DEBUG(10, ("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset)));
+       DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
        result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
-       DEBUG(10, ("[CEPH] pwrite(...) = %llu\n", llu(result)));
+       DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
        WRAP_RETURN(result);
 }
 
@@ -462,7 +492,7 @@ static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp,
 {
        off_t result = 0;
 
-       DEBUG(10, ("[CEPH] cephwrap_lseek\n"));
+       DBG_DEBUG("[CEPH] cephwrap_lseek\n");
        /* Cope with 'stat' file opens. */
        if (fsp->fh->fd != -1) {
                result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
@@ -476,7 +506,7 @@ static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, fil
        /*
         * We cannot support sendfile because libceph is in user space.
         */
-       DEBUG(10, ("[CEPH] cephwrap_sendfile\n"));
+       DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
        errno = ENOTSUP;
        return -1;
 }
@@ -490,7 +520,7 @@ static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
        /*
         * We cannot support recvfile because libceph is in user space.
         */
-       DEBUG(10, ("[CEPH] cephwrap_recvfile\n"));
+       DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
        errno=ENOTSUP;
        return -1;
 }
@@ -500,7 +530,7 @@ static int cephwrap_rename(struct vfs_handle_struct *handle,
                          const struct smb_filename *smb_fname_dst)
 {
        int result = -1;
-       DEBUG(10, ("[CEPH] cephwrap_rename\n"));
+       DBG_DEBUG("[CEPH] cephwrap_rename\n");
        if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
                errno = ENOENT;
                return result;
@@ -513,38 +543,160 @@ static int cephwrap_rename(struct vfs_handle_struct *handle,
 static int cephwrap_fsync(struct vfs_handle_struct *handle, files_struct *fsp)
 {
        int result;
-       DEBUG(10, ("[CEPH] cephwrap_fsync\n"));
+       DBG_DEBUG("[CEPH] cephwrap_fsync\n");
        result = ceph_fsync(handle->data, fsp->fh->fd, false);
        WRAP_RETURN(result);
 }
 
-static void cephwrap_init_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src)
+#ifdef HAVE_CEPH_STATX
+#define SAMBA_STATX_ATTR_MASK  (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
+
+static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
+{
+       if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK)
+               DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
+                               __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
+
+       dst->st_ex_dev = stx->stx_dev;
+       dst->st_ex_rdev = stx->stx_rdev;
+       dst->st_ex_ino = stx->stx_ino;
+       dst->st_ex_mode = stx->stx_mode;
+       dst->st_ex_uid = stx->stx_uid;
+       dst->st_ex_gid = stx->stx_gid;
+       dst->st_ex_size = stx->stx_size;
+       dst->st_ex_nlink = stx->stx_nlink;
+       dst->st_ex_atime = stx->stx_atime;
+       dst->st_ex_btime = stx->stx_btime;
+       dst->st_ex_ctime = stx->stx_ctime;
+       dst->st_ex_mtime = stx->stx_mtime;
+       dst->st_ex_calculated_birthtime = false;
+       dst->st_ex_blksize = stx->stx_blksize;
+       dst->st_ex_blocks = stx->stx_blocks;
+}
+
+static int cephwrap_stat(struct vfs_handle_struct *handle,
+                       struct smb_filename *smb_fname)
+{
+       int result = -1;
+       struct ceph_statx stx;
+
+       DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
+
+       if (smb_fname->stream_name) {
+               errno = ENOENT;
+               return result;
+       }
+
+       result = ceph_statx(handle->data, smb_fname->base_name, &stx,
+                               SAMBA_STATX_ATTR_MASK, 0);
+       DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
+       if (result < 0) {
+               WRAP_RETURN(result);
+       } else {
+               DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
+                          "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
+                          "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
+                          llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
+                          llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
+                          llu(stx.stx_size), llu(stx.stx_blksize),
+                          llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
+                          llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
+       }
+       init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
+       DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
+       return result;
+}
+
+static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
+{
+       int result = -1;
+       struct ceph_statx stx;
+
+       DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
+       result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
+                               SAMBA_STATX_ATTR_MASK, 0);
+       DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
+       if (result < 0) {
+               WRAP_RETURN(result);
+       } else {
+               DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
+                          "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
+                          "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
+                          llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
+                          llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
+                          llu(stx.stx_size), llu(stx.stx_blksize),
+                          llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
+                          llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
+       }
+       init_stat_ex_from_ceph_statx(sbuf, &stx);
+       DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
+       return result;
+}
+
+static int cephwrap_lstat(struct vfs_handle_struct *handle,
+                        struct smb_filename *smb_fname)
+{
+       int result = -1;
+       struct ceph_statx stx;
+
+       DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
+
+       if (smb_fname->stream_name) {
+               errno = ENOENT;
+               return result;
+       }
+
+       result = ceph_statx(handle->data, smb_fname->base_name, &stx,
+                               SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
+       DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
+       if (result < 0) {
+               WRAP_RETURN(result);
+       }
+       init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
+       return result;
+}
+
+static int cephwrap_ntimes(struct vfs_handle_struct *handle,
+                        const struct smb_filename *smb_fname,
+                        struct smb_file_time *ft)
 {
-       ZERO_STRUCT(*dst);
+       struct ceph_statx stx = { 0 };
+       int result;
+       int mask = 0;
+
+       if (!null_timespec(ft->atime)) {
+               stx.stx_atime = ft->atime;
+               mask |= CEPH_SETATTR_ATIME;
+       }
+       if (!null_timespec(ft->mtime)) {
+               stx.stx_mtime = ft->mtime;
+               mask |= CEPH_SETATTR_MTIME;
+       }
+       if (!null_timespec(ft->create_time)) {
+               stx.stx_btime = ft->create_time;
+               mask |= CEPH_SETATTR_BTIME;
+       }
 
-       dst->st_ex_dev = src->st_dev;
-       dst->st_ex_ino = src->st_ino;
-       dst->st_ex_mode = src->st_mode;
-       dst->st_ex_nlink = src->st_nlink;
-       dst->st_ex_uid = src->st_uid;
-       dst->st_ex_gid = src->st_gid;
-       dst->st_ex_rdev = src->st_rdev;
-       dst->st_ex_size = src->st_size;
-       dst->st_ex_atime.tv_sec = src->st_atime;
-       dst->st_ex_mtime.tv_sec = src->st_mtime;
-       dst->st_ex_ctime.tv_sec = src->st_ctime;
-       dst->st_ex_btime.tv_sec = src->st_mtime;
-       dst->st_ex_blksize = src->st_blksize;
-       dst->st_ex_blocks = src->st_blocks;
+       if (!mask) {
+               return 0;
+       }
+
+       result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
+       DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
+                               ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
+                               ft->create_time.tv_sec, result);
+       return result;
 }
 
+#else /* HAVE_CEPH_STATX */
+
 static int cephwrap_stat(struct vfs_handle_struct *handle,
                        struct smb_filename *smb_fname)
 {
        int result = -1;
        struct stat stbuf;
 
-       DEBUG(10, ("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
+       DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
 
        if (smb_fname->stream_name) {
                errno = ENOENT;
@@ -552,19 +704,21 @@ static int cephwrap_stat(struct vfs_handle_struct *handle,
        }
 
        result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
-       DEBUG(10, ("[CEPH] stat(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
        if (result < 0) {
                WRAP_RETURN(result);
        } else {
-               DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
+               DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
                           "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
                           "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
                           llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
                           stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
-                          llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime)));
+                          llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
        }
-       cephwrap_init_stat_ex_from_stat(&(smb_fname->st), &stbuf);
-       DEBUG(10, ("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode));
+       init_stat_ex_from_stat(
+                       &smb_fname->st, &stbuf,
+                       lp_fake_directory_create_times(SNUM(handle->conn)));
+       DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
        return result;
 }
 
@@ -573,22 +727,24 @@ static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, S
        int result = -1;
        struct stat stbuf;
 
-       DEBUG(10, ("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd));
+       DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
        result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
-       DEBUG(10, ("[CEPH] fstat(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
        if (result < 0) {
                WRAP_RETURN(result);
        } else {
-               DEBUG(10, ("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
+               DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
                           "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
                           "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
                           llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
                           stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
-                          llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime)));
+                          llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
        }
 
-       cephwrap_init_stat_ex_from_stat(sbuf, &stbuf);
-       DEBUG(10, ("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode));
+       init_stat_ex_from_stat(
+                       sbuf, &stbuf,
+                       lp_fake_directory_create_times(SNUM(handle->conn)));
+       DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
        return result;
 }
 
@@ -598,7 +754,7 @@ static int cephwrap_lstat(struct vfs_handle_struct *handle,
        int result = -1;
        struct stat stbuf;
 
-       DEBUG(10, ("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
+       DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
 
        if (smb_fname->stream_name) {
                errno = ENOENT;
@@ -606,34 +762,72 @@ static int cephwrap_lstat(struct vfs_handle_struct *handle,
        }
 
        result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
-       DEBUG(10, ("[CEPH] lstat(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
        if (result < 0) {
                WRAP_RETURN(result);
        }
-       cephwrap_init_stat_ex_from_stat(&(smb_fname->st), &stbuf);
+       init_stat_ex_from_stat(
+                       &smb_fname->st, &stbuf,
+                       lp_fake_directory_create_times(SNUM(handle->conn)));
+       return result;
+}
+
+static int cephwrap_ntimes(struct vfs_handle_struct *handle,
+                        const struct smb_filename *smb_fname,
+                        struct smb_file_time *ft)
+{
+       struct utimbuf buf;
+       int result;
+
+       if (null_timespec(ft->atime)) {
+               buf.actime = smb_fname->st.st_ex_atime.tv_sec;
+       } else {
+               buf.actime = ft->atime.tv_sec;
+       }
+       if (null_timespec(ft->mtime)) {
+               buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
+       } else {
+               buf.modtime = ft->mtime.tv_sec;
+       }
+       if (!null_timespec(ft->create_time)) {
+               set_create_timespec_ea(handle->conn, smb_fname,
+                                      ft->create_time);
+       }
+       if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
+           buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
+               return 0;
+       }
+
+       result = ceph_utime(handle->data, smb_fname->base_name, &buf);
+       DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
+                               ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
+                               ft->create_time.tv_sec, result);
        return result;
 }
+#endif /* HAVE_CEPH_STATX */
 
 static int cephwrap_unlink(struct vfs_handle_struct *handle,
                          const struct smb_filename *smb_fname)
 {
        int result = -1;
 
-       DEBUG(10, ("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname)));
+       DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
        if (smb_fname->stream_name) {
                errno = ENOENT;
                return result;
        }
        result = ceph_unlink(handle->data, smb_fname->base_name);
-       DEBUG(10, ("[CEPH] unlink(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
-static int cephwrap_chmod(struct vfs_handle_struct *handle,  const char *path, mode_t mode)
+static int cephwrap_chmod(struct vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       mode_t mode)
 {
        int result;
 
-       DEBUG(10, ("[CEPH] chmod(%p, %s, %d)\n", handle, path, mode));
+       DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
 
        /*
         * We need to do this due to the fact that the default POSIX ACL
@@ -644,15 +838,18 @@ static int cephwrap_chmod(struct vfs_handle_struct *handle,  const char *path, m
 
        {
                int saved_errno = errno; /* We might get ENOSYS */
-               if ((result = SMB_VFS_CHMOD_ACL(handle->conn, path, mode)) == 0) {
+               result = SMB_VFS_CHMOD_ACL(handle->conn,
+                                       smb_fname,
+                                       mode);
+               if (result == 0) {
                        return result;
                }
                /* Error - return the old errno. */
                errno = saved_errno;
        }
 
-       result = ceph_chmod(handle->data, path, mode);
-       DEBUG(10, ("[CEPH] chmod(...) = %d\n", result));
+       result = ceph_chmod(handle->data, smb_fname->base_name, mode);
+       DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
@@ -660,7 +857,7 @@ static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp,
 {
        int result;
 
-       DEBUG(10, ("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode));
+       DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
 
        /*
         * We need to do this due to the fact that the default POSIX ACL
@@ -679,7 +876,7 @@ static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp,
 
 #if defined(HAVE_FCHMOD)
        result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
-       DEBUG(10, ("[CEPH] fchmod(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
        WRAP_RETURN(result);
 #else
        errno = ENOSYS;
@@ -687,12 +884,15 @@ static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp,
        return -1;
 }
 
-static int cephwrap_chown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
+static int cephwrap_chown(struct vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       uid_t uid,
+                       gid_t gid)
 {
        int result;
-       DEBUG(10, ("[CEPH] chown(%p, %s, %d, %d)\n", handle, path, uid, gid));
-       result = ceph_chown(handle->data, path, uid, gid);
-       DEBUG(10, ("[CEPH] chown(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
+       result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
+       DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
@@ -701,9 +901,9 @@ static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp,
        int result;
 #ifdef HAVE_FCHOWN
 
-       DEBUG(10, ("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid));
+       DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
        result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
-       DEBUG(10, ("[CEPH] fchown(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
        WRAP_RETURN(result);
 #else
        errno = ENOSYS;
@@ -712,20 +912,22 @@ static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp,
        return result;
 }
 
-static int cephwrap_lchown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
+static int cephwrap_lchown(struct vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       uid_t uid,
+                       gid_t gid)
 {
        int result;
-
-       DEBUG(10, ("[CEPH] lchown(%p, %s, %d, %d)\n", handle, path, uid, gid));
-       result = ceph_lchown(handle->data, path, uid, gid);
-       DEBUG(10, ("[CEPH] lchown(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
+       result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
+       DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
 static int cephwrap_chdir(struct vfs_handle_struct *handle,  const char *path)
 {
        int result = -1;
-       DEBUG(10, ("[CEPH] chdir(%p, %s)\n", handle, path));
+       DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, path);
        /*
         * If the path is just / use chdir because Ceph is below / and
         * cannot deal with changing directory above its mount point
@@ -734,31 +936,17 @@ static int cephwrap_chdir(struct vfs_handle_struct *handle,  const char *path)
                return chdir(path);
 
        result = ceph_chdir(handle->data, path);
-       DEBUG(10, ("[CEPH] chdir(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
 static char *cephwrap_getwd(struct vfs_handle_struct *handle)
 {
        const char *cwd = ceph_getcwd(handle->data);
-       DEBUG(10, ("[CEPH] getwd(%p) = %s\n", handle, cwd));
+       DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
        return SMB_STRDUP(cwd);
 }
 
-static int cephwrap_ntimes(struct vfs_handle_struct *handle,
-                        const struct smb_filename *smb_fname,
-                        struct smb_file_time *ft)
-{
-       struct utimbuf buf;
-       buf.actime = ft->atime.tv_sec;
-       buf.modtime = ft->mtime.tv_sec;
-       int result = ceph_utime(handle->data, smb_fname->base_name, &buf);
-       DEBUG(10, ("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
-                               ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
-                               ft->create_time.tv_sec, result));
-       return result;
-}
-
 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
 {
        off_t space_to_write;
@@ -793,22 +981,19 @@ static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_str
           emulation is being done by the libc (like on AIX with JFS1). In that
           case we do our own emulation. fallocate implementations can
           return ENOTSUP or EINVAL in cases like that. */
-       ret = SMB_VFS_FALLOCATE(fsp, VFS_FALLOCATE_EXTEND_SIZE,
-                               pst->st_ex_size, space_to_write);
-       if (ret == ENOSPC) {
-               errno = ENOSPC;
+       ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
+       if (ret == -1 && errno == ENOSPC) {
                return -1;
        }
        if (ret == 0) {
                return 0;
        }
        DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
-               "error %d. Falling back to slow manual allocation\n", ret));
+               "error %d. Falling back to slow manual allocation\n", errno));
 
        /* available disk space is enough or not? */
-       space_avail = get_dfree_info(fsp->conn,
-                                    fsp->fsp_name->base_name, false,
-                                    &bsize,&dfree,&dsize);
+       space_avail =
+           get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
        /* space_avail is 1k blocks */
        if (space_avail == (uint64_t)-1 ||
                        ((uint64_t)space_to_write/1024 > space_avail) ) {
@@ -817,13 +1002,7 @@ static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_str
        }
 
        /* Write out the real space on disk. */
-       ret = vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
-       if (ret != 0) {
-               errno = ret;
-               ret = -1;
-       }
-
-       return 0;
+       return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
 }
 
 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
@@ -833,7 +1012,7 @@ static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fs
        char c = 0;
        off_t currpos;
 
-       DEBUG(10, ("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len)));
+       DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
 
        if (lp_strict_allocate(SNUM(fsp->conn))) {
                result = strict_allocate_ftruncate(handle, fsp, len);
@@ -901,14 +1080,14 @@ static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fs
 
 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
 {
-       DEBUG(10, ("[CEPH] lock\n"));
+       DBG_DEBUG("[CEPH] lock\n");
        return true;
 }
 
 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
-                               uint32 share_mode, uint32 access_mask)
+                               uint32_t share_mode, uint32_t access_mask)
 {
-       DEBUG(10, ("[CEPH] kernel_flock\n"));
+       DBG_DEBUG("[CEPH] kernel_flock\n");
        /*
         * We must return zero here and pretend all is good.
         * One day we might have this in CEPH.
@@ -918,7 +1097,7 @@ static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct
 
 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
 {
-       DEBUG(10, ("[CEPH] getlock returning false and errno=0\n"));
+       DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
 
        errno = 0;
        return false;
@@ -934,7 +1113,7 @@ static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struc
 {
        int result = -1;
 
-       DEBUG(10, ("[CEPH] linux_setlease\n"));
+       DBG_DEBUG("[CEPH] linux_setlease\n");
        errno = ENOSYS;
        return result;
 }
@@ -942,36 +1121,36 @@ static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struc
 static int cephwrap_symlink(struct vfs_handle_struct *handle,  const char *oldpath, const char *newpath)
 {
        int result = -1;
-       DEBUG(10, ("[CEPH] symlink(%p, %s, %s)\n", handle, oldpath, newpath));
+       DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle, oldpath, newpath);
        result = ceph_symlink(handle->data, oldpath, newpath);
-       DEBUG(10, ("[CEPH] symlink(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
 static int cephwrap_readlink(struct vfs_handle_struct *handle,  const char *path, char *buf, size_t bufsiz)
 {
        int result = -1;
-       DEBUG(10, ("[CEPH] readlink(%p, %s, %p, %llu)\n", handle, path, buf, llu(bufsiz)));
+       DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle, path, buf, llu(bufsiz));
        result = ceph_readlink(handle->data, path, buf, bufsiz);
-       DEBUG(10, ("[CEPH] readlink(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
 static int cephwrap_link(struct vfs_handle_struct *handle,  const char *oldpath, const char *newpath)
 {
        int result = -1;
-       DEBUG(10, ("[CEPH] link(%p, %s, %s)\n", handle, oldpath, newpath));
+       DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle, oldpath, newpath);
        result = ceph_link(handle->data, oldpath, newpath);
-       DEBUG(10, ("[CEPH] link(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] link(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
 static int cephwrap_mknod(struct vfs_handle_struct *handle,  const char *pathname, mode_t mode, SMB_DEV_T dev)
 {
        int result = -1;
-       DEBUG(10, ("[CEPH] mknod(%p, %s)\n", handle, pathname));
+       DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, pathname);
        result = ceph_mknod(handle->data, pathname, mode, dev);
-       DEBUG(10, ("[CEPH] mknod(...) = %d\n", result));
+       DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
        WRAP_RETURN(result);
 }
 
@@ -1003,27 +1182,10 @@ static char *cephwrap_realpath(struct vfs_handle_struct *handle,  const char *pa
                                handle->conn->connectpath, path);
                if (r < 0) return NULL;
        }
-       DEBUG(10, ("[CEPH] realpath(%p, %s) = %s\n", handle, path, result));
+       DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
        return result;
 }
 
-static NTSTATUS cephwrap_notify_watch(struct vfs_handle_struct *vfs_handle,
-                                    struct sys_notify_context *ctx,
-                                    const char *path,
-                                    uint32_t *filter,
-                                    uint32_t *subdir_filter,
-                                    void (*callback)(struct sys_notify_context *ctx,
-                                                     void *private_data,
-                                                     struct notify_event *ev),
-                                    void *private_data,
-                                    void *handle_p)
-{
-       /*
-        * We cannot call inotify on files the kernel does not know about
-        */
-       return NT_STATUS_OK;
-}
-
 static int cephwrap_chflags(struct vfs_handle_struct *handle, const char *path,
                           unsigned int flags)
 {
@@ -1057,9 +1219,10 @@ static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
 
 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size)
 {
-       DEBUG(10, ("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle, path, name, value, llu(size)));
-       int ret = ceph_getxattr(handle->data, path, name, value, size);
-       DEBUG(10, ("[CEPH] getxattr(...) = %d\n", ret));
+       int ret;
+       DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle, path, name, value, llu(size));
+       ret = ceph_getxattr(handle->data, path, name, value, size);
+       DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
        if (ret < 0) {
                WRAP_RETURN(ret);
        } else {
@@ -1069,9 +1232,14 @@ static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,const char *pa
 
 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
 {
-       DEBUG(10, ("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size)));
-       int ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
-       DEBUG(10, ("[CEPH] fgetxattr(...) = %d\n", ret));
+       int ret;
+       DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
+#if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
+       ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
+#else
+       ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
+#endif
+       DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
        if (ret < 0) {
                WRAP_RETURN(ret);
        } else {
@@ -1081,9 +1249,10 @@ static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files
 
 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
 {
-       DEBUG(10, ("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size)));
-       int ret = ceph_listxattr(handle->data, path, list, size);
-       DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret));
+       int ret;
+       DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size));
+       ret = ceph_listxattr(handle->data, path, list, size);
+       DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
        if (ret < 0) {
                WRAP_RETURN(ret);
        } else {
@@ -1094,9 +1263,10 @@ static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle, const char *
 #if 0
 static ssize_t cephwrap_llistxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
 {
-       DEBUG(10, ("[CEPH] llistxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size)));
-       int ret = ceph_llistxattr(handle->data, path, list, size);
-       DEBUG(10, ("[CEPH] listxattr(...) = %d\n", ret));
+       int ret;
+       DBG_DEBUG("[CEPH] llistxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size));
+       ret = ceph_llistxattr(handle->data, path, list, size);
+       DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
        if (ret < 0) {
                WRAP_RETURN(ret);
        } else {
@@ -1107,9 +1277,14 @@ static ssize_t cephwrap_llistxattr(struct vfs_handle_struct *handle, const char
 
 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
 {
-       DEBUG(10, ("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size)));
-       int ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
-       DEBUG(10, ("[CEPH] flistxattr(...) = %d\n", ret));
+       int ret;
+       DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
+#if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
+       ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
+#else
+       ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
+#endif
+       DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
        if (ret < 0) {
                WRAP_RETURN(ret);
        } else {
@@ -1119,33 +1294,46 @@ static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct file
 
 static int cephwrap_removexattr(struct vfs_handle_struct *handle, const char *path, const char *name)
 {
-       DEBUG(10, ("[CEPH] removexattr(%p, %s, %s)\n", handle, path, name));
-       int ret = ceph_removexattr(handle->data, path, name);
-       DEBUG(10, ("[CEPH] removexattr(...) = %d\n", ret));
+       int ret;
+       DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle, path, name);
+       ret = ceph_removexattr(handle->data, path, name);
+       DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
        WRAP_RETURN(ret);
 }
 
 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
 {
-       DEBUG(10, ("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name));
-       int ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
-       DEBUG(10, ("[CEPH] fremovexattr(...) = %d\n", ret));
+       int ret;
+       DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
+#if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
+       ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
+#else
+       ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
+#endif
+       DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
        WRAP_RETURN(ret);
 }
 
 static int cephwrap_setxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
 {
-       DEBUG(10, ("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle, path, name, value, llu(size), flags));
-       int ret = ceph_setxattr(handle->data, path, name, value, size, flags);
-       DEBUG(10, ("[CEPH] setxattr(...) = %d\n", ret));
+       int ret;
+       DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle, path, name, value, llu(size), flags);
+       ret = ceph_setxattr(handle->data, path, name, value, size, flags);
+       DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
        WRAP_RETURN(ret);
 }
 
 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
 {
-       DEBUG(10, ("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags));
-       int ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
-       DEBUG(10, ("[CEPH] fsetxattr(...) = %d\n", ret));
+       int ret;
+       DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
+#if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
+       ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
+                            name, value, size, flags);
+#else
+       ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
+#endif
+       DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
        WRAP_RETURN(ret);
 }
 
@@ -1156,25 +1344,11 @@ static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_st
         * We do not support AIO yet.
         */
 
-       DEBUG(10, ("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp));
+       DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
        errno = ENOTSUP;
        return false;
 }
 
-static bool cephwrap_is_offline(struct vfs_handle_struct *handle,
-                               const struct smb_filename *fname,
-                               SMB_STRUCT_STAT *sbuf)
-{
-       return false;
-}
-
-static int cephwrap_set_offline(struct vfs_handle_struct *handle,
-                               const struct smb_filename *fname)
-{
-       errno = ENOTSUP;
-       return -1;
-}
-
 static struct vfs_fn_pointers ceph_fns = {
        /* Disk operations */
 
@@ -1232,7 +1406,6 @@ static struct vfs_fn_pointers ceph_fns = {
        .link_fn = cephwrap_link,
        .mknod_fn = cephwrap_mknod,
        .realpath_fn = cephwrap_realpath,
-       .notify_watch_fn = cephwrap_notify_watch,
        .chflags_fn = cephwrap_chflags,
        .get_real_filename_fn = cephwrap_get_real_filename,
        .connectpath_fn = cephwrap_connectpath,
@@ -1247,16 +1420,21 @@ static struct vfs_fn_pointers ceph_fns = {
        .setxattr_fn = cephwrap_setxattr,
        .fsetxattr_fn = cephwrap_fsetxattr,
 
+       /* 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_file_fn = posixacl_xattr_acl_set_file,
+       .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
+       .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
+
        /* aio operations */
        .aio_force_fn = cephwrap_aio_force,
-
-       /* offline operations */
-       .is_offline_fn = cephwrap_is_offline,
-       .set_offline_fn = cephwrap_set_offline
 };
 
-NTSTATUS vfs_ceph_init(void);
-NTSTATUS vfs_ceph_init(void)
+NTSTATUS vfs_ceph_init(TALLOC_CTX *);
+NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
 {
        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
                                "ceph", &ceph_fns);