Commit Graph

230 Commits

Author SHA1 Message Date
Nalin Dahyabhai b0c1c886c3 "pull up" images when creating them, too
We previously started "pulling up" images when we changed their names,
and started denying the presence of images in read-only stores which
shared their ID with an image in the read-write store, so that it would
be possible to "remove" names from an image in read-only storage.  We
forgot about the Flags field, so start pulling that up, too.

Do all of the above when we're asked to create an image, since denying
the presence of images with the same ID in read-only stores would
prevent us from finding the image by any of the names that it "had" just
a moment before we created the new record.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2023-04-06 18:21:11 -04:00
Nalin Dahyabhai 0f2bccfa56 Complete "pulling up" of images in updateNames()
When updateNames() copies an image's record from a read-only store into
the read-write store, copy the accompanying data as well.

Add fields for setting data items at creation-time to LayerOptions,
ImageOptions, and ContainerOptions to make this easier for us and our
consumers.

Replace the store-specific Create() (and the one CreateWithFlags() and
Put()) with private create() and put() methods, since they're not
intended for consumption outside of this package, and add Flags to the
options structures we pass into those methods.  In create() methods,
make copies of those passed-in options structures before modifying any
of their contents.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2023-03-31 10:36:30 -04:00
Daniel J Walsh 0ee26255cd
Run codespell on codebase
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2023-02-09 12:27:59 -05:00
Nalin Dahyabhai 6d91bc12f3 cmd: add a CLI wrapper for GarbageCollect
Add "gc" as an action for the CLI wrapper, for running the
GarbageCollect() method.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2023-01-26 16:09:00 -05:00
Miloslav Trmač ffeaed8fa4 Optimize the "no changes" case of layerStore.startReading further
In that case, we can just get read locks, confirm that nothing has changed,
and continue; no need for any serialization on exclusively holding
loadMut / inProcessLock.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-01-04 00:29:39 +01:00
Miloslav Trmač 717d171f22 Rework in-process concurrency control of layerStore
Instead of basing this on exclusivity loading via loadMut (which was incorrect,
because contrary to the original design, the r.layerspathModified
check in r.Modified() could trigger during the lifetime of a read lock)
use a very traditional read-write lock to protect the fields of imageStore.

Also explicitly document how concurrent access to fields of imageStore
is managed.

Note that for the btrfs and zfs graph drivers, Diff() can trigger
Mount() and unmount() in a way that violates the locking design.
That's not fixed in this PR.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-01-04 00:29:27 +01:00
Miloslav Trmač d173b026cb Annotate layerStore methods with the required lock access
Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-01-04 00:29:27 +01:00
Miloslav Trmač 4950eef972 Don't fix, just document, a locking bug
This should be fixed, it just seems too hard to do without
breaking API (and performance).

So, just be clear about that to warn future readers.

It's tracked in https://github.com/containers/storage/issues/1379 .

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-01-04 00:29:26 +01:00
Miloslav Trmač 16b28bae49 Don't reload the mount data in ParentOwners and Mounted
We can't safely do that because the read-only callers don't allow us
to write to layerStore state.

Luckily, with the recent changes to Mounted, we don't really need to
reload in those places.

Also, fairly extensively document the locking design or implications
for users.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-01-04 00:29:26 +01:00
Miloslav Trmač 845c2f4a30 Eliminate racy uses of Layer.MountCount
Instead of reading that value, releasing the mount lock,
and then unmounting, provide a "conditional" unmount mode.
And use that in the existing "loop unmounting" code.

That's at least safer against concurrent processes unmounting
the same layer. But the callers that try to "really unmount"
the layer in a loop are still possibly racing against other processes
trying to mount the layer in the meantime.

I'm not quite sure that we need the "conditional" parameter as an
explicit choice; it seems fairly likely that Umount() should just fail
with ErrLayerNotMounted for all !force callers. I chose to use the flag
to be conservative WRT possible unknown constraints.

Similarly, it's not very clear to me that the unmount loops need to exist;
maybe they should just be unmount(force=true, conditional=true).

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2023-01-03 23:47:16 +01:00
Alexander Larsson e546955f90 layer store: Don't reload the layer store after we save it
The lockfile we use propertly handles the case that we Touch() it. In
other words, a later Modified() call will return false.

