Change:
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks! If the matter is security related, please disclose it privately via --We have even encountered such case that pod continuously reports “Unable to attach or mount volumes for pod;...” when kubelet restarted. The reasons are listed in details as below: , as result of apiserver instantaneous unstablility, dswp get pvc‘s pv spec failed, then the pvc volume does not be to dsw. , syncStates() lists all the volume directories locally, and recontructs the volume from local volume, if the volume isn't in dsw, it will put the recontructed volume to asw, but now the volume.OuterVolumeSpecName isn't correct. chance, at this time, In , the fail to pvc volume is to dsw again normally in reconcile() -mountAttachVolumes(), it compares dsw and asw by volume's innerVolumename, it's all the same. but it could not sense the OuterVolumeSpecName dismatch. so it will not re-mount again to update asw cache , it checks pod's volume attach or mount success by comparing volume.OuterVolumeSpecName and , but this pv'c OuterVolumeSpecName isn't correct in asw. so pod continuously reports “Unable to attach or mount volumes for pod;...” reconcile() could sense the reconstruct volume's dismatch to the dsw, then re-mount again to make volume cache consistency Kubernetes version (use ): 1.19.4 Cloud provider or hardware configuration: OS (e.g: ): Kernel (e.g. ): Install tools: Network plugin and version (if this is a network-related bug): Others:
/sig node
/triage accepted
/assign
CC
I think this is a point that can be optimized. /cc
I will give a fix for this
Thanks for reporting the issue, this innerSpecName and outerSpecName are confusing and cause issues. Please ping me for review when you have a fix. Thanks!
Please don't triage your own issues immediately, give someone else a chance to review them :( /sig storage
okay, I know

Discussion:
// to the node. This list can be used to determine volumes that are either in-use // or have a mount/unmount operation pending. GetAttachedVolumes() []AttachedVolume <ins> // SyncReconstructedVolume check the volume.outerVolumeSpecName in asw and // the one populated from dsw , if they do not match, update this field from the value from dsw. SyncReconstructedVolume(volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName, outerVolumeSpecName string) </ins> } // MountedVolume represents a volume that has successfully been mounted to a pod.

return unmountedVolumes } <ins> func (asw *actualStateOfWorld) SyncReconstructedVolume(volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName, outerVolumeSpecName string) { asw.Lock() defer asw.Unlock() if volumeObj, volumeExists := asw.attachedVolumes[volumeName]; volumeExists { if podObj, podExists := volumeObj.mountedPods[podName]; podExists { if podObj.outerVolumeSpecName != outerVolumeSpecName { podObj.outerVolumeSpecName = outerVolumeSpecName asw.attachedVolumes[volumeName].mountedPods[podName] = podObj } } } } </ins> func (asw *actualStateOfWorld) newAttachedVolume( attachedVolume *attachedVolume) AttachedVolume { return AttachedVolume{

} // Add volume to desired state of world <del> _, err = dswp.desiredStateOfWorld.AddPodToVolume( </del> <ins> uniqueVolumeName, err := dswp.desiredStateOfWorld.AddPodToVolume( </ins> uniquePodName, pod, volumeSpec, podVolume.Name, volumeGidValue) if err != nil { klog.ErrorS(err, "Failed to add volume to desiredStateOfWorld", "pod", klog.KObj(pod), "volumeName", podVolume.Name, "volumeSpecName", volumeSpec.Name())

} else { klog.V(4).InfoS("Added volume to desired state", "pod", klog.KObj(pod), "volumeName", podVolume.Name, "volumeSpecName", volumeSpec.Name()) } <ins> // sync reconstructed volume dswp.actualStateOfWorld.SyncReconstructedVolume(uniqueVolumeName, uniquePodName, podVolume.Name) </ins> if expandInUsePV { dswp.checkVolumeFSResize(pod, podVolume, pvc, volumeSpec,

return dswp, fakePodManager } <ins> func TestFindAndAddNewPods_WithRescontructedVolume(t *testing.T) { // create dswp dswp, fakePodManager := prepareDswpWithVolume(t) // create pod fakeOuterVolumeName := "dswp-test-volume-name" containers := []v1.Container{ { VolumeMounts: []v1.VolumeMount{ { Name:      fakeOuterVolumeName, MountPath: "/mnt", }, }, }, } pod := createPodWithVolume("dswp-test-pod", fakeOuterVolumeName, "file-bound", containers) fakePodManager.AddPod(pod) podName := util.GetUniquePodName(pod) mode := v1.PersistentVolumeFilesystem pv := &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: fakeOuterVolumeName, }, Spec: v1.PersistentVolumeSpec{ ClaimRef:   &v1.ObjectReference{Namespace: "ns", Name: "file-bound"}, VolumeMode: &mode, }, } generatedVolumeName := "fake-plugin/" + pod.Spec.Volumes[0].Name uniqueVolumeName := v1.UniqueVolumeName(generatedVolumeName) expectedOuterVolumeName := "dswp-test-volume-name" opts := operationexecutor.MarkVolumeOpts{ PodName:             podName, PodUID:              pod.UID, VolumeName:          uniqueVolumeName, OuterVolumeSpecName: generatedVolumeName, // fake reconstructed volume VolumeGidVolume:     "", VolumeSpec:          volume.NewSpecFromPersistentVolume(pv, false), VolumeMountState:    operationexecutor.VolumeMounted, } dswp.actualStateOfWorld.MarkVolumeAsAttached(opts.VolumeName, opts.VolumeSpec, "fake-node", "") dswp.actualStateOfWorld.MarkVolumeAsMounted(opts) dswp.findAndAddNewPods() mountedVolumes := dswp.actualStateOfWorld.GetMountedVolumesForPod(podName) found := false for _, volume := range mountedVolumes { if volume.OuterVolumeSpecName == expectedOuterVolumeName { found = true break } } if !found { t.Fatalf( "Could not found pod volume %v in the list of actual state of world volumes to mount.", expectedOuterVolumeName) } } </ins> func TestFindAndAddNewPods_WithReprocessPodAndVolumeRetrievalError(t *testing.T) { // create dswp dswp, fakePodManager := prepareDswpWithVolume(t)

volumeSpec: volumeSpec, // volume.volumeSpecName is actually InnerVolumeSpecName. It will not be used // for volume cleanup. <del> // TODO: in case pod is added back before reconciler starts to unmount, we can update this field from desired state information </del> <ins> // in case pod is added back to desired state, outerVolumeSpecName will be updated from dsw information. // See issue #103143 and its fix for details. </ins> outerVolumeSpecName: volume.volumeSpecName, pod:                 pod, deviceMounter:       deviceMounter,