From 47d5b60af8d48574ff6d11ca37dbff5a6f56815b Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Tue, 21 Jul 2020 13:55:10 +0200 Subject: [PATCH] rbd: disable reflink while creating XFS filesystems Current versions of the mkfs.xfs binary enable reflink support by default. This causes problems on systems where the kernel does not support this feature. When the kernel the feature does not support, but the filesystem has it enabled, the following error is logged in `dmesg`: XFS: Superblock has unknown read-only compatible features (0x4) enabled Introduce a check to see if mkfs.xfs supports the `-m reflink=` option. In case it does, pass `-m reflink=0` while creating the filesystem. The check is executed once during the first XFS filesystem creation. The result of the check is cached until the nodeserver restarts. Fixes: #966 Signed-off-by: Niels de Vos --- internal/rbd/nodeserver.go | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/internal/rbd/nodeserver.go b/internal/rbd/nodeserver.go index 0053ffa43..78c50e81d 100644 --- a/internal/rbd/nodeserver.go +++ b/internal/rbd/nodeserver.go @@ -22,6 +22,7 @@ import ( "fmt" "os" "strconv" + "strings" csicommon "github.com/ceph/ceph-csi/internal/csi-common" "github.com/ceph/ceph-csi/internal/journal" @@ -61,6 +62,13 @@ type stageTransaction struct { devicePath string } +const ( + // values for xfsHasReflink + xfsReflinkUnset int = iota + xfsReflinkNoSupport + xfsReflinkSupport +) + var ( kernelRelease = "" // deepFlattenSupport holds the list of kernel which support mapping rbd @@ -84,6 +92,10 @@ var ( Backport: true, }, // RHEL 8.2 } + + // xfsHasReflink is set by xfsSupportsReflink(), use the function when + // checking the support for reflink + xfsHasReflink = xfsReflinkUnset ) // NodeStageVolume mounts the volume to a staging path on the node. @@ -460,6 +472,11 @@ func (ns *NodeServer) mountVolumeToStagePath(ctx context.Context, req *csi.NodeS args = []string{"-m0", "-Enodiscard,lazy_itable_init=1,lazy_journal_init=1", devicePath} } else if fsType == "xfs" { args = []string{"-K", devicePath} + // always disable reflink + // TODO: make enabling an option, see ceph/ceph-csi#1256 + if ns.xfsSupportsReflink() { + args = append(args, "-m", "reflink=0") + } } if len(args) > 0 { cmdOut, cmdErr := diskMounter.Exec.Command("mkfs."+fsType, args...).CombinedOutput() @@ -869,3 +886,27 @@ func openEncryptedDevice(ctx context.Context, volOptions *rbdVolume, devicePath return mapperFilePath, nil } + +// xfsSupportsReflink checks if mkfs.xfs supports the "-m reflink=0|1" +// argument. In case it is supported, return true. +func (ns *NodeServer) xfsSupportsReflink() bool { + // return cached value, if set + if xfsHasReflink != xfsReflinkUnset { + return xfsHasReflink == xfsReflinkSupport + } + + // run mkfs.xfs in the same namespace as formatting would be done in + // mountVolumeToStagePath() + diskMounter := &mount.SafeFormatAndMount{Interface: ns.mounter, Exec: utilexec.New()} + out, err := diskMounter.Exec.Command("mkfs.xfs").CombinedOutput() + if err != nil { + // mkfs.xfs should fail with an error message (and help text) + if strings.Contains(string(out), "reflink=0|1") { + xfsHasReflink = xfsReflinkSupport + return true + } + } + + xfsHasReflink = xfsReflinkNoSupport + return false +}