However, we're also looking at the mtime, which was failing. This
uses the new AtomicWriteFileWithOpts() feature to also record the
mtime of the file we write on updates.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
2022-12-09 08:57:13 +01:00
Miloslav Trmač ac110ce1be Fix locking in store.canUseShifting
This was using the graphDriver field without locks, and the graph driver itself,
while the implementation assumed exclusivity.

Luckily all callers are actually holding the layer store lock for writing, so
use that for exclusion. (layerStore already seems to extensively assume
that locking the layer store for writing guarantees exclusive access to the graph driver,
and because we always recreate a layer store after recreating the graph driver,
that is true in practice.)

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-12-05 18:50:13 +01:00
Miloslav Trmač 55d11a0389 Make change tracking error-resilient
Only update recorded LastWrite values _after_ we succesfully reload
container/image/layer stores; so, if the reload fails, the functions
will keep failing instead of using obsolete (and possibly partially loaded
and completely invalid) data.

Also, further improve mount change tracking, so that if layerStore.load()
loads it, we don't reload it afterwards.

This does not change the store.graphLock users; they will need to be cleaned up
more comprehensively, and separately, in the future.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-29 18:12:43 +01:00
Miloslav Trmač b8bcdf7681 Improve mounts reloads
If the mounts file is changed, don't reload all of the layers
as well. This is more efficient, and it will allow us to better
track/update r.lastWrite and r.mountsLastWrite in the future.

Exiting code calling reloadMountsIfChanged() indicates that this
must already be safe.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-29 18:12:43 +01:00
Miloslav Trmač b2d3379ed4 Deprecate *LockFile.Modified and *LockFile.Touch
They are a shared state across all users of the *LockFile in the process,
and therefore incorrect to use for any single consumer for change tracking.

Direct users to user the new GetLastWrite, ModifiedSince, and RecordWrite,
instead, and convert all c/storage users.

In addition to just being correct, the new API is also more efficient:
- We now initialize stores with GetLastWrite before loading state;
  so, we don't trigger an immediate reload on the _second_ use of a store,
  due to the problematic semantics of .Modified().
- Unlike Modified() and Touch(), the new APi can be safely used without
  locking *LockFile.stateMutex, for a tiny speedup.

The conversion is, for now, trivial, just immediately updating the lastWrite
value after the ModifiedSince call.  That will get better.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-29 18:12:43 +01:00
Miloslav Trmač b74fdf4d23 Convert all c/storage users of Locker to *lockfile.LockFile
This will allow us to benefit from new features.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-29 18:12:43 +01:00
Miloslav Trmač f1c6fb0ce7 Factor out layerStore.reloadMountsIfChanged
... so that we don't need to update 4 separate copies.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-29 18:12:43 +01:00
Miloslav Trmač d24b8c5a13 Fix layerStore.saveLayers
- Don't exit after saving only one of the locations
- Only touch the lock once if saving both of the locations

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-29 18:12:43 +01:00
Alexander Larsson ddf18d41da Add Store.GarbageCollect() method
This looks in the container store for existing data dirs with ids not in
the container files and removes them. It also adds an (optional) driver
method to list available layers, then uses this and compares it to the
layers json file and removes layers that are not references.

Losing track of containers and layers can potentially happen in the
case of some kind of unclean shutdown, but mainly it happens at reboot
when using transient storage mode. Such users are recommended to run
a garbage collect at boot.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
2022-11-14 16:36:30 +01:00
Alexander Larsson 58bf1c03e4 layer store: Handle volatile and transient layer
We store information about the layers in two files, layers.json and
volatile-layers.json. This allows us to treat the two stores
differently, for example saving the volatile json with the NoSync
option, which is faster (but less robust).

In normal mode we store only layers for the containers that are marked
volatile (`--rm`), as these are not expected to persist anyway. This way
informantion about such containers are faster to save, and in case
of an unclean shutdown we only risk loss of information about other
such volatile containers.

