2021-08-23 13:14:53 +00:00
|
|
|
//go:build linux && !exclude_disk_quota && cgo
|
2020-08-10 16:00:09 +00:00
|
|
|
|
|
|
|
package quota // import "github.com/docker/docker/quota"
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
)
|
|
|
|
|
|
|
|
// CanTestQuota - checks if xfs prjquota can be tested
|
|
|
|
// returns a reason if not
|
|
|
|
func CanTestQuota() (string, bool) {
|
|
|
|
if os.Getuid() != 0 {
|
|
|
|
return "requires mounts", false
|
|
|
|
}
|
|
|
|
_, err := exec.LookPath("mkfs.xfs")
|
|
|
|
if err != nil {
|
|
|
|
return "mkfs.xfs not found in PATH", false
|
|
|
|
}
|
|
|
|
return "", true
|
|
|
|
}
|
|
|
|
|
|
|
|
// PrepareQuotaTestImage - prepares an xfs prjquota test image
|
|
|
|
// returns the path the the image on success
|
|
|
|
func PrepareQuotaTestImage(t *testing.T) (string, error) {
|
2023-11-24 13:33:20 +00:00
|
|
|
// imageSize is the size of the test-image. The minimum size allowed
|
|
|
|
// is 300MB.
|
|
|
|
//
|
|
|
|
// See https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git/commit/?id=6e0ed3d19c54603f0f7d628ea04b550151d8a262
|
|
|
|
const imageSize = 300 * 1024 * 1024
|
|
|
|
|
2020-08-10 16:00:09 +00:00
|
|
|
mkfs, err := exec.LookPath("mkfs.xfs")
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
// create a sparse image
|
2021-08-24 10:10:50 +00:00
|
|
|
imageFile, err := os.CreateTemp("", "xfs-image")
|
2020-08-10 16:00:09 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
imageFileName := imageFile.Name()
|
|
|
|
if _, err = imageFile.Seek(imageSize-1, 0); err != nil {
|
|
|
|
os.Remove(imageFileName)
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if _, err = imageFile.Write([]byte{0}); err != nil {
|
|
|
|
os.Remove(imageFileName)
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if err = imageFile.Close(); err != nil {
|
|
|
|
os.Remove(imageFileName)
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
// The reason for disabling these options is sometimes people run with a newer userspace
|
|
|
|
// than kernelspace
|
|
|
|
out, err := exec.Command(mkfs, "-m", "crc=0,finobt=0", imageFileName).CombinedOutput()
|
|
|
|
if len(out) > 0 {
|
|
|
|
t.Log(string(out))
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
os.Remove(imageFileName)
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return imageFileName, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// WrapMountTest - wraps a test function such that it has easy access to a mountPoint and testDir
|
|
|
|
// with guaranteed prjquota or guaranteed no prjquota support.
|
|
|
|
func WrapMountTest(imageFileName string, enableQuota bool, testFunc func(t *testing.T, mountPoint, backingFsDev, testDir string)) func(*testing.T) {
|
|
|
|
return func(t *testing.T) {
|
|
|
|
mountOptions := "loop"
|
|
|
|
|
|
|
|
if enableQuota {
|
|
|
|
mountOptions = mountOptions + ",prjquota"
|
|
|
|
}
|
|
|
|
|
2023-07-17 20:56:14 +00:00
|
|
|
mountPoint := t.TempDir()
|
2020-08-10 16:00:09 +00:00
|
|
|
out, err := exec.Command("mount", "-o", mountOptions, imageFileName, mountPoint).CombinedOutput()
|
|
|
|
if err != nil {
|
|
|
|
_, err := os.Stat("/proc/fs/xfs")
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
t.Skip("no /proc/fs/xfs")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-17 20:56:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("assertion failed: error is not nil: %v: mount failed: %s", err, out)
|
|
|
|
}
|
2020-08-10 16:00:09 +00:00
|
|
|
|
|
|
|
defer func() {
|
2023-07-17 20:56:14 +00:00
|
|
|
if err := unix.Unmount(mountPoint, 0); err != nil {
|
|
|
|
t.Fatalf("assertion failed: error is not nil: %v", err)
|
|
|
|
}
|
2020-08-10 16:00:09 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
backingFsDev, err := makeBackingFsDev(mountPoint)
|
2023-07-17 20:56:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("assertion failed: error is not nil: %v", err)
|
|
|
|
}
|
2020-08-10 16:00:09 +00:00
|
|
|
|
2021-08-24 10:10:50 +00:00
|
|
|
testDir, err := os.MkdirTemp(mountPoint, "per-test")
|
2023-07-17 20:56:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("assertion failed: error is not nil: %v", err)
|
|
|
|
}
|
2020-08-10 16:00:09 +00:00
|
|
|
defer os.RemoveAll(testDir)
|
|
|
|
|
|
|
|
testFunc(t, mountPoint, backingFsDev, testDir)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WrapQuotaTest - wraps a test function such that is has easy and guaranteed access to a quota Control
|
|
|
|
// instance with a quota test dir under its control.
|
|
|
|
func WrapQuotaTest(testFunc func(t *testing.T, ctrl *Control, mountPoint, testDir, testSubDir string)) func(t *testing.T, mountPoint, backingFsDev, testDir string) {
|
|
|
|
return func(t *testing.T, mountPoint, backingFsDev, testDir string) {
|
|
|
|
ctrl, err := NewControl(testDir)
|
2023-07-17 20:56:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("assertion failed: error is not nil: %v", err)
|
|
|
|
}
|
2020-08-10 16:00:09 +00:00
|
|
|
|
2021-08-24 10:10:50 +00:00
|
|
|
testSubDir, err := os.MkdirTemp(testDir, "quota-test")
|
2023-07-17 20:56:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("assertion failed: error is not nil: %v", err)
|
|
|
|
}
|
2020-08-10 16:00:09 +00:00
|
|
|
testFunc(t, ctrl, mountPoint, testDir, testSubDir)
|
|
|
|
}
|
|
|
|
}
|