From c873391c1dc2c12b2cf9724bfaab9e77472a9bce Mon Sep 17 00:00:00 2001 From: hime Date: Mon, 23 Dec 2024 18:40:32 +0000 Subject: [PATCH 1/3] Support read_ahead_kb and max_ratio configs through mount options. --- cmd/csi_driver/Dockerfile | 5 ++ deploy/base/node/node.yaml | 6 ++ pkg/csi_mounter/csi_mounter.go | 119 ++++++++++++++++++++++++++-- pkg/csi_mounter/csi_mounter_test.go | 75 ++++++++++++++++-- 4 files changed, 192 insertions(+), 13 deletions(-) diff --git a/cmd/csi_driver/Dockerfile b/cmd/csi_driver/Dockerfile index 9ae13244a..f28d5220d 100644 --- a/cmd/csi_driver/Dockerfile +++ b/cmd/csi_driver/Dockerfile @@ -49,6 +49,10 @@ FROM distroless-$TARGETARCH AS output-image # Copy the mount/umount binaries COPY --from=debian /bin/mount /bin/mount COPY --from=debian /bin/umount /bin/umount +COPY --from=debian /bin/mountpoint /bin/mountpoint +# We should try to remove these +COPY --from=debian /bin/sh /bin/sh +COPY --from=debian /bin/cat /bin/cat # Copy shared libraries into distroless base. COPY --from=debian ${LD_LINUX_FILE} ${LIB_DIR} @@ -68,6 +72,7 @@ COPY --from=debian /usr/bin/ldd /usr/bin/ldd SHELL ["/bin/bash", "-c"] RUN if ldd /bin/mount | grep "not found"; then echo "!!! Missing deps for mount command !!!" && exit 1; fi RUN if ldd /bin/umount | grep "not found"; then echo "!!! Missing deps for umount command !!!" && exit 1; fi +RUN if ldd /bin/mountpoint | grep "not found"; then echo "!!! Missing deps for mountpoint command !!!" && exit 1; fi # Final build stage, create the real Docker image with ENTRYPOINT FROM output-image diff --git a/deploy/base/node/node.yaml b/deploy/base/node/node.yaml index a319e9a5d..9d0286675 100755 --- a/deploy/base/node/node.yaml +++ b/deploy/base/node/node.yaml @@ -78,6 +78,8 @@ spec: mountPath: /csi - name: fuse-socket-dir mountPath: /sockets + - name: host-sysfs + mountPath: /sys - name: csi-driver-registrar securityContext: readOnlyRootFilesystem: true @@ -121,6 +123,10 @@ spec: type: DirectoryOrCreate - name: fuse-socket-dir emptyDir: {} + - name: host-sysfs + hostPath: + path: /sys + type: Directory # https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ # See "special case". This will tolerate everything. Node component should # be scheduled on all nodes. diff --git a/pkg/csi_mounter/csi_mounter.go b/pkg/csi_mounter/csi_mounter.go index b9bd639d6..d5c2b5dc2 100644 --- a/pkg/csi_mounter/csi_mounter.go +++ b/pkg/csi_mounter/csi_mounter.go @@ -24,7 +24,10 @@ import ( "fmt" "net" "os" + "os/exec" "path/filepath" + "regexp" + "strconv" "strings" "sync" "syscall" @@ -38,7 +41,18 @@ import ( "k8s.io/mount-utils" ) -const socketName = "socket" +const ( + socketName = "socket" + readAheadKBMountFlagRegexPattern = "^read_ahead_kb=(.+)$" + maxRatioMountFlagRegexPattern = "^max_ratio=(.+)$" + readAheadKBMountFlag = "read_ahead_kb" + maxRatioMountFlag = "max_ratio" +) + +var ( + readAheadKBMountFlagRegex = regexp.MustCompile(readAheadKBMountFlagRegexPattern) + maxRatioMountFlagRegex = regexp.MustCompile(maxRatioMountFlagRegexPattern) +) // Mounter provides the Cloud Storage FUSE CSI implementation of mount.Interface // for the linux platform. @@ -68,7 +82,10 @@ func (m *Mounter) Mount(source string, target string, fstype string, options []s m.mux.Lock() defer m.mux.Unlock() - csiMountOptions, sidecarMountOptions := prepareMountOptions(options) + csiMountOptions, sidecarMountOptions, sysfsBDI, err := prepareMountOptions(options) + if err != nil { + return err + } // Prepare sidecar mounter MountConfig mc := sidecarmounter.MountConfig{ @@ -96,6 +113,17 @@ func (m *Mounter) Mount(source string, target string, fstype string, options []s return fmt.Errorf("failed to mount the fuse filesystem: %w", err) } + if len(sysfsBDI) != 0 { + go func() { + // updateReadAheadAndMaxRatio may hang until the file descriptor (fd) is either consumed or canceled. + // It will succeed once dfuse finishes the mount process, or it will fail if dfuse fails + // or the mount point is cleaned up due to mounting failures. + if err := updateSysfsConfig(target, sysfsBDI); err != nil { + klog.Errorf("%v failed to update read_ahead_kb or max_ratio: %v", logPrefix, err) + } + }() + } + listener, err := m.createSocket(target, logPrefix) if err != nil { // If mount failed at this step, @@ -125,6 +153,60 @@ func (m *Mounter) Mount(source string, target string, fstype string, options []s return nil } +// updateSysfsConfig modifies the kernel page cache settings based on the read_ahead_kb or max_ratio provided in the mountOption, +// and verifies that the values are successfully updated after the operation completes. +func updateSysfsConfig(targetMountPath string, sysfsBDI map[string]int64) error { + start := time.Now() + cmd := exec.Command("mountpoint", "-d", targetMountPath) + output, err := cmd.CombinedOutput() + if err != nil { + klog.Errorf("Error executing mountpoint command on target path %s: %v", targetMountPath, err) + if exitError, ok := err.(*exec.ExitError); ok { + klog.Errorf("Exit code: %d", exitError.ExitCode()) + } + + return err + } + + outputStr := strings.TrimSpace(string(output)) + klog.Infof("Output of mountpoint for target mount path %s: %s", targetMountPath, output) + + for key, value := range sysfsBDI { + // Update the target value. + sysClassEchoCmd := fmt.Sprintf("echo %d > /sys/class/bdi/%s/%s", value, outputStr, key) + klog.V(4).Infof("Executing command %s", sysClassEchoCmd) + cmd := exec.Command("sh", "-c", sysClassEchoCmd) + _, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("failed to execute command %q: %v", sysClassEchoCmd, err) + } + + // Verify updated value. + sysClassCatCmd := fmt.Sprintf("cat /sys/class/bdi/%s/%s", outputStr, key) + klog.V(4).Infof("Executing command %s", sysClassCatCmd) + cmd = exec.Command("sh", "-c", sysClassCatCmd) + op, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("failed to execute command %q: %v", sysClassCatCmd, err) + } + klog.V(4).Infof("Output of %q : %s", sysClassCatCmd, op) + + opStr := strings.TrimSpace(string(op)) + updatedVal, err := strconv.ParseInt(opStr, 10, 0) + if err != nil { + return fmt.Errorf("invalid %s: %v", key, err) + } + if updatedVal != value { + return fmt.Errorf("mismatch in %s, expected %d, got %d", key, value, updatedVal) + } + + currentTime := time.Now() + klog.Infof("Successfully set %s to %d for mountPoint %s at '%v' (elapsed time: %v)", key, value, targetMountPath, currentTime, time.Since(start)) + } + + return nil +} + func (m *Mounter) UnmountWithForce(target string, umountTimeout time.Duration) error { m.cleanupSocket(target) @@ -216,7 +298,7 @@ func startAcceptConn(l net.Listener, logPrefix string, msg []byte, fd int, cance klog.V(4).Infof("%v exiting the listener goroutine.", logPrefix) } -func prepareMountOptions(options []string) ([]string, []string) { +func prepareMountOptions(options []string) (csiMountOptions []string, sidecarMountOptions []string, sysfsBDI map[string]int64, err error) { allowedOptions := map[string]bool{ "exec": true, "noexec": true, @@ -227,7 +309,7 @@ func prepareMountOptions(options []string) ([]string, []string) { "dirsync": true, } - csiMountOptions := []string{ + csiMountOptions = []string{ "nodev", "nosuid", "allow_other", @@ -248,6 +330,7 @@ func prepareMountOptions(options []string) ([]string, []string) { } } + sysfsBDI = make(map[string]int64) for _, o := range optionSet.List() { if strings.HasPrefix(o, "o=") { v := o[2:] @@ -258,7 +341,33 @@ func prepareMountOptions(options []string) ([]string, []string) { } optionSet.Delete(o) } + + if readAheadKB := readAheadKBMountFlagRegex.FindStringSubmatch(o); len(readAheadKB) == 2 { + // There is only one matching pattern in readAheadKBMountFlagRegex + // If found, it will be at index 1 + readAheadKBInt, err := strconv.ParseInt(readAheadKB[1], 10, 0) + if err != nil { + return nil, nil, nil, fmt.Errorf("invalid read_ahead_kb mount flag %q: %v", o, err) + } + if readAheadKBInt < 0 { + return nil, nil, nil, fmt.Errorf("invalid negative value for read_ahead_kb mount flag: %q", o) + } + sysfsBDI[readAheadKBMountFlag] = readAheadKBInt + optionSet.Delete(o) + } + + if maxRatio := maxRatioMountFlagRegex.FindStringSubmatch(o); len(maxRatio) == 2 { + maxRatioInt, err := strconv.ParseInt(maxRatio[1], 10, 0) + if err != nil { + return nil, nil, nil, fmt.Errorf("invalid max_ratio mount flag %q: %v", o, err) + } + if maxRatioInt < 0 || maxRatioInt > 100 { + return nil, nil, nil, fmt.Errorf("invalid value for max_ratio mount flag: %q", o) + } + sysfsBDI[maxRatioMountFlag] = maxRatioInt + optionSet.Delete(o) + } } - return csiMountOptions, optionSet.List() + return csiMountOptions, optionSet.List(), sysfsBDI, nil } diff --git a/pkg/csi_mounter/csi_mounter_test.go b/pkg/csi_mounter/csi_mounter_test.go index c0e471215..8fc8f1aa8 100644 --- a/pkg/csi_mounter/csi_mounter_test.go +++ b/pkg/csi_mounter/csi_mounter_test.go @@ -42,44 +42,103 @@ func TestPrepareMountArgs(t *testing.T) { inputMountOptions []string expecteCsiMountOptions []string expecteSidecarMountOptions []string + expectedSysfsBDI map[string]int64 + expectErr bool }{ { name: "should return valid options correctly with empty input", inputMountOptions: []string{}, expecteCsiMountOptions: defaultCsiMountOptions, expecteSidecarMountOptions: []string{}, + expectedSysfsBDI: map[string]int64{}, }, { name: "should return valid options correctly with CSI mount options only", inputMountOptions: []string{"ro", "o=noexec", "o=noatime", "o=invalid"}, expecteCsiMountOptions: append(defaultCsiMountOptions, "ro", "noexec", "noatime"), expecteSidecarMountOptions: []string{}, + expectedSysfsBDI: map[string]int64{}, }, { name: "should return valid options correctly with sidecar mount options only", inputMountOptions: []string{"implicit-dirs", "max-conns-per-host=10"}, expecteCsiMountOptions: defaultCsiMountOptions, expecteSidecarMountOptions: []string{"implicit-dirs", "max-conns-per-host=10"}, + expectedSysfsBDI: map[string]int64{}, }, { name: "should return valid options correctly with CSI and sidecar mount options", inputMountOptions: []string{"ro", "implicit-dirs", "max-conns-per-host=10", "o=noexec", "o=noatime", "o=invalid"}, expecteCsiMountOptions: append(defaultCsiMountOptions, "ro", "noexec", "noatime"), expecteSidecarMountOptions: []string{"implicit-dirs", "max-conns-per-host=10"}, + expectedSysfsBDI: map[string]int64{}, + }, + { + name: "should return valid options correctly with CSI and sidecar mount options with read ahead configs", + inputMountOptions: []string{"ro", "implicit-dirs", "max-conns-per-host=10", "o=noexec", "o=noatime", "o=invalid", "read_ahead_kb=4096", "max_ratio=100"}, + expecteCsiMountOptions: append(defaultCsiMountOptions, "ro", "noexec", "noatime"), + expecteSidecarMountOptions: []string{"implicit-dirs", "max-conns-per-host=10"}, + expectedSysfsBDI: map[string]int64{"read_ahead_kb": 4096, "max_ratio": 100}, + }, + { + name: "invalid read ahead - not int", + inputMountOptions: append(defaultCsiMountOptions, "read_ahead_kb=abc"), + expectErr: true, + }, + { + name: "invalid read ahead - negative", + inputMountOptions: append(defaultCsiMountOptions, "read_ahead_kb=-1"), + expectErr: true, + }, + { + name: "invalid max ratio - not int", + inputMountOptions: append(defaultCsiMountOptions, "max_ratio=abc"), + expectErr: true, + }, + { + name: "invalid max ratio - negative", + inputMountOptions: append(defaultCsiMountOptions, "max_ratio=-1"), + expectErr: true, + }, + { + name: "invalid max ratio - greater than 100", + inputMountOptions: append(defaultCsiMountOptions, "max_ratio=101"), + expectErr: true, }, } for _, tc := range testCases { - t.Logf("test case: %s", tc.name) + t.Run(tc.name, func(t *testing.T) { + t.Logf("test case: %s", tc.name) + + c, s, sysfsBDI, err := prepareMountOptions(tc.inputMountOptions) + + if tc.expectErr && err == nil { + t.Errorf("test %q failed: expected an error, but got nil", tc.name) + + return + } + if !tc.expectErr && err != nil { + t.Errorf("test %q failed: unexpected error: %v", tc.name, err) + + return + } + if tc.expectErr { + return + } + + if !reflect.DeepEqual(countOptionOccurrence(c), countOptionOccurrence(tc.expecteCsiMountOptions)) { + t.Errorf("Got options %v, but expected %v", c, tc.expecteCsiMountOptions) + } - c, s := prepareMountOptions(tc.inputMountOptions) - if !reflect.DeepEqual(countOptionOccurrence(c), countOptionOccurrence(tc.expecteCsiMountOptions)) { - t.Errorf("Got options %v, but expected %v", c, tc.expecteCsiMountOptions) - } + if !reflect.DeepEqual(countOptionOccurrence(s), countOptionOccurrence(tc.expecteSidecarMountOptions)) { + t.Errorf("Got options %v, but expected %v", s, tc.expecteSidecarMountOptions) + } - if !reflect.DeepEqual(countOptionOccurrence(s), countOptionOccurrence(tc.expecteSidecarMountOptions)) { - t.Errorf("Got options %v, but expected %v", s, tc.expecteSidecarMountOptions) - } + if !reflect.DeepEqual(sysfsBDI, tc.expectedSysfsBDI) { + t.Errorf("Got sysfsBDI %v, expected %v", sysfsBDI, tc.expectedSysfsBDI) + } + }) } } From a0903291cb761e60b81330ef10d609e8555608ad Mon Sep 17 00:00:00 2001 From: hime Date: Mon, 23 Dec 2024 21:01:54 +0000 Subject: [PATCH 2/3] Fix go lint failures for base commit. --- pkg/csi_mounter/csi_mounter.go | 19 ++++++++++--------- pkg/csi_mounter/csi_mounter_test.go | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pkg/csi_mounter/csi_mounter.go b/pkg/csi_mounter/csi_mounter.go index d5c2b5dc2..2a096b0ce 100644 --- a/pkg/csi_mounter/csi_mounter.go +++ b/pkg/csi_mounter/csi_mounter.go @@ -161,7 +161,8 @@ func updateSysfsConfig(targetMountPath string, sysfsBDI map[string]int64) error output, err := cmd.CombinedOutput() if err != nil { klog.Errorf("Error executing mountpoint command on target path %s: %v", targetMountPath, err) - if exitError, ok := err.(*exec.ExitError); ok { + var exitError *exec.ExitError + if errors.As(err, &exitError) { klog.Errorf("Exit code: %d", exitError.ExitCode()) } @@ -178,7 +179,7 @@ func updateSysfsConfig(targetMountPath string, sysfsBDI map[string]int64) error cmd := exec.Command("sh", "-c", sysClassEchoCmd) _, err := cmd.CombinedOutput() if err != nil { - return fmt.Errorf("failed to execute command %q: %v", sysClassEchoCmd, err) + return fmt.Errorf("failed to execute command %q: %w", sysClassEchoCmd, err) } // Verify updated value. @@ -187,14 +188,14 @@ func updateSysfsConfig(targetMountPath string, sysfsBDI map[string]int64) error cmd = exec.Command("sh", "-c", sysClassCatCmd) op, err := cmd.CombinedOutput() if err != nil { - return fmt.Errorf("failed to execute command %q: %v", sysClassCatCmd, err) + return fmt.Errorf("failed to execute command %q: %w", sysClassCatCmd, err) } klog.V(4).Infof("Output of %q : %s", sysClassCatCmd, op) opStr := strings.TrimSpace(string(op)) updatedVal, err := strconv.ParseInt(opStr, 10, 0) if err != nil { - return fmt.Errorf("invalid %s: %v", key, err) + return fmt.Errorf("invalid %s: %w", key, err) } if updatedVal != value { return fmt.Errorf("mismatch in %s, expected %d, got %d", key, value, updatedVal) @@ -298,7 +299,7 @@ func startAcceptConn(l net.Listener, logPrefix string, msg []byte, fd int, cance klog.V(4).Infof("%v exiting the listener goroutine.", logPrefix) } -func prepareMountOptions(options []string) (csiMountOptions []string, sidecarMountOptions []string, sysfsBDI map[string]int64, err error) { +func prepareMountOptions(options []string) ([]string, []string, map[string]int64, error) { allowedOptions := map[string]bool{ "exec": true, "noexec": true, @@ -309,7 +310,7 @@ func prepareMountOptions(options []string) (csiMountOptions []string, sidecarMou "dirsync": true, } - csiMountOptions = []string{ + csiMountOptions := []string{ "nodev", "nosuid", "allow_other", @@ -330,7 +331,7 @@ func prepareMountOptions(options []string) (csiMountOptions []string, sidecarMou } } - sysfsBDI = make(map[string]int64) + sysfsBDI := make(map[string]int64) for _, o := range optionSet.List() { if strings.HasPrefix(o, "o=") { v := o[2:] @@ -347,7 +348,7 @@ func prepareMountOptions(options []string) (csiMountOptions []string, sidecarMou // If found, it will be at index 1 readAheadKBInt, err := strconv.ParseInt(readAheadKB[1], 10, 0) if err != nil { - return nil, nil, nil, fmt.Errorf("invalid read_ahead_kb mount flag %q: %v", o, err) + return nil, nil, nil, fmt.Errorf("invalid read_ahead_kb mount flag %q: %w", o, err) } if readAheadKBInt < 0 { return nil, nil, nil, fmt.Errorf("invalid negative value for read_ahead_kb mount flag: %q", o) @@ -359,7 +360,7 @@ func prepareMountOptions(options []string) (csiMountOptions []string, sidecarMou if maxRatio := maxRatioMountFlagRegex.FindStringSubmatch(o); len(maxRatio) == 2 { maxRatioInt, err := strconv.ParseInt(maxRatio[1], 10, 0) if err != nil { - return nil, nil, nil, fmt.Errorf("invalid max_ratio mount flag %q: %v", o, err) + return nil, nil, nil, fmt.Errorf("invalid max_ratio mount flag %q: %w", o, err) } if maxRatioInt < 0 || maxRatioInt > 100 { return nil, nil, nil, fmt.Errorf("invalid value for max_ratio mount flag: %q", o) diff --git a/pkg/csi_mounter/csi_mounter_test.go b/pkg/csi_mounter/csi_mounter_test.go index 8fc8f1aa8..226ac7ad4 100644 --- a/pkg/csi_mounter/csi_mounter_test.go +++ b/pkg/csi_mounter/csi_mounter_test.go @@ -109,6 +109,7 @@ func TestPrepareMountArgs(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + t.Parallel() t.Logf("test case: %s", tc.name) c, s, sysfsBDI, err := prepareMountOptions(tc.inputMountOptions) From da1a89aa55a4513c89bddef21b2f296c43a56526 Mon Sep 17 00:00:00 2001 From: hime Date: Mon, 23 Dec 2024 22:31:38 +0000 Subject: [PATCH 3/3] Remove sh dependency. --- cmd/csi_driver/Dockerfile | 3 +- pkg/csi_mounter/csi_mounter.go | 50 ++++++++++++++-------------------- 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/cmd/csi_driver/Dockerfile b/cmd/csi_driver/Dockerfile index f28d5220d..37a8618cf 100644 --- a/cmd/csi_driver/Dockerfile +++ b/cmd/csi_driver/Dockerfile @@ -50,8 +50,6 @@ FROM distroless-$TARGETARCH AS output-image COPY --from=debian /bin/mount /bin/mount COPY --from=debian /bin/umount /bin/umount COPY --from=debian /bin/mountpoint /bin/mountpoint -# We should try to remove these -COPY --from=debian /bin/sh /bin/sh COPY --from=debian /bin/cat /bin/cat # Copy shared libraries into distroless base. @@ -73,6 +71,7 @@ SHELL ["/bin/bash", "-c"] RUN if ldd /bin/mount | grep "not found"; then echo "!!! Missing deps for mount command !!!" && exit 1; fi RUN if ldd /bin/umount | grep "not found"; then echo "!!! Missing deps for umount command !!!" && exit 1; fi RUN if ldd /bin/mountpoint | grep "not found"; then echo "!!! Missing deps for mountpoint command !!!" && exit 1; fi +RUN if ldd /bin/cat | grep "not found"; then echo "!!! Missing deps for cat command !!!" && exit 1; fi # Final build stage, create the real Docker image with ENTRYPOINT FROM output-image diff --git a/pkg/csi_mounter/csi_mounter.go b/pkg/csi_mounter/csi_mounter.go index 2a096b0ce..c2ee16ec6 100644 --- a/pkg/csi_mounter/csi_mounter.go +++ b/pkg/csi_mounter/csi_mounter.go @@ -115,7 +115,7 @@ func (m *Mounter) Mount(source string, target string, fstype string, options []s if len(sysfsBDI) != 0 { go func() { - // updateReadAheadAndMaxRatio may hang until the file descriptor (fd) is either consumed or canceled. + // updateSysfsConfig may hang until the file descriptor (fd) is either consumed or canceled. // It will succeed once dfuse finishes the mount process, or it will fail if dfuse fails // or the mount point is cleaned up due to mounting failures. if err := updateSysfsConfig(target, sysfsBDI); err != nil { @@ -156,7 +156,7 @@ func (m *Mounter) Mount(source string, target string, fstype string, options []s // updateSysfsConfig modifies the kernel page cache settings based on the read_ahead_kb or max_ratio provided in the mountOption, // and verifies that the values are successfully updated after the operation completes. func updateSysfsConfig(targetMountPath string, sysfsBDI map[string]int64) error { - start := time.Now() + // Command will hang until mount completes. cmd := exec.Command("mountpoint", "-d", targetMountPath) output, err := cmd.CombinedOutput() if err != nil { @@ -173,36 +173,28 @@ func updateSysfsConfig(targetMountPath string, sysfsBDI map[string]int64) error klog.Infof("Output of mountpoint for target mount path %s: %s", targetMountPath, output) for key, value := range sysfsBDI { - // Update the target value. - sysClassEchoCmd := fmt.Sprintf("echo %d > /sys/class/bdi/%s/%s", value, outputStr, key) - klog.V(4).Infof("Executing command %s", sysClassEchoCmd) - cmd := exec.Command("sh", "-c", sysClassEchoCmd) - _, err := cmd.CombinedOutput() - if err != nil { - return fmt.Errorf("failed to execute command %q: %w", sysClassEchoCmd, err) - } + writeErr := func(targetDevice, key string) error { + // Update the target value. + sysfsBDIPath := filepath.Join("/sys/class/bdi/", targetDevice, key) + file, err := os.OpenFile(sysfsBDIPath, os.O_WRONLY|os.O_TRUNC, 0644) + if err != nil { + return fmt.Errorf("failed to open file %q: %w", sysfsBDIPath, err) + } + defer file.Close() - // Verify updated value. - sysClassCatCmd := fmt.Sprintf("cat /sys/class/bdi/%s/%s", outputStr, key) - klog.V(4).Infof("Executing command %s", sysClassCatCmd) - cmd = exec.Command("sh", "-c", sysClassCatCmd) - op, err := cmd.CombinedOutput() - if err != nil { - return fmt.Errorf("failed to execute command %q: %w", sysClassCatCmd, err) - } - klog.V(4).Infof("Output of %q : %s", sysClassCatCmd, op) + _, err = file.Write([]byte(fmt.Sprintf("%d\n", value))) - opStr := strings.TrimSpace(string(op)) - updatedVal, err := strconv.ParseInt(opStr, 10, 0) - if err != nil { - return fmt.Errorf("invalid %s: %w", key, err) - } - if updatedVal != value { - return fmt.Errorf("mismatch in %s, expected %d, got %d", key, value, updatedVal) - } + if err != nil { + return fmt.Errorf("failed to write to file %q: %w", "echo", err) + } - currentTime := time.Now() - klog.Infof("Successfully set %s to %d for mountPoint %s at '%v' (elapsed time: %v)", key, value, targetMountPath, currentTime, time.Since(start)) + klog.Infof("Updated %s to %d", sysfsBDIPath, value) + + return nil + }(outputStr, key) + if writeErr != nil { + return err + } } return nil