In transient mode all container layers (but not image layers) are
stored in the volatile json, and additionally it is stored in tmpfs.
This improving performance as well as automatically making sure no
container layers are persisted across boots.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
2022-11-14 16:36:30 +01:00
Miloslav Trmač 7f6a670c44 Clean up inconsistent layer state in readers
... instead of failing for duplicate names, and instead of
ignoring the "incomplete" state of layers.

Try up to 3 times if other writers are creating inconsistent
state in the meantime.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-10 16:13:53 +01:00
Miloslav Trmač 48c7d2048f Be a bit more accurate about incomplete layer deletion
- In read-write stores, fail even readers if there are incomplete
  layers.  Right now that would increase observed failures (OTOH
  with better consistency), but we'll fix that again soon
- Decide whether to save read-write stores strictly based on
  the need to clean up, instead of cleaning up opportunistically
  (which is less predictable).
- Correctly return the right error, depending on whether there
  are duplicate layers

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-10 16:13:53 +01:00
Miloslav Trmač 859d1791b8 In load methods, track the inconsistency we want to fix
... as an error value instead of just a boolean.  That
will allow extending the logic to more kinds of inconsistencies,
and consolidates the specifics of the inconsistency knowledge
into a single place.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-10 16:13:53 +01:00
Miloslav Trmač 765414fbdb Use the simplest possible error handling flow in reloadIfChanged
... instead of combining control flow branches; we will change
behavior on some of them.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-11-10 16:13:53 +01:00
Miloslav Trmač f6776bf5dc Remove always-true err == nil checks
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-25 20:54:12 +02:00
Miloslav Trmač 68ec0a1202 Don't silently ignore failures to delete incomplete layers
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-25 20:51:24 +02:00
Miloslav Trmač 7c5820ae1d Don't silently ignore failures to decode metadata JSON
Also tighten the scope of some error variables a bit.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-25 20:50:23 +02:00
Miloslav Trmač 8e270346d0 Modify layerStore not to rely on lockfile.Locked()
Instead, have the callers of ReloadIfChanged provide the
locking state.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-21 21:10:33 +02:00
Miloslav Trmač 5c6186fe81 Fix {layerStore,imageStore}.startWriting()
This is a bad bug: we wouldn't reload state from disk
at all in writers.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-19 06:35:44 +02:00
Miloslav Trmač d0ad132945 Move layerStore.{ReloadIfChanged,Modified}
.. to be closer to the lock / load set of methods.

Only moves unchanged code, should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:40:00 +02:00
Miloslav Trmač dbe5fe3059 Remove Lock/Unlock methods from layerStore
They are now only used in the constructors, so use a variant
of startReading/startWriting instead.  This code path is not
performance-critical, so let's share as much code as possible
to ensure consistency in locking.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:33 +02:00
Miloslav Trmač d2defdb9fa Remove Save() from rwLayerStore API
It is done implicitly by all writers already.

Also fix the documentation not to point at an explicit Touch(),
which is not actually necessary.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:27 +02:00
Miloslav Trmač 328ccce601 Remove Load() and ReloadIfChanged() from roLayerStore API
Callers should just use startReading/startWriting.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:27 +02:00
Miloslav Trmač ee9708644f Remove Modified() from the roLayerStore API
It is an internal helper for ReloadIfChanged, with
no external users.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:27 +02:00
Miloslav Trmač 5791a561df Remove unused lockfile forwarders from roLayerStore API
The only callers are internal, have them access r.lockfile directly.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:27 +02:00
Miloslav Trmač 124e526285 Remove a completely unused method from roLayerStore
Exposing the internals of the lock is not necessary, and exposes
too many implementation details.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač c935245fe4 Move the writing lock methods from roLayerStore to rwLayerStore
... for a bit of extra safety.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač f9678cd44b Replace layerStore.{Lock,Unlock} with {startWriting,stopWriting}
This integrates ReloadIfChanged, and makes it clearer that the responsibility
for maintaining locking details is with the layerStore; we can change it
in a single place.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač c4089b6e3d Replace layerStore.{RLock,Unlock} with {startReading,stopReading}
This integrates ReloadIfChanged, and makes it clearer that the responsibility
for maintaining locking details is with the layerStore; we can change it
in a single place.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Miloslav Trmač d5b48bef6e Copy methods from included interfaces directly into *LayerStore
... so that we can modify/replace them.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-17 21:39:19 +02:00
Daniel J Walsh d02a89afb6
Merge branch 'main' into warnings 2022-10-14 13:46:03 -04:00
Miloslav Trmač 703cbe965b Simplify the name update call stack
Instead of going
	3 store methods
	store.updateNames+enum
	3 sub-store methods
	subStore.updateNames+enum
	applyNameOperation+enum,
