Commit Graph

230 Commits

Author SHA1 Message Date
Jan Rodák f9aef81079
Integrate the temporary directory into layer deletion
This enables deferred deletion of physical files outside of global locks, improving performance and reducing lock contention.

Signed-off-by: Jan Rodák <hony.com@seznam.cz>
2025-07-10 11:33:54 +02:00
Giuseppe Scrivano e8d7b9e061
drivers: Allow map-specific ID shifting decisions
The `SupportsShifting` method signature has been updated
to include `uidmap` and `gidmap` parameters.

Previously, a driver could only declare general support
for shifting.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2025-06-09 09:01:51 +02:00
Miloslav Trmač 59e6d24252 Use io.SeekStart instead of hard-coding 0.
Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2025-05-14 20:53:29 +02:00
Giuseppe Scrivano f5bdfdc07e
chunked: use temporary file for tar-split data
Replace the in-memory buffer with a O_TMPFILE file.  This reduces the
memory requirements for a partial pull since the tar-split data can be
written to disk.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2025-04-29 12:26:57 +02:00
openshift-merge-bot[bot] f1c4bdf1d7
Merge pull request #2306 from kolyshkin/modernize
Use `slices` and `maps` more where appropriate
2025-04-01 22:00:08 +00:00
openshift-merge-bot[bot] 6f4bc1fa7c
Merge pull request #2305 from kolyshkin/for-range
Use for range over integers
2025-04-01 21:57:19 +00:00
Kir Kolyshkin 73b194b8ed Use for range over integers
This form is available since Go 1.22 (see
https://tip.golang.org/ref/spec#For_range) and will probably be seen
more and more in the new code.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-03-31 15:39:12 -07:00
Kir Kolyshkin c3ff7f58df Use any instead of interface{}
It's available since Go 1.18 (see https://pkg.go.dev/builtin#any).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-03-31 15:37:25 -07:00
Kir Kolyshkin e2507ef9d7 layers: use slices.Sort
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2025-03-31 14:40:17 -07:00
Giuseppe Scrivano 11a5b7b098
layers: write read only layers to imagestore
when an imagestore is used, a R/O layer must be written to the
layers.json under the imagestore, not graphroot.

The lock on the imagestore is already taken through the
multipleLockFile{} mechanism in place.

Closes: https://github.com/containers/storage/issues/2257

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2025-02-20 09:24:55 +01:00
Sascha Grunert 7850f88e2d
Remove hashicorp dependencies
The dependencies are licensed under MPL-2.0 which is not allowed in the
CNCF.

https://github.com/cncf/foundation/blob/main/license-exceptions

https://github.com/cncf/foundation/blob/main/allowed-third-party-license-policy.md#cncf-allowlist-license-policy

Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
2025-02-03 09:52:24 +01:00
Giuseppe Scrivano a67a6556fb
store: new function Dedup()
expose a new API to deduplicate files in the images.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2024-12-09 16:41:59 +01:00
Paul Holzinger 99b0d2d423
store: correctly remove incomplete layers on load.
In go one should never modify a slice while also iterating over it at
the same time. This causes weird side effects as the underlying array
elements are shifted around without the range loop index knowing.
So if you delete a element the loop will then actually skip the next one
and theoretically access out of bounds on the last element which does
not panic but rather return the default zero type, nil here which then
causes the panic on layer.Flags == nil.

Here is a simple example to show the behavior:
func main() {
	slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	for _, num := range slice {
		if num == 5 {
			slice = slices.DeleteFunc(slice, func(n int) bool {
				return n == 5
			})
		}
		fmt.Println(num)
	}
}

The loop will not print 6, but then as last number it prints 0 (the
default zero type for an int).

Fixes #2184

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
2024-12-03 15:11:25 +01:00
Jan Rodák 43d00099b2
Refactor of copying maps
Removes the duplicate copy*Map function using the general function newMapFrom.
Reduces the allocation of empty maps using the copyMapPrefferingNil function.
This change may affect the behavior so that instead of an empty allocated map, a nil will be returned.

Signed-off-by: Jan Rodák <hony.com@seznam.cz>
2024-10-25 10:24:48 +02:00
Jan Rodák 8a4741b74d
Refactor operations with slices
Removes duplicate copy*Slice functions using a generic copy function
or replaces them with the slices.Clone function.
Also simplifies the stringSliceWithoutValue function.
These changes should not change the behavior.

Signed-off-by: Jan Rodák <hony.com@seznam.cz>
2024-10-25 10:23:12 +02:00
Miloslav Trmač 208aee3c9a Use the correct Go doc list syntax
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-10-16 00:34:54 +02:00
Miloslav Trmač 7eb4a104ef Explicitly differentiate between empty and missing tar-split
Empty tar-split shouldn't ever happen, but being precise
here doesn't hurt.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-10-14 20:10:07 +02:00
Miloslav Trmač 71fc790550 Don't set UncompressedSize on chunked pull
The current value obtained by summing the sizes of regular file contents
does not match the size of the uncompressed layer tarball.

We don't have a convenient source to compute the correct size
for estargz without pulling the full layer and defeating the point;
so we must allow for the size being unknown.

For recent zstd:chunked images, we have the full tar-split,
so we can compute the correct size; that will happen in
the following commits.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-10-14 20:10:07 +02:00
Jan Rodák 5537f8ab2d
Revert the use of the slices.Clone function
because it does not return nil when the slice length is 0.
This behavior caused the slices.Clone function to allocate
a unnecessary amount of memory when the slice length is 0,
and the c/common tests failed.

Signed-off-by: Jan Rodák <hony.com@seznam.cz>
2024-10-08 14:26:51 +02:00
Giuseppe Scrivano a315bbfa0c
drivers: drop unused args from ApplyDiffWithDiffer
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2024-09-19 09:33:27 +02:00
Giuseppe Scrivano e8ea2b2bb0
chunked: fix reuse of the layers cache
the global singleton was never updated, causing the cache to be always
recreated for each layer.

It is not possible to keep the layersCache mutex for the entire load()
since it calls into some store APIs causing a deadlock since
findDigestInternal() is already called while some store locks are
held.

Another benefit is that now only one goroutine can run load()
preventing multiple calls to load() to happen in parallel doing the
same work.

Closes: https://github.com/containers/storage/issues/2023

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2024-09-19 09:33:27 +02:00
Miloslav Trmač 35b3e0f41b Avoid unnecessary manually-coded loops
Use the "slices", "maps" standard library packages, or other
readily-available features.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-09-05 19:45:45 +02:00
Miloslav Trmač 1fa3161756 Use slices.Delete* instead of manual append
Conservatively use Index* + Delete to delete the
first element where it's not obvious that the code would really
want to delete all instances.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-09-05 19:44:49 +02:00
Miloslav Trmač 751c13d2a0 Use slices.Clone where appropriate
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-09-05 19:44:47 +02:00
Miloslav Trmač 74c273e30a Be clearer about the layer store locking rules
... as modified by https://github.com/containers/storage/pull/2036 .

Also document a LOCKING BUG I don't now care to fix.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-08-30 16:38:22 +02:00
Giuseppe Scrivano 28cba3014b
chunked: store compressed digest if validated
if the compressed digest was validated, as it happens when
'pull_options = {convert_images = "true"}' is set, then store it as
well so that reusing the blob by its compressed digest works.

Previously, when an image converted to zstd:chunked was pulled a
second time, it would not be recognized by its compressed digest,
resulting in the need to re-pull the image again.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2024-07-10 09:41:41 +02:00
Giuseppe Scrivano 0ab61dfb6c
store: lock both graphroot and the imagestore root
when an image store is used, lock it as well as the graphroot.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2024-02-29 16:35:58 +01:00
Giuseppe Scrivano f31412a314
layers: add infra to lock multiple files
this is a preparation for the next commit, which will use this feature.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2024-02-29 16:34:29 +01:00
Miloslav Trmač 41a2f9d942 Save our layer before calling SetBigData and other large I/O
SetBigData itself calls saveFor; so doing that before raises
fewer questions about stale data / stepping over each other.

The change in timing is externally-observable, but should hopefully
not matter much in practice, because this code is typically called
from layerStore.create as a part of an atomic create+populate operation
proptected by incompleteFlag.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-02-26 21:04:14 +01:00
Giuseppe Scrivano 21ed482eca
store: new API ApplyStagedLayer
Add a race-condition-free alternative to using CreateLayer and
ApplyDiffFromStagingDirectory, ensuring the store is locked for the
entire duration while the layer is being created and populated.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2024-02-15 21:57:00 +01:00
Giuseppe Scrivano c6de01cf31
driver: simplify ApplyDiffFromStagingDirectory
enforce that the stagingDirectory must have the same value as the
diffOutput.Target variable.  It allows to simplify the internal API.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2024-02-15 21:56:59 +01:00
Miloslav Trmač 2ca0e2772a Add LayerOptions.OriginalSize
This allows us to correctly set (CompresedDigest, CompressedSize)
when copying data from another layer; in that case we don't have the
compressed data, so computing the size from compressedCounter
sets an incorrect value.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-02-13 21:56:05 +01:00
Miloslav Trmač 52ab5bfec8 Optimize digest computation for uncompressed layers
When the caller provides neither OriginalDigest nor
UncompressedDigest, only digest the layer once.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2024-02-13 21:51:10 +01:00
Giuseppe Scrivano 17bc7c5bfb
overlay: inhibit filegetter with composefs
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2023-12-11 15:06:41 +01:00
Giuseppe Scrivano 15ac716f16
layers: add option to initialize layer Flags
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2023-12-04 16:58:13 +01:00
Giuseppe Scrivano f424bfcf9f
store: new struct to pass ApplyDiffWithDiffer opts
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2023-12-04 16:58:13 +01:00
Giuseppe Scrivano 106e2d1730
layers: add new TOCDigest attribute
introduce the TOCDigest field for a layer. TOCDigest is designed to
store the digest of the Table of Contents (TOC) of the blob.

It is useful when the UncompressedDigest cannot be validated during a
partial image pull, but the TOC itself is validated.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2023-12-04 16:58:13 +01:00
Miloslav Trmač 58bb75773b Don't call UpdateLayerIDMap when creating a layer with no parent
AFAICS this call is intended to "remap" the parent layer's contents to the
desired IDMappings; but when there is no parent layer, there is
nothing to remap.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-10-25 16:45:49 +02:00
Miloslav Trmač 339628c8f5 Shorten the scope of some variables
Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-10-25 16:45:37 +02:00
Giuseppe Scrivano 7bbf6ed448
chunked: generate tar-split as part of zstd:chunked
change the file format to store the tar-split as part of the
zstd:chunked image.  This will allow clients to rebuild the entire
tarball without having to download it fully.

also store the uncompressed digest for the tarball, so that it can be
stored into the storage database.

Needs: https://github.com/containers/image/pull/1976

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2023-06-17 00:31:39 +02:00
Nalin Dahyabhai 79b8f9401e compareCheckDirectory: learn about ID maps
Handle old-fashioned ID mappings when looking at layers.  Nowadays,
we'll use an idmapped mount if we can, but we shouldn't blow up if we
had to chown a layer because we couldn't use an idmapped mount.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2023-06-13 14:14:56 -04:00
Miloslav Trmač 02cb8ed5fe Ensure compressor.Close() is called on error paths
Reportedly this is showing up as leaked goroutines in CRI-O:
https://issues.redhat.com/browse/OCPBUGS-10290 .

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-06-13 02:17:30 +02:00
Miloslav Trmač f2a1367f54 Fix a race in use of tarlog.tarLogger
tarLogger calls the provided callback in a separate
goroutine, and that can happen after tarLogger.Write
returns; tarLogger.Close is requried to ensure the callbacks
have all been correctly called, and the created uidLog and gidLog
values can be consumed.

So, move most of the IO pipeline that is formed around the
layer stream into a nested function that terminates earlier, notably
so that the "defer idLogger.Close()" is called at the appropriate time.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-06-13 02:16:37 +02:00
Miloslav Trmač a6b3f79a56 Move some variable declarations upfront
We will want to move the next part of the code
into a closure; move variables that will be
accessed outside of that section.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-06-13 02:06:21 +02:00
Miloslav Trmač 867f763e81 Don't ignore pgzip.NewWriterLevel failures
AFAICS that can't fail with current pgzip; and
pgzip.NewWriter also calls NewWriteLevel, but it just
swallows the error.

Any failure would therefore be very unexpected;
report it instead of suppressing it.0

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-06-13 01:35:42 +02:00
Kir Kolyshkin a4d8f720a2 Format sources with gofumpt
gofumpt is a superset of gofmt, enabling some more code formatting
rules.

This commit is brought to you by

	gofumpt -w .

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2023-05-26 16:17:31 -07:00
Miloslav Trmač 96fd3ff643 Don't silently ignore errors decoding mountpoints.json
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-05-19 18:51:36 +02:00
Giuseppe Scrivano ed76ab945c
store: ensure lockfile is updated before writes
The lockfile's write record is now updated prior to the actual write
operation.  This ensures that, in the event of an unexpected
termination, other processes are correctly notified of an initiated
write operation.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2023-05-18 23:44:23 +02:00
Miloslav Trmač 90fa73079a Don't use bytes.NewBuffer to read data
The documentation says
> The new Buffer takes ownership of buf, and the
> caller should not use buf after this call.

so use the more directly applicable, and simpler, bytes.Reader
instead, to avoid this potentially risky use.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-04-14 22:34:53 +02:00
Nalin Dahyabhai d10c03bc3d Extend driver.ListLayers()
Implement ListLayers() for the aufs, btrfs, and devicemapper drivers,
along with a unit test for them.
Stop filtering out directories with names that aren't 64-hex chars in
vfs and overlay ListLayers() implementations, which is more a convention
than a hard rule.
Have layerStore.Wipe() try to remove remaining listed layers after it
removes the layers that the layerStore knew of.
Close() a dangling ReadCloser in NaiveCreateFromTemplate.
Switch from using plain defer to using t.Cleanup() to handle deleting
layers that tests create, have the addManyLayers() test function do so
as well.
Remove vfs.CopyDir, which near as I can tell isn't referenced anywhere.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2023-04-12 16:05:09 -04:00