@@ -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,25 @@ 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
+ // ext4 and ext3 replays the journal which needs write permission. So noload option stops that
324
+ if readonly && (fstype == defaultLinuxFsType || fstype == fsTypeExt3 ) {
325
+ klog .V (4 ).Infof ("Failed to mount CSI volume read-only, retry mounting with extra option noload" )
326
+
327
+ options = append (options , "noload" )
328
+ err = formatAndMount (devicePath , stagingTargetPath , fstype , options , ns .Mounter )
329
+ if err == nil {
330
+ klog .V (4 ).Infof ("NodeStageVolume succeeded with \" noload\" option on %v to %s" , volumeID , stagingTargetPath )
331
+ return & csi.NodeStageVolumeResponse {}, nil
332
+ }
333
+ }
316
334
return nil , status .Error (codes .Internal ,
317
335
fmt .Sprintf ("Failed to format and mount device from (%q) to (%q) with fstype (%q) and options (%q): %v" ,
318
336
devicePath , stagingTargetPath , fstype , options , err ))
0 commit comments