simplify to
	3 store methods
	store.updateNames+enum
	subStore.updateNames+enum
	applyNameOperation+enum,

Should not change behavior. Looking purely at updateNameOperation,
invalid values would now be detected after doing more work,
but there is no way for an external caller to trigger use of
an invalid value anyway.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-14 17:23:08 +02:00
Miloslav Trmač 5e410ef763 Misc individual warning fixes
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-14 17:17:53 +02:00
Daniel J Walsh 714f4fc6e8
Merge pull request #1380 from mtrmac/misc
Two misc. cleanups
2022-10-13 10:36:30 -04:00
Miloslav Trmač 487febfe07 Remove unused layerStore.LoadLocked
Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-11 19:29:37 +02:00
Miloslav Trmač b157e14dd0 Remove completely unused *Store.Lookup() methods
Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-11 19:29:02 +02:00
Miloslav Trmač 821084ee68 Make all the various *Store interfaces, apart from storage.Store, private
There is no public way to obtain implementations of these interfaces; so
replace the public interfaces with private ones, to make it clear that we
_can_ modify them.

For formal API compatibility, preserve the old interface definitions
as copies.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-11 19:25:19 +02:00
Miloslav Trmač e2b1c19e34 Remove unused uidMap and gidMap fields from layerStore
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-11 19:19:55 +02:00
Miloslav Trmač 082a8161ed Remove lockfile.Locker.RecursiveLock
It is not valid as currently implemented, and there is no known user.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-07 19:45:14 +02:00
Miloslav Trmač c3dc83d3c2 Handle errors when compressing (or reading) layer diffs
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-01 02:53:06 +02:00
Miloslav Trmač 74931e97b0 Add missing error handling on error recovery paths
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-01 02:53:04 +02:00
Miloslav Trmač 9ca93b641f r.mountsLockfile.Touch() directly in saveMounts()
... instead of doing it in callers.

This makes it clearer that the Touch() always happens,
and it adds error handling.

OTOH there might be some undocumented reason why the Touch()
should happen in callers even if the saveMounts() call is
not reached.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-01 02:46:53 +02:00
Miloslav Trmač a02dbdbfa1 Only touch lock files after successful JSON writes
AtomicWriteFile truly is atomic, it only changes the file
on success. So there's no point notifying other processes about
a changed file if we failed, they are going to see the same JSON data.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-01 02:46:52 +02:00
Miloslav Trmač fb2df5d9fd Replace uses of deprecated functions from opencontainers/selinux/go-selinux/label
That also avoids warnings about missing error checks.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-01 02:46:52 +02:00
Miloslav Trmač d1de06c839 Be explicit about how we ignore errors using trucindex.TruncIndex
This does not change behavior, it just makes it clearer
what is going on.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-10-01 02:46:52 +02:00
Mikhail Khachayants e35b061b85 Fix accessing to layer without lock
There was a possibility to panic due to such behavior:
attempted to update last-writer in lockfile without the write lock

Fixes: https://github.com/containers/storage/issues/1324

Signed-off-by: Mikhail Khachayants <tyler92@inbox.ru>
2022-09-21 17:27:23 +04:00
Nalin Dahyabhai 627c202718 layers.Wipe(): try to remove layers before their parents
When removing layers, try to remove layers before removing their
parents, as the lower-level driver may enforce the dependency beyond
what the higher-level logic does or knows.

