@@ -39,6 +39,7 @@ import (
3939 "github.com/containerd/containerd/v2/core/metadata"
4040 "github.com/containerd/containerd/v2/core/metadata/boltutil"
4141 "github.com/containerd/containerd/v2/core/mount"
42+ "github.com/containerd/containerd/v2/internal/kmutex"
4243 "github.com/containerd/containerd/v2/pkg/gc"
4344 "github.com/containerd/containerd/v2/pkg/namespaces"
4445)
@@ -103,6 +104,7 @@ func NewManager(db *bolt.DB, targetDir string, opts ...Opt) (mount.Manager, erro
103104 targets : tr ,
104105 handlers : options .handlers ,
105106 rootMap : rootMap ,
107+ activate : kmutex .New (),
106108 }, nil
107109}
108110
@@ -112,7 +114,8 @@ type mountManager struct {
112114 handlers map [string ]mount.Handler
113115 rootMap map [string ]* os.Root
114116
115- rwlock sync.RWMutex
117+ rwlock sync.RWMutex
118+ activate kmutex.KeyedLocker
116119}
117120
118121func (mm * mountManager ) Close () error {
@@ -131,6 +134,14 @@ func (mm *mountManager) Activate(ctx context.Context, name string, mounts []moun
131134 return mount.ActivationInfo {}, err
132135 }
133136
137+ // Serialize concurrent activations of the same name to prevent a
138+ // racing Activate from misidentifying an in-progress activation as
139+ // a stale record and destroying it.
140+ if err := mm .activate .Lock (ctx , name ); err != nil {
141+ return mount.ActivationInfo {}, err
142+ }
143+ defer mm .activate .Unlock (name )
144+
134145 log .G (ctx ).WithField ("name" , name ).WithField ("mounts" , mounts ).Debugf ("activating mount" )
135146
136147 lid , leased := leases .FromContext (ctx )
@@ -229,6 +240,7 @@ func (mm *mountManager) Activate(ctx context.Context, name string, mounts []moun
229240 defer mm .rwlock .RUnlock ()
230241
231242 var mid uint64
243+ var staleMID uint64
232244
233245 if err := mm .db .Update (func (tx * bolt.Tx ) error {
234246 v1bkt , err := tx .CreateBucketIfNotExists ([]byte ("v1" ))
@@ -246,8 +258,38 @@ func (mm *mountManager) Activate(ctx context.Context, name string, mounts []moun
246258 }
247259 bkt , err := mbkt .CreateBucket ([]byte (name ))
248260 if err != nil {
249- // If already exists, return already exists
250- return err
261+ existing := mbkt .Bucket ([]byte (name ))
262+ if existing == nil {
263+ return err
264+ }
265+ // If the mount is fully activated, return already exists
266+ // so the caller can reuse the existing mount.
267+ if existing .Bucket (bucketKeyActive ) != nil {
268+ return fmt .Errorf ("mount %q: %w" , name , errdefs .ErrAlreadyExists )
269+ }
270+ // The mount bucket exists but was never fully activated
271+ // (e.g., process crashed between creating the bucket and
272+ // completing activation). Clean up the stale entry and
273+ // proceed with a fresh activation. Save the old mount ID
274+ // so the target directory can be cleaned up after the
275+ // transaction commits.
276+ staleMID = readID (existing )
277+ if lid := existing .Get (bucketKeyLease ); len (lid ) > 0 {
278+ if lsbkt := nsbkt .Bucket (bucketKeyLeases ); lsbkt != nil {
279+ if lbkt := lsbkt .Bucket (lid ); lbkt != nil {
280+ if err := lbkt .Delete ([]byte (name )); err != nil {
281+ return err
282+ }
283+ }
284+ }
285+ }
286+ if err := mbkt .DeleteBucket ([]byte (name )); err != nil {
287+ return err
288+ }
289+ bkt , err = mbkt .CreateBucket ([]byte (name ))
290+ if err != nil {
291+ return err
292+ }
251293 }
252294
253295 mid , err = v1bkt .NextSequence ()
@@ -297,6 +339,19 @@ func (mm *mountManager) Activate(ctx context.Context, name string, mounts []moun
297339 return mount.ActivationInfo {}, err
298340 }
299341
342+ // If a stale incomplete activation was found, clean up its target
343+ // directory which may contain leftover mounts from before a crash.
344+ if staleMID != 0 {
345+ staleTarget := filepath .Join (mm .targets .Name (), strconv .FormatUint (staleMID , 10 ))
346+ if err := unmountAll (ctx , staleTarget , mm .handlers ); err != nil {
347+ if os .IsNotExist (err ) {
348+ log .G (ctx ).WithError (err ).WithField ("mountid" , staleMID ).Debug ("stale activation target does not exist, skipping cleanup" )
349+ } else {
350+ log .G (ctx ).WithError (err ).WithField ("mountid" , staleMID ).Warn ("failed to unmount stale activation target" )
351+ }
352+ }
353+ }
354+
300355 defer func () {
301356 // If error, rollback and remove by name
302357 if retErr != nil {
@@ -483,7 +538,24 @@ func (mm *mountManager) Activate(ctx context.Context, name string, mounts []moun
483538 return err
484539 }
485540
486- // TODO: Save all system mounts
541+ if len (info .System ) > 0 {
542+ if len (info .System ) > 255 {
543+ return fmt .Errorf ("too many system mounts (%d): maximum 255" , len (info .System ))
544+ }
545+ sbkt , err := bkt .CreateBucket (bucketKeySystem )
546+ if err != nil {
547+ return err
548+ }
549+ for i , sm := range info .System {
550+ cur , err := sbkt .CreateBucket ([]byte {byte (i )})
551+ if err != nil {
552+ return err
553+ }
554+ if err = putSystemMount (cur , sm ); err != nil {
555+ return err
556+ }
557+ }
558+ }
487559
488560 return nil
489561 }); err != nil {
@@ -552,6 +624,36 @@ func readActiveMount(bkt *bolt.Bucket) (mount.ActiveMount, error) {
552624 return active , nil
553625}
554626
627+ func putSystemMount (bkt * bolt.Bucket , m mount.Mount ) error {
628+ if err := bkt .Put (bucketKeyType , []byte (m .Type )); err != nil {
629+ return err
630+ }
631+ if err := bkt .Put (bucketKeySource , []byte (m .Source )); err != nil {
632+ return err
633+ }
634+ if err := bkt .Put (bucketKeyTarget , []byte (m .Target )); err != nil {
635+ return err
636+ }
637+ if len (m .Options ) > 0 {
638+ if err := bkt .Put (bucketKeyOptions , []byte (strings .Join (m .Options , "\x00 " ))); err != nil {
639+ return err
640+ }
641+ }
642+ return nil
643+ }
644+
645+ func readSystemMount (bkt * bolt.Bucket ) mount.Mount {
646+ m := mount.Mount {
647+ Type : string (bkt .Get (bucketKeyType )),
648+ Source : string (bkt .Get (bucketKeySource )),
649+ Target : string (bkt .Get (bucketKeyTarget )),
650+ }
651+ if v := bkt .Get (bucketKeyOptions ); len (v ) > 0 {
652+ m .Options = strings .Split (string (v ), "\x00 " )
653+ }
654+ return m
655+ }
656+
555657func readActivationInfo (name string , bkt * bolt.Bucket ) (mount.ActivationInfo , error ) {
556658 info := mount.ActivationInfo {
557659 Name : name ,
@@ -568,6 +670,14 @@ func readActivationInfo(name string, bkt *bolt.Bucket) (mount.ActivationInfo, er
568670 return mount.ActivationInfo {}, err
569671 }
570672 }
673+ if sbkt := bkt .Bucket (bucketKeySystem ); sbkt != nil {
674+ if err := sbkt .ForEachBucket (func (k []byte ) error {
675+ info .System = append (info .System , readSystemMount (sbkt .Bucket (k )))
676+ return nil
677+ }); err != nil {
678+ return mount.ActivationInfo {}, err
679+ }
680+ }
571681 lbls , err := boltutil .ReadLabels (bkt )
572682 if err != nil {
573683 return mount.ActivationInfo {}, err
0 commit comments