1 Star 0 Fork 58

gnaygnil/docker

forked from src-openEuler/docker 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
0004-prjquota-support-set-filesystem-quot.patch 13.46 KB
一键复制 编辑 原始数据 按行查看 历史
gnaygnil 提交于 2020-02-13 15:36 . docker: Fixed build error and URL
From a8f05692638bf50826ed9533f2a5282e2cde359d Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:13:41 +0800
Subject: [PATCH 004/111] prjquota: support set filesystem
quota if ext4 support project quota
reason:Support set filesystem quota if ext4 support project quota
Change-Id: I99d28f248e758837cbf8b615e673ee7d8e36be7b
Signed-off-by: Lei Jitang <leijitang@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/daemon_unix.go | 19 ++
.../daemon/graphdriver/overlay2/overlay.go | 10 +-
.../daemon/graphdriver/quota/projectquota.go | 176 +++++++++++++++---
.../daemon/graphdriver/vfs/quota_linux.go | 13 +-
4 files changed, 191 insertions(+), 27 deletions(-)
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index b69eede21c..1b35df4950 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -633,6 +633,25 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
}
}
+ if hostConfig.StorageOpt != nil && daemon.imageService.GraphDriverForOS(runtime.GOOS) == "overlay2" {
+ _, exist := hostConfig.StorageOpt["size"]
+ if exist {
+ status := daemon.imageService.LayerStoreStatus()[runtime.GOOS]
+ if status[0][0] == "Backing Filesystem" && status[0][1] == "extfs" {
+ if hostConfig.Privileged {
+ warnings = append(warnings, "filesystem quota for overlay2 over ext4 can't take affect with privileged container")
+ } else {
+ for _, cap := range hostConfig.CapAdd {
+ if cap == "SYS_RESOURCE" {
+ warnings = append(warnings, "filesystem quota for overlay2 over ext4 can't take affect with CAP_SYS_RESOURCE")
+ break
+ }
+ }
+ }
+ }
+ }
+ }
+
return warnings, nil
}
diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go
index 6b3236f8f3..36ae182bcd 100644
--- a/components/engine/daemon/graphdriver/overlay2/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay2/overlay.go
@@ -216,16 +216,16 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps)
- if backingFs == "xfs" {
- // Try to enable project quota support over xfs.
- if d.quotaCtl, err = quota.NewControl(home); err == nil {
+ if backingFs == "xfs" || backingFs == "extfs" {
+ // Try to enable project quota support over xfs and extfs.
+ if d.quotaCtl, err = quota.NewControl(home, backingFs); err == nil {
projectQuotaSupported = true
} else if opts.quota.Size > 0 {
return nil, fmt.Errorf("Storage option overlay2.size not supported. Filesystem does not support Project Quota: %v", err)
}
} else if opts.quota.Size > 0 {
// if xfs is not the backing fs then error out if the storage-opt overlay2.size is used.
- return nil, fmt.Errorf("Storage Option overlay2.size only supported for backingFS XFS. Found %v", backingFs)
+ return nil, fmt.Errorf("Storage Option overlay2.size only supported for backingFS XFS or ext4. Found %v", backingFs)
}
logger.Debugf("backingFs=%s, projectQuotaSupported=%v", backingFs, projectQuotaSupported)
@@ -341,7 +341,7 @@ func (d *Driver) Cleanup() error {
// file system.
func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
if opts != nil && len(opts.StorageOpt) != 0 && !projectQuotaSupported {
- return fmt.Errorf("--storage-opt is supported only for overlay over xfs with 'pquota' mount option")
+ return fmt.Errorf("--storage-opt is supported only for overlay over xfs or ext4 with 'pquota' mount option")
}
if opts == nil {
diff --git a/components/engine/daemon/graphdriver/quota/projectquota.go b/components/engine/daemon/graphdriver/quota/projectquota.go
index 93e85823af..7d879eb81d 100644
--- a/components/engine/daemon/graphdriver/quota/projectquota.go
+++ b/components/engine/daemon/graphdriver/quota/projectquota.go
@@ -38,8 +38,8 @@ struct fsxattr {
#ifndef PRJQUOTA
#define PRJQUOTA 2
#endif
-#ifndef XFS_PROJ_QUOTA
-#define XFS_PROJ_QUOTA 2
+#ifndef PROJ_QUOTA
+#define PROJ_QUOTA 2
#endif
#ifndef Q_XSETPQLIM
#define Q_XSETPQLIM QCMD(Q_XSETQLIM, PRJQUOTA)
@@ -49,6 +49,28 @@ struct fsxattr {
#endif
const int Q_XGETQSTAT_PRJQUOTA = QCMD(Q_XGETQSTAT, PRJQUOTA);
+
+#ifndef Q_XGETPQSTAT
+#define Q_XGETPQSTAT QCMD(Q_XGETQSTAT, PRJQUOTA)
+#endif
+
+#ifndef Q_SETPQUOTA
+#define Q_SETPQUOTA (unsigned int)QCMD(Q_SETQUOTA, PRJQUOTA)
+#endif
+
+#ifndef Q_GETPQUOTA
+#define Q_GETPQUOTA (unsigned int)QCMD(Q_GETQUOTA, PRJQUOTA)
+#endif
+
+#define PDQ_ACCT_BIT 4
+#define PDQ_ENFD_BIT 5
+
+#ifndef QUOTA_PDQ_ACCT
+#define QUOTA_PDQ_ACCT (1<<PDQ_ACCT_BIT)
+#endif
+#ifndef QUOTA_PDQ_ENFD
+#define QUOTA_PDQ_ENFD (1<<PDQ_ENFD_BIT)
+#endif
*/
import "C"
import (
@@ -56,6 +78,8 @@ import (
"io/ioutil"
"path"
"path/filepath"
+ "sync"
+ "syscall"
"unsafe"
rsystem "github.com/opencontainers/runc/libcontainer/system"
@@ -74,6 +98,17 @@ type Control struct {
backingFsBlockDev string
nextProjectID uint32
quotas map[string]uint32
+ quotaOps QuotafileOps
+ lock sync.Mutex
+}
+
+// QuotafileOps is a interface for quotafile operations
+type QuotafileOps interface {
+ // SetProjectQuota sets the project quota for project id on block device
+ SetProjectQuota(dev string, projectID uint32, quota Quota) error
+
+ // GetProjectQuota gets the project quota for project id on block device
+ GetProjectQuota(dev string, projectID uint32, quota *Quota) error
}
// NewControl - initialize project quota support.
@@ -98,7 +133,7 @@ type Control struct {
// on it. If that works, continue to scan existing containers to map allocated
// project ids.
//
-func NewControl(basePath string) (*Control, error) {
+func NewControl(basePath string, fs string) (*Control, error) {
//
// If we are running in a user namespace quota won't be supported for
// now since makeBackingFsDev() will try to mknod().
@@ -141,7 +176,28 @@ func NewControl(basePath string) (*Control, error) {
quota := Quota{
Size: 0,
}
- if err := setProjectQuota(backingFsBlockDev, minProjectID, quota); err != nil {
+ //
+ // Get the quota stat to check whether the system support project quota
+ //
+ stat, err := getQuotaStat(backingFsBlockDev)
+ if err != nil || stat != 2 {
+ if err != nil {
+ logrus.Warnf("Get quota stat failed with: %v", err)
+ }
+ return nil, fmt.Errorf("quota isn't supported on your system")
+ }
+
+ var quotaOps QuotafileOps
+
+ if fs == "xfs" {
+ quotaOps = new(XfsQuota)
+ } else if fs == "extfs" {
+ quotaOps = new(Ext4Quota)
+ } else {
+ return nil, fmt.Errorf("quota isn't supported for filesystem %q", fs)
+ }
+
+ if err := quotaOps.SetProjectQuota(backingFsBlockDev, minProjectID, quota); err != nil {
return nil, err
}
@@ -149,6 +205,7 @@ func NewControl(basePath string) (*Control, error) {
backingFsBlockDev: backingFsBlockDev,
nextProjectID: minProjectID + 1,
quotas: make(map[string]uint32),
+ quotaOps: quotaOps,
}
//
@@ -167,6 +224,7 @@ func NewControl(basePath string) (*Control, error) {
// for that project id
func (q *Control) SetQuota(targetPath string, quota Quota) error {
+ q.lock.Lock()
projectID, ok := q.quotas[targetPath]
if !ok {
projectID = q.nextProjectID
@@ -176,26 +234,32 @@ func (q *Control) SetQuota(targetPath string, quota Quota) error {
//
err := setProjectID(targetPath, projectID)
if err != nil {
+ q.lock.Lock()
return err
}
q.quotas[targetPath] = projectID
q.nextProjectID++
}
+ q.lock.Unlock()
//
// set the quota limit for the container's project id
//
logrus.Debugf("SetQuota(%s, %d): projectID=%d", targetPath, quota.Size, projectID)
- return setProjectQuota(q.backingFsBlockDev, projectID, quota)
+ return q.quotaOps.SetProjectQuota(q.backingFsBlockDev, projectID, quota)
}
-// setProjectQuota - set the quota for project id on xfs block device
-func setProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) error {
+// XfsQuota is a struct implements quota operations
+type XfsQuota struct {
+}
+
+// SetProjectQuota - set the quota for project id on xfs block device
+func (q *XfsQuota) SetProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) error {
var d C.fs_disk_quota_t
d.d_version = C.FS_DQUOT_VERSION
d.d_id = C.__u32(projectID)
- d.d_flags = C.XFS_PROJ_QUOTA
+ d.d_flags = C.PROJ_QUOTA
d.d_fieldmask = C.FS_DQ_BHARD | C.FS_DQ_BSOFT
d.d_blk_hardlimit = C.__u64(quota.Size / 512)
@@ -215,20 +279,11 @@ func setProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) er
return nil
}
-// GetQuota - get the quota limits of a directory that was configured with SetQuota
-func (q *Control) GetQuota(targetPath string, quota *Quota) error {
-
- projectID, ok := q.quotas[targetPath]
- if !ok {
- return fmt.Errorf("quota not found for path : %s", targetPath)
- }
-
- //
- // get the quota limit for the container's project id
- //
+// GetProjectQuota gets the project quota for projectID on dev
+func (q *XfsQuota) GetProjectQuota(backingFsBlockDev string, projectID uint32, quota *Quota) error {
var d C.fs_disk_quota_t
- var cs = C.CString(q.backingFsBlockDev)
+ var cs = C.CString(backingFsBlockDev)
defer C.free(unsafe.Pointer(cs))
_, _, errno := unix.Syscall6(unix.SYS_QUOTACTL, C.Q_XGETPQUOTA,
@@ -236,13 +291,92 @@ func (q *Control) GetQuota(targetPath string, quota *Quota) error {
uintptr(unsafe.Pointer(&d)), 0, 0)
if errno != 0 {
return fmt.Errorf("Failed to get quota limit for projid %d on %s: %v",
- projectID, q.backingFsBlockDev, errno.Error())
+ projectID, backingFsBlockDev, errno.Error())
}
quota.Size = uint64(d.d_blk_hardlimit) * 512
return nil
}
+// Ext4Quota is a struct implements quota operations
+type Ext4Quota struct {
+}
+
+// SetProjectQuota - set the quota for project id on ext4 block device
+func (q *Ext4Quota) SetProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) error {
+ var d C.struct_if_dqblk
+ d.dqb_bhardlimit = C.__u64(quota.Size / 1024)
+ d.dqb_bsoftlimit = d.dqb_bhardlimit
+ d.dqb_valid = C.QIF_LIMITS
+
+ var cs = C.CString(backingFsBlockDev)
+ defer C.free(unsafe.Pointer(cs))
+
+ _, _, errno := syscall.Syscall6(syscall.SYS_QUOTACTL, C.Q_SETPQUOTA,
+ uintptr(unsafe.Pointer(cs)), uintptr(C.__u32(projectID)),
+ uintptr(unsafe.Pointer(&d)), 0, 0)
+ if errno != 0 {
+ return fmt.Errorf("Failed to set quota limit for projid %d on %s: %v",
+ projectID, backingFsBlockDev, errno.Error())
+ }
+
+ return nil
+}
+
+func (q *Ext4Quota) GetProjectQuota(backingFsBlockDev string, projectID uint32, quota *Quota) error {
+ var d C.struct_if_dqblk
+ d.dqb_valid = C.QIF_USAGE
+
+ var cs = C.CString(backingFsBlockDev)
+ defer C.free(unsafe.Pointer(cs))
+
+ _, _, errno := syscall.Syscall6(syscall.SYS_QUOTACTL, C.Q_SETPQUOTA,
+ uintptr(unsafe.Pointer(cs)), uintptr(C.__u32(projectID)),
+ uintptr(unsafe.Pointer(&d)), 0, 0)
+ if errno != 0 {
+ return fmt.Errorf("Failed to get quota limit for projid %d on %s: %v",
+ projectID, backingFsBlockDev, errno.Error())
+ }
+
+ quota.Size = uint64(d.dqb_bhardlimit) * 1024
+
+ return nil
+}
+
+// getQuotaStat - get the quota stat
+// return 2 means quota is on
+func getQuotaStat(backingFsBlockDev string) (int, error) {
+ var info C.fs_quota_stat_t
+
+ var cs = C.CString(backingFsBlockDev)
+ defer C.free(unsafe.Pointer(cs))
+ _, _, errno := syscall.Syscall6(syscall.SYS_QUOTACTL, C.Q_XGETPQSTAT,
+ uintptr(unsafe.Pointer(cs)), 0,
+ uintptr(unsafe.Pointer(&info)), 0, 0)
+ if errno != 0 {
+ return -1, fmt.Errorf("Failed to get quota stat on %s: %v",
+ backingFsBlockDev, errno.Error())
+ }
+
+ return int((info.qs_flags&C.QUOTA_PDQ_ACCT)>>C.PDQ_ACCT_BIT + (info.qs_flags&C.QUOTA_PDQ_ENFD)>>C.PDQ_ENFD_BIT), nil
+}
+
+// GetQuota - get the quota limits of a directory that was configured with SetQuota
+func (q *Control) GetQuota(targetPath string, quota *Quota) error {
+ q.lock.Lock()
+ projectID, ok := q.quotas[targetPath]
+ q.lock.Unlock()
+ if !ok {
+ return fmt.Errorf("quota not found for path : %s", targetPath)
+ }
+
+ //
+ // get the quota limit for the container's project id
+ //
+
+ return q.quotaOps.GetProjectQuota(q.backingFsBlockDev, projectID, quota)
+}
+
// getProjectID - get the project id of path on xfs
func getProjectID(targetPath string) (uint32, error) {
dir, err := openDir(targetPath)
diff --git a/components/engine/daemon/graphdriver/vfs/quota_linux.go b/components/engine/daemon/graphdriver/vfs/quota_linux.go
index 0d5c3a7b98..bb2f571834 100644
--- a/components/engine/daemon/graphdriver/vfs/quota_linux.go
+++ b/components/engine/daemon/graphdriver/vfs/quota_linux.go
@@ -1,6 +1,7 @@
package vfs // import "github.com/docker/docker/daemon/graphdriver/vfs"
import (
+ "github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/daemon/graphdriver/quota"
"github.com/sirupsen/logrus"
)
@@ -10,7 +11,17 @@ type driverQuota struct {
}
func setupDriverQuota(driver *Driver) {
- if quotaCtl, err := quota.NewControl(driver.home); err == nil {
+ // Probe fs type before setting quota, now only supports xfs and extfs
+ fsMagic, err := graphdriver.GetFSMagic(driver.home)
+ if err != nil {
+ return
+ }
+ fsName, ok := graphdriver.FsNames[fsMagic]
+ if !ok {
+ return
+ }
+
+ if quotaCtl, err := quota.NewControl(driver.home, fsName); err == nil {
driver.quotaCtl = quotaCtl
} else if err != quota.ErrQuotaNotSupported {
logrus.Warnf("Unable to setup quota: %v\n", err)
--
2.17.1
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/gnaygnil/docker.git
git@gitee.com:gnaygnil/docker.git
gnaygnil
docker
docker
master

搜索帮助