@@ -60,6 +60,7 @@ const (
60
60
volumeLimitBig int64 = 127
61
61
defaultLinuxFsType = "ext4"
62
62
defaultWindowsFsType = "ntfs"
63
+ fsTypeExt3 = "ext3"
63
64
)
64
65
65
66
func getDefaultFsType () string {
@@ -311,8 +312,29 @@ func (ns *GCENodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStage
311
312
return & csi.NodeStageVolumeResponse {}, nil
312
313
}
313
314
315
+ readonly , _ := getReadOnlyFromCapability (volumeCapability )
316
+ if readonly {
317
+ options = append (options , "ro" )
318
+ klog .V (4 ).Infof ("CSI volume is read-only, mounting with extra option ro" )
319
+ }
320
+
314
321
err = formatAndMount (devicePath , stagingTargetPath , fstype , options , ns .Mounter )
315
322
if err != nil {
323
+ // If a volume is created from a content source like snapshot or cloning, the filesystem might get marked
324
+ // as "dirty" even if it is otherwise consistent and ext3/4 will try to restore to a consistent state by replaying
325
+ // the journal which is not possible in read-only mode. So we'll try again with noload option to skip it. This may
326
+ // allow mounting of an actually inconsistent filesystem, but because the mount is read-only no further damage should
327
+ // be caused.
328
+ if readonly && (fstype == defaultLinuxFsType || fstype == fsTypeExt3 ) {
329
+ klog .V (4 ).Infof ("Failed to mount CSI volume read-only, retry mounting with extra option noload" )
330
+
331
+ options = append (options , "noload" )
332
+ err = formatAndMount (devicePath , stagingTargetPath , fstype , options , ns .Mounter )
333
+ if err == nil {
334
+ klog .V (4 ).Infof ("NodeStageVolume succeeded with \" noload\" option on %v to %s" , volumeID , stagingTargetPath )
335
+ return & csi.NodeStageVolumeResponse {}, nil
336
+ }
337
+ }
316
338
return nil , status .Error (codes .Internal ,
317
339
fmt .Sprintf ("Failed to format and mount device from (%q) to (%q) with fstype (%q) and options (%q): %v" ,
318
340
devicePath , stagingTargetPath , fstype , options , err ))
0 commit comments