]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
vfs_ceph_new: use low-level APIs for linkat
authorShachar Sharon <ssharon@redhat.com>
Thu, 20 Jun 2024 19:46:52 +0000 (22:46 +0300)
committerGünther Deschner <gd@samba.org>
Mon, 29 Jul 2024 14:51:37 +0000 (14:51 +0000)
Implement link operations using libcephfs' low-level APIs. Requires two
phase operation: resolve (by-lookup) reference to inode and then do the
actual (hard) link operation using parent dir-inode reference to the
locally-cached inode.

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

Signed-off-by: Shachar Sharon <ssharon@redhat.com>
Reviewed-by: Guenther Deschner <gd@samba.org>
Reviewed-by: Anoop C S <anoopcs@samba.org>
source3/modules/vfs_ceph_new.c

index 1d4f6ff1ad43b18cdfb03d88c7f61baa395596eb..fcce851c5f9d38692b2879ed4551ef7d7db248e0 100644 (file)
@@ -944,6 +944,18 @@ static int vfs_ceph_ll_fallocate(const struct vfs_handle_struct *handle,
        return ceph_ll_fallocate(cmount_of(handle), cfh->fh, mode, off, len);
 }
 
+static int vfs_ceph_ll_link(const struct vfs_handle_struct *handle,
+                           const struct vfs_ceph_fh *dircfh,
+                           const char *name,
+                           const struct vfs_ceph_iref *iref)
+{
+       return ceph_ll_link(cmount_of(handle),
+                           iref->inode,
+                           dircfh->iref.inode,
+                           name,
+                           dircfh->uperm);
+}
+
 /* Ceph Inode-refernce get/put wrappers */
 static int vfs_ceph_iget(const struct vfs_handle_struct *handle,
                         uint64_t ino,
@@ -2177,40 +2189,50 @@ out:
 }
 
 static int vfs_ceph_linkat(struct vfs_handle_struct *handle,
-               files_struct *srcfsp,
-               const struct smb_filename *old_smb_fname,
-               files_struct *dstfsp,
-               const struct smb_filename *new_smb_fname,
-               int flags)
-{
-       struct smb_filename *full_fname_old = NULL;
-       struct smb_filename *full_fname_new = NULL;
+                          files_struct *srcfsp,
+                          const struct smb_filename *old_smb_fname,
+                          files_struct *dstfsp,
+                          const struct smb_filename *new_smb_fname,
+                          int flags)
+{
+       struct vfs_ceph_fh *src_dircfh = NULL;
+       struct vfs_ceph_fh *dst_dircfh = NULL;
+       struct vfs_ceph_iref iref = {0};
+       const char *name = old_smb_fname->base_name;
+       const char *newname = new_smb_fname->base_name;
        int result = -1;
 
-       full_fname_old = full_path_from_dirfsp_atname(talloc_tos(),
-                                       srcfsp,
-                                       old_smb_fname);
-       if (full_fname_old == NULL) {
+       /* Prevent special linkat modes until it is required by VFS layer */
+       if (flags & (AT_EMPTY_PATH | AT_SYMLINK_FOLLOW)) {
+               errno = ENOTSUP;
                return -1;
        }
-       full_fname_new = full_path_from_dirfsp_atname(talloc_tos(),
-                                       dstfsp,
-                                       new_smb_fname);
-       if (full_fname_new == NULL) {
-               TALLOC_FREE(full_fname_old);
-               return -1;
+
+       DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle, name, newname);
+
+       result = vfs_ceph_fetch_fh(handle, srcfsp, &src_dircfh);
+       if (result != 0) {
+               goto out;
        }
 
-       DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
-                       full_fname_old->base_name,
-                       full_fname_new->base_name);
+       result = vfs_ceph_fetch_fh(handle, dstfsp, &dst_dircfh);
+       if (result != 0) {
+               goto out;
+       }
+
+       result = vfs_ceph_ll_lookupat(handle, src_dircfh, name, &iref);
+       if (result != 0) {
+               goto out;
+       }
 
-       result = ceph_link(cmount_of(handle),
-                          full_fname_old->base_name,
-                          full_fname_new->base_name);
+       result = vfs_ceph_ll_link(handle, dst_dircfh, newname, &iref);
+       if (result != 0) {
+               goto out;
+       }
+
+       vfs_ceph_iput(handle, &iref);
+out:
        DBG_DEBUG("[CEPH] link(...) = %d\n", result);
-       TALLOC_FREE(full_fname_old);
-       TALLOC_FREE(full_fname_new);
        return status_code(result);
 }