Jelajahi Sumber

Merge pull request #311 from kolyshkin/18.09-quota-map

[18.09 backport] projectquota: protect concurrent map access (ENGCORE-920)
Sebastiaan van Stijn 6 tahun lalu
induk
melakukan
ebb8bfca60

+ 1 - 9
daemon/graphdriver/copy/copy.go

@@ -2,14 +2,6 @@
 
 package copy // import "github.com/docker/docker/daemon/graphdriver/copy"
 
-/*
-#include <linux/fs.h>
-
-#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
 		}

+ 22 - 0
daemon/graphdriver/copy/copy_cgo.go

@@ -0,0 +1,22 @@
+// +build linux,cgo
+
+package copy // import "github.com/docker/docker/daemon/graphdriver/copy"
+
+/*
+#include <linux/fs.h>
+
+#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
+}

+ 13 - 0
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
+}

+ 10 - 17
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.
@@ -166,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
 
 		//
@@ -176,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()
 	}
 
 	//
@@ -217,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)
 	}
@@ -289,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)

+ 18 - 0
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
+}

+ 19 - 0
daemon/graphdriver/quota/types.go

@@ -0,0 +1,19 @@
+// +build linux
+
+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
+}
+
+// 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
+	sync.RWMutex      // protect nextProjectID and quotas map
+	nextProjectID     uint32
+	quotas            map[string]uint32
+}

+ 5 - 12
daemon/stats/collector_unix.go

@@ -9,13 +9,9 @@ import (
 	"strings"
 
 	"github.com/opencontainers/runc/libcontainer/system"
+	"golang.org/x/sys/unix"
 )
 
-/*
-#include <unistd.h>
-*/
-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
 }