Repository: kubernetes-csi/csi-driver-smb
Pull request #498 (2022-06-11 11:39:50)

feat: create subdir if not exists
<!--  Thanks for sending a pull request!  Here are some tips for you:

1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. For reference on required PR/issue labels, read here:
https://git.k8s.io/community/contributors/devel/release.md#issue-kind-label
3. Ensure you have added or ran the appropriate tests for your PR: https://git.k8s.io/community/contributors/devel/testing.md
4. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
5. Follow the instructions for writing a release note: https://git.k8s.io/community/contributors/guide/release-notes.md
6. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->

**What type of PR is this?**
/kind feature

**What this PR does / why we need it**:
feat: create subdir if not exists
In original behavior, `subDir` must exist if it's provided in storage class, this PR would create subdir if not exists

**Which issue(s) this PR fixes**:
<!-- 
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #

**Requirements**:
- [ ] uses [conventional commit messages](https://www.conventionalcommits.org/)
  <!-- Common commit types:
        build: Build 🏭
        chore: Maintenance 🔧
        ci: Continuous Integration 💜
        docs: Documentation 📘
        feat: Features 🌈
        fix: Bug Fixes 🐞
        perf: Performance Improvements 🚀
        refactor: Code Refactoring 💎
        revert: Revert Change ◀️
        style: Code Style 🎶
        security: Security Fix 🛡️
        test: Testing 💚 -->
- [ ] includes documentation
- [ ] adds unit tests
- [ ] tested upgrade from previous version

**Special notes for your reviewer**:


**Release note**:
```
feat: create subdir if not exists
```


k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-csi/csi-driver-smb/pull/498#" title="Author self-approved">andyzhangx</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-csi%2Fcsi-driver-smb).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-csi/csi-driver-smb/blob/master/OWNERS)~~ [andyzhangx]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
coveralls: ## Pull Request Test Coverage Report for [Build 2479821440](https://coveralls.io/builds/49942277)

* **5** of **7**   **(71.43%)**  changed or added relevant lines in **1** file are covered.
* **1** unchanged line in **1** file lost coverage.
* Overall coverage remained the same at **84.498%**

---

|  Changes Missing Coverage | Covered Lines | Changed/Added Lines | % |
| :-----|--------------|--------|---: |
| [pkg/smb/controllerserver.go](https://coveralls.io/builds/49942277/source?filename=pkg%2Fsmb%2Fcontrollerserver.go#L84) | 5 | 7 | 71.43%
<!-- | **Total:** | **5** | **7** | **71.43%** | -->

|  Files with Coverage Reduction | New Missed Lines | % |
| :-----|--------------|--: |
| [pkg/smb/controllerserver.go](https://coveralls.io/builds/49942277/source?filename=pkg%2Fsmb%2Fcontrollerserver.go#L86) | 1 | 80.56% |
<!-- | **Total:** | **1** |  | -->

|  Totals | [![Coverage Status](https://coveralls.io/builds/49942277/badge)](https://coveralls.io/builds/49942277) |
| :-- | --: |
| Change from base [Build 2439455779](https://coveralls.io/builds/49733224): |  0.0% |
| Covered Lines: | 774 |
| Relevant Lines: | 916 |

---
##### 💛  - [Coveralls](https://coveralls.io)

k8s-ci-robot: @andyzhangx: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-csi-driver-smb-e2e-vmss | 12e1a8ceb41a3ec8a7869aab71094f5569c37129 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-vmss/1535589659072008192) | true | `/test pull-csi-driver-smb-e2e-vmss`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-smb&pr=498). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Aandyzhangx). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-smb/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
andyzhangx: /retest
andyzhangx: /test pull-csi-driver-smb-e2e-capz
/test pull-csi-driver-smb-e2e-capz-windows-2019
k8s-ci-robot: @andyzhangx: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-csi-driver-smb-e2e-capz | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz/1535606921170522112) | false | `/test pull-csi-driver-smb-e2e-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-smb&pr=498). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Aandyzhangx). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-smb/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @andyzhangx: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-csi-driver-smb-e2e-capz | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz/1535606921170522112) | false | `/test pull-csi-driver-smb-e2e-capz`
pull-csi-driver-smb-e2e-capz-windows-2019 | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz-windows-2019/1535606921212465152) | false | `/test pull-csi-driver-smb-e2e-capz-windows-2019`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-smb&pr=498). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Aandyzhangx). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-smb/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @andyzhangx: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-csi-driver-smb-e2e-capz | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz/1535606921170522112) | false | `/test pull-csi-driver-smb-e2e-capz`
pull-csi-driver-smb-e2e-capz-windows-2019 | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz-windows-2019/1535606921212465152) | false | `/test pull-csi-driver-smb-e2e-capz-windows-2019`
pull-csi-driver-smb-external-e2e | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-external-e2e/1535606726454153216) | true | `/test pull-csi-driver-smb-external-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-smb&pr=498). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Aandyzhangx). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-smb/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
andyzhangx: /test pull-csi-driver-smb-external-e2e
k8s-ci-robot: @andyzhangx: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-csi-driver-smb-e2e-capz | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz/1535606921170522112) | false | `/test pull-csi-driver-smb-e2e-capz`
pull-csi-driver-smb-e2e-capz-windows-2019 | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz-windows-2019/1535606921212465152) | false | `/test pull-csi-driver-smb-e2e-capz-windows-2019`
pull-csi-driver-smb-e2e-windows | 72ec802608aab9e59c738b3707e3693f46619aeb | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-windows/1535806929010429952) | true | `/test pull-csi-driver-smb-e2e-windows`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-smb&pr=498). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Aandyzhangx). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-smb/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
andyzhangx: /retest
k8s-ci-robot: @andyzhangx: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-csi-driver-smb-e2e-capz | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz/1535606921170522112) | false | `/test pull-csi-driver-smb-e2e-capz`
pull-csi-driver-smb-e2e-capz-windows-2019 | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz-windows-2019/1535606921212465152) | false | `/test pull-csi-driver-smb-e2e-capz-windows-2019`
pull-csi-driver-smb-e2e | 295e50ac33dfd8948fdece7545250f529c08b40c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e/1535948171597844480) | true | `/test pull-csi-driver-smb-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-smb&pr=498). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Aandyzhangx). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-smb/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
andyzhangx: /retest
k8s-ci-robot: @andyzhangx: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-csi-driver-smb-e2e-capz | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz/1535606921170522112) | false | `/test pull-csi-driver-smb-e2e-capz`
pull-csi-driver-smb-e2e-capz-windows-2019 | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz-windows-2019/1535606921212465152) | false | `/test pull-csi-driver-smb-e2e-capz-windows-2019`
pull-csi-driver-smb-e2e-windows-containerd | 18b9ab88cf9d6b3c7b723def1d64fda2c6a25c7a | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-windows-containerd/1535962826844147712) | true | `/test pull-csi-driver-smb-e2e-windows-containerd`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-smb&pr=498). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Aandyzhangx). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-smb/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @andyzhangx: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-csi-driver-smb-e2e-capz | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz/1535606921170522112) | false | `/test pull-csi-driver-smb-e2e-capz`
pull-csi-driver-smb-e2e-capz-windows-2019 | aa4b45b211398ee630370c0e7a8c9367780bef12 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-capz-windows-2019/1535606921212465152) | false | `/test pull-csi-driver-smb-e2e-capz-windows-2019`
pull-csi-driver-smb-e2e-windows-containerd | 18b9ab88cf9d6b3c7b723def1d64fda2c6a25c7a | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-windows-containerd/1535962826844147712) | true | `/test pull-csi-driver-smb-e2e-windows-containerd`
pull-csi-driver-smb-e2e-windows | 18b9ab88cf9d6b3c7b723def1d64fda2c6a25c7a | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-smb/498/pull-csi-driver-smb-e2e-windows/1535962826798010368) | true | `/test pull-csi-driver-smb-e2e-windows`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-smb&pr=498). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Aandyzhangx). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-smb/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->

Patch:
diff --git a/docs/driver-parameters.md b/docs/driver-parameters.md
index 967effdc9..d5caa47eb 100644
--- a/docs/driver-parameters.md
+++ b/docs/driver-parameters.md
@@ -6,7 +6,7 @@
 Name | Meaning | Available Value | Mandatory | Default value
 --- | --- | --- | --- | ---
 source | Samba Server address | `//smb-server-address/sharename` </br>([Azure File](https://docs.microsoft.com/en-us/azure/storage/files/storage-files-introduction) format: `//accountname.file.core.windows.net/filesharename`) | Yes |
