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 <ndevos@redhat.com>
This commit is contained in:
Niels de Vos 2020-07-21 13:55:10 +02:00 committed by mergify[bot]
parent 526da43b6a
commit 47d5b60af8

View File

@ -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
}