WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d8c7b93
Add Protected field to volume configuration and data structures
tobwen Aug 14, 2025
e47cc07
Implement volume protection methods and creation options
tobwen Aug 14, 2025
0e4d810
Add runtime methods for protected volume handling and pruning
tobwen Aug 14, 2025
582a324
Add protected volume support to entity types and interfaces
tobwen Aug 14, 2025
5093a24
Implement protected volume filtering support
tobwen Aug 14, 2025
6c9fab0
Add protected volume support to ABI implementation
tobwen Aug 14, 2025
26df32d
Add HTTP API support for protected volumes
tobwen Aug 14, 2025
b338530
Add --protected flag to volume create command
tobwen Aug 14, 2025
c15a40f
Add volume protect/unprotect command
tobwen Aug 14, 2025
2a52a0e
Add --include-protected flag to volume rm command
tobwen Aug 14, 2025
a719edd
Add protected volume support to system prune command
tobwen Aug 14, 2025
a69f407
Add VolumeProtect stub implementation for tunnel/remote clients
tobwen Aug 16, 2025
3e91c2b
Fix volume pruning to respect include protected flag in system prune
tobwen Aug 16, 2025
13659c6
Rename term "protected" to "pinned"
tobwen Aug 16, 2025
82f8a07
Move Pinned field from VolumeConfig to VolumeState
tobwen Aug 18, 2025
0b22776
Update Pinned() method to read from state with proper locking
tobwen Aug 18, 2025
bd5c99f
Update remaining methods to use state.Pinned instead of config.Pinned
tobwen Aug 18, 2025
f474ae8
Rename Volume.Pinned() to Volume.IsPinned() for clarity
tobwen Oct 3, 2025
bce524b
Remove unused volume creation option and runtime method
tobwen Oct 3, 2025
21af724
Refactor volume creation to set pinned status after creation
tobwen Oct 3, 2025
8495adf
Add early return optimization to Volume.SetPinned()
tobwen Oct 3, 2025
488fbb9
Add support for pinned volumes in system reset operation
tobwen Oct 3, 2025
e9bfbee
Update documentation and comments to include system reset operations
tobwen Oct 3, 2025
8e637aa
Simplify system prune warning message generation
tobwen Oct 3, 2025
61fa665
Add support for including pinned volumes in reset
tobwen Oct 4, 2025
3260d5b
DOCS: Add volume pinning functionality
tobwen Oct 4, 2025
9de90a4
Bugfix for pinned volumes in system reset
tobwen Oct 4, 2025
09835ab
Update import paths from v5 to v6
tobwen Dec 11, 2025
afe78aa
Linting...
tobwen Dec 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/podman/common/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,7 @@ func AutocompleteVolumeFilters(cmd *cobra.Command, _ []string, toComplete string
"label=": nil,
"name=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
"opt=": nil,
"pinned=": getBoolCompletion,
"scope=": local,
"since=": getImg,
"until=": nil,
Expand Down
11 changes: 9 additions & 2 deletions cmd/podman/system/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ var (
ValidArgsFunction: completion.AutocompleteNone,
Example: `podman system prune`,
}
force bool
force bool
includePinned bool
)

func init() {
Expand All @@ -50,6 +51,7 @@ func init() {
flags.BoolVar(&pruneOptions.External, "external", false, "Remove container data in storage not controlled by podman")
flags.BoolVar(&pruneOptions.Build, "build", false, "Remove build containers")
flags.BoolVar(&pruneOptions.Volume, "volumes", false, "Prune volumes")
flags.BoolVar(&includePinned, "include-pinned", false, "Include pinned volumes in prune operation")
filterFlagName := "filter"
flags.StringArrayVar(&filters, filterFlagName, []string{}, "Provide filter values (e.g. 'label=<key>=<value>')")
_ = pruneCommand.RegisterFlagCompletionFunc(filterFlagName, common.AutocompletePruneFilters)
Expand Down Expand Up @@ -81,6 +83,11 @@ func prune(_ *cobra.Command, _ []string) error {
}
}

// Set the include pinned flag for volume pruning
if pruneOptions.Volume {
pruneOptions.VolumePruneOptions.IncludePinned = includePinned
}

// Remove all unused pods, containers, images, networks, and volume data.
pruneOptions.Filters, err = parse.FilterArgumentsIntoFilters(filters)
if err != nil {
Expand Down Expand Up @@ -137,7 +144,7 @@ func createPruneWarningMessage(pruneOpts entities.SystemPruneOptions) string {
}
return `WARNING! This command removes:
- all stopped containers
- all networks not used by at least one container%s%s
- all networks not used by at least one container%s%s (optionally including pinned volumes)
- all dangling images
- all dangling build cache

Expand Down
21 changes: 16 additions & 5 deletions cmd/podman/system/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/containers/buildah/pkg/volumes"
"github.com/containers/podman/v6/cmd/podman/registry"
"github.com/containers/podman/v6/cmd/podman/validate"
"github.com/containers/podman/v6/pkg/domain/entities"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"go.podman.io/common/pkg/completion"
Expand All @@ -19,7 +20,7 @@ import (
var (
systemResetDescription = `Reset podman storage back to default state

All containers will be stopped and removed, and all images, volumes, networks and container content will be removed.
All containers will be stopped and removed, and all images, volumes (excluding pinned volumes), networks and container content will be removed.
This command does not restart podman.service and podman.socket systemd units. You may need to manually restart it after running this command.
`
systemResetCommand = &cobra.Command{
Expand All @@ -32,7 +33,8 @@ var (
ValidArgsFunction: completion.AutocompleteNone,
}

forceFlag bool
forceFlag bool
resetIncludePinned bool
)

func init() {
Expand All @@ -42,6 +44,7 @@ func init() {
})
flags := systemResetCommand.Flags()
flags.BoolVarP(&forceFlag, "force", "f", false, "Do not prompt for confirmation")
flags.BoolVar(&resetIncludePinned, "include-pinned", false, "Include pinned volumes in reset operation")
}

func reset(_ *cobra.Command, _ []string) {
Expand All @@ -53,14 +56,19 @@ func reset(_ *cobra.Command, _ []string) {
// Prompt for confirmation if --force is not set
if !forceFlag {
reader := bufio.NewReader(os.Stdin)
fmt.Println(`WARNING! This will remove:
volumeMsg := " - all volumes (excluding pinned volumes)"
if resetIncludePinned {
volumeMsg = " - all volumes"
}
fmt.Printf(`WARNING! This will remove:
- all containers
- all pods
- all images
- all networks
- all build cache
- all machines
- all volumes`)
%s
`, volumeMsg)

info, _ := registry.ContainerEngine().Info(registry.Context())
// lets not hard fail in case of an error
Expand Down Expand Up @@ -93,7 +101,10 @@ func reset(_ *cobra.Command, _ []string) {
}

// ContainerEngine() is unusable and shut down after this.
if err := registry.ContainerEngine().Reset(registry.Context()); err != nil {
resetOptions := entities.SystemResetOptions{
IncludePinned: resetIncludePinned,
}
if err := registry.ContainerEngine().Reset(registry.Context(), resetOptions); err != nil {
logrus.Error(err)
}

Expand Down
6 changes: 6 additions & 0 deletions cmd/podman/volumes/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var (
Ignore bool
UID int
GID int
Pinned bool
}{}
)

Expand Down Expand Up @@ -68,6 +69,10 @@ func init() {
gidFlagName := "gid"
flags.IntVar(&opts.GID, gidFlagName, 0, "Set the GID of the volume owner")
_ = createCommand.RegisterFlagCompletionFunc(gidFlagName, completion.AutocompleteNone)

pinnedFlagName := "pinned"
flags.BoolVar(&opts.Pinned, pinnedFlagName, false, "Mark volume as pinned (excluded from system prune by default)")
_ = createCommand.RegisterFlagCompletionFunc(pinnedFlagName, completion.AutocompleteNone)
}

func create(cmd *cobra.Command, args []string) error {
Expand All @@ -92,6 +97,7 @@ func create(cmd *cobra.Command, args []string) error {
if cmd.Flags().Changed("gid") {
createOpts.GID = &opts.GID
}
createOpts.Pinned = opts.Pinned
response, err := registry.ContainerEngine().VolumeCreate(context.Background(), createOpts)
if err != nil {
return err
Expand Down
66 changes: 66 additions & 0 deletions cmd/podman/volumes/pin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package volumes

import (
"context"
"fmt"

"github.com/containers/podman/v6/cmd/podman/common"
"github.com/containers/podman/v6/cmd/podman/registry"
"github.com/containers/podman/v6/pkg/domain/entities"
"github.com/spf13/cobra"
)

var (
pinDescription = `Mark or unmark a volume as pinned.

Pinned volumes are excluded from system prune and system reset operations.`

pinCommand = &cobra.Command{
Use: "pin [options] VOLUME [VOLUME...]",
Short: "Mark or unmark volume as pinned",
Long: pinDescription,
RunE: pin,
ValidArgsFunction: common.AutocompleteVolumes,
Example: `podman volume pin myvol
podman volume pin --unpin myvol
podman volume pin vol1 vol2 vol3`,
}
)

var (
pinOptions = entities.VolumePinOptions{}
)

func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: pinCommand,
Parent: volumeCmd,
})
flags := pinCommand.Flags()
flags.BoolVar(&pinOptions.Unpin, "unpin", false, "Remove pinning from volume")
}

func pin(_ *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("must specify at least one volume name")
}

responses, err := registry.ContainerEngine().VolumePin(context.Background(), args, pinOptions)
if err != nil {
return err
}

for _, r := range responses {
if r.Err != nil {
fmt.Printf("Error pinning volume %s: %v\n", r.Id, r.Err)
} else {
if pinOptions.Unpin {
fmt.Printf("Volume %s is now unpinned\n", r.Id)
} else {
fmt.Printf("Volume %s is now pinned\n", r.Id)
}
}
}

return nil
}
4 changes: 3 additions & 1 deletion cmd/podman/volumes/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ var (
RunE: prune,
ValidArgsFunction: completion.AutocompleteNone,
}
filter = []string{}
filter = []string{}
pruneOptions = entities.VolumePruneOptions{}
)

func init() {
Expand All @@ -44,6 +45,7 @@ func init() {
flags.StringArrayVar(&filter, filterFlagName, []string{}, "Provide filter values (e.g. 'label=<key>=<value>')")
_ = pruneCommand.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteVolumeFilters)
flags.BoolP("force", "f", false, "Do not prompt for confirmation")
flags.BoolVar(&pruneOptions.IncludePinned, "include-pinned", false, "Do not prune pinned volumes")
}

func prune(cmd *cobra.Command, _ []string) error {
Expand Down
10 changes: 5 additions & 5 deletions cmd/podman/volumes/rm.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ var (
)

var (
rmOptions = entities.VolumeRmOptions{}
stopTimeout int
rmOptions = entities.VolumeRmOptions{}
stopTimeout int
includePinned bool
)

func init() {
Expand All @@ -45,6 +46,7 @@ func init() {
flags := rmCommand.Flags()
flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all volumes")
flags.BoolVarP(&rmOptions.Force, "force", "f", false, "Remove a volume by force, even if it is being used by a container")
flags.BoolVar(&includePinned, "include-pinned", false, "Include pinned volumes in removal operation")
timeFlagName := "time"
flags.IntVarP(&stopTimeout, timeFlagName, "t", int(containerConfig.Engine.StopTimeout), "Seconds to wait for running containers to stop before killing the container")
_ = rmCommand.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone)
Expand All @@ -62,6 +64,7 @@ func rm(cmd *cobra.Command, args []string) error {
timeout := uint(stopTimeout)
rmOptions.Timeout = &timeout
}
rmOptions.IncludePinned = includePinned
responses, err := registry.ContainerEngine().VolumeRm(context.Background(), args, rmOptions)
if err != nil {
if rmOptions.Force && strings.Contains(err.Error(), define.ErrNoSuchVolume.Error()) {
Expand All @@ -74,9 +77,6 @@ func rm(cmd *cobra.Command, args []string) error {
if r.Err == nil {
fmt.Println(r.Id)
} else {
if rmOptions.Force && strings.Contains(r.Err.Error(), define.ErrNoSuchVolume.Error()) {
continue
}
setExitCode(r.Err)
errs = append(errs, r.Err)
}
Expand Down
6 changes: 5 additions & 1 deletion docs/source/markdown/podman-system-prune.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ podman\-system\-prune - Remove all unused pods, containers, images, networks, an

Use the **--all** option to delete all unused images. Unused images are dangling images as well as any image that does not have any containers based on it.

By default, volumes are not removed to prevent important data from being deleted if there is currently no container using the volume. Use the **--volumes** flag when running the command to prune volumes as well.
By default, volumes are not removed to prevent important data from being deleted if there is currently no container using the volume. Use the **--volumes** flag when running the command to prune volumes as well. By default, pinned volumes are excluded from pruning even when **--volumes** is specified. Use the **--include-pinned** flag to include pinned volumes in the prune operation.

By default, build containers are not removed to prevent interference with builds in progress. Use the **--build** flag when running the command to remove build containers as well.

Expand Down Expand Up @@ -59,6 +59,10 @@ Do not prompt for confirmation

Print usage statement

#### **--include-pinned**

Include pinned volumes in the prune operation when **--volumes** is specified. By default, pinned volumes are excluded from pruning to protect important data. This flag only has an effect when **--volumes** is also used.

#### **--volumes**

Prune volumes currently unused by any container
Expand Down
6 changes: 6 additions & 0 deletions docs/source/markdown/podman-system-reset.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ podman\-system\-reset - Reset storage back to initial state
It also removes the configured graphRoot and runRoot directories. Make sure these are not set to
some important directory.

By default, pinned volumes are excluded from the reset operation to protect important data. Use the **--include-pinned** flag to include pinned volumes in the reset.

This command must be run **before** changing any of the following fields in the
`containers.conf` or `storage.conf` files: `driver`, `static_dir`, `tmp_dir`
or `volume_path`.
Expand All @@ -30,6 +32,10 @@ Do not prompt for confirmation

Print usage statement

#### **--include-pinned**

Include pinned volumes in the reset operation. By default, pinned volumes are excluded from the reset to protect important data.

## EXAMPLES

Reset all storage back to a clean initialized state.
Expand Down
11 changes: 10 additions & 1 deletion docs/source/markdown/podman-volume-create.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ This option is mandatory when using the **image** driver.

When not using the **local** and **image** drivers, the given options are passed directly to the volume plugin. In this case, supported options are dictated by the plugin in question, not Podman.

#### **--pinned**

Mark the volume as pinned. Pinned volumes are excluded from **podman system prune** and **podman system reset** operations by default, protecting them from accidental deletion during cleanup operations. The pinned status can be changed later using **podman volume pin**.

#### **--uid**=*uid*

Set the UID that the volume will be created as. Differently than `--opt o=uid=*uid*`, the specified value is not passed to the mount operation. The specified UID will own the volume's mount point directory and affects the volume chown operation.
Expand Down Expand Up @@ -137,6 +141,11 @@ Create volume overriding the owner UID and GID.
# podman volume create --uid 1000 --gid 1000 myvol
```

Create a pinned volume that is protected from system prune operations.
```
$ podman volume create --pinned datavol
```

Create image named volume using the specified local image in containers/storage.
```
# podman volume create --driver image --opt image=fedora:latest fedoraVol
Expand Down Expand Up @@ -214,7 +223,7 @@ If performance is the priority, please check out the more performant [goofys](ht


## SEE ALSO
**[podman(1)](podman.1.md)**, **[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)**, **[podman-volume(1)](podman-volume.1.md)**, **mount(8)**, **xfs_quota(8)**, **xfs_quota(8)**, **projects(5)**, **projid(5)**
**[podman(1)](podman.1.md)**, **[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)**, **[podman-volume(1)](podman-volume.1.md)**, **[podman-volume-pin(1)](podman-volume-pin.1.md)**, **mount(8)**, **xfs_quota(8)**, **xfs_quota(8)**, **projects(5)**, **projid(5)**

## HISTORY
January 2020, updated with information on volume plugins by Matthew Heon <[email protected]>
Expand Down
1 change: 1 addition & 0 deletions docs/source/markdown/podman-volume-inspect.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Valid placeholders for the Go template are listed below:
| .Status ... | Status of the volume |
| .StorageID | StorageID of the volume |
| .Timeout | Timeout of the volume |
| .Pinned | Whether the volume is pinned |
| .UID | UID the volume was created with |

#### **--help**
Expand Down
12 changes: 12 additions & 0 deletions docs/source/markdown/podman-volume-ls.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Volumes can be filtered by the following attributes:
| label | [Key] or [Key=Value] Label assigned to a volume |
| name | [Name] Volume name (accepts regex) |
| opt | Matches a storage driver options |
| pinned | [Bool] Matches volumes based on their pinned status (true/false) |
| scope | Filters volume by scope |
| after/since | Filter by volumes created after the given VOLUME (name or tag) |
| until | Only remove volumes created before given timestamp |
Expand Down Expand Up @@ -59,6 +60,7 @@ Valid placeholders for the Go template are listed below:
| .Status ... | Status of the volume |
| .StorageID | StorageID of the volume |
| .Timeout | Timeout of the volume |
| .Pinned | Whether the volume is pinned |
| .UID | UID of volume |
| .VolumeConfigResponse ... | Don't use |

Expand Down Expand Up @@ -99,6 +101,16 @@ List volumes with the label key=value.
$ podman volume ls --filter label=key=value
```

List all pinned volumes.
```
$ podman volume ls --filter pinned=true
```

List all non-pinned volumes.
```
$ podman volume ls --filter pinned=false
```

## SEE ALSO
**[podman(1)](podman.1.md)**, **[podman-volume(1)](podman-volume.1.md)**

Expand Down
Loading