From 2458452a3b96d0e6f6dfa44d7c30585db83c2fd1 Mon Sep 17 00:00:00 2001 From: Chun Chen Date: Thu, 24 Sep 2015 09:21:28 +0800 Subject: [PATCH] Try to resize data and metadata loopback file when initiating devicemapper Signed-off-by: Chun Chen --- daemon/graphdriver/btrfs/btrfs.go | 2 +- daemon/graphdriver/devmapper/deviceset.go | 17 +++++++- .../graphdriver/devmapper/devmapper_test.go | 39 +++++++++++++++++++ daemon/graphdriver/devmapper/driver.go | 2 +- daemon/graphdriver/fsdiff.go | 20 +++++----- daemon/graphdriver/overlay/overlay.go | 2 +- daemon/graphdriver/vfs/driver.go | 2 +- daemon/graphdriver/zfs/zfs.go | 2 +- 8 files changed, 69 insertions(+), 17 deletions(-) diff --git a/daemon/graphdriver/btrfs/btrfs.go b/daemon/graphdriver/btrfs/btrfs.go index d0ad27d370..56fd7f1970 100644 --- a/daemon/graphdriver/btrfs/btrfs.go +++ b/daemon/graphdriver/btrfs/btrfs.go @@ -52,7 +52,7 @@ func Init(home string, options []string) (graphdriver.Driver, error) { home: home, } - return graphdriver.NaiveDiffDriver(driver), nil + return graphdriver.NewNaiveDiffDriver(driver), nil } // Driver contains information about the filesystem mounted. diff --git a/daemon/graphdriver/devmapper/deviceset.go b/daemon/graphdriver/devmapper/deviceset.go index 0bdb585306..b079064029 100644 --- a/daemon/graphdriver/devmapper/deviceset.go +++ b/daemon/graphdriver/devmapper/deviceset.go @@ -232,7 +232,7 @@ func (devices *DeviceSet) hasImage(name string) bool { // ensureImage creates a sparse file of bytes at the path // /devicemapper/. -// If the file already exists, it does nothing. +// If the file already exists and new size is larger than its current size, it grows to the new size. // Either way it returns the full path. func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) { dirname := devices.loopbackDir() @@ -242,7 +242,7 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) { return "", err } - if _, err := os.Stat(filename); err != nil { + if fi, err := os.Stat(filename); err != nil { if !os.IsNotExist(err) { return "", err } @@ -256,6 +256,19 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) { if err := file.Truncate(size); err != nil { return "", err } + } else { + if fi.Size() < size { + file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0600) + if err != nil { + return "", err + } + defer file.Close() + if err := file.Truncate(size); err != nil { + return "", fmt.Errorf("Unable to grow loopback file %s: %v", filename, err) + } + } else if fi.Size() > size { + logrus.Warnf("Can't shrink loopback file %s", filename) + } } return filename, nil } diff --git a/daemon/graphdriver/devmapper/devmapper_test.go b/daemon/graphdriver/devmapper/devmapper_test.go index 40439dff74..4c466b4238 100644 --- a/daemon/graphdriver/devmapper/devmapper_test.go +++ b/daemon/graphdriver/devmapper/devmapper_test.go @@ -3,8 +3,10 @@ package devmapper import ( + "fmt" "testing" + "github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver/graphtest" ) @@ -40,3 +42,40 @@ func TestDevmapperCreateSnap(t *testing.T) { func TestDevmapperTeardown(t *testing.T) { graphtest.PutDriver(t) } + +func TestDevmapperReduceLoopBackSize(t *testing.T) { + tenMB := int64(10 * 1024 * 1024) + testChangeLoopBackSize(t, -tenMB, defaultDataLoopbackSize, defaultMetaDataLoopbackSize) +} + +func TestDevmapperIncreaseLoopBackSize(t *testing.T) { + tenMB := int64(10 * 1024 * 1024) + testChangeLoopBackSize(t, tenMB, defaultDataLoopbackSize+tenMB, defaultMetaDataLoopbackSize+tenMB) +} + +func testChangeLoopBackSize(t *testing.T, delta, expectDataSize, expectMetaDataSize int64) { + driver := graphtest.GetDriver(t, "devicemapper").(*graphtest.Driver).Driver.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver) + defer graphtest.PutDriver(t) + // make sure data or metadata loopback size are the default size + if s := driver.DeviceSet.Status(); s.Data.Total != uint64(defaultDataLoopbackSize) || s.Metadata.Total != uint64(defaultMetaDataLoopbackSize) { + t.Fatalf("data or metadata loop back size is incorrect") + } + if err := driver.Cleanup(); err != nil { + t.Fatal(err) + } + //Reload + d, err := Init(driver.home, []string{ + fmt.Sprintf("dm.loopdatasize=%d", defaultDataLoopbackSize+delta), + fmt.Sprintf("dm.loopmetadatasize=%d", defaultMetaDataLoopbackSize+delta), + }) + if err != nil { + t.Fatalf("error creating devicemapper driver: %v", err) + } + driver = d.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver) + if s := driver.DeviceSet.Status(); s.Data.Total != uint64(expectDataSize) || s.Metadata.Total != uint64(expectMetaDataSize) { + t.Fatalf("data or metadata loop back size is incorrect") + } + if err := driver.Cleanup(); err != nil { + t.Fatal(err) + } +} diff --git a/daemon/graphdriver/devmapper/driver.go b/daemon/graphdriver/devmapper/driver.go index b744bef788..67657f65e7 100644 --- a/daemon/graphdriver/devmapper/driver.go +++ b/daemon/graphdriver/devmapper/driver.go @@ -57,7 +57,7 @@ func Init(home string, options []string) (graphdriver.Driver, error) { home: home, } - return graphdriver.NaiveDiffDriver(d), nil + return graphdriver.NewNaiveDiffDriver(d), nil } func (d *Driver) String() string { diff --git a/daemon/graphdriver/fsdiff.go b/daemon/graphdriver/fsdiff.go index 63643dc4d3..0582d76dcf 100644 --- a/daemon/graphdriver/fsdiff.go +++ b/daemon/graphdriver/fsdiff.go @@ -11,29 +11,29 @@ import ( "github.com/docker/docker/pkg/ioutils" ) -// naiveDiffDriver takes a ProtoDriver and adds the +// NaiveDiffDriver takes a ProtoDriver and adds the // capability of the Diffing methods which it may or may not // support on its own. See the comment on the exported -// NaiveDiffDriver function below. +// NewNaiveDiffDriver function below. // Notably, the AUFS driver doesn't need to be wrapped like this. -type naiveDiffDriver struct { +type NaiveDiffDriver struct { ProtoDriver } -// NaiveDiffDriver returns a fully functional driver that wraps the +// NewNaiveDiffDriver returns a fully functional driver that wraps the // given ProtoDriver and adds the capability of the following methods which // it may or may not support on its own: // Diff(id, parent string) (archive.Archive, error) // Changes(id, parent string) ([]archive.Change, error) // ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) // DiffSize(id, parent string) (size int64, err error) -func NaiveDiffDriver(driver ProtoDriver) Driver { - return &naiveDiffDriver{ProtoDriver: driver} +func NewNaiveDiffDriver(driver ProtoDriver) Driver { + return &NaiveDiffDriver{ProtoDriver: driver} } // Diff produces an archive of the changes between the specified // layer and its parent layer which may be "". -func (gdw *naiveDiffDriver) Diff(id, parent string) (arch archive.Archive, err error) { +func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch archive.Archive, err error) { driver := gdw.ProtoDriver layerFs, err := driver.Get(id, "") @@ -84,7 +84,7 @@ func (gdw *naiveDiffDriver) Diff(id, parent string) (arch archive.Archive, err e // Changes produces a list of changes between the specified layer // and its parent layer. If parent is "", then all changes will be ADD changes. -func (gdw *naiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) { +func (gdw *NaiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) { driver := gdw.ProtoDriver layerFs, err := driver.Get(id, "") @@ -109,7 +109,7 @@ func (gdw *naiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) // ApplyDiff extracts the changeset from the given diff into the // layer with the specified id and parent, returning the size of the // new layer in bytes. -func (gdw *naiveDiffDriver) ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) { +func (gdw *NaiveDiffDriver) ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) { driver := gdw.ProtoDriver // Mount the root filesystem so we can apply the diff/layer. @@ -132,7 +132,7 @@ func (gdw *naiveDiffDriver) ApplyDiff(id, parent string, diff archive.Reader) (s // DiffSize calculates the changes between the specified layer // and its parent and returns the size in bytes of the changes // relative to its base filesystem directory. -func (gdw *naiveDiffDriver) DiffSize(id, parent string) (size int64, err error) { +func (gdw *NaiveDiffDriver) DiffSize(id, parent string) (size int64, err error) { driver := gdw.ProtoDriver changes, err := gdw.Changes(id, parent) diff --git a/daemon/graphdriver/overlay/overlay.go b/daemon/graphdriver/overlay/overlay.go index e8a070d92d..18771c7a98 100644 --- a/daemon/graphdriver/overlay/overlay.go +++ b/daemon/graphdriver/overlay/overlay.go @@ -43,7 +43,7 @@ type naiveDiffDriverWithApply struct { // NaiveDiffDriverWithApply returns a NaiveDiff driver with custom ApplyDiff. func NaiveDiffDriverWithApply(driver ApplyDiffProtoDriver) graphdriver.Driver { return &naiveDiffDriverWithApply{ - Driver: graphdriver.NaiveDiffDriver(driver), + Driver: graphdriver.NewNaiveDiffDriver(driver), applyDiff: driver, } } diff --git a/daemon/graphdriver/vfs/driver.go b/daemon/graphdriver/vfs/driver.go index 4bf26e4095..85b23b2a68 100644 --- a/daemon/graphdriver/vfs/driver.go +++ b/daemon/graphdriver/vfs/driver.go @@ -23,7 +23,7 @@ func Init(home string, options []string) (graphdriver.Driver, error) { d := &Driver{ home: home, } - return graphdriver.NaiveDiffDriver(d), nil + return graphdriver.NewNaiveDiffDriver(d), nil } // Driver holds information about the driver, home directory of the driver. diff --git a/daemon/graphdriver/zfs/zfs.go b/daemon/graphdriver/zfs/zfs.go index 0142890b0d..305aec867c 100644 --- a/daemon/graphdriver/zfs/zfs.go +++ b/daemon/graphdriver/zfs/zfs.go @@ -103,7 +103,7 @@ func Init(base string, opt []string) (graphdriver.Driver, error) { options: options, filesystemsCache: filesystemsCache, } - return graphdriver.NaiveDiffDriver(d), nil + return graphdriver.NewNaiveDiffDriver(d), nil } func parseOptions(opt []string) (zfsOptions, error) {