@@ -31,6 +31,7 @@ import (
31
31
"github.com/containerd/containerd/snapshots"
32
32
"github.com/containerd/containerd/snapshots/storage"
33
33
"github.com/containerd/continuity/fs"
34
+ "github.com/moby/locker"
34
35
"github.com/pkg/errors"
35
36
)
36
37
@@ -136,11 +137,29 @@ const (
136
137
)
137
138
138
139
const (
139
- roDir = iota // overlayfs as rootfs. upper + lower (overlaybd)
140
- rwDir // mount overlaybd as rootfs
141
- rwDev // use overlaybd directly
140
+ roDir = "overlayfs" // overlayfs as rootfs. upper + lower (overlaybd)
141
+ rwDir = "dir" // mount overlaybd as rootfs
142
+ rwDev = "dev" // use overlaybd directly
142
143
)
143
144
145
+ type BootConfig struct {
146
+ Address string `json:"address"`
147
+ Root string `json:"root"`
148
+ LogLevel string `json:"verbose"`
149
+ LogReportCaller bool `json:"logReportCaller"`
150
+ Mode string `json:"mode"` // fs, dir or dev
151
+ AutoRemoveDev bool `json:"autoRemoveDev"`
152
+ }
153
+
154
+ func DefaultBootConfig () * BootConfig {
155
+ return & BootConfig {
156
+ LogLevel : "info" ,
157
+ Mode : "overlayfs" ,
158
+ LogReportCaller : false ,
159
+ AutoRemoveDev : false ,
160
+ }
161
+ }
162
+
144
163
// SnapshotterConfig is used to configure the snapshotter instance
145
164
type SnapshotterConfig struct {
146
165
// OverlayBDUtilBinDir contains overlaybd-create/overlaybd-commit tools
@@ -189,47 +208,59 @@ type Opt func(config *SnapshotterConfig) error
189
208
// #
190
209
// - metadata.db
191
210
type snapshotter struct {
192
- root string
193
- mode string
194
- config SnapshotterConfig
195
- ms * storage.MetaStore
196
- indexOff bool
211
+ root string
212
+ mode string
213
+ config SnapshotterConfig
214
+ metacopyOption string
215
+ ms * storage.MetaStore
216
+ indexOff bool
217
+ autoRemoveDev bool
218
+
219
+ locker * locker.Locker
197
220
}
198
221
199
222
// NewSnapshotter returns a Snapshotter which uses block device based on overlayFS.
200
- func NewSnapshotter (root string , mode string , opts ... Opt ) (snapshots.Snapshotter , error ) {
223
+ func NewSnapshotter (bootConfig * BootConfig , opts ... Opt ) (snapshots.Snapshotter , error ) {
201
224
config := defaultConfig
202
225
for _ , opt := range opts {
203
226
if err := opt (& config ); err != nil {
204
227
return nil , err
205
228
}
206
229
}
207
230
208
- if err := os .MkdirAll (root , 0700 ); err != nil {
231
+ if err := os .MkdirAll (bootConfig . Root , 0700 ); err != nil {
209
232
return nil , err
210
233
}
211
234
212
- ms , err := storage .NewMetaStore (filepath .Join (root , "metadata.db" ))
235
+ ms , err := storage .NewMetaStore (filepath .Join (bootConfig . Root , "metadata.db" ))
213
236
if err != nil {
214
237
return nil , err
215
238
}
216
239
217
- if err := os .Mkdir (filepath .Join (root , "snapshots" ), 0700 ); err != nil && ! os .IsExist (err ) {
240
+ if err := os .Mkdir (filepath .Join (bootConfig . Root , "snapshots" ), 0700 ); err != nil && ! os .IsExist (err ) {
218
241
return nil , err
219
242
}
220
243
244
+ metacopyOption := ""
245
+ if _ , err := os .Stat ("/sys/module/overlay/parameters/metacopy" ); err == nil {
246
+ metacopyOption = "metacopy=on"
247
+ }
248
+
221
249
// figure out whether "index=off" option is recognized by the kernel
222
250
var indexOff bool
223
251
if _ , err = os .Stat ("/sys/module/overlay/parameters/index" ); err == nil {
224
252
indexOff = true
225
253
}
226
254
227
255
return & snapshotter {
228
- root : root ,
229
- mode : mode ,
230
- ms : ms ,
231
- indexOff : indexOff ,
232
- config : config ,
256
+ root : bootConfig .Root ,
257
+ mode : bootConfig .Mode ,
258
+ ms : ms ,
259
+ indexOff : indexOff ,
260
+ config : config ,
261
+ metacopyOption : metacopyOption ,
262
+ autoRemoveDev : bootConfig .AutoRemoveDev ,
263
+ locker : locker .New (),
233
264
}, nil
234
265
}
235
266
@@ -301,9 +332,9 @@ func (o *snapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, e
301
332
return usage , nil
302
333
}
303
334
304
- func (o * snapshotter ) getWritableType (ctx context.Context , id string , info snapshots.Info ) (mode int ) {
335
+ func (o * snapshotter ) getWritableType (ctx context.Context , id string , info snapshots.Info ) (mode string ) {
305
336
defer func () {
306
- log .G (ctx ).Infof ("snapshot R/W label: %d " , mode )
337
+ log .G (ctx ).Infof ("snapshot R/W label: %s " , mode )
307
338
}()
308
339
// check image type (OCIv1 or overlaybd)
309
340
if id != "" {
@@ -315,7 +346,7 @@ func (o *snapshotter) getWritableType(ctx context.Context, id string, info snaps
315
346
log .G (ctx ).Debugf ("empty snID get. It should be an initial layer." )
316
347
}
317
348
// overlaybd
318
- rwMode := func (m string ) int {
349
+ rwMode := func (m string ) string {
319
350
if m == "dir" {
320
351
return rwDir
321
352
}
@@ -431,11 +462,14 @@ func (o *snapshotter) createMountPoint(ctx context.Context, kind snapshots.Kind,
431
462
432
463
stype := storageTypeNormal
433
464
writeType := o .getWritableType (ctx , parentID , info )
465
+
434
466
// If Preparing for rootfs, find metadata from its parent (top layer), launch and mount backstore device.
435
467
if _ , ok := info .Labels [labelKeyTargetSnapshotRef ]; ! ok {
468
+ log .G (ctx ).Infof ("Preparing rootfs. writeType: %s" , writeType )
436
469
if writeType != roDir {
437
470
stype = storageTypeLocalBlock
438
471
if err := o .constructOverlayBDSpec (ctx , key , true ); err != nil {
472
+ log .G (ctx ).Errorln (err .Error ())
439
473
return nil , err
440
474
}
441
475
} else if parent != "" {
@@ -486,7 +520,7 @@ func (o *snapshotter) createMountPoint(ctx context.Context, kind snapshots.Kind,
486
520
log .G (ctx ).Warnf ("cannot get fs type from label, %v" , obdInfo .Labels )
487
521
fsType = "ext4"
488
522
}
489
- log .G (ctx ).Debugf ("attachAndMountBlockDevice (obdID: %s, writeType: %d , fsType %s, targetPath: %s)" ,
523
+ log .G (ctx ).Debugf ("attachAndMountBlockDevice (obdID: %s, writeType: %s , fsType %s, targetPath: %s)" ,
490
524
obdID , writeType , fsType , o .overlaybdTargetPath (obdID ))
491
525
if err = o .attachAndMountBlockDevice (ctx , obdID , writeType , fsType , parent == "" ); err != nil {
492
526
log .G (ctx ).Errorf ("%v" , err )
@@ -514,7 +548,7 @@ func (o *snapshotter) createMountPoint(ctx context.Context, kind snapshots.Kind,
514
548
switch stype {
515
549
case storageTypeNormal :
516
550
m = o .normalOverlayMount (s )
517
- log .G (ctx ).Debugf ("return mount point(R/W mode: %d ): %v" , writeType , m )
551
+ log .G (ctx ).Debugf ("return mount point(R/W mode: %s ): %v" , writeType , m )
518
552
case storageTypeLocalBlock , storageTypeRemoteBlock :
519
553
m , err = o .basedOnBlockDeviceMount (ctx , s , writeType )
520
554
if err != nil {
@@ -559,6 +593,11 @@ func (o *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, er
559
593
log .G (ctx ).Debugf ("Mounts (key: %s, id: %s, parentID: %s, kind: %d)" , key , s .ID , s .ParentIDs , s .Kind )
560
594
561
595
if len (s .ParentIDs ) > 0 {
596
+ o .locker .Lock (s .ID )
597
+ defer o .locker .Unlock (s .ID )
598
+ o .locker .Lock (s .ParentIDs [0 ])
599
+ defer o .locker .Unlock (s .ParentIDs [0 ])
600
+
562
601
_ , info , _ , err := storage .GetInfo (ctx , key )
563
602
if err != nil {
564
603
return nil , errors .Wrap (err , "failed to get info" )
@@ -732,6 +771,24 @@ func (o *snapshotter) Remove(ctx context.Context, key string) (err error) {
732
771
}
733
772
}
734
773
774
+ // for TypeNormal, verify its(parent) meets the condition of overlaybd format
775
+ if o .autoRemoveDev {
776
+ if s , err := storage .GetSnapshot (ctx , key ); err == nil && s .Kind == snapshots .KindActive && len (s .ParentIDs ) > 0 {
777
+ o .locker .Lock (s .ID )
778
+ defer o .locker .Unlock (s .ID )
779
+ o .locker .Lock (s .ParentIDs [0 ])
780
+ defer o .locker .Unlock (s .ParentIDs [0 ])
781
+
782
+ log .G (ctx ).Debugf ("try to verify parent snapshots format." )
783
+ if st , err := o .identifySnapshotStorageType (ctx , s .ParentIDs [0 ], info ); err == nil && st != storageTypeNormal {
784
+ err = o .unmountAndDetachBlockDevice (ctx , s .ParentIDs [0 ], "" )
785
+ if err != nil {
786
+ return errors .Wrapf (err , "failed to destroy target device for snapshot %s" , key )
787
+ }
788
+ }
789
+ }
790
+ }
791
+
735
792
defer func () {
736
793
if err != nil && rollback {
737
794
if rerr := t .Rollback (); rerr != nil {
@@ -797,10 +854,10 @@ func (o *snapshotter) prepareDirectory(ctx context.Context, snapshotDir string,
797
854
return td , nil
798
855
}
799
856
800
- func (o * snapshotter ) basedOnBlockDeviceMount (ctx context.Context , s storage.Snapshot , writeType int ) (m []mount.Mount , err error ) {
857
+ func (o * snapshotter ) basedOnBlockDeviceMount (ctx context.Context , s storage.Snapshot , writeType string ) (m []mount.Mount , err error ) {
801
858
defer func () {
802
859
if err == nil {
803
- log .G (ctx ).Infof ("return mount point(R/W mode: %d ): %v" , writeType , m )
860
+ log .G (ctx ).Infof ("return mount point(R/W mode: %s ): %v" , writeType , m )
804
861
} else {
805
862
log .G (ctx ).Errorf ("basedOnBlockDeviceMount return error: %v" , err )
806
863
}
@@ -1017,9 +1074,21 @@ func (o *snapshotter) identifySnapshotStorageType(ctx context.Context, id string
1017
1074
// check writable data file
1018
1075
filePath = o .overlaybdWritableDataPath (id )
1019
1076
st , err = o .identifyLocalStorageType (filePath )
1020
- if err != nil && os .IsNotExist (err ) {
1077
+ if err == nil {
1078
+ return st , nil
1079
+ }
1080
+ if os .IsNotExist (err ) {
1081
+ // check config.v1.json
1082
+ log .G (ctx ).Debugf ("failed to identify by writable_data(sn: %s), try to identify by config.v1.json" , id )
1083
+ filePath = o .overlaybdConfPath (id )
1084
+ if _ , err := os .Stat (filePath ); err == nil {
1085
+ log .G (ctx ).Debugf ("%s/config.v1.json found, return storageTypeRemoteBlock" , id )
1086
+ return storageTypeRemoteBlock , nil
1087
+ }
1021
1088
return storageTypeNormal , nil
1022
1089
}
1090
+ log .G (ctx ).Debugf ("storageType(sn: %s): %d" , id , st )
1091
+
1023
1092
return st , err
1024
1093
}
1025
1094
0 commit comments