Do this by sorting by creation time as an attempt at flattening the
layer tree into an ordered list.  It won't be correct if a parent layer
needed to be recreated, but it's more likely to be correct otherwise.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2022-09-14 12:30:55 -04:00
Miloslav Trmač a1ccc9d862 Use os.WriteFile instead of ioutil.WriteFile
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-09-12 16:31:34 +02:00
Miloslav Trmač 4b28197720 Use os.ReadFile instead of ioutil.ReadFile
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-09-12 16:30:43 +02:00
Miloslav Trmač 20b101467b Only read the result of os.Stat if err == nil
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-09-09 18:43:03 +02:00
Miloslav Trmač b5a28e2648 Update layerspathModified before reading the contents
... to ensure that any changes after we start reading
the data trigger a future reload.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-09-09 18:42:32 +02:00
Mikhail Khachayants a360de27f3
Fix data race between ReloadIfChanged and read-only usage of layerStore
There was a race condition if a goroutine accessed to layerStore public
methods under RO lock and at the same time ReloadIfChanged was called.
In real life, it can occurr when there are two concurrent PlayKube
requests in Podman.

Signed-off-by: Mikhail Khachayants <tyler92@inbox.ru>
2022-09-05 19:40:17 +03:00
Daniel J Walsh 3f8c0dc0de
Wrap errors properly with fmt.Errorf
Also returned errors should not begine with a capatalized errors.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2022-07-12 13:26:10 -04:00
Sascha Grunert 3455d12729
Switch to golang native error wrapping
We now use the golang error wrapping format specifier `%w` instead of the
deprecated github.com/pkg/errors package.

Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
2022-07-07 13:22:46 +02:00
Miloslav Trmač 70cd76bfb0 Create a persistent record of an incomplete layer before creating it
... so that it can be also automatically cleaned up.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-04-22 16:07:46 +02:00
Miloslav Trmač c7ae082b70 Consolidate the error handling cleanup into a defer
... so that we don't repeat it all over the place.

Introduce a pretty ugly cleanupFailureContext variable
for that purpose; still, it's better than copy&pasting everything.

This will be even more useful soon.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-04-22 16:07:46 +02:00
Miloslav Trmač ce3c7ffbd2 Don't use named return values in layerStore.Put
We will need want to refer to "layer" in a defer
block, in order to delete that layer. That doesn't work
with "layer" being a named return value, because a
(return nil, -1, ...) sets "layer" to nil.

So, turn "layer" into a local variable, and use an unnamed
return value. And beause all return values must be named,
or unnamed, consistently, turn "size" and "err" also into
local variables.

Then decrease the scope of the "size" and "err" local variables
to simplify understanding the code a bit.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-04-22 16:07:46 +02:00
Miloslav Trmač e25b3d4baf Always use layerStore.Delete when recovering from failures
... so that we also remove the layer from layerStore.layers
and the like.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-04-22 16:07:46 +02:00
Miloslav Trmač 99789d119a Always save an "incomplete" layer record first
For now, this only causes two redundant saves for
non-tarball layers, which is not useful; but it will allow
us to build infrastructure for saving the incomplete record
much earlier.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-04-22 16:07:46 +02:00
Miloslav Trmač f8454e82b6 Remove a redundant check
err must be nil at that point.

This also un-indents the success case, so that
it proceeds as a straight-line code.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-04-22 16:07:46 +02:00
Nalin Dahyabhai 2de654ba2c layerStore.Put(): update digest-based indexes when creating from templates
When we're creating a layer using another layer as a template, add the
new layer's uncompressed and compressed digest to the maps we use to
index layers using those digests.

When we forgot to do that, searching for a layer by either would still
turn up the original template, so this didn't really break anything.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2022-04-18 15:11:38 -04:00
Nalin Dahyabhai 861436bbe8 layerStore.PutAdditionalLayer(): fix a copy/paste error
We mistakenly mixed up the uncompressed and compressed digests when
populating the by-uncompressed-digest map.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2022-04-18 15:10:56 -04:00
Nalin Dahyabhai d76b3606fc Fully populate layer records for mapped image top layers
When we create a copy of an image's top layer that's intended to be
identical to the top layer, except for having some set of ID mappings
already applied to it, copy over the template layer's compressed and
uncompressed digest and size information, compression information,
tar-split data, and lists of used UIDs and GIDs, if we have them.

