Skip to content

Commit 360dff9

Browse files
authored
Merge pull request #302 from WaberZhuang/main
check if snapshot holds mountpoint before remove
2 parents 1fce068 + 7a270c8 commit 360dff9

File tree

3 files changed

+70
-13
lines changed

3 files changed

+70
-13
lines changed

internal/log/helper.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
Copyright The Accelerated Container Image Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package log
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
clog "github.com/containerd/log"
24+
)
25+
26+
func TracedErrorf(ctx context.Context, format string, args ...any) error {
27+
err := fmt.Errorf(format, args...)
28+
clog.G(ctx).Error(err)
29+
return err
30+
}

pkg/snapshot/overlay.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/containerd/accelerated-container-image/pkg/label"
3030
"github.com/containerd/accelerated-container-image/pkg/snapshot/diskquota"
3131

32+
mylog "github.com/containerd/accelerated-container-image/internal/log"
3233
"github.com/containerd/accelerated-container-image/pkg/metrics"
3334
"github.com/data-accelerator/zdfs"
3435
"github.com/sirupsen/logrus"
@@ -944,7 +945,7 @@ func (o *snapshotter) Remove(ctx context.Context, key string) (err error) {
944945
if err == nil {
945946
err = o.unmountAndDetachBlockDevice(ctx, id, key)
946947
if err != nil {
947-
return errors.Wrapf(err, "failed to destroy target device for snapshot %s", key)
948+
return mylog.TracedErrorf(ctx, "failed to destroy target device for snapshot %s: %w", key, err)
948949
}
949950
}
950951
}
@@ -961,12 +962,20 @@ func (o *snapshotter) Remove(ctx context.Context, key string) (err error) {
961962
if st, err := o.identifySnapshotStorageType(ctx, s.ParentIDs[0], info); err == nil && st != storageTypeNormal {
962963
err = o.unmountAndDetachBlockDevice(ctx, s.ParentIDs[0], "")
963964
if err != nil {
964-
return errors.Wrapf(err, "failed to destroy target device for snapshot %s", key)
965+
return mylog.TracedErrorf(ctx, "failed to destroy target device for snapshot %s: %w", key, err)
965966
}
966967
}
967968
}
968969
}
969970

971+
// Just in case, check if snapshot contains mountpoint
972+
mounted, err := o.isMounted(ctx, o.overlaybdMountpoint(id))
973+
if err != nil {
974+
return mylog.TracedErrorf(ctx, "failed to check mountpoint: %w", err)
975+
} else if mounted {
976+
return mylog.TracedErrorf(ctx, "try to remove snapshot %s which still have mountpoint", id)
977+
}
978+
970979
_, _, err = storage.Remove(ctx, key)
971980
if err != nil {
972981
return errors.Wrap(err, "failed to remove")

pkg/snapshot/storage.go

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,45 @@ const (
6868
obdMaxDataAreaMB = 4
6969
)
7070

71+
type mountMatcherFunc func(fields []string, separatorIndex int) bool
72+
7173
func (o *snapshotter) checkOverlaybdInUse(ctx context.Context, dir string) (bool, error) {
74+
matcher := func(fields []string, separatorIndex int) bool {
75+
// ... but in Linux <= 3.9 mounting a cifs with spaces in a share name
76+
// (like "//serv/My Documents") _may_ end up having a space in the last field
77+
// of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs
78+
// option unc= is ignored, so a space should not appear. In here we ignore
79+
// those "extra" fields caused by extra spaces.
80+
fstype := fields[separatorIndex+1]
81+
vfsOpts := fields[separatorIndex+3]
82+
return fstype == "overlay" && strings.Contains(vfsOpts, dir)
83+
}
84+
return o.matchMounts(ctx, matcher)
85+
}
86+
87+
func (o *snapshotter) isMounted(ctx context.Context, mountpoint string) (bool, error) {
88+
matcher := func(fields []string, separatorIndex int) bool {
89+
mp := fields[4]
90+
return path.Clean(mountpoint) == path.Clean(mp)
91+
}
92+
return o.matchMounts(ctx, matcher)
93+
}
94+
95+
func (o *snapshotter) matchMounts(ctx context.Context, matcher mountMatcherFunc) (bool, error) {
7296
f, err := os.Open("/proc/self/mountinfo")
7397
if err != nil {
7498
return false, err
7599
}
76100
defer f.Close()
77-
b, err := o.parseAndCheckMounted(ctx, f, dir)
101+
b, err := o.parseAndCheckMounted(ctx, f, matcher)
78102
if err != nil {
79103
log.G(ctx).Errorf("Parsing mounts fields, error: %v", err)
80104
return false, err
81105
}
82106
return b, nil
83107
}
84108

85-
func (o *snapshotter) parseAndCheckMounted(ctx context.Context, r io.Reader, dir string) (bool, error) {
109+
func (o *snapshotter) parseAndCheckMounted(ctx context.Context, r io.Reader, matcher mountMatcherFunc) (bool, error) {
86110
s := bufio.NewScanner(r)
87111
for s.Scan() {
88112
if err := s.Err(); err != nil {
@@ -139,21 +163,15 @@ func (o *snapshotter) parseAndCheckMounted(ctx context.Context, r io.Reader, dir
139163
log.G(ctx).Warnf("Parsing '%s' failed: not enough fields after a separator", text)
140164
continue
141165
}
142-
// ... but in Linux <= 3.9 mounting a cifs with spaces in a share name
143-
// (like "//serv/My Documents") _may_ end up having a space in the last field
144-
// of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs
145-
// option unc= is ignored, so a space should not appear. In here we ignore
146-
// those "extra" fields caused by extra spaces.
147-
fstype := fields[i+1]
148-
vfsOpts := fields[i+3]
149-
if fstype == "overlay" && strings.Contains(vfsOpts, dir) {
166+
167+
if matcher(fields, i) {
150168
return true, nil
151169
}
152170
}
153171
return false, nil
154172
}
155173

156-
// unmountAndDetachBlockDevice
174+
// unmountAndDetachBlockDevice will do nothing if the device is already destroyed
157175
func (o *snapshotter) unmountAndDetachBlockDevice(ctx context.Context, snID string, snKey string) (err error) {
158176
devName, err := os.ReadFile(o.overlaybdBackstoreMarkFile(snID))
159177
if err != nil {

0 commit comments

Comments
 (0)