]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
vfs_ceph_new: detect case sensitivity in CephFS
authorXavi Hernandez <xhernandez@redhat.com>
Tue, 4 Mar 2025 11:48:41 +0000 (12:48 +0100)
committerJule Anger <janger@samba.org>
Tue, 18 Mar 2025 15:46:17 +0000 (15:46 +0000)
CephFS has recently added support for case insensitive access to the
file system. This modification detects whether the shared volume is case
sensitive or not and reports the FILE_CASE_SENSITIVE_SEARCH capability
accordingly.

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

Signed-off-by: Xavi Hernandez <xhernandez@redhat.com>
Reviewed-by: Anoop C S <anoopcs@redhat.com>
Reviewed-by: Guenther Deschner <gd@samba.org>
Autobuild-User(master): Günther Deschner <gd@samba.org>
Autobuild-Date(master): Tue Mar 11 20:34:26 UTC 2025 on atb-devel-224

(cherry picked from commit a52602030e6ba0e1bcddf5f611464b58076fadd0)

source3/modules/vfs_ceph_new.c

index 05c2a72d57f8ec7791c6fa446d11c642dbb4bb06..4f1849b3ed57b27352c494d54f3be50588db44e5 100644 (file)
@@ -113,6 +113,15 @@ struct vfs_ceph_config {
        enum vfs_cephfs_proxy_mode proxy;
        void *libhandle;
 
+       /*
+       * This field stores the Samba capabilities for the share represented
+       * by this struct. The share capabilities are computed once during the
+       * module startup and then cached here for future references.
+       *
+       * It's completely independent of the CephFS capabilities concept.
+       */
+       uint32_t capabilities;
+
        CEPH_FN(ceph_ll_walk);
        CEPH_FN(ceph_ll_getattr);
        CEPH_FN(ceph_ll_setattr);
@@ -1932,12 +1941,79 @@ static uint64_t vfs_ceph_disk_free(struct vfs_handle_struct *handle,
        return *dfree;
 }
 
+static int vfs_ceph_check_case_sensitivity(struct vfs_handle_struct *handle,
+                                          uint32_t *capabilities)
+{
+       struct vfs_ceph_iref iref = {0};
+       char value[8] = {0};
+       struct vfs_ceph_config *config = NULL;
+       uint32_t caps;
+       int ret;
+
+       SMB_VFS_HANDLE_GET_DATA(handle, config, struct vfs_ceph_config,
+                               return -ENOMEM);
+
+       if (config->capabilities != 0) {
+               *capabilities = config->capabilities;
+               return 0;
+       }
+
+       /*
+        * In CephFS, case sensitivity configuration is inherited by default,
+        * but it can be manually overridden by an administrator. Samba assumes
+        * that all directories inherit the configuration from the root of the
+        * share and the administrator doesn't change it manually.
+        */
+       ret = vfs_ceph_iget(handle, handle->conn->connectpath, 0, &iref);
+       if (ret != 0) {
+               return ret;
+       }
+
+       caps = FILE_CASE_PRESERVED_NAMES;
+
+       ret = vfs_ceph_ll_getxattr(handle, &iref, "ceph.dir.casesensitive",
+                                  value, sizeof(value) - 1);
+       if (ret < 0) {
+               if (ret != -ENODATA) {
+                       DBG_ERR("[CEPH] failed to get case sensitivity "
+                               "settings: path='%s' %s",
+                               handle->conn->connectpath, strerror(-ret));
+                       goto out;
+               }
+
+               /*
+                * The xattr is not defined, so the filesystem is case sensitive
+                * by default.
+                */
+               caps |= FILE_CASE_SENSITIVE_SEARCH;
+       } else {
+               /*
+                * We only accept "0" as 'false' (as defined in the CephFS
+                * documentation). All other values are interpreted as 'true'
+                */
+               if (strcmp(value, "0") != 0) {
+                       caps |= FILE_CASE_SENSITIVE_SEARCH;
+               }
+       }
+
+       config->capabilities = caps;
+       *capabilities = caps;
+
+       ret = 0;
+
+out:
+       vfs_ceph_iput(handle, &iref);
+
+       return ret;
+}
+
 static int vfs_ceph_statvfs(struct vfs_handle_struct *handle,
                            const struct smb_filename *smb_fname,
                            struct vfs_statvfs_struct *statbuf)
 {
        struct statvfs statvfs_buf = { 0 };
        struct vfs_ceph_iref iref = {0};
+       uint32_t caps = 0;
        int ret;
 
        ret = vfs_ceph_iget(handle, smb_fname->base_name, 0, &iref);
@@ -1950,6 +2026,11 @@ static int vfs_ceph_statvfs(struct vfs_handle_struct *handle,
                goto out;
        }
 
+       ret = vfs_ceph_check_case_sensitivity(handle, &caps);
+       if (ret < 0) {
+               goto out;
+       }
+
        statbuf->OptimalTransferSize = statvfs_buf.f_frsize;
        statbuf->BlockSize = statvfs_buf.f_bsize;
        statbuf->TotalBlocks = statvfs_buf.f_blocks;
@@ -1958,8 +2039,7 @@ static int vfs_ceph_statvfs(struct vfs_handle_struct *handle,
        statbuf->TotalFileNodes = statvfs_buf.f_files;
        statbuf->FreeFileNodes = statvfs_buf.f_ffree;
        statbuf->FsIdentifier = statvfs_buf.f_fsid;
-       statbuf->FsCapabilities =
-               FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
+       statbuf->FsCapabilities = caps;
 
        DBG_DEBUG("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, "
                  "f_bavail: %ld\n",