The lack of sizing information was forcing ImageSize() to regenerate the
diffs to determine the size of the mapped layers, which shouldn't have
been necessary.

Teach the overlay DiffGetter to look for files in the diff directories
of lower layers if we can't find them in the current layer, so that
tar-split can retrieve content that we didn't have to pull up.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2022-04-12 15:39:51 -04:00
Aditya R 4c37491c64
store: add independent AddNames and RemoveNames for images,layers,containers
Adds AddNames and RemoveNames so operations which are invoked in parallel
manner can use it without destroying names from storage.

For instance

We are deleting names which were already written in store.
This creates faulty behavior when builds are invoked in parallel manner, as
this removes names for other builds.

To fix this behavior we must append to already written names and
override if needed. But this should be optional and not break public API

Following patch will be used by parallel operations at podman or buildah end, directly or indirectly.

Signed-off-by: Aditya R <arajan@redhat.com>
2022-03-01 01:33:35 +05:30
Miloslav Trmač 5654974253 Warn if we are deleting an incomplete layer
... to help diagnosing later possible broken references
to this layer; compare https://github.com/containers/storage/issues/1136 .

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-02-23 13:56:14 +01:00
Giuseppe Scrivano d79d62e8dd
Merge pull request #1146 from mtrmac/remove-dead-id
Remove dead code
2022-02-22 14:46:25 +01:00
Miloslav Trmač 05075bab21 Fix a pasto from #1138
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-02-22 01:32:02 +01:00
Miloslav Trmač c89fbcf121 Remove dead code
id is known to be non-empty because we generate
a random value earlier in the function, in that case.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-02-22 00:21:11 +01:00
Miloslav Trmač f3e5d1ff6c Try to delete also the metadata of an incomplete layer
Account for the "diff != nil" path; try to remove even
the metadata of a layer on a failure saving.

Not that there's _much_ hope to be able to save
the version without the new layer when we weren't able
to save the version with the new layer.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-02-16 22:32:32 +01:00
Miloslav Trmač 52a44fbf6d Log all kinds of failures to delete a layer
Currently, if the attempts to recover from a failure
themselves fail, we don't record that at all.

That makes diagnosing the situation, or hypothetically
detecting that the cleanup could never work, much
harder.

So, log the errors.

Alternatively, we could include those failures as extra
text in the returned error; that's less likely to be lost
(e.g. a Go caller would have the extra text available, without
setting up extra infrastructure to capture logs), but possibly
harder to follow.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-02-16 22:30:31 +01:00
Miloslav Trmač 956af18716 Mark a layer to be deleted on cleanup before instructing the graph driver
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-02-12 01:18:05 +01:00
Miloslav Trmač 5e12c7a897 Extract layerHasIncompleteFlag from layerStore.Load
Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2022-02-12 01:18:05 +01:00
Nalin Dahyabhai e5ea934de0 layerStore.Diff(): don't use an unnecessary buffer
Don't ReadAll() from a Reader to create a buffer and then create another
Reader to read from that buffer.

Don't close a file and a decompressor that we're using to read the
file's contents when we we may still need to read from them after the
current function returns.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2021-12-13 13:14:11 -05:00
Daniel J Walsh 534b0b3281
Standardize on capatalized logrus messages, and remove stutters
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-09-23 14:43:35 -04:00
Miloslav Trmač dc64cb6547 Add LayerOptions.OriginalDigest and LayerOptions.UncompressedDigest
This allows callers of Store.PutLayer to provide the values if
they have already computed them, so that ApplyDiff does not need
to compute them again.

This could quite significantly reduce CPU usage.

The code is a bit clumsy in the use of compressedWriter; it
might make sense to implement a ReadCounter counterpart to the
existing WriteCounter.

