|
@@ -24,6 +24,7 @@ import (
|
|
|
"github.com/docker/docker/pkg/mount"
|
|
|
"github.com/docker/docker/pkg/parsers"
|
|
|
"github.com/docker/docker/pkg/parsers/kernel"
|
|
|
+ "github.com/docker/go-units"
|
|
|
|
|
|
"github.com/opencontainers/runc/libcontainer/label"
|
|
|
)
|
|
@@ -76,15 +77,25 @@ const (
|
|
|
idLength = 26
|
|
|
)
|
|
|
|
|
|
+type overlayOptions struct {
|
|
|
+ overrideKernelCheck bool
|
|
|
+ quota graphdriver.Quota
|
|
|
+}
|
|
|
+
|
|
|
// Driver contains information about the home directory and the list of active mounts that are created using this driver.
|
|
|
type Driver struct {
|
|
|
- home string
|
|
|
- uidMaps []idtools.IDMap
|
|
|
- gidMaps []idtools.IDMap
|
|
|
- ctr *graphdriver.RefCounter
|
|
|
+ home string
|
|
|
+ uidMaps []idtools.IDMap
|
|
|
+ gidMaps []idtools.IDMap
|
|
|
+ ctr *graphdriver.RefCounter
|
|
|
+ quotaCtl *graphdriver.QuotaCtl
|
|
|
+ options overlayOptions
|
|
|
}
|
|
|
|
|
|
-var backingFs = "<unknown>"
|
|
|
+var (
|
|
|
+ backingFs = "<unknown>"
|
|
|
+ projectQuotaSupported = false
|
|
|
+)
|
|
|
|
|
|
func init() {
|
|
|
graphdriver.Register(driverName, Init)
|
|
@@ -150,11 +161,16 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
|
|
|
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)),
|
|
|
}
|
|
|
|
|
|
- return d, nil
|
|
|
-}
|
|
|
+ if backingFs == "xfs" {
|
|
|
+ // Try to enable project quota support over xfs.
|
|
|
+ if d.quotaCtl, err = graphdriver.NewQuotaCtl(home); err == nil {
|
|
|
+ projectQuotaSupported = true
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-type overlayOptions struct {
|
|
|
- overrideKernelCheck bool
|
|
|
+ logrus.Debugf("backingFs=%s, projectQuotaSupported=%v", backingFs, projectQuotaSupported)
|
|
|
+
|
|
|
+ return d, nil
|
|
|
}
|
|
|
|
|
|
func parseOptions(options []string) (*overlayOptions, error) {
|
|
@@ -171,6 +187,7 @@ func parseOptions(options []string) (*overlayOptions, error) {
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
+
|
|
|
default:
|
|
|
return nil, fmt.Errorf("overlay2: Unknown option %s\n", key)
|
|
|
}
|
|
@@ -253,8 +270,8 @@ func (d *Driver) CreateReadWrite(id, parent, mountLabel string, storageOpt map[s
|
|
|
// The parent filesystem is used to configure these directories for the overlay.
|
|
|
func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) (retErr error) {
|
|
|
|
|
|
- if len(storageOpt) != 0 {
|
|
|
- return fmt.Errorf("--storage-opt is not supported for overlay")
|
|
|
+ if len(storageOpt) != 0 && !projectQuotaSupported {
|
|
|
+ return fmt.Errorf("--storage-opt is supported only for overlay over xfs with 'pquota' mount option")
|
|
|
}
|
|
|
|
|
|
dir := d.dir(id)
|
|
@@ -277,6 +294,20 @@ func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]str
|
|
|
}
|
|
|
}()
|
|
|
|
|
|
+ if len(storageOpt) > 0 {
|
|
|
+ driver := &Driver{}
|
|
|
+ if err := d.parseStorageOpt(storageOpt, driver); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ if driver.options.quota.Size > 0 {
|
|
|
+ // Set container disk quota limit
|
|
|
+ if err := d.quotaCtl.SetQuota(dir, driver.options.quota); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if err := idtools.MkdirAs(path.Join(dir, "diff"), 0755, rootUID, rootGID); err != nil {
|
|
|
return err
|
|
|
}
|
|
@@ -316,6 +347,26 @@ func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]str
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
+// Parse overlay storage options
|
|
|
+func (d *Driver) parseStorageOpt(storageOpt map[string]string, driver *Driver) error {
|
|
|
+ // Read size to set the disk project quota per container
|
|
|
+ for key, val := range storageOpt {
|
|
|
+ key := strings.ToLower(key)
|
|
|
+ switch key {
|
|
|
+ case "size":
|
|
|
+ size, err := units.RAMInBytes(val)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ driver.options.quota.Size = uint64(size)
|
|
|
+ default:
|
|
|
+ return fmt.Errorf("Unknown option %s", key)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
func (d *Driver) getLower(parent string) (string, error) {
|
|
|
parentDir := d.dir(parent)
|
|
|
|