Skip to content

Commit 1b4ca9e

Browse files
committed
Prototype temporary directory
Signed-off-by: Jan Rodák <[email protected]>
1 parent 78f4258 commit 1b4ca9e

File tree

11 files changed

+529
-25
lines changed

11 files changed

+529
-25
lines changed

drivers/aufs/aufs.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import (
4545
mountpk "github.com/containers/storage/pkg/mount"
4646
"github.com/containers/storage/pkg/parsers"
4747
"github.com/containers/storage/pkg/system"
48+
"github.com/containers/storage/pkg/tempdir"
4849
"github.com/containers/storage/pkg/unshare"
4950
"github.com/opencontainers/selinux/go-selinux/label"
5051
"github.com/sirupsen/logrus"
@@ -781,3 +782,9 @@ func (a *Driver) SupportsShifting() bool {
781782
func (a *Driver) Dedup(req graphdriver.DedupArgs) (graphdriver.DedupResult, error) {
782783
return graphdriver.DedupResult{}, nil
783784
}
785+
786+
// DeferredRemove is not implemented.
787+
// It calls Remove directly.
788+
func (a *Driver) DeferredRemove(id string) (tempdir.CleanupTempDirFunc, error) {
789+
return nil, a.Remove(id)
790+
}

drivers/btrfs/btrfs.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"github.com/containers/storage/pkg/mount"
3737
"github.com/containers/storage/pkg/parsers"
3838
"github.com/containers/storage/pkg/system"
39+
"github.com/containers/storage/pkg/tempdir"
3940
"github.com/docker/go-units"
4041
"github.com/opencontainers/selinux/go-selinux/label"
4142
"github.com/sirupsen/logrus"
@@ -678,3 +679,9 @@ func (d *Driver) AdditionalImageStores() []string {
678679
func (d *Driver) Dedup(req graphdriver.DedupArgs) (graphdriver.DedupResult, error) {
679680
return graphdriver.DedupResult{}, nil
680681
}
682+
683+
// DeferredRemove is not implemented.
684+
// It calls Remove directly.
685+
func (d *Driver) DeferredRemove(id string) (tempdir.CleanupTempDirFunc, error) {
686+
return nil, d.Remove(id)
687+
}

drivers/driver.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/containers/storage/pkg/directory"
1414
"github.com/containers/storage/pkg/fileutils"
1515
"github.com/containers/storage/pkg/idtools"
16+
"github.com/containers/storage/pkg/tempdir"
1617
digest "github.com/opencontainers/go-digest"
1718
"github.com/sirupsen/logrus"
1819
"github.com/vbatts/tar-split/tar/storage"
@@ -124,6 +125,7 @@ type ProtoDriver interface {
124125
CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *CreateOpts, readWrite bool) error
125126
// Remove attempts to remove the filesystem layer with this id.
126127
Remove(id string) error
128+
DeferredRemove(id string) (tempdir.CleanupTempDirFunc, error)
127129
// Get returns the mountpoint for the layered filesystem referred
128130
// to by this id. You can optionally specify a mountLabel or "".
129131
// Optionally it gets the mappings used to create the layer.

drivers/overlay/overlay.go

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/containers/storage/pkg/mount"
3535
"github.com/containers/storage/pkg/parsers"
3636
"github.com/containers/storage/pkg/system"
37+
"github.com/containers/storage/pkg/tempdir"
3738
"github.com/containers/storage/pkg/unshare"
3839
units "github.com/docker/go-units"
3940
digest "github.com/opencontainers/go-digest"
@@ -1314,15 +1315,16 @@ func (d *Driver) Remove(id string) error {
13141315
lid, err := os.ReadFile(path.Join(dir, "link"))
13151316
if err == nil {
13161317
if err := os.RemoveAll(path.Join(d.home, linkDir, string(lid))); err != nil {
1317-
logrus.Debugf("Failed to remove link: %v", err)
1318+
logrus.Debugf("Failed to Add to stage Directory link: %v", err)
13181319
}
13191320
}
13201321

13211322
d.releaseAdditionalLayerByID(id)
13221323

1323-
if err := system.EnsureRemoveAll(dir); err != nil && !os.IsNotExist(err) {
1324-
return err
1324+
if err := system.EnsureRemoveAll(dir); err != nil {
1325+
return fmt.Errorf("failed to add to stage directory: %w", err)
13251326
}
1327+
13261328
if d.quotaCtl != nil {
13271329
d.quotaCtl.ClearQuota(dir)
13281330
if d.imageStore != "" {
@@ -1332,6 +1334,35 @@ func (d *Driver) Remove(id string) error {
13321334
return nil
13331335
}
13341336

1337+
func (d *Driver) DeferredRemove(id string) (tempdir.CleanupTempDirFunc, error) {
1338+
t, err := tempdir.NewTempDir(filepath.Join(d.homeDirForImageStore(), stagingDir))
1339+
if err != nil {
1340+
return nil, err
1341+
}
1342+
1343+
dir := d.dir(id)
1344+
lid, err := os.ReadFile(path.Join(dir, "link"))
1345+
if err == nil {
1346+
if err := t.Add(path.Join(d.home, linkDir, string(lid))); err != nil {
1347+
logrus.Debugf("Failed to Add to stage Directory link: %v", err)
1348+
}
1349+
}
1350+
1351+
d.releaseAdditionalLayerByID(id)
1352+
1353+
if err := t.Add(dir); err != nil {
1354+
return t.Cleanup, fmt.Errorf("failed to add to stage directory: %w", err)
1355+
}
1356+
1357+
if d.quotaCtl != nil {
1358+
d.quotaCtl.ClearQuota(dir)
1359+
if d.imageStore != "" {
1360+
d.quotaCtl.ClearQuota(d.imageStore)
1361+
}
1362+
}
1363+
return t.Cleanup, nil
1364+
}
1365+
13351366
// recreateSymlinks goes through the driver's home directory and checks if the diff directory
13361367
// under each layer has a symlink created for it under the linkDir. If the symlink does not
13371368
// exist, it creates them
@@ -1358,8 +1389,8 @@ func (d *Driver) recreateSymlinks() error {
13581389
// Check that for each layer, there's a link in "l" with the name in
13591390
// the layer's "link" file that points to the layer's "diff" directory.
13601391
for _, dir := range dirs {
1361-
// Skip over the linkDir and anything that is not a directory
1362-
if dir.Name() == linkDir || !dir.IsDir() {
1392+
// Skip over the linkDir and anything that is not a directory or tempDir
1393+
if dir.Name() == linkDir || !dir.IsDir() || dir.Name() == stagingDir { // Note for review: Not sure if skipping stagingDir is correct
13631394
continue
13641395
}
13651396
// Read the "link" file under each layer to get the name of the symlink

drivers/vfs/driver.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/containers/storage/pkg/idtools"
1818
"github.com/containers/storage/pkg/parsers"
1919
"github.com/containers/storage/pkg/system"
20+
"github.com/containers/storage/pkg/tempdir"
2021
"github.com/opencontainers/selinux/go-selinux/label"
2122
"github.com/sirupsen/logrus"
2223
"github.com/vbatts/tar-split/tar/storage"
@@ -241,7 +242,18 @@ func (d *Driver) dir(id string) string {
241242

242243
// Remove deletes the content from the directory for a given id.
243244
func (d *Driver) Remove(id string) error {
244-
return system.EnsureRemoveAll(d.dir(id))
245+
return os.RemoveAll(d.dir(id))
246+
}
247+
248+
func (d *Driver) DeferredRemove(id string) (tempdir.CleanupTempDirFunc, error) {
249+
t, err := tempdir.NewTempDir(d.home)
250+
if err != nil {
251+
return nil, err
252+
}
253+
if err := t.Add(d.dir(id)); err != nil {
254+
return nil, err
255+
}
256+
return t.Cleanup, nil
245257
}
246258

247259
// Get returns the directory for the given id.

drivers/windows/windows.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"github.com/containers/storage/pkg/longpath"
3333
"github.com/containers/storage/pkg/reexec"
3434
"github.com/containers/storage/pkg/system"
35+
"github.com/containers/storage/pkg/tempdir"
3536
units "github.com/docker/go-units"
3637
"github.com/sirupsen/logrus"
3738
"golang.org/x/sys/windows"
@@ -1014,3 +1015,9 @@ func parseStorageOpt(storageOpt map[string]string) (*storageOptions, error) {
10141015
}
10151016
return &options, nil
10161017
}
1018+
1019+
// DeferredRemove is not implemented.
1020+
// It calls Remove directly.
1021+
func (d *Driver) DeferredRemove(id string) (tempdir.CleanupTempDirFunc, error) {
1022+
return nil, d.Remove(id)
1023+
}

drivers/zfs/zfs.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/containers/storage/pkg/idtools"
1818
"github.com/containers/storage/pkg/mount"
1919
"github.com/containers/storage/pkg/parsers"
20+
"github.com/containers/storage/pkg/tempdir"
2021
zfs "github.com/mistifyio/go-zfs/v3"
2122
"github.com/opencontainers/selinux/go-selinux/label"
2223
"github.com/sirupsen/logrus"
@@ -406,6 +407,12 @@ func (d *Driver) Remove(id string) error {
406407
return nil
407408
}
408409

410+
// DeferredRemove is not implemented.
411+
// It calls Remove directly.
412+
func (d *Driver) DeferredRemove(id string) (tempdir.CleanupTempDirFunc, error) {
413+
return nil, d.Remove(id)
414+
}
415+
409416
// Get returns the mountpoint for the given id after creating the target directories if necessary.
410417
func (d *Driver) Get(id string, options graphdriver.MountOpts) (_ string, retErr error) {
411418
mountpoint := d.mountPath(id)

layers.go

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/containers/storage/pkg/stringid"
2727
"github.com/containers/storage/pkg/system"
2828
"github.com/containers/storage/pkg/tarlog"
29+
"github.com/containers/storage/pkg/tempdir"
2930
"github.com/containers/storage/pkg/truncindex"
3031
"github.com/klauspost/pgzip"
3132
digest "github.com/opencontainers/go-digest"
@@ -293,6 +294,9 @@ type rwLayerStore interface {
293294
// Delete deletes a layer with the specified name or ID.
294295
Delete(id string) error
295296

297+
// Delete deletes a layer with the specified name or ID.
298+
DeferredDelete(id string) (tempdir.CleanupTempDirFunc, error)
299+
296300
// Wipe deletes all layers.
297301
Wipe() error
298302

@@ -411,11 +415,12 @@ func newMultipleLockFile(l ...*lockfile.LockFile) *multipleLockFile {
411415
type layerStore struct {
412416
// The following fields are only set when constructing layerStore, and must never be modified afterwards.
413417
// They are safe to access without any other locking.
414-
lockfile *multipleLockFile // lockfile.IsReadWrite can be used to distinguish between read-write and read-only layer stores.
415-
mountsLockfile *lockfile.LockFile // Can _only_ be obtained with inProcessLock held.
416-
rundir string
417-
jsonPath [numLayerLocationIndex]string
418-
layerdir string
418+
lockfile *multipleLockFile // lockfile.IsReadWrite can be used to distinguish between read-write and read-only layer stores.
419+
mountsLockfile *lockfile.LockFile // Can _only_ be obtained with inProcessLock held.
420+
rundir string
421+
jsonPath [numLayerLocationIndex]string
422+
layerdir string
423+
tempDirRootPath string
419424

420425
inProcessLock sync.RWMutex // Can _only_ be obtained with lockfile held.
421426
// The following fields can only be read/written with read/write ownership of inProcessLock, respectively.
@@ -794,6 +799,12 @@ func (r *layerStore) load(lockedForWriting bool) (bool, error) {
794799
layers := []*Layer{}
795800
ids := make(map[string]*Layer)
796801

802+
if r.lockfile.IsReadWrite() {
803+
if err := tempdir.RecoverStaleDirs(r.tempDirRootPath); err != nil {
804+
return false, err
805+
}
806+
}
807+
797808
for locationIndex := range numLayerLocationIndex {
798809
location := layerLocationFromIndex(locationIndex)
799810
rpath := r.jsonPath[locationIndex]
@@ -935,7 +946,12 @@ func (r *layerStore) load(lockedForWriting bool) (bool, error) {
935946
// Now actually delete the layers
936947
for _, layer := range layersToDelete {
937948
logrus.Warnf("Found incomplete layer %q, deleting it", layer.ID)
938-
err := r.deleteInternal(layer.ID)
949+
cleanupFunc, err := r.deleteInternal(layer.ID)
950+
defer func() {
951+
if err := cleanupFunc(); err != nil {
952+
logrus.Errorf("Error cleaning up temporary directories: %v", err)
953+
}
954+
}()
939955
if err != nil {
940956
// Don't return the error immediately, because deleteInternal does not saveLayers();
941957
// Even if deleting one incomplete layer fails, call saveLayers() so that other possible successfully
@@ -1158,7 +1174,8 @@ func (s *store) newLayerStore(rundir, layerdir, imagedir string, driver drivers.
11581174
layersImageDir,
11591175
filepath.Join(volatileDir, "volatile-layers.json"),
11601176
},
1161-
layerdir: layerdir,
1177+
layerdir: layerdir,
1178+
tempDirRootPath: s.graphRoot,
11621179

11631180
byid: make(map[string]*Layer),
11641181
byname: make(map[string]*Layer),
@@ -1920,13 +1937,15 @@ func layerHasIncompleteFlag(layer *Layer) bool {
19201937
}
19211938

19221939
// Requires startWriting.
1923-
func (r *layerStore) deleteInternal(id string) error {
1940+
// Caller MUST run CleanupTemporaryDirectories() after this. Ideally outside of
1941+
// the startWriting.
1942+
func (r *layerStore) deleteInternal(id string) (tempdir.CleanupTempDirFunc, error) {
19241943
if !r.lockfile.IsReadWrite() {
1925-
return fmt.Errorf("not allowed to delete layers at %q: %w", r.layerdir, ErrStoreIsReadOnly)
1944+
return nil, fmt.Errorf("not allowed to delete layers at %q: %w", r.layerdir, ErrStoreIsReadOnly)
19261945
}
19271946
layer, ok := r.lookup(id)
19281947
if !ok {
1929-
return ErrLayerUnknown
1948+
return nil, ErrLayerUnknown
19301949
}
19311950
// Ensure that if we are interrupted, the layer will be cleaned up.
19321951
if !layerHasIncompleteFlag(layer) {
@@ -1935,16 +1954,33 @@ func (r *layerStore) deleteInternal(id string) error {
19351954
}
19361955
layer.Flags[incompleteFlag] = true
19371956
if err := r.saveFor(layer); err != nil {
1938-
return err
1957+
return nil, err
19391958
}
19401959
}
1960+
tempDirectory, err := tempdir.NewTempDir(r.tempDirRootPath)
1961+
if err != nil {
1962+
return nil, err
1963+
}
19411964
// We never unset incompleteFlag; below, we remove the entire object from r.layers.
19421965
id = layer.ID
1943-
if err := r.driver.Remove(id); err != nil && !errors.Is(err, os.ErrNotExist) {
1944-
return err
1966+
var cleanFunc tempdir.CleanupTempDirFunc
1967+
if cleanFunc, err = r.driver.DeferredRemove(id); err != nil && !errors.Is(err, os.ErrNotExist) {
1968+
return cleanFunc, err
1969+
}
1970+
1971+
finalCleanFunc := func() error {
1972+
if err := tempDirectory.Cleanup(); err != nil {
1973+
return err
1974+
}
1975+
if err := cleanFunc(); err != nil {
1976+
return err
1977+
}
1978+
return nil
19451979
}
1946-
os.Remove(r.tspath(id))
1947-
os.RemoveAll(r.datadir(id))
1980+
_ = tempDirectory.Add(r.tspath(id))
1981+
// os.Remove(r.tspath(id))
1982+
_ = tempDirectory.Add(r.datadir(id))
1983+
// os.RemoveAll(r.datadir(id))
19481984
delete(r.byid, id)
19491985
for _, name := range layer.Names {
19501986
delete(r.byname, name)
@@ -1968,7 +2004,7 @@ func (r *layerStore) deleteInternal(id string) error {
19682004
}) {
19692005
selinux.ReleaseLabel(mountLabel)
19702006
}
1971-
return nil
2007+
return finalCleanFunc, nil
19722008
}
19732009

19742010
// Requires startWriting.
@@ -2006,12 +2042,42 @@ func (r *layerStore) Delete(id string) error {
20062042
return err
20072043
}
20082044
}
2009-
if err := r.deleteInternal(id); err != nil {
2010-
return err
2045+
cleanFunc, err := r.deleteInternal(id)
2046+
rmErr := cleanFunc()
2047+
if err != nil || rmErr != nil {
2048+
return errors.Join(err, rmErr)
20112049
}
20122050
return r.saveFor(layer)
20132051
}
20142052

2053+
// Requires startWriting.
2054+
// Caller MUST run CleanupTemporaryDirectories() after this. Ideally outside of
2055+
// the startWriting.
2056+
func (r *layerStore) DeferredDelete(id string) (tempdir.CleanupTempDirFunc, error) {
2057+
layer, ok := r.lookup(id)
2058+
if !ok {
2059+
return nil, ErrLayerUnknown
2060+
}
2061+
id = layer.ID
2062+
// The layer may already have been explicitly unmounted, but if not, we
2063+
// should try to clean that up before we start deleting anything at the
2064+
// driver level.
2065+
for {
2066+
_, err := r.unmount(id, false, true)
2067+
if err == ErrLayerNotMounted {
2068+
break
2069+
}
2070+
if err != nil {
2071+
return nil, err
2072+
}
2073+
}
2074+
cleanFunc, err := r.deleteInternal(id)
2075+
if err != nil {
2076+
return cleanFunc, err
2077+
}
2078+
return cleanFunc, r.saveFor(layer)
2079+
}
2080+
20152081
// Requires startReading or startWriting.
20162082
func (r *layerStore) Exists(id string) bool {
20172083
_, ok := r.lookup(id)

0 commit comments

Comments
 (0)