(Note that it remains the case that during pulls, both c/image/storage
and ApplyDiff decompress the stream; c/image/storage stores the
compressed, not the decompressed, version in a temporary file.
Nothing changes about that here - it's not obvious that changing it
is worth it, and anyway it's a different concept for a different
PR/discussion.)

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-08-21 18:30:42 +02:00
Miloslav Trmač acd9a24f98 Reorganize uncompressedCounter
Have it count the input to idLogger instead of uncompressedDigester;
they should get exactly the same data, but we are going to make
uncompressedDigester optional.

Also make the uncompressedDigester use a separate line so that we
can later change it more easily.

Should not change (observable) behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-08-21 18:30:42 +02:00
Miloslav Trmač 0182717ec6 Only compute {un,}compressedDigester.Digest() once
It is a tiny bit expensive, but most importantly
this moves the uses of {un,}compressedDigester so that
we can later make them optional.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-08-21 18:30:42 +02:00
Miloslav Trmač 12ac28b3d7 Reorganize the "defragmented" reader construction a bit.
Have one section deal with detecting compression and re-assembling
the original stream, and another with computing the length and digest
of the original stream.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-08-21 18:30:42 +02:00
Miloslav Trmač bfe784b920 Rename {un,}compressedDigest to {un,}compressedDigester
We will need ...Digest variables to hold the actual values.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2021-08-21 18:30:42 +02:00
Daniel J Walsh 8a026ab8b4
Merge pull request #990 from rhatdan/main
Add codespell fixes
2021-08-12 06:40:40 -04:00
Daniel J Walsh 28b7592b36
Add codespell fixes
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2021-08-11 16:46:21 -04:00
Nalin Dahyabhai 885552f8fc ApplyDiff: compress saved headers without concurrency
When we're applying a diff, we compress the headers and stash them
elsewhere so that we can use them to correctly reconstruct the layer if
we need to extract its contents later.

By default, the compression uses a 1MB block, and up to GOMAXPROCS
threads, which results in allocating GOMAXPROCS megabytes of memory up
front.  That can be much more than we need, especially if the system has
many, many cores.  Drop it down to 1 megabyte.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2021-08-11 16:10:46 -04:00
Sascha Grunert f637c5e250
Reload layer storage if layers.json got externally modified
This helps long running processes like CRI-O to determine changes to the
local storage, while handling corrupted images automatically.

The corresponding fix in Podman [0] handles corrupt layers by reloading
the image. This does not work for CRI-O, because it will not reload the
storage on subsequent calls of pullImage if no storage modification has
been done.

[0]: b4bd886fcc

Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
2021-06-17 13:16:48 +02:00
Daniel J Walsh 5477b9995b
Merge pull request #926 from giuseppe/fix-race-reload-store
store: fix graphLock reload
2021-05-27 12:26:57 -04:00
Giuseppe Scrivano abb54202ce
store: ReloadIfChanged propagates errors from Modified()
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2021-05-27 14:55:42 +02:00
Valentin Rothberg b57567e7ba delete_internal: return error early
Return the error early instead of having big branch to improve
readability of the code.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2021-05-27 10:39:02 +02:00
ktock 2bb8cde363 Enable to export layers from Additional Layer Store
Currently, layers aquired from additional layer store cannot be exported
(e.g. `podman save`, `podman push`).

This is because the current additional layer store exposes only *extracted view*
of layers. Tar is not reproducible so the runtime cannot reproduce the tar
archive that has the same diff ID as the original.

This commit solves this issue by introducing a new API "`blob`" to the
additional layer store. This file exposes the raw contents of that layer. When
*(c/storage).layerStore.Diff is called, it acquires the diff contents from this
`blob` file which the same digest as the original layer.

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
2021-05-15 10:38:39 +09:00
Daniel J Walsh 4f69205462
Merge pull request #775 from giuseppe/zstd-chunked
Enable zstd:chunked support in containers/image
2021-05-14 16:11:58 -04:00
Giuseppe Scrivano 0f5231b7bb
store: new method ROFileBasedStore.ReloadIfChanged()
add a new method to reload the store information from the hard disk if
has changed.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2021-05-13 09:05:42 +02:00
Giuseppe Scrivano c2a5fd1bb7
drivers: add interface to directly write diff
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2021-05-07 11:29:25 +02:00