From 434ce4ee782f807e79b97342d183c7996fa7d727 Mon Sep 17 00:00:00 2001 From: Niraj Yadav Date: Wed, 27 Nov 2024 15:08:29 +0530 Subject: [PATCH] rbd: Use assume_storage_prezeroed when formatting Instead of passing lazy_itable_init=1 and lazy_journal_init=1 to mkfs.ext4, pass assume_storage_prezeroed=1 which is stronger and allows the filesystem to skip inode table zeroing completely instead of simply doing it lazily. The support for this flag is checked by trying to format a fake temporary image with mkfs.ext4 and checking its STDERR. Closes: #4948 Signed-off-by: Niraj Yadav --- internal/rbd/nodeserver.go | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/internal/rbd/nodeserver.go b/internal/rbd/nodeserver.go index 905fcf8affe..4209f259c3d 100644 --- a/internal/rbd/nodeserver.go +++ b/internal/rbd/nodeserver.go @@ -67,6 +67,10 @@ const ( xfsReflinkNoSupport xfsReflinkSupport + ext4PrezeroedUnset + ext4PrezeroedNoSupport + ext4PrezeroedSupport + staticVol = "staticVolume" volHealerCtx = "volumeHealerContext" tryOtherMounters = "tryOtherMounters" @@ -100,6 +104,9 @@ var ( // checking the support for reflink. xfsHasReflink = xfsReflinkUnset + // ext4HasPrezeroed is set by ext4SupportsPrezeroed() + ext4SupportsPrezeroed = ext4PrezeroedUnset + mkfsDefaultArgs = map[string][]string{ "ext4": {"-m0", "-Enodiscard,lazy_itable_init=1,lazy_journal_init=1"}, "xfs": {"-K"}, @@ -794,6 +801,9 @@ func (ns *NodeServer) mountVolumeToStagePath( if existingFormat == "" && !staticVol && !readOnly && !isBlock { args := mkfsDefaultArgs[fsType] + if fsType == "ext4" && ns.ext4SupportsPrezeroed() { + args = []string{"-m0", "-Enodiscard,assume_storage_prezeroed=1"} + } // if the VolumeContext contains "mkfsOptions", use those as args instead volumeCtx := req.GetVolumeContext() @@ -1314,6 +1324,44 @@ func (ns *NodeServer) xfsSupportsReflink() bool { return false } +// ext4SupportsPrezeroed checks if the ext4 filesystem supports the +// "assume_storage_prezeroed" option. It does this by creating a temporary +// image file, attempting to format it with the ext4 filesystem using the +// "assume_storage_prezeroed" option, and checking the output for errors. +func (ns *NodeServer) ext4SupportsPrezeroed() bool { + if ext4SupportsPrezeroed != ext4PrezeroedUnset { + return ext4SupportsPrezeroed == ext4PrezeroedSupport + } + + tempImage := "/tmp/prezeroed.img" + ctx := context.TODO() + _, _, err := util.ExecCommand(ctx, "dd", "if=/dev/zero", "of="+tempImage, "bs=1M", "count=1") + if err != nil { + log.ErrorLog(ctx, "failed to create temporary image %s: %v", tempImage, err) + + return false + } + defer os.Remove(tempImage) + + diskMounter := &mount.SafeFormatAndMount{Interface: ns.Mounter, Exec: utilexec.New()} + + // `-n`` Causes mke2fs to not actually create a file system, but display what it would do if it were to create a file system. + out, err := diskMounter.Exec.Command("mkfs.ext4", "-n", "-Enodiscard,assume_storage_prezeroed=1", tempImage).CombinedOutput() + if err != nil { + if strings.Contains(string(out), "Bad option(s) specified") { + ext4SupportsPrezeroed = ext4PrezeroedNoSupport + } + + // if the error is not due to the missing option, we can't be sure + // if the option is supported or not, return false optimistically + return false + } + + ext4SupportsPrezeroed = ext4PrezeroedSupport + + return true +} + // NodeGetVolumeStats returns volume stats. func (ns *NodeServer) NodeGetVolumeStats( ctx context.Context,