Change:
<!-- This form is for bug reports and feature requests ONLY! If you're looking for help check and the . If the matter is security related, please disclose it privately via --Is this a BUG REPORT or FEATURE REQUEST?: /kind bug /sig windows What happened: After creating pods having PersistentVolumeClaims and deleting them, the logs are getting filled with errors regarding failing to unmount the volume [1]. Additionally, tests requiring PVCs will hang several minutes while waiting the PV to unmount [2]. [1] [2] What you expected to happen: There shouldn't be any issues while unmounting the volume, the tests shouldn't have to wait several minutes waiting for the volume to be unmounted. How to reproduce it (as minimally and precisely as possible): pod requiring PVC. the pod. logs for error messages regarding the volume not being able to be unmounted. Anything else we need to know?: Environment: Kubernetes version (use ): v1.11.2 Cloud provider or hardware configuration: Azure, acs-engine v0.21.2 (: ) OS (e.g. from /etc/os-release): Windows Server 1803 Kernel (e.g. ): Install tools: Others:
/sig azure /assign
what's your PVC type? is it azure disk?
thanks for reporting. I have identified that this is a regression introduced by UnmountDevice common code mainly for linux: the root cause is is not well implemented Error code is like following: I have a different implementation for func on windows wich could fix this issue, will file a PR tomorrow.

Discussion:
return links, nil } <ins> // GetMountRefs : empty implementation here since there is no place to query all mount points on Windows </ins> func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) { if _, err := os.Stat(normalizeWindowsPath(pathname)); os.IsNotExist(err) { return []string{}, nil } else if err != nil { return nil, err } <del> refs, err := getAllParentLinks(normalizeWindowsPath(pathname)) if err != nil { return nil, err } return refs, nil </del> <ins> return []string{pathname}, nil </ins> } // Note that on windows, it always returns 0. We actually don't set FSGroup on

// this func must run in admin mode, otherwise it will fail func TestGetMountRefs(t *testing.T) { <del> fm := &FakeMounter{MountPoints: []MountPoint{}} mountPath := `c:secondmountpath` expectedRefs := []string{`c:`, `c:firstmountpath`, mountPath} // remove symbolic links first for i := 1; i < len(expectedRefs); i++ { removeLink(expectedRefs[i]) } // create symbolic links for i := 1; i < len(expectedRefs); i++ { if err := makeLink(expectedRefs[i], expectedRefs[i-1]); err != nil { t.Errorf("makeLink failed: %v", err) } </del> <ins> tests := []struct { mountPath    string expectedRefs []string }{ { mountPath:    `c:windows`, expectedRefs: []string{`c:windows`}, }, { mountPath:    `c:doesnotexist`, expectedRefs: []string{}, }, </ins> } <del> if refs, err := fm.GetMountRefs(mountPath); err != nil || !setEquivalent(expectedRefs, refs) { t.Errorf("getMountRefs(%q) = %v, error: %v; expected %v", mountPath, refs, err, expectedRefs) } </del> <ins> mounter := Mounter{"fake/path"} </ins> <del> // remove symbolic links for i := 1; i < len(expectedRefs); i++ { if err := removeLink(expectedRefs[i]); err != nil { t.Errorf("removeLink failed: %v", err) </del> <ins> for _, test := range tests { if refs, err := mounter.GetMountRefs(test.mountPath); err != nil || !setEquivalent(test.expectedRefs, refs) { t.Errorf("getMountRefs(%q) = %v, error: %v; expected %v", test.mountPath, refs, err, test.expectedRefs) </ins> } } }