]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
vfs_ceph_new: implement DFS hooks using libcephfs low-level APIs
authorShachar Sharon <ssharon@redhat.com>
Mon, 12 Aug 2024 11:45:53 +0000 (14:45 +0300)
committerJule Anger <janger@samba.org>
Mon, 17 Feb 2025 09:53:26 +0000 (09:53 +0000)
Refactor the VFS hooks 'create_dfs_pathat_fn' and 'read_dfs_pathat_fn'
in 'vfs_ceph_new.c' to use libcephfs low-level APIs: instead of using
path-based operations (as done in legacy 'vfs_ceph.c') use inode based
operations to create and read msdfs symbolic-links values.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15703

Signed-off-by: Shachar Sharon <ssharon@redhat.com>
Reviewed-by: Anoop C S <anoopcs@samba.org>
Reviewed-by: Guenther Deschner <gd@samba.org>
Autobuild-User(master): Günther Deschner <gd@samba.org>
Autobuild-Date(master): Wed Sep 11 19:09:41 UTC 2024 on atb-devel-224

(cherry picked from commit 0cedd74e47ab919528420761a5bd2acb198f084c)

source3/modules/vfs_ceph_new.c

index 8d4866e054bff41e130169ba85b679291b00d3bd..ce46eff69cfdcf659c2940aed7b7be67a4522117 100644 (file)
@@ -757,12 +757,13 @@ static int vfs_ceph_ll_lookup(const struct vfs_handle_struct *handle,
        return 0;
 }
 
-static int vfs_ceph_ll_lookupat(const struct vfs_handle_struct *handle,
-                               const struct vfs_ceph_fh *parent_fh,
-                               const char *name,
-                               struct vfs_ceph_iref *iref)
+static int vfs_ceph_ll_lookup2(const struct vfs_handle_struct *handle,
+                              const struct vfs_ceph_fh *parent_fh,
+                              const char *name,
+                              unsigned want,
+                              struct vfs_ceph_iref *iref,
+                              struct ceph_statx *stx)
 {
-       struct ceph_statx stx = {.stx_ino = 0};
        struct Inode *inode = NULL;
        int ret = -1;
 
@@ -773,19 +774,55 @@ static int vfs_ceph_ll_lookupat(const struct vfs_handle_struct *handle,
                             parent_fh->iref.inode,
                             name,
                             &inode,
-                            &stx,
-                            CEPH_STATX_INO,
+                            stx,
+                            want | CEPH_STATX_INO,
                             0,
                             parent_fh->uperm);
        if (ret != 0) {
                return ret;
        }
        iref->inode = inode;
-       iref->ino = stx.stx_ino;
+       iref->ino = stx->stx_ino;
        iref->owner = true;
        return 0;
 }
 
+static int vfs_ceph_ll_lookupat(const struct vfs_handle_struct *handle,
+                               const struct vfs_ceph_fh *parent_fh,
+                               const char *name,
+                               struct vfs_ceph_iref *iref)
+{
+       struct ceph_statx stx = {.stx_ino = 0};
+
+       return vfs_ceph_ll_lookup2(handle,
+                                  parent_fh,
+                                  name,
+                                  CEPH_STATX_INO,
+                                  iref,
+                                  &stx);
+}
+
+static int vfs_ceph_ll_lookupat2(const struct vfs_handle_struct *handle,
+                                const struct vfs_ceph_fh *parent_fh,
+                                const char *name,
+                                struct vfs_ceph_iref *iref,
+                                SMB_STRUCT_STAT *st)
+{
+       struct ceph_statx stx = {.stx_ino = 0};
+       int ret;
+
+       ret = vfs_ceph_ll_lookup2(handle,
+                                 parent_fh,
+                                 name,
+                                 CEPH_STATX_ALL_STATS,
+                                 iref,
+                                 &stx);
+       if (ret == 0) {
+               smb_stat_from_ceph_statx(st, &stx);
+       }
+       return ret;
+}
+
 static int vfs_ceph_ll_open(const struct vfs_handle_struct *handle,
                            struct vfs_ceph_fh *cfh,
                            int flags)
@@ -1961,44 +1998,6 @@ static int vfs_ceph_fsync_recv(struct tevent_req *req,
        return 0;
 }
 
-static void init_stat_ex_from_ceph_statx(struct stat_ex *dst,
-                                        const struct ceph_statx *stx)
-{
-       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));
-
-       if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK) {
-               DBG_WARNING("%s: stx->stx_mask is incorrect "
-                           "(wanted %x, got %x)\n",
-                           __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_blksize = stx->stx_blksize;
-       dst->st_ex_blocks = stx->stx_blocks;
-}
-
 static int vfs_ceph_stat(struct vfs_handle_struct *handle,
                        struct smb_filename *smb_fname)
 {
@@ -2856,12 +2855,12 @@ static NTSTATUS vfs_ceph_create_dfs_pathat(struct vfs_handle_struct *handle,
        NTSTATUS status = NT_STATUS_NO_MEMORY;
        int ret;
        char *msdfs_link = NULL;
-       struct smb_filename *full_fname = NULL;
+       struct vfs_ceph_fh *dircfh = NULL;
+       struct vfs_ceph_iref iref = {0};
 
-       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
-                                               dirfsp,
-                                               smb_fname);
-       if (full_fname == NULL) {
+       ret = vfs_ceph_fetch_fh(handle, dirfsp, &dircfh);
+       if (ret != 0) {
+               status = map_nt_error_from_unix(-ret);
                goto out;
        }
 
@@ -2873,20 +2872,20 @@ static NTSTATUS vfs_ceph_create_dfs_pathat(struct vfs_handle_struct *handle,
                goto out;
        }
 
-       ret = ceph_symlink(cmount_of(handle),
-                          msdfs_link,
-                          full_fname->base_name);
+       ret = vfs_ceph_ll_symlinkat(handle,
+                                   dircfh,
+                                   smb_fname->base_name,
+                                   msdfs_link,
+                                   &iref);
        if (ret == 0) {
+               vfs_ceph_iput(handle, &iref);
                status = NT_STATUS_OK;
        } else {
                status = map_nt_error_from_unix(-ret);
-        }
-
-  out:
+       }
 
-       DBG_DEBUG("[CEPH] create_dfs_pathat(%s) = %s\n",
-                       full_fname != NULL ? full_fname->base_name : "",
-                       nt_errstr(status));
+out:
+       DBG_DEBUG("[CEPH] create_dfs_pathat(...) = %s\n", nt_errstr(status));
 
        TALLOC_FREE(frame);
        return status;
@@ -2909,22 +2908,23 @@ static NTSTATUS vfs_ceph_read_dfs_pathat(struct vfs_handle_struct *handle,
                                size_t *preferral_count)
 {
        NTSTATUS status = NT_STATUS_NO_MEMORY;
-       size_t bufsize;
+       size_t bufsize = 0;
        char *link_target = NULL;
-       int referral_len;
+       int referral_len = 0;
        bool ok;
 #if defined(HAVE_BROKEN_READLINK)
        char link_target_buf[PATH_MAX];
 #else
        char link_target_buf[7];
 #endif
-       struct ceph_statx stx = { 0 };
-       struct smb_filename *full_fname = NULL;
+       SMB_STRUCT_STAT st = {0};
+       struct vfs_ceph_fh *dircfh = NULL;
+       struct vfs_ceph_iref iref = {0};
        int ret;
 
        if (is_named_stream(smb_fname)) {
                status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
-               goto err;
+               goto out;
        }
 
        if (ppreflist == NULL && preferral_count == NULL) {
@@ -2938,85 +2938,80 @@ static NTSTATUS vfs_ceph_read_dfs_pathat(struct vfs_handle_struct *handle,
                bufsize = PATH_MAX;
                link_target = talloc_array(mem_ctx, char, bufsize);
                if (!link_target) {
-                       goto err;
+                       goto out;
                }
        }
 
-       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
-                                                 dirfsp,
-                                                 smb_fname);
-       if (full_fname == NULL) {
-               status = NT_STATUS_NO_MEMORY;
-               goto err;
+       ret = vfs_ceph_fetch_fh(handle, dirfsp, &dircfh);
+       if (ret != 0) {
+               status = map_nt_error_from_unix(-ret);
+               goto out;
        }
 
-       ret = ceph_statx(cmount_of(handle),
-                        full_fname->base_name,
-                        &stx,
-                        SAMBA_STATX_ATTR_MASK,
-                        AT_SYMLINK_NOFOLLOW);
-       if (ret < 0) {
+       ret = vfs_ceph_ll_lookupat2(handle,
+                                   dircfh,
+                                   smb_fname->base_name,
+                                   &iref,
+                                   &st);
+       if (ret != 0) {
                status = map_nt_error_from_unix(-ret);
-               goto err;
+               goto out;
+       }
+
+       if (!S_ISLNK(st.st_ex_mode)) {
+               DBG_INFO("%s is not a link.\n", smb_fname->base_name);
+               status = NT_STATUS_OBJECT_TYPE_MISMATCH;
+               goto out;
        }
 
-       referral_len = ceph_readlink(cmount_of(handle),
-                                    full_fname->base_name,
+       ret = vfs_ceph_ll_readlinkat(handle,
+                                    dircfh,
+                                    &iref,
                                     link_target,
                                     bufsize - 1);
-       if (referral_len < 0) {
-               /* ceph errors are -errno. */
-               if (-referral_len == EINVAL) {
-                       DBG_INFO("%s is not a link.\n",
-                               full_fname->base_name);
-                       status = NT_STATUS_OBJECT_TYPE_MISMATCH;
-               } else {
-                       status = map_nt_error_from_unix(-referral_len);
-                       DBG_ERR("Error reading "
-                               "msdfs link %s: %s\n",
-                               full_fname->base_name,
-                       strerror(errno));
-               }
-                goto err;
+       if (ret < 0) {
+               DBG_ERR("Error reading msdfs link %s: %d\n",
+                       smb_fname->base_name, ret);
+               status = map_nt_error_from_unix(-ret);
+               goto out;
        }
+
+       referral_len = ret;
        link_target[referral_len] = '\0';
+       DBG_INFO("%s -> %s\n", smb_fname->base_name, link_target);
+
+       if (!strnequal(link_target, "msdfs:", 6)) {
+               status = NT_STATUS_OBJECT_TYPE_MISMATCH;
+               goto out;
+       }
+
+       status = NT_STATUS_OK;
+       if (ppreflist == NULL && preferral_count == NULL) {
+               /* Early return for checking if this is a DFS link. */
+               goto out;
+       }
+
+       ok = parse_msdfs_symlink(mem_ctx,
+                       lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
+                       link_target,
+                       ppreflist,
+                       preferral_count);
 
-        DBG_INFO("%s -> %s\n",
-                        full_fname->base_name,
-                        link_target);
-
-        if (!strnequal(link_target, "msdfs:", 6)) {
-                status = NT_STATUS_OBJECT_TYPE_MISMATCH;
-                goto err;
-        }
-
-        if (ppreflist == NULL && preferral_count == NULL) {
-                /* Early return for checking if this is a DFS link. */
-               TALLOC_FREE(full_fname);
-               init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
-                return NT_STATUS_OK;
-        }
-
-        ok = parse_msdfs_symlink(mem_ctx,
-                        lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
-                        link_target,
-                        ppreflist,
-                        preferral_count);
-
-        if (ok) {
-               init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
-                status = NT_STATUS_OK;
-        } else {
-                status = NT_STATUS_NO_MEMORY;
-        }
-
-  err:
-
-        if (link_target != link_target_buf) {
-                TALLOC_FREE(link_target);
-        }
-       TALLOC_FREE(full_fname);
-        return status;
+       if (!ok) {
+               status = NT_STATUS_NO_MEMORY;
+       }
+
+out:
+       DBG_DEBUG("[CEPH] read_dfs_pathat(...) = %s\n", nt_errstr(status));
+
+       vfs_ceph_iput(handle, &iref);
+       if ((link_target != NULL) && (link_target != link_target_buf)) {
+               TALLOC_FREE(link_target);
+       }
+       if (NT_STATUS_IS_OK(status)) {
+               memcpy(&smb_fname->st, &st, sizeof(smb_fname->st));
+       }
+       return status;
 }
 
 static struct vfs_fn_pointers ceph_new_fns = {