Repository: ydb-platform/nbs
Pull request #3135: [CSI] Enable discard mount option only for YDB-based disks
Author: login: antonmyagkov
Labels: name: blockstore
description: Add this label to run only cloud/blockstore build and tests on PR
Created: 2025-03-04T12:59:52Z | Merged: 2025-03-13T07:59:27Z

https://github.com/ydb-platform/nbs/issues/3129


Diff:
diff --git a/cloud/blockstore/tools/csi_driver/cmd/nbs-csi-driver/main.go b/cloud/blockstore/tools/csi_driver/cmd/nbs-csi-driver/main.go
index 0b852707c7c..87a21f6ba31 100644
--- a/cloud/blockstore/tools/csi_driver/cmd/nbs-csi-driver/main.go
+++ b/cloud/blockstore/tools/csi_driver/cmd/nbs-csi-driver/main.go
@@ -35,6 +35,7 @@ func main() {
 	flag.UintVar(&cfg.NfsLocalEndpointPort, "nfs-local-endpoint-port", 0, "NFS local endpoint port")
 	flag.StringVar(&cfg.NfsLocalEndpointSocket, "nfs-local-endpoint-socket", "", "NFS local endpoint unix socket path")
 	flag.StringVar(&cfg.MountOptions, "mount-options", "grpid", "Comma-separated list of filesystem mount options")
+	flag.BoolVar(&cfg.UseDiscardForYDBBasedDisks, "use-discard-for-ydb-based-disks", false, "Enable discard option for mounted filesystem. Applied only for YDB-based disks.")
 
 	flag.Parse()
 
diff --git a/cloud/blockstore/tools/csi_driver/internal/driver/controller.go b/cloud/blockstore/tools/csi_driver/internal/driver/controller.go
index 547da84ff7a..9aa6e29ceec 100644
--- a/cloud/blockstore/tools/csi_driver/internal/driver/controller.go
+++ b/cloud/blockstore/tools/csi_driver/internal/driver/controller.go
@@ -28,34 +28,6 @@ var nbsServerControllerServiceCapabilities = []*csi.ControllerServiceCapability{
 	},
 }
 
-func getStorageMediaKind(parameters map[string]string) storagecoreapi.EStorageMediaKind {
-	kind, ok := parameters["storage-media-kind"]
-	if ok {
-		switch kind {
-		case "hdd":
-			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_HDD
-		case "hybrid":
-			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_HDD
-		case "ssd":
-			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD
-		case "ssd_nonrepl":
-			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_NONREPLICATED
-		case "ssd_mirror2":
-			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_MIRROR2
-		case "ssd_mirror3":
-			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_MIRROR3
-		case "ssd_local":
-			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_LOCAL
-		case "hdd_local":
-			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_HDD_LOCAL
-		case "hdd_nonrepl":
-			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_HDD_NONREPLICATED
-		}
-	}
-
-	return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 
 type nbsServerControllerService struct {
diff --git a/cloud/blockstore/tools/csi_driver/internal/driver/driver.go b/cloud/blockstore/tools/csi_driver/internal/driver/driver.go
index 69fabd731a0..35f831b0944 100644
--- a/cloud/blockstore/tools/csi_driver/internal/driver/driver.go
+++ b/cloud/blockstore/tools/csi_driver/internal/driver/driver.go
@@ -67,6 +67,7 @@ type Config struct {
 	NfsLocalEndpointPort       uint
 	NfsLocalEndpointSocket     string
 	MountOptions               string
+	UseDiscardForYDBBasedDisks bool
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -256,7 +257,8 @@ func NewDriver(cfg Config) (*Driver, error) {
 			clients.nfsEndpointClient,
 			clients.nfsLocalEndpointClient,
 			mounter.NewMounter(),
-			strings.Split(cfg.MountOptions, ",")))
+			strings.Split(cfg.MountOptions, ","),
+			cfg.UseDiscardForYDBBasedDisks))
 
 	return &Driver{
 		grpcServer: grpcServer,
diff --git a/cloud/blockstore/tools/csi_driver/internal/driver/helper.go b/cloud/blockstore/tools/csi_driver/internal/driver/helper.go
new file mode 100644
index 00000000000..3c192ff1914
--- /dev/null
+++ b/cloud/blockstore/tools/csi_driver/internal/driver/helper.go
@@ -0,0 +1,47 @@
+package driver
+
+import (
+	storagecoreapi "github.com/ydb-platform/nbs/cloud/storage/core/protos"
+)
+
+func getStorageMediaKind(parameters map[string]string) storagecoreapi.EStorageMediaKind {
+	kind, ok := parameters["storage-media-kind"]
+	if ok {
+		switch kind {
+		case "hdd":
+			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_HDD
+		case "hybrid":
+			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_HDD
+		case "ssd":
+			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD
+		case "ssd_nonrepl":
+			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_NONREPLICATED
+		case "ssd_mirror2":
+			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_MIRROR2
+		case "ssd_mirror3":
+			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_MIRROR3
+		case "ssd_local":
+			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_LOCAL
+		case "hdd_local":
+			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_HDD_LOCAL
+		case "hdd_nonrepl":
+			return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_HDD_NONREPLICATED
+		}
+	}
+
+	return storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD
+}
+
+func isDiskRegistryMediaKind(mediaKind storagecoreapi.EStorageMediaKind) bool {
+	switch mediaKind {
+	case storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_NONREPLICATED,
+		storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_MIRROR2,
+		storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_MIRROR3,
+		storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_SSD_LOCAL,
+		storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_HDD_LOCAL,
+		storagecoreapi.EStorageMediaKind_STORAGE_MEDIA_HDD_NONREPLICATED:
+		return true
+	default:
+		return false
+	}
+}
diff --git a/cloud/blockstore/tools/csi_driver/internal/driver/node.go b/cloud/blockstore/tools/csi_driver/internal/driver/node.go
index 38086cfb013..e6584b90e05 100644
--- a/cloud/blockstore/tools/csi_driver/internal/driver/node.go
+++ b/cloud/blockstore/tools/csi_driver/internal/driver/node.go
@@ -124,6 +124,8 @@ type nodeService struct {
 	mounter        mounter.Interface
 	volumeOps      *sync.Map
 	mountOptions   []string
+
+	useDiscardForYDBBasedDisks bool
 }
 
 func newNodeService(
@@ -138,22 +140,24 @@ func newNodeService(
 	nfsClient nfsclient.EndpointClientIface,
 	nfsLocalClient nfsclient.EndpointClientIface,
 	mounter mounter.Interface,
-	mountOptions []string) csi.NodeServer {
+	mountOptions []string,
+	useDiscardForYDBBasedDisks bool) csi.NodeServer {
 
 	return &nodeService{
-		nodeId:              nodeId,
-		clientId:            clientId,
-		vmMode:              vmMode,
-		socketsDir:          socketsDir,
-		nbsClient:           nbsClient,
-		nfsClient:           nfsClient,
-		nfsLocalClient:      nfsLocalClient,
-		mounter:             mounter,
-		targetFsPathRegexp:  regexp.MustCompile(targetFsPathPattern),
-		targetBlkPathRegexp: regexp.MustCompile(targetBlkPathPattern),
-		localFsOverrides:    localFsOverrides,
-		volumeOps:           new(sync.Map),
-		mountOptions:        mountOptions,
+		nodeId:                     nodeId,
+		clientId:                   clientId,
+		vmMode:                     vmMode,
+		socketsDir:                 socketsDir,
+		nbsClient:                  nbsClient,
+		nfsClient:                  nfsClient,
+		nfsLocalClient:             nfsLocalClient,
+		mounter:                    mounter,
+		targetFsPathRegexp:         regexp.MustCompile(targetFsPathPattern),
+		targetBlkPathRegexp:        regexp.MustCompile(targetBlkPathPattern),
+		localFsOverrides:           localFsOverrides,
+		volumeOps:                  new(sync.Map),
+		mountOptions:               mountOptions,
+		useDiscardForYDBBasedDisks: useDiscardForYDBBasedDisks,
 	}
 }
 
@@ -740,6 +744,10 @@ func (s *nodeService) nodeStageDiskAsFilesystem(
 		mountOptions = append(mountOptions, "errors=remount-ro")
 	}
 
+	if s.useDiscardForYDBBasedDisks && !isDiskRegistryMediaKind(getStorageMediaKind(req.VolumeContext)) {
+		mountOptions = append(mountOptions, "discard")
+	}
+
 	if mnt != nil {
 		for _, flag := range mnt.MountFlags {
 			mountOptions = append(mountOptions, flag)
diff --git a/cloud/blockstore/tools/csi_driver/internal/driver/node_test.go b/cloud/blockstore/tools/csi_driver/internal/driver/node_test.go
index 6eb298a2c70..30a4c323fc3 100644
--- a/cloud/blockstore/tools/csi_driver/internal/driver/node_test.go
+++ b/cloud/blockstore/tools/csi_driver/internal/driver/node_test.go
@@ -75,6 +75,7 @@ func doTestPublishUnpublishVolumeForKubevirt(t *testing.T, backend string, devic
 		nfsLocalClient,
 		mounter,
 		[]string{},
+		false,
 	)
 
 	accessMode := csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER
@@ -268,6 +269,7 @@ func doTestStagedPublishUnpublishVolumeForKubevirt(t *testing.T, backend string,
 		nfsLocalClient,
 		mounter,
 		[]string{},
+		false,
 	)
 
 	accessMode := csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER
@@ -491,7 +493,8 @@ func TestPublishUnpublishDiskForInfrakuber(t *testing.T) {
 		nil,
 		nil, // nfsLocalClient
 		mounter,
-		[]string{"grpid", "discard"},
+		[]string{"grpid"},
+		true,
 	)
 
 	volumeCapability := csi.VolumeCapability{
@@ -534,7 +537,7 @@ func TestPublishUnpublishDiskForInfrakuber(t *testing.T) {
 	mockCallIsMountPoint := mounter.On("IsMountPoint", stagingTargetPath).Return(false, nil)
 
 	mounter.On("FormatAndMount", nbdDeviceFile, stagingTargetPath, "ext4",
-		[]string{"grpid", "discard", "errors=remount-ro"}).Return(nil)
+		[]string{"grpid", "errors=remount-ro", "discard"}).Return(nil)
 
 	_, err = nodeService.NodeStageVolume(ctx, &csi.NodeStageVolumeRequest{
 		VolumeId:          diskId,
@@ -648,6 +651,7 @@ func TestPublishUnpublishDeviceForInfrakuber(t *testing.T) {
 		nil, // nfsLocalClient
 		mounter,
 		[]string{},
+		false,
 	)
 
 	volumeCapability := csi.VolumeCapability{
@@ -802,6 +806,7 @@ func TestGetVolumeStatCapabilitiesWithoutVmMode(t *testing.T) {
 		nil, // nfsLocalClient
 		mounter,
 		[]string{},
+		false,
 	)
 
 	ctx := context.Background()
@@ -869,6 +874,7 @@ func TestGetVolumeStatCapabilitiesWithVmMode(t *testing.T) {
 		nil, // nfsLocalClient
 		mounter,
 		[]string{},
+		false,
 	)
 
 	ctx := context.Background()
@@ -926,6 +932,7 @@ func TestPublishDeviceWithReadWriteManyModeIsNotSupportedWithNBS(t *testing.T) {
 		nil, // nfsLocalClient
 		mounter,
 		[]string{},
+		false,
 	)
 
 	_, err := nodeService.NodeStageVolume(ctx, &csi.NodeStageVolumeRequest{
@@ -1007,6 +1014,7 @@ func TestGrpcTimeoutForIKubevirt(t *testing.T) {
 		nfsLocalClient,
 		mounter,
 		[]string{},
+		false,
 	)
 
 	accessMode := csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER
@@ -1094,6 +1102,7 @@ func TestGrpcTimeoutForInfrakuber(t *testing.T) {
 		nil,
 		mounter,
 		[]string{},
+		false,
 	)
 
 	volumeCapability := csi.VolumeCapability{
diff --git a/cloud/blockstore/tools/csi_driver/internal/driver/ya.make b/cloud/blockstore/tools/csi_driver/internal/driver/ya.make
index fc4279c7efc..fe0b8b4df32 100644
--- a/cloud/blockstore/tools/csi_driver/internal/driver/ya.make
+++ b/cloud/blockstore/tools/csi_driver/internal/driver/ya.make
@@ -5,6 +5,7 @@ SRCS(
     driver.go
     identity.go
     node.go
+    helper.go
 )
 
 GO_TEST_SRCS(


Reviews:
user: login: SvartMetal
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-11T19:43:33Z
user: login: SvartMetal
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-11T19:44:18Z
user: login: antonmyagkov
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-11T20:39:28Z
user: login: antonmyagkov
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-11T20:39:33Z
user: login: SvartMetal
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-11T21:31:07Z
user: login: drbasic
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-13T07:57:08Z

Review comments:
diff_hunk: @@ -67,6 +67,7 @@ type Config struct {
 	NfsLocalEndpointPort       uint
 	NfsLocalEndpointSocket     string
 	MountOptions               string
+	Discard                    bool
path: cloud/blockstore/tools/csi_driver/internal/driver/driver.go
user: login: SvartMetal
body: UseDiscardForYDBBasedDisks
created_at: 2025-03-11T19:43:33Z
author_association: COLLABORATOR
diff_hunk: @@ -124,6 +124,7 @@ type nodeService struct {
 	mounter        mounter.Interface
 	volumeOps      *sync.Map
 	mountOptions   []string
+	discard        bool
path: cloud/blockstore/tools/csi_driver/internal/driver/node.go
user: login: SvartMetal
body: useDiscardForYDBBasedDisks
created_at: 2025-03-11T19:44:17Z
author_association: COLLABORATOR
diff_hunk: @@ -67,6 +67,7 @@ type Config struct {
 	NfsLocalEndpointPort       uint
 	NfsLocalEndpointSocket     string
 	MountOptions               string
+	Discard                    bool
path: cloud/blockstore/tools/csi_driver/internal/driver/driver.go
user: login: antonmyagkov
body: fixed
created_at: 2025-03-11T20:39:28Z
author_association: COLLABORATOR
diff_hunk: @@ -124,6 +124,7 @@ type nodeService struct {
 	mounter        mounter.Interface
 	volumeOps      *sync.Map
 	mountOptions   []string
+	discard        bool
path: cloud/blockstore/tools/csi_driver/internal/driver/node.go
user: login: antonmyagkov
body: fixed
created_at: 2025-03-11T20:39:33Z
author_association: COLLABORATOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-04T14:19:01Z
body: <!-- status pr=3135, run=9656, build_preset=linux-x86_64-relwithdebinfo, dry_run=False -->
> [!NOTE]
> This is an automated comment that will be appended during run.

:green_circle: **linux-x86_64-relwithdebinfo**: all tests PASSED for commit 6ac5db5db64c89b17419469c85e5e8157530c471.
| TESTS | PASSED | ERRORS | FAILED | SKIPPED | MUTED<sup>[?](https://github.com/ydb-platform/nbs/tree/main/.github/config "All mute rules are defined here")</sup> |
| ---: | ---: | ---: | ---: | ---: | ---: |
| [6479](https://github-actions-s3.storage.eu-north1.nebius.cloud/ydb-platform/nbs/PR-check/13654309742/1/nebius-x86-64/summary/ya-test.html) | [6479](https://github-actions-s3.storage.eu-north1.nebius.cloud/ydb-platform/nbs/PR-check/13654309742/1/nebius-x86-64/summary/ya-test.html#PASS) | 0 | 0 | 0 | 0 |
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-10T21:48:21Z
body: <!-- status pr=3135, run=9815, build_preset=linux-x86_64-relwithdebinfo, dry_run=False -->
> [!NOTE]
> This is an automated comment that will be appended during run.

:green_circle: **linux-x86_64-relwithdebinfo**: all tests PASSED for commit 8699c9f13280964b159b81528dad4b490d1f26c1.
| TESTS | PASSED | ERRORS | FAILED | SKIPPED | MUTED<sup>[?](https://github.com/ydb-platform/nbs/tree/main/.github/config "All mute rules are defined here")</sup> |
| ---: | ---: | ---: | ---: | ---: | ---: |
| [3676](https://github-actions-s3.storage.eu-north1.nebius.cloud/ydb-platform/nbs/PR-check/13774995759/1/nebius-x86-64/summary/ya-test.html) | [3676](https://github-actions-s3.storage.eu-north1.nebius.cloud/ydb-platform/nbs/PR-check/13774995759/1/nebius-x86-64/summary/ya-test.html#PASS) | 0 | 0 | 0 | 0 |
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-11T21:06:20Z
body: <!-- status pr=3135, run=9840, build_preset=linux-x86_64-relwithdebinfo, dry_run=False -->
> [!NOTE]
> This is an automated comment that will be appended during run.

:green_circle: **linux-x86_64-relwithdebinfo**: all tests PASSED for commit 6060fa6b6c7a9bf61c617989871a01303f015a7a.
| TESTS | PASSED | ERRORS | FAILED | SKIPPED | MUTED<sup>[?](https://github.com/ydb-platform/nbs/tree/main/.github/config "All mute rules are defined here")</sup> |
| ---: | ---: | ---: | ---: | ---: | ---: |
| [3676](https://github-actions-s3.storage.eu-north1.nebius.cloud/ydb-platform/nbs/PR-check/13797730299/1/nebius-x86-64/summary/ya-test.html) | [3676](https://github-actions-s3.storage.eu-north1.nebius.cloud/ydb-platform/nbs/PR-check/13797730299/1/nebius-x86-64/summary/ya-test.html#PASS) | 0 | 0 | 0 | 0 |
author_association: CONTRIBUTOR