aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiuseppe Scrivano <gscrivan@redhat.com>2022-04-28 11:39:12 +0200
committerMatthew Heon <matthew.heon@pm.me>2022-05-03 13:36:00 -0400
commite5d6b6b0a2cfdbb21506b8f5e741cf719c149cb4 (patch)
tree25b5d7c4451f702c7c7162116139ac6297888744
parent77f147468c4bf514dd5a2951a29128f226d1186c (diff)
downloadpodman-e5d6b6b0a2cfdbb21506b8f5e741cf719c149cb4.tar.gz
podman-e5d6b6b0a2cfdbb21506b8f5e741cf719c149cb4.tar.bz2
podman-e5d6b6b0a2cfdbb21506b8f5e741cf719c149cb4.zip
volume: add new option -o o=noquota
add a new option to completely disable xfs quota usage for a volume. xfs quota set on a volume, even just for tracking disk usage, can cause weird errors if the volume is later re-used by a container with a different quota projid. More specifically, link(2) and rename(2) might fail with EXDEV if the source file has a projid that is different from the parent directory. To prevent such kind of issues, the volume should be created beforehand with `podman volume create -o o=noquota $ID` Closes: https://github.com/containers/podman/issues/14049 Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
-rw-r--r--docs/source/markdown/podman-volume-create.1.md3
-rw-r--r--libpod/options.go13
-rw-r--r--libpod/runtime_volume_linux.go39
-rw-r--r--libpod/volume.go3
-rw-r--r--libpod/volume_internal.go3
-rw-r--r--pkg/domain/infra/abi/parse/parse.go5
-rwxr-xr-xtest/test_podman_baseline.sh22
7 files changed, 70 insertions, 18 deletions
diff --git a/docs/source/markdown/podman-volume-create.1.md b/docs/source/markdown/podman-volume-create.1.md
index 365a5acac..06fadcaa1 100644
--- a/docs/source/markdown/podman-volume-create.1.md
+++ b/docs/source/markdown/podman-volume-create.1.md
@@ -38,7 +38,8 @@ The `device` option sets the device to be mounted, and is equivalent to the `dev
The `o` option sets options for the mount, and is equivalent to the `-o` flag to **mount(8)** with these exceptions:
- The `o` option supports `uid` and `gid` options to set the UID and GID of the created volume that are not normally supported by **mount(8)**.
- - The `o` option supports the `size` option to set the maximum size of the created volume and the `inodes` option to set the maximum number of inodes for the volume. Currently these flags are only supported on "xfs" file system mounted with the `prjquota` flag described in the **xfs_quota(8)** man page.
+ - The `o` option supports the `size` option to set the maximum size of the created volume, the `inodes` option to set the maximum number of inodes for the volume and `noquota` to completely disable quota support even for tracking of disk usage. Currently these flags are only supported on "xfs" file system mounted with the `prjquota` flag described in the **xfs_quota(8)** man page.
+ - The `o` option supports .
- Using volume options other then the UID/GID options with the **local** driver requires root privileges.
When not using the **local** driver, the given options are passed directly to the volume plugin. In this case, supported options are dictated by the plugin in question, not Podman.
diff --git a/libpod/options.go b/libpod/options.go
index 57e2d7cf6..98eb45e76 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1634,6 +1634,19 @@ func WithVolumeNoChown() VolumeCreateOption {
}
}
+// WithVolumeDisableQuota prevents the volume from being assigned a quota.
+func WithVolumeDisableQuota() VolumeCreateOption {
+ return func(volume *Volume) error {
+ if volume.valid {
+ return define.ErrVolumeFinalized
+ }
+
+ volume.config.DisableQuota = true
+
+ return nil
+ }
+}
+
// withSetAnon sets a bool notifying libpod that this volume is anonymous and
// should be removed when containers using it are removed and volumes are
// specified for removal.
diff --git a/libpod/runtime_volume_linux.go b/libpod/runtime_volume_linux.go
index 241f6e2f2..f8788e183 100644
--- a/libpod/runtime_volume_linux.go
+++ b/libpod/runtime_volume_linux.go
@@ -73,7 +73,7 @@ func (r *Runtime) newVolume(options ...VolumeCreateOption) (_ *Volume, deferredE
return nil, errors.Wrapf(err, "invalid volume option %s for driver 'local'", key)
}
}
- case "o", "type", "uid", "gid", "size", "inodes":
+ case "o", "type", "uid", "gid", "size", "inodes", "noquota":
// Do nothing, valid keys
default:
return nil, errors.Wrapf(define.ErrInvalidArg, "invalid mount option %s for driver 'local'", key)
@@ -111,23 +111,28 @@ func (r *Runtime) newVolume(options ...VolumeCreateOption) (_ *Volume, deferredE
if err := LabelVolumePath(fullVolPath); err != nil {
return nil, err
}
- projectQuotaSupported := false
-
- q, err := quota.NewControl(r.config.Engine.VolumePath)
- if err == nil {
- projectQuotaSupported = true
- }
- quota := quota.Quota{}
- if volume.config.Size > 0 || volume.config.Inodes > 0 {
- if !projectQuotaSupported {
- return nil, errors.New("Volume options size and inodes not supported. Filesystem does not support Project Quota")
+ if volume.config.DisableQuota {
+ if volume.config.Size > 0 || volume.config.Inodes > 0 {
+ return nil, errors.New("volume options size and inodes cannot be used without quota")
}
- quota.Size = volume.config.Size
- quota.Inodes = volume.config.Inodes
- }
- if projectQuotaSupported {
- if err := q.SetQuota(fullVolPath, quota); err != nil {
- return nil, errors.Wrapf(err, "failed to set size quota size=%d inodes=%d for volume directory %q", volume.config.Size, volume.config.Inodes, fullVolPath)
+ } else {
+ projectQuotaSupported := false
+ q, err := quota.NewControl(r.config.Engine.VolumePath)
+ if err == nil {
+ projectQuotaSupported = true
+ }
+ quota := quota.Quota{}
+ if volume.config.Size > 0 || volume.config.Inodes > 0 {
+ if !projectQuotaSupported {
+ return nil, errors.New("volume options size and inodes not supported. Filesystem does not support Project Quota")
+ }
+ quota.Size = volume.config.Size
+ quota.Inodes = volume.config.Inodes
+ }
+ if projectQuotaSupported {
+ if err := q.SetQuota(fullVolPath, quota); err != nil {
+ return nil, errors.Wrapf(err, "failed to set size quota size=%d inodes=%d for volume directory %q", volume.config.Size, volume.config.Inodes, fullVolPath)
+ }
}
}
diff --git a/libpod/volume.go b/libpod/volume.go
index bffafdc15..ab461a37f 100644
--- a/libpod/volume.go
+++ b/libpod/volume.go
@@ -52,6 +52,9 @@ type VolumeConfig struct {
Size uint64 `json:"size"`
// Inodes maximum of the volume.
Inodes uint64 `json:"inodes"`
+ // DisableQuota indicates that the volume should completely disable using any
+ // quota tracking.
+ DisableQuota bool `json:"disableQuota,omitempty"`
}
// VolumeState holds the volume's mutable state.
diff --git a/libpod/volume_internal.go b/libpod/volume_internal.go
index 9850c2ea1..e0ebb729d 100644
--- a/libpod/volume_internal.go
+++ b/libpod/volume_internal.go
@@ -52,6 +52,9 @@ func (v *Volume) needsMount() bool {
if _, ok := v.config.Options["SIZE"]; ok {
index++
}
+ if _, ok := v.config.Options["NOQUOTA"]; ok {
+ index++
+ }
// when uid or gid is set there is also the "o" option
// set so we have to ignore this one as well
if index > 0 {
diff --git a/pkg/domain/infra/abi/parse/parse.go b/pkg/domain/infra/abi/parse/parse.go
index 2d1adab74..3bac2ef99 100644
--- a/pkg/domain/infra/abi/parse/parse.go
+++ b/pkg/domain/infra/abi/parse/parse.go
@@ -73,6 +73,11 @@ func VolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error)
finalVal = append(finalVal, o)
// set option "GID": "$gid"
volumeOptions["GID"] = splitO[1]
+ case "noquota":
+ logrus.Debugf("Removing noquota from options and adding WithVolumeDisableQuota")
+ libpodOptions = append(libpodOptions, libpod.WithVolumeDisableQuota())
+ // set option "NOQUOTA": "true"
+ volumeOptions["NOQUOTA"] = "true"
default:
finalVal = append(finalVal, o)
}
diff --git a/test/test_podman_baseline.sh b/test/test_podman_baseline.sh
index 5a420fe60..5ef2d1bda 100755
--- a/test/test_podman_baseline.sh
+++ b/test/test_podman_baseline.sh
@@ -309,6 +309,28 @@ else
echo "Overlay test within limits failed"
fi
+before=`xfs_quota -x -c 'report -N -p' $TMPDIR | grep -c ^#`
+podman $PODMANBASE volume create -o o=noquota test-no-quota
+after=`xfs_quota -x -c 'report -N -p' $TMPDIR | grep -c ^#`
+
+if [ $before != $after ];
+then
+ echo "Test -o=noquota doesn't create a projid failed"
+else
+ echo "Test -o=noquota doesn't create a projid passed"
+fi
+
+before=`xfs_quota -x -c 'report -N -p' $TMPDIR | grep -c ^#`
+podman $PODMANBASE volume create -o test-no-quota
+after=`xfs_quota -x -c 'report -N -p' $TMPDIR | grep -c ^#`
+
+if [ $before == $after ];
+then
+ echo "Test without -o=noquota creates a projid failed"
+else
+ echo "Test without -o=noquota creates a projid passed"
+fi
+
########
# Expected to fail
########