-subDir | existing sub directory under smb share |  | No | sub directory must exist otherwise mount would fail
+subDir | sub directory under smb share |  | No | if sub directory does not exist, this driver would create a new one
 csi.storage.k8s.io/provisioner-secret-name | secret name that stores `username`, `password`(`domain` is optional); if secret is provided, driver will create a sub directory with PV name under `source` | existing secret name |  No  |
 csi.storage.k8s.io/provisioner-secret-namespace | namespace where the secret is | existing secret namespace |  No  |
 csi.storage.k8s.io/node-stage-secret-name | secret name that stores `username`, `password`(`domain` is optional) | existing secret name |  Yes  |
diff --git a/pkg/smb/controllerserver.go b/pkg/smb/controllerserver.go
index 3421b0cdc..11b0f734e 100644
--- a/pkg/smb/controllerserver.go
+++ b/pkg/smb/controllerserver.go
@@ -39,7 +39,7 @@ type smbVolume struct {
 	// Volume id
 	id string
 	// Address of the SMB server.
-	sourceField string
+	source string
 	// Subdirectory of the SMB server to create volumes under
 	subDir string
 	// size of volume
@@ -51,7 +51,7 @@ type smbVolume struct {
 // Ordering of elements in the CSI volume id.
 // ID is of the form {server}/{subDir}.
 const (
-	idsourceField = iota
+	idSource = iota
 	idSubDir
 	idUUID
 	totalIDElements // Always last
@@ -81,8 +81,8 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
 	secrets := req.GetSecrets()
 	createSubDir := len(secrets) > 0
 	if len(smbVol.uuid) > 0 {
-		klog.V(2).Infof("existing subDir(%s) is provided, skip subdirectory creation", smbVol.subDir)
-		createSubDir = false
+		klog.V(2).Infof("create subdirectory(%s) if not exists", smbVol.subDir)
+		createSubDir = true
 	}
 
 	volCap := volumeCapabilities[0]
@@ -106,11 +106,11 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
 		}()
 		// Create subdirectory under base-dir
 		// TODO: revisit permissions
-		internalVolumePath := d.getInternalVolumePath(smbVol)
+		internalVolumePath := getInternalVolumePath(d.workingMountDir, smbVol)
 		if err = os.Mkdir(internalVolumePath, 0777); err != nil && !os.IsExist(err) {
 			return nil, status.Errorf(codes.Internal, "failed to make subdirectory: %v", err.Error())
 		}
-		parameters[subDirField] = smbVol.subDir
+		setKeyValueInMap(parameters, subDirField, smbVol.subDir)
 	} else {
 		klog.V(2).Infof("CreateVolume(%s) does not create subdirectory", name)
 	}
@@ -145,10 +145,6 @@ func (d *Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest)
 
 	secrets := req.GetSecrets()
 	deleteSubDir := len(secrets) > 0
-	if len(smbVol.uuid) > 0 {
-		klog.V(2).Infof("existing subDir(%s) is provided, skip subdirectory deletion", smbVol.subDir)
-		deleteSubDir = false
-	}
 	if !deleteSubDir {
 		options := strings.Split(mountOptions, ",")
 		if hasGuestMountOptions(options) {
@@ -169,7 +165,7 @@ func (d *Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest)
 		}()
 
 		// Delete subdirectory under base-dir
-		internalVolumePath := d.getInternalVolumePath(smbVol)
+		internalVolumePath := getInternalVolumePath(d.workingMountDir, smbVol)
 		klog.V(2).Infof("Removing subdirectory at %v", internalVolumePath)
 		if err = os.RemoveAll(internalVolumePath); err != nil {
 			return nil, status.Errorf(codes.Internal, "failed to delete subdirectory: %v", err.Error())
@@ -244,23 +240,9 @@ func (d *Driver) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsReques
 	return nil, status.Error(codes.Unimplemented, "")
 }
 
-// Given a smbVolume, return a CSI volume id
-func getVolumeIDFromSmbVol(vol *smbVolume) string {
-	idElements := make([]string, totalIDElements)
-	idElements[idsourceField] = strings.Trim(vol.sourceField, "/")
-	idElements[idSubDir] = strings.Trim(vol.subDir, "/")
-	idElements[idUUID] = vol.uuid
-	return strings.Join(idElements, separator)
-}
-
-// Get working directory for CreateVolume and DeleteVolume
-func (d *Driver) getInternalMountPath(vol *smbVolume) string {
-	return filepath.Join(d.workingMountDir, vol.subDir)
-}
-
 // Mount smb server at base-dir
 func (d *Driver) internalMount(ctx context.Context, vol *smbVolume, volCap *csi.VolumeCapability, secrets map[string]string) error {
-	stagingPath := d.getInternalMountPath(vol)
+	stagingPath := getInternalMountPath(d.workingMountDir, vol)
 
 	if volCap == nil {
 		volCap = &csi.VolumeCapability{
@@ -270,11 +252,11 @@ func (d *Driver) internalMount(ctx context.Context, vol *smbVolume, volCap *csi.
 		}
 	}
 
-	klog.V(4).Infof("internally mounting %v at %v", sourceField, stagingPath)
+	klog.V(4).Infof("internally mounting %v at %v", vol.source, stagingPath)
 	_, err := d.NodeStageVolume(ctx, &csi.NodeStageVolumeRequest{
 		StagingTargetPath: stagingPath,
 		VolumeContext: map[string]string{
-			sourceField: vol.sourceField,
+			sourceField: vol.source,
 		},
 		VolumeCapability: volCap,
 		VolumeId:         vol.id,
@@ -285,17 +267,38 @@ func (d *Driver) internalMount(ctx context.Context, vol *smbVolume, volCap *csi.
 
 // Unmount smb server at base-dir
 func (d *Driver) internalUnmount(ctx context.Context, vol *smbVolume) error {
-	targetPath := d.getInternalMountPath(vol)
+	targetPath := getInternalMountPath(d.workingMountDir, vol)
 
 	// Unmount smb server at base-dir
 	klog.V(4).Infof("internally unmounting %v", targetPath)
 	_, err := d.NodeUnstageVolume(ctx, &csi.NodeUnstageVolumeRequest{
 		VolumeId:          vol.id,
-		StagingTargetPath: d.getInternalMountPath(vol),
+		StagingTargetPath: targetPath,
 	})
 	return err
 }
 
+// Given a smbVolume, return a CSI volume id
+func getVolumeIDFromSmbVol(vol *smbVolume) string {
+	idElements := make([]string, totalIDElements)
+	idElements[idSource] = strings.Trim(vol.source, "/")
+	idElements[idSubDir] = strings.Trim(vol.subDir, "/")
+	idElements[idUUID] = vol.uuid
+	return strings.Join(idElements, separator)
+}
+
+// getInternalMountPath: get working directory for CreateVolume and DeleteVolume
+func getInternalMountPath(workingMountDir string, vol *smbVolume) string {
+	if vol == nil {
+		return ""
+	}
+	mountDir := vol.uuid
+	if vol.uuid == "" {
+		mountDir = vol.subDir
+	}
+	return filepath.Join(workingMountDir, mountDir)
+}
+
 // Convert VolumeCreate parameters to an smbVolume
 func newSMBVolume(name string, size int64, params map[string]string) (*smbVolume, error) {
 	var source, subDir string
@@ -317,8 +320,8 @@ func newSMBVolume(name string, size int64, params map[string]string) (*smbVolume
 	}
 
 	vol := &smbVolume{
-		sourceField: source,
-		size:        size,
+		source: source,
+		size:   size,
 	}
 	if subDir == "" {
 		// use pv name by default if not specified
@@ -339,8 +342,8 @@ func newSMBVolume(name string, size int64, params map[string]string) (*smbVolume
 //     CreateVolume calls in parallel and they may use the same underlying share.
 //     Instead of refcounting how many CreateVolume calls are using the same
 //     share, it's simpler to just do a mount per request.
-func (d *Driver) getInternalVolumePath(vol *smbVolume) string {
-	return filepath.Join(d.getInternalMountPath(vol), vol.subDir)
+func getInternalVolumePath(workingMountDir string, vol *smbVolume) string {
+	return filepath.Join(getInternalMountPath(workingMountDir, vol), vol.subDir)
 }
 
 // Convert into smbVolume into a csi.Volume
@@ -359,13 +362,16 @@ func (d *Driver) smbVolToCSI(vol *smbVolume, parameters map[string]string) *csi.
 func getSmbVolFromID(id string) (*smbVolume, error) {
 	segments := strings.Split(id, separator)
 	if len(segments) < 2 {
-		return nil, fmt.Errorf("Could not split %q into server and subDir", id)
+		return nil, fmt.Errorf("could not split %q into server and subDir", id)
+	}
+	source := segments[0]
+	if !strings.HasPrefix(segments[0], "//") {
+		source = "//" + source
 	}
-	source := "//" + segments[0]
 	vol := &smbVolume{
-		id:          id,
-		sourceField: source,
-		subDir:      segments[1],
+		id:     id,
+		source: source,
+		subDir: segments[1],
 	}
 	if len(segments) >= 3 {
 		vol.uuid = segments[2]
diff --git a/pkg/smb/smb.go b/pkg/smb/smb.go
index 602c3d095..6a5f68f3f 100644
--- a/pkg/smb/smb.go
+++ b/pkg/smb/smb.go
@@ -141,3 +141,18 @@ func hasGuestMountOptions(options []string) bool {
 	}
 	return false
 }
+
+// setKeyValueInMap set key/value pair in map
+// key in the map is case insensitive, if key already exists, overwrite existing value
+func setKeyValueInMap(m map[string]string, key, value string) {
+	if m == nil {
+		return
+	}
+	for k := range m {
+		if strings.EqualFold(k, key) {
+			m[k] = value
+			return
+		}
+	}
+	m[key] = value
+}


Test patch:
diff --git a/pkg/smb/controllerserver_test.go b/pkg/smb/controllerserver_test.go
index 7262b978a..683747dec 100644
--- a/pkg/smb/controllerserver_test.go
+++ b/pkg/smb/controllerserver_test.go
@@ -457,6 +457,13 @@ func TestGetSmbVolFromID(t *testing.T) {
 			subDir:    "pvc-4729891a-f57e-4982-9c60-e9884af1be2f",
 			expectErr: false,
 		},
+		{
+			desc:      "correct volume id with //",
+			volumeID:  "//smb-server.default.svc.cluster.local/share#pvc-4729891a-f57e-4982-9c60-e9884af1be2f",
+			source:    "//smb-server.default.svc.cluster.local/share",
+			subDir:    "pvc-4729891a-f57e-4982-9c60-e9884af1be2f",
+			expectErr: false,
+		},
 		{
 			desc:      "correct volume id with empty uuid",
 			volumeID:  "smb-server.default.svc.cluster.local/share#pvc-4729891a-f57e-4982-9c60-e9884af1be2f#",
@@ -493,7 +500,7 @@ func TestGetSmbVolFromID(t *testing.T) {
 			smbVolume, err := getSmbVolFromID(test.volumeID)
 
 			if !test.expectErr {
-				assert.Equal(t, smbVolume.sourceField, test.source)
+				assert.Equal(t, smbVolume.source, test.source)
 				assert.Equal(t, smbVolume.subDir, test.subDir)
 				assert.Equal(t, smbVolume.uuid, test.uuid)
 				assert.Nil(t, err)
@@ -513,24 +520,24 @@ func TestGetVolumeIDFromSmbVol(t *testing.T) {
 		{
 			desc: "volume without uuid",
 			vol: &smbVolume{
-				sourceField: "//smb-server.default.svc.cluster.local/share",
-				subDir:      "subdir",
+				source: "//smb-server.default.svc.cluster.local/share",
+				subDir: "subdir",
 			},
 			result: "smb-server.default.svc.cluster.local/share#subdir#",
 		},
 		{
 			desc: "volume with uuid",
 			vol: &smbVolume{
-				sourceField: "//smb-server.default.svc.cluster.local/share",
-				subDir:      "subdir",
-				uuid:        "uuid",
+				source: "//smb-server.default.svc.cluster.local/share",
+				subDir: "subdir",
+				uuid:   "uuid",
 			},
 			result: "smb-server.default.svc.cluster.local/share#subdir#uuid",
 		},
 		{
 			desc: "volume without subdir",
 			vol: &smbVolume{
-				sourceField: "//smb-server.default.svc.cluster.local/share",
+				source: "//smb-server.default.svc.cluster.local/share",
 			},
 			result: "smb-server.default.svc.cluster.local/share##",
 		},
@@ -542,6 +549,44 @@ func TestGetVolumeIDFromSmbVol(t *testing.T) {
 	}
 }
 
+func TestGetInternalMountPath(t *testing.T) {
+	cases := []struct {
+		desc            string
+		workingMountDir string
+		vol             *smbVolume
+		result          string
+	}{
+		{
+			desc:            "nil volume",
+			workingMountDir: "/tmp",
+			result:          "",
+		},
+		{
+			desc:            "uuid not empty",
+			workingMountDir: "/tmp",
+			vol: &smbVolume{
+				subDir: "subdir",
+				uuid:   "uuid",
+			},
+			result: filepath.Join("/tmp", "uuid"),
+		},
+		{
+			desc:            "uuid empty",
+			workingMountDir: "/tmp",
+			vol: &smbVolume{
+				subDir: "subdir",
+				uuid:   "",
+			},
+			result: filepath.Join("/tmp", "subdir"),
+		},
+	}
+
+	for _, test := range cases {
+		path := getInternalMountPath(test.workingMountDir, test.vol)
+		assert.Equal(t, path, test.result)
+	}
+}
+
 func TestNewSMBVolume(t *testing.T) {
 	cases := []struct {
 		desc      string
@@ -560,11 +605,11 @@ func TestNewSMBVolume(t *testing.T) {
 				"subDir": "subdir",
 			},
 			expectVol: &smbVolume{
-				id:          "smb-server.default.svc.cluster.local/share#subdir#pv-name",
-				sourceField: "//smb-server.default.svc.cluster.local/share",
-				subDir:      "subdir",
-				size:        100,
-				uuid:        "pv-name",
+				id:     "smb-server.default.svc.cluster.local/share#subdir#pv-name",
+				source: "//smb-server.default.svc.cluster.local/share",
+				subDir: "subdir",
+				size:   100,
+				uuid:   "pv-name",
 			},
 		},
 		{
@@ -575,11 +620,11 @@ func TestNewSMBVolume(t *testing.T) {
 				"source": "//smb-server.default.svc.cluster.local/share",
 			},
 			expectVol: &smbVolume{
-				id:          "smb-server.default.svc.cluster.local/share#pv-name#",
-				sourceField: "//smb-server.default.svc.cluster.local/share",
-				subDir:      "pv-name",
-				size:        200,
-				uuid:        "",
+				id:     "smb-server.default.svc.cluster.local/share#pv-name#",
+				source: "//smb-server.default.svc.cluster.local/share",
+				subDir: "pv-name",
+				size:   200,
+				uuid:   "",
 			},
 		},
 		{
diff --git a/pkg/smb/smb_test.go b/pkg/smb/smb_test.go
index b6a05fdfd..e3d97a7c9 100644
--- a/pkg/smb/smb_test.go
+++ b/pkg/smb/smb_test.go
@@ -20,6 +20,7 @@ import (
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"reflect"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -175,3 +176,57 @@ func TestHasGuestMountOptions(t *testing.T) {
 		}
 	}
 }
+
+func TestSetKeyValueInMap(t *testing.T) {
+	tests := []struct {
+		desc     string
+		m        map[string]string
+		key      string
+		value    string
+		expected map[string]string
+	}{
+		{
+			desc:  "nil map",
+			key:   "key",
+			value: "value",
+		},
+		{
+			desc:     "empty map",
+			m:        map[string]string{},
+			key:      "key",
+			value:    "value",
+			expected: map[string]string{"key": "value"},
+		},
+		{
+			desc:  "non-empty map",
+			m:     map[string]string{"k": "v"},
+			key:   "key",
+			value: "value",
+			expected: map[string]string{
+				"k":   "v",
+				"key": "value",
+			},
+		},
+		{
+			desc:     "same key already exists",
+			m:        map[string]string{"subDir": "value2"},
+			key:      "subDir",
+			value:    "value",
+			expected: map[string]string{"subDir": "value"},
+		},
+		{
+			desc:     "case insentive key already exists",
+			m:        map[string]string{"subDir": "value2"},
+			key:      "subdir",
+			value:    "value",
+			expected: map[string]string{"subDir": "value"},
+		},
+	}
+
+	for _, test := range tests {
+		setKeyValueInMap(test.m, test.key, test.value)
+		if !reflect.DeepEqual(test.m, test.expected) {
+			t.Errorf("test[%s]: unexpected output: %v, expected result: %v", test.desc, test.m, test.expected)
+		}
+	}
+}
diff --git a/test/e2e/dynamic_provisioning_test.go b/test/e2e/dynamic_provisioning_test.go
index 99e3cdc06..9aee901bf 100644
--- a/test/e2e/dynamic_provisioning_test.go
+++ b/test/e2e/dynamic_provisioning_test.go
@@ -167,44 +167,6 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
 		test.Run(cs, ns)
 	})
 
-	ginkgo.It("[createSubDir] should create multiple PV objects, bind to PVCs and attach all to different pods on the same node [smb.csi.k8s.io] [Windows]", func() {
-		pods := []testsuites.PodDetails{
-			{
-				Cmd: convertToPowershellCommandIfNecessary("while true; do echo $(date -u) >> /mnt/test-1/data; sleep 100; done"),
-				Volumes: []testsuites.VolumeDetails{
-					{
-						ClaimSize: "10Gi",
-						VolumeMount: testsuites.VolumeMountDetails{
-							NameGenerate:      "test-volume-",
-							MountPathGenerate: "/mnt/test-",
-						},
-					},
-				},
-				IsWindows: isWindowsCluster,
-			},
-			{
-				Cmd: convertToPowershellCommandIfNecessary("while true; do echo $(date -u) >> /mnt/test-1/data; sleep 100; done"),
-				Volumes: []testsuites.VolumeDetails{
-					{
-						ClaimSize: "10Gi",
-						VolumeMount: testsuites.VolumeMountDetails{
-							NameGenerate:      "test-volume-",
-							MountPathGenerate: "/mnt/test-",
-						},
-					},
-				},
-				IsWindows: isWindowsCluster,
-			},
-		}
-		test := testsuites.DynamicallyProvisionedCollocatedPodTest{
-			CSIDriver:              testDriver,
-			Pods:                   pods,
-			ColocatePods:           true,
-			StorageClassParameters: defaultStorageClassParameters,
-		}
-		test.Run(cs, ns)
-	})
-
 	// Track issue https://github.com/kubernetes/kubernetes/issues/70505
 	ginkgo.It("should create a volume on demand and mount it as readOnly in a pod [smb.csi.k8s.io]", func() {
 		// Windows volume does not support readOnly
diff --git a/test/e2e/suite_test.go b/test/e2e/suite_test.go
index 10f5a9aed..c48f509c2 100644
--- a/test/e2e/suite_test.go
+++ b/test/e2e/suite_test.go
@@ -55,8 +55,8 @@ var (
 		"csi.storage.k8s.io/node-stage-secret-namespace":  "default",
 	}
 	subDirStorageClassParameters = map[string]string{
-		"source": "//smb-server.default.svc.cluster.local/",
-		"subDir": "share",
+		"source": "//smb-server.default.svc.cluster.local/share",
+		"subDir": "subDirectory",
 		"csi.storage.k8s.io/provisioner-secret-name":      "smbcreds",
 		"csi.storage.k8s.io/provisioner-secret-namespace": "default",
 		"csi.storage.k8s.io/node-stage-secret-name":       "smbcreds",