From d5b730736f58c232f6b314ece7815e3246f76055 Mon Sep 17 00:00:00 2001 From: Shwetha Acharya Date: Fri, 3 Jul 2026 12:26:34 +0530 Subject: [PATCH] mgr/smb: add fruit:nfs_aces=no for macOS compatibility mode When macOS client compatibility is enabled, add the global Samba configuration option 'fruit:nfs_aces = no' to disable NFS ACE handling in the fruit VFS module. This improves compatibility with macOS SMB clients by preventing conflicts between NFS-style ACLs and macOS extended attributes. The configuration is automatically applied when: - Creating a new cluster with --client-compat=macos - Updating an existing cluster to macOS mode Signed-off-by: Shwetha K Acharya --- src/pybind/mgr/smb/handler.py | 5 ++ src/pybind/mgr/smb/tests/test_handler.py | 88 ++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/src/pybind/mgr/smb/handler.py b/src/pybind/mgr/smb/handler.py index a6270243ba9..ec081aad4d8 100644 --- a/src/pybind/mgr/smb/handler.py +++ b/src/pybind/mgr/smb/handler.py @@ -1176,6 +1176,11 @@ def _generate_config(conf: _ClusterConf) -> Dict[str, Any]: cluster_global_opts['smb ports'] = str(_smb_port(cluster)) _set_debug_level(cluster_global_opts, conf) + # Disable NFS ACE handling for macOS compatibility + # See https://tracker.ceph.com/issues/78052 for rationale and follow-up. + if cluster.is_macos_compatibility_enabled: + cluster_global_opts['fruit:nfs_aces'] = 'no' + # Check if cluster has RGW shares and add global RGW options has_rgw_shares = any(share.resource.rgw for share in conf.shares) if has_rgw_shares: diff --git a/src/pybind/mgr/smb/tests/test_handler.py b/src/pybind/mgr/smb/tests/test_handler.py index eb470cdc414..1564605c655 100644 --- a/src/pybind/mgr/smb/tests/test_handler.py +++ b/src/pybind/mgr/smb/tests/test_handler.py @@ -1824,3 +1824,91 @@ def test_apply_share_with_qos(thandler): assert share_dict['cephfs']['qos']['write_bw_limit'] == "2097152" assert share_dict['cephfs']['qos']['read_burst_mult'] == 20 assert share_dict['cephfs']['qos']['write_burst_mult'] == 15 + + +def test_generate_config_macos_compat(thandler): + """Test that macOS compatibility adds fruit:nfs_aces = no to global config.""" + thandler.internal_store.overwrite( + { + 'clusters.foo': { + 'resource_type': 'ceph.smb.cluster', + 'cluster_id': 'foo', + 'auth_mode': 'user', + 'intent': 'present', + 'client_compat': 'macos', + 'user_group_settings': [ + { + 'source_type': 'empty', + } + ], + }, + 'shares.foo.s1': { + 'resource_type': 'ceph.smb.share', + 'cluster_id': 'foo', + 'share_id': 's1', + 'intent': 'present', + 'name': 'MacShare', + 'readonly': False, + 'browseable': True, + 'cephfs': { + 'volume': 'cephfs', + 'path': '/', + 'provider': 'samba-vfs', + }, + }, + } + ) + + thandler._sync_clusters(['foo']) + cfg = thandler.public_store['foo', 'config.smb'].get() + assert cfg + # Verify fruit:nfs_aces is set to 'no' in global options + assert cfg['globals']['foo']['options']['fruit:nfs_aces'] == 'no' + # Verify VFS modules include fruit and streams_xattr + share_vfs = cfg['shares']['MacShare']['options']['vfs objects'] + assert 'fruit' in share_vfs + assert 'streams_xattr' in share_vfs + + +def test_generate_config_default_compat(thandler): + """Test that default compatibility does not add fruit:nfs_aces.""" + thandler.internal_store.overwrite( + { + 'clusters.foo': { + 'resource_type': 'ceph.smb.cluster', + 'cluster_id': 'foo', + 'auth_mode': 'user', + 'intent': 'present', + 'client_compat': 'default', + 'user_group_settings': [ + { + 'source_type': 'empty', + } + ], + }, + 'shares.foo.s1': { + 'resource_type': 'ceph.smb.share', + 'cluster_id': 'foo', + 'share_id': 's1', + 'intent': 'present', + 'name': 'DefaultShare', + 'readonly': False, + 'browseable': True, + 'cephfs': { + 'volume': 'cephfs', + 'path': '/', + 'provider': 'samba-vfs', + }, + }, + } + ) + + thandler._sync_clusters(['foo']) + cfg = thandler.public_store['foo', 'config.smb'].get() + assert cfg + # Verify fruit:nfs_aces is NOT in global options + assert 'fruit:nfs_aces' not in cfg['globals']['foo']['options'] + # Verify VFS modules do NOT include fruit and streams_xattr + share_vfs = cfg['shares']['DefaultShare']['options']['vfs objects'] + assert 'fruit' not in share_vfs + assert 'streams_xattr' not in share_vfs -- 2.47.3