Browse Source

Persist the quota size for btrfs so that daemon restart keeps quota

This commit is an extension of fix for 29325 based on the review comment.
In this commit, the quota size for btrfs is kept in `/var/lib/docker/btrfs/quotas`
so that a daemon restart keeps quota.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
Yong Tang 8 years ago
parent
commit
16328cc207
1 changed files with 37 additions and 0 deletions
  1. 37 0
      daemon/graphdriver/btrfs/btrfs.go

+ 37 - 0
daemon/graphdriver/btrfs/btrfs.go

@@ -16,10 +16,12 @@ import "C"
 
 
 import (
 import (
 	"fmt"
 	"fmt"
+	"io/ioutil"
 	"math"
 	"math"
 	"os"
 	"os"
 	"path"
 	"path"
 	"path/filepath"
 	"path/filepath"
+	"strconv"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
 	"syscall"
 	"syscall"
@@ -477,6 +479,14 @@ func (d *Driver) subvolumesDirID(id string) string {
 	return path.Join(d.subvolumesDir(), id)
 	return path.Join(d.subvolumesDir(), id)
 }
 }
 
 
+func (d *Driver) quotasDir() string {
+	return path.Join(d.home, "quotas")
+}
+
+func (d *Driver) quotasDirID(id string) string {
+	return path.Join(d.quotasDir(), id)
+}
+
 // CreateReadWrite creates a layer that is writable for use as a container
 // CreateReadWrite creates a layer that is writable for use as a container
 // file system.
 // file system.
 func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
 func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
@@ -485,6 +495,7 @@ func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts
 
 
 // Create the filesystem with given id.
 // Create the filesystem with given id.
 func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
 func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
+	quotas := path.Join(d.home, "quotas")
 	subvolumes := path.Join(d.home, "subvolumes")
 	subvolumes := path.Join(d.home, "subvolumes")
 	rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
 	rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
 	if err != nil {
 	if err != nil {
@@ -521,9 +532,16 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
 		if err := d.parseStorageOpt(storageOpt, driver); err != nil {
 		if err := d.parseStorageOpt(storageOpt, driver); err != nil {
 			return err
 			return err
 		}
 		}
+
 		if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil {
 		if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil {
 			return err
 			return err
 		}
 		}
+		if err := idtools.MkdirAllAs(quotas, 0700, rootUID, rootGID); err != nil {
+			return err
+		}
+		if err := ioutil.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(driver.options.size)), 0644); err != nil {
+			return err
+		}
 	}
 	}
 
 
 	// if we have a remapped root (user namespaces enabled), change the created snapshot
 	// if we have a remapped root (user namespaces enabled), change the created snapshot
@@ -588,6 +606,14 @@ func (d *Driver) Remove(id string) error {
 	if _, err := os.Stat(dir); err != nil {
 	if _, err := os.Stat(dir); err != nil {
 		return err
 		return err
 	}
 	}
+	quotasDir := d.quotasDirID(id)
+	if _, err := os.Stat(quotasDir); err == nil {
+		if err := os.Remove(quotasDir); err != nil {
+			return err
+		}
+	} else if !os.IsNotExist(err) {
+		return err
+	}
 
 
 	// Call updateQuotaStatus() to invoke status update
 	// Call updateQuotaStatus() to invoke status update
 	d.updateQuotaStatus()
 	d.updateQuotaStatus()
@@ -616,6 +642,17 @@ func (d *Driver) Get(id, mountLabel string) (string, error) {
 		return "", fmt.Errorf("%s: not a directory", dir)
 		return "", fmt.Errorf("%s: not a directory", dir)
 	}
 	}
 
 
+	if quota, err := ioutil.ReadFile(d.quotasDirID(id)); err == nil {
+		if size, err := strconv.ParseUint(string(quota), 10, 64); err == nil && size >= d.options.minSpace {
+			if err := d.subvolEnableQuota(); err != nil {
+				return "", err
+			}
+			if err := subvolLimitQgroup(dir, size); err != nil {
+				return "", err
+			}
+		}
+	}
+
 	return dir, nil
 	return dir, nil
 }
 }