From 36678eaf72ca33ed079b440405195a2f0cc59a62 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Sun, 2 Jun 2019 12:18:58 -0700 Subject: [PATCH 1/4] quota: add noncgo build tag Signed-off-by: Tonis Tiigi (cherry picked from commit 186cd7cf4a4d3a02ca7e7a18d6d923245f3187b0) Signed-off-by: Kir Kolyshkin Upstream-commit: 0dd47afda5c3d7e83f6b7b8766634e8bcacb041a Component: engine --- .../daemon/graphdriver/quota/projectquota.go | 15 +-------------- .../quota/projectquota_unsupported.go | 18 ++++++++++++++++++ .../engine/daemon/graphdriver/quota/types.go | 16 ++++++++++++++++ 3 files changed, 35 insertions(+), 14 deletions(-) create mode 100644 components/engine/daemon/graphdriver/quota/projectquota_unsupported.go create mode 100644 components/engine/daemon/graphdriver/quota/types.go diff --git a/components/engine/daemon/graphdriver/quota/projectquota.go b/components/engine/daemon/graphdriver/quota/projectquota.go index 93e85823af..b94c686983 100644 --- a/components/engine/daemon/graphdriver/quota/projectquota.go +++ b/components/engine/daemon/graphdriver/quota/projectquota.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux,!exclude_disk_quota // // projectquota.go - implements XFS project quota controls @@ -63,19 +63,6 @@ import ( "golang.org/x/sys/unix" ) -// Quota limit params - currently we only control blocks hard limit -type Quota struct { - Size uint64 -} - -// Control - Context to be used by storage driver (e.g. overlay) -// who wants to apply project quotas to container dirs -type Control struct { - backingFsBlockDev string - nextProjectID uint32 - quotas map[string]uint32 -} - // NewControl - initialize project quota support. // Test to make sure that quota can be set on a test dir and find // the first project id to be used for the next container create. diff --git a/components/engine/daemon/graphdriver/quota/projectquota_unsupported.go b/components/engine/daemon/graphdriver/quota/projectquota_unsupported.go new file mode 100644 index 0000000000..7422d5b432 --- /dev/null +++ b/components/engine/daemon/graphdriver/quota/projectquota_unsupported.go @@ -0,0 +1,18 @@ +// +build linux,exclude_disk_quota + +package quota // import "github.com/docker/docker/daemon/graphdriver/quota" + +func NewControl(basePath string) (*Control, error) { + return nil, ErrQuotaNotSupported +} + +// SetQuota - assign a unique project id to directory and set the quota limits +// for that project id +func (q *Control) SetQuota(targetPath string, quota Quota) error { + return ErrQuotaNotSupported +} + +// GetQuota - get the quota limits of a directory that was configured with SetQuota +func (q *Control) GetQuota(targetPath string, quota *Quota) error { + return ErrQuotaNotSupported +} diff --git a/components/engine/daemon/graphdriver/quota/types.go b/components/engine/daemon/graphdriver/quota/types.go new file mode 100644 index 0000000000..90f71520a7 --- /dev/null +++ b/components/engine/daemon/graphdriver/quota/types.go @@ -0,0 +1,16 @@ +// +build linux + +package quota // import "github.com/docker/docker/daemon/graphdriver/quota" + +// Quota limit params - currently we only control blocks hard limit +type Quota struct { + Size uint64 +} + +// Control - Context to be used by storage driver (e.g. overlay) +// who wants to apply project quotas to container dirs +type Control struct { + backingFsBlockDev string + nextProjectID uint32 + quotas map[string]uint32 +} From 920f2a46aadff4be4d900c8b1173c33caab37d28 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Sun, 2 Jun 2019 12:19:22 -0700 Subject: [PATCH 2/4] copy: allow non-cgo build Signed-off-by: Tonis Tiigi (cherry picked from commit 230a55d337f67a2850fd3206500c5c2a89f9e2e7) Signed-off-by: Kir Kolyshkin Upstream-commit: 1da22d7201f5fdedf3c6732163819d56a7571414 Component: engine --- .../engine/daemon/graphdriver/copy/copy.go | 10 +-------- .../daemon/graphdriver/copy/copy_cgo.go | 22 +++++++++++++++++++ .../daemon/graphdriver/copy/copy_nocgo.go | 13 +++++++++++ 3 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 components/engine/daemon/graphdriver/copy/copy_cgo.go create mode 100644 components/engine/daemon/graphdriver/copy/copy_nocgo.go diff --git a/components/engine/daemon/graphdriver/copy/copy.go b/components/engine/daemon/graphdriver/copy/copy.go index 70ae9ce230..f8125403c4 100644 --- a/components/engine/daemon/graphdriver/copy/copy.go +++ b/components/engine/daemon/graphdriver/copy/copy.go @@ -2,14 +2,6 @@ package copy // import "github.com/docker/docker/daemon/graphdriver/copy" -/* -#include - -#ifndef FICLONE -#define FICLONE _IOW(0x94, 9, int) -#endif -*/ -import "C" import ( "container/list" "fmt" @@ -50,7 +42,7 @@ func copyRegular(srcPath, dstPath string, fileinfo os.FileInfo, copyWithFileRang defer dstFile.Close() if *copyWithFileClone { - _, _, err = unix.Syscall(unix.SYS_IOCTL, dstFile.Fd(), C.FICLONE, srcFile.Fd()) + err = fiClone(srcFile, dstFile) if err == nil { return nil } diff --git a/components/engine/daemon/graphdriver/copy/copy_cgo.go b/components/engine/daemon/graphdriver/copy/copy_cgo.go new file mode 100644 index 0000000000..6bd34864fb --- /dev/null +++ b/components/engine/daemon/graphdriver/copy/copy_cgo.go @@ -0,0 +1,22 @@ +// +build linux,cgo + +package copy // import "github.com/docker/docker/daemon/graphdriver/copy" + +/* +#include + +#ifndef FICLONE +#define FICLONE _IOW(0x94, 9, int) +#endif +*/ +import "C" +import ( + "os" + + "golang.org/x/sys/unix" +) + +func fiClone(srcFile, dstFile *os.File) error { + _, _, err := unix.Syscall(unix.SYS_IOCTL, dstFile.Fd(), C.FICLONE, srcFile.Fd()) + return err +} diff --git a/components/engine/daemon/graphdriver/copy/copy_nocgo.go b/components/engine/daemon/graphdriver/copy/copy_nocgo.go new file mode 100644 index 0000000000..89e3c7f51e --- /dev/null +++ b/components/engine/daemon/graphdriver/copy/copy_nocgo.go @@ -0,0 +1,13 @@ +// +build linux,!cgo + +package copy // import "github.com/docker/docker/daemon/graphdriver/copy" + +import ( + "os" + + "golang.org/x/sys/unix" +) + +func fiClone(srcFile, dstFile *os.File) error { + return unix.ENOSYS +} From 542fc26354dd0e66300c9226c11f463d4ce4e2c8 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Tue, 4 Jun 2019 20:55:46 -0700 Subject: [PATCH 3/4] stats: avoid cgo in collector Signed-off-by: Tonis Tiigi (cherry picked from commit cf104d85c35947c25dcd86cef19aa97fe31e4bbd) Signed-off-by: Kir Kolyshkin Upstream-commit: a83a1dcbeaa1aef3f99c71a0b2d88552d45ac444 Component: engine --- .../engine/daemon/stats/collector_unix.go | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/components/engine/daemon/stats/collector_unix.go b/components/engine/daemon/stats/collector_unix.go index 2480aceb51..dbc9e6081e 100644 --- a/components/engine/daemon/stats/collector_unix.go +++ b/components/engine/daemon/stats/collector_unix.go @@ -9,13 +9,9 @@ import ( "strings" "github.com/opencontainers/runc/libcontainer/system" + "golang.org/x/sys/unix" ) -/* -#include -*/ -import "C" - // platformNewStatsCollector performs platform specific initialisation of the // Collector structure. func platformNewStatsCollector(s *Collector) { @@ -71,13 +67,10 @@ func (s *Collector) getSystemCPUUsage() (uint64, error) { } func (s *Collector) getNumberOnlineCPUs() (uint32, error) { - i, err := C.sysconf(C._SC_NPROCESSORS_ONLN) - // According to POSIX - errno is undefined after successful - // sysconf, and can be non-zero in several cases, so look for - // error in returned value not in errno. - // (https://sourceware.org/bugzilla/show_bug.cgi?id=21536) - if i == -1 { + var cpuset unix.CPUSet + err := unix.SchedGetaffinity(0, &cpuset) + if err != nil { return 0, err } - return uint32(i), nil + return uint32(cpuset.Count()), nil } From 018dd5e3eb3749ecebca520cf9b5be1602f0d40c Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 31 Jul 2019 11:02:42 -0700 Subject: [PATCH 4/4] projectquota: protect concurrent map access Protect access to q.quotas map, and lock around changing nextProjectID. Techinically, the lock in findNextProjectID() is not needed as it is only called during initialization, but one can never be too careful. Fixes: 52897d1c092 ("projectquota: utility class for project quota controls") Signed-off-by: Kir Kolyshkin (cherry picked from commit 1ac0a66a64a906911d0708cd0e5fa397a2f0b595) Signed-off-by: Kir Kolyshkin Upstream-commit: 7027bb9bedae63879c1e41894739ba0ea2deedc1 Component: engine --- .../engine/daemon/graphdriver/quota/projectquota.go | 12 +++++++++--- components/engine/daemon/graphdriver/quota/types.go | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/components/engine/daemon/graphdriver/quota/projectquota.go b/components/engine/daemon/graphdriver/quota/projectquota.go index b94c686983..beda0f82c0 100644 --- a/components/engine/daemon/graphdriver/quota/projectquota.go +++ b/components/engine/daemon/graphdriver/quota/projectquota.go @@ -153,9 +153,11 @@ func NewControl(basePath string) (*Control, error) { // SetQuota - assign a unique project id to directory and set the quota limits // for that project id func (q *Control) SetQuota(targetPath string, quota Quota) error { - + q.RLock() projectID, ok := q.quotas[targetPath] + q.RUnlock() if !ok { + q.Lock() projectID = q.nextProjectID // @@ -163,11 +165,12 @@ func (q *Control) SetQuota(targetPath string, quota Quota) error { // err := setProjectID(targetPath, projectID) if err != nil { + q.Unlock() return err } - q.quotas[targetPath] = projectID q.nextProjectID++ + q.Unlock() } // @@ -204,8 +207,9 @@ func setProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) er // GetQuota - get the quota limits of a directory that was configured with SetQuota func (q *Control) GetQuota(targetPath string, quota *Quota) error { - + q.RLock() projectID, ok := q.quotas[targetPath] + q.RUnlock() if !ok { return fmt.Errorf("quota not found for path : %s", targetPath) } @@ -276,6 +280,8 @@ func setProjectID(targetPath string, projectID uint32) error { // findNextProjectID - find the next project id to be used for containers // by scanning driver home directory to find used project ids func (q *Control) findNextProjectID(home string) error { + q.Lock() + defer q.Unlock() files, err := ioutil.ReadDir(home) if err != nil { return fmt.Errorf("read directory failed : %s", home) diff --git a/components/engine/daemon/graphdriver/quota/types.go b/components/engine/daemon/graphdriver/quota/types.go index 90f71520a7..036c3249a1 100644 --- a/components/engine/daemon/graphdriver/quota/types.go +++ b/components/engine/daemon/graphdriver/quota/types.go @@ -2,6 +2,8 @@ package quota // import "github.com/docker/docker/daemon/graphdriver/quota" +import "sync" + // Quota limit params - currently we only control blocks hard limit type Quota struct { Size uint64 @@ -11,6 +13,7 @@ type Quota struct { // who wants to apply project quotas to container dirs type Control struct { backingFsBlockDev string + sync.RWMutex // protect nextProjectID and quotas map nextProjectID uint32 quotas map[string]uint32 }