github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/daemon/graphdriver/devmapper/devmapper_test.go (about)

     1  // +build linux
     2  
     3  package devmapper
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"os/exec"
     9  	"syscall"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/docker/docker/daemon/graphdriver"
    14  	"github.com/docker/docker/daemon/graphdriver/graphtest"
    15  	"github.com/docker/docker/pkg/parsers/kernel"
    16  	"golang.org/x/sys/unix"
    17  )
    18  
    19  func init() {
    20  	// Reduce the size of the base fs and loopback for the tests
    21  	defaultDataLoopbackSize = 300 * 1024 * 1024
    22  	defaultMetaDataLoopbackSize = 200 * 1024 * 1024
    23  	defaultBaseFsSize = 300 * 1024 * 1024
    24  	defaultUdevSyncOverride = true
    25  	if err := initLoopbacks(); err != nil {
    26  		panic(err)
    27  	}
    28  }
    29  
    30  // initLoopbacks ensures that the loopback devices are properly created within
    31  // the system running the device mapper tests.
    32  func initLoopbacks() error {
    33  	statT, err := getBaseLoopStats()
    34  	if err != nil {
    35  		return err
    36  	}
    37  	// create at least 8 loopback files, ya, that is a good number
    38  	for i := 0; i < 8; i++ {
    39  		loopPath := fmt.Sprintf("/dev/loop%d", i)
    40  		// only create new loopback files if they don't exist
    41  		if _, err := os.Stat(loopPath); err != nil {
    42  			if mkerr := syscall.Mknod(loopPath,
    43  				uint32(statT.Mode|syscall.S_IFBLK), int((7<<8)|(i&0xff)|((i&0xfff00)<<12))); mkerr != nil {
    44  				return mkerr
    45  			}
    46  			os.Chown(loopPath, int(statT.Uid), int(statT.Gid))
    47  		}
    48  	}
    49  	return nil
    50  }
    51  
    52  // getBaseLoopStats inspects /dev/loop0 to collect uid,gid, and mode for the
    53  // loop0 device on the system.  If it does not exist we assume 0,0,0660 for the
    54  // stat data
    55  func getBaseLoopStats() (*syscall.Stat_t, error) {
    56  	loop0, err := os.Stat("/dev/loop0")
    57  	if err != nil {
    58  		if os.IsNotExist(err) {
    59  			return &syscall.Stat_t{
    60  				Uid:  0,
    61  				Gid:  0,
    62  				Mode: 0660,
    63  			}, nil
    64  		}
    65  		return nil, err
    66  	}
    67  	return loop0.Sys().(*syscall.Stat_t), nil
    68  }
    69  
    70  // This avoids creating a new driver for each test if all tests are run
    71  // Make sure to put new tests between TestDevmapperSetup and TestDevmapperTeardown
    72  func TestDevmapperSetup(t *testing.T) {
    73  	graphtest.GetDriver(t, "devicemapper")
    74  }
    75  
    76  func TestDevmapperCreateEmpty(t *testing.T) {
    77  	graphtest.DriverTestCreateEmpty(t, "devicemapper")
    78  }
    79  
    80  func TestDevmapperCreateBase(t *testing.T) {
    81  	graphtest.DriverTestCreateBase(t, "devicemapper")
    82  }
    83  
    84  func TestDevmapperCreateSnap(t *testing.T) {
    85  	graphtest.DriverTestCreateSnap(t, "devicemapper")
    86  }
    87  
    88  func TestDevmapperTeardown(t *testing.T) {
    89  	graphtest.PutDriver(t)
    90  }
    91  
    92  func TestDevmapperReduceLoopBackSize(t *testing.T) {
    93  	tenMB := int64(10 * 1024 * 1024)
    94  	testChangeLoopBackSize(t, -tenMB, defaultDataLoopbackSize, defaultMetaDataLoopbackSize)
    95  }
    96  
    97  func TestDevmapperIncreaseLoopBackSize(t *testing.T) {
    98  	tenMB := int64(10 * 1024 * 1024)
    99  	testChangeLoopBackSize(t, tenMB, defaultDataLoopbackSize+tenMB, defaultMetaDataLoopbackSize+tenMB)
   100  }
   101  
   102  func testChangeLoopBackSize(t *testing.T, delta, expectDataSize, expectMetaDataSize int64) {
   103  	driver := graphtest.GetDriver(t, "devicemapper").(*graphtest.Driver).Driver.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver)
   104  	defer graphtest.PutDriver(t)
   105  	// make sure data or metadata loopback size are the default size
   106  	if s := driver.DeviceSet.Status(); s.Data.Total != uint64(defaultDataLoopbackSize) || s.Metadata.Total != uint64(defaultMetaDataLoopbackSize) {
   107  		t.Fatal("data or metadata loop back size is incorrect")
   108  	}
   109  	if err := driver.Cleanup(); err != nil {
   110  		t.Fatal(err)
   111  	}
   112  	//Reload
   113  	d, err := Init(driver.home, []string{
   114  		fmt.Sprintf("dm.loopdatasize=%d", defaultDataLoopbackSize+delta),
   115  		fmt.Sprintf("dm.loopmetadatasize=%d", defaultMetaDataLoopbackSize+delta),
   116  	}, nil, nil)
   117  	if err != nil {
   118  		t.Fatalf("error creating devicemapper driver: %v", err)
   119  	}
   120  	driver = d.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver)
   121  	if s := driver.DeviceSet.Status(); s.Data.Total != uint64(expectDataSize) || s.Metadata.Total != uint64(expectMetaDataSize) {
   122  		t.Fatal("data or metadata loop back size is incorrect")
   123  	}
   124  	if err := driver.Cleanup(); err != nil {
   125  		t.Fatal(err)
   126  	}
   127  }
   128  
   129  // Make sure devices.Lock() has been release upon return from cleanupDeletedDevices() function
   130  func TestDevmapperLockReleasedDeviceDeletion(t *testing.T) {
   131  	driver := graphtest.GetDriver(t, "devicemapper").(*graphtest.Driver).Driver.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver)
   132  	defer graphtest.PutDriver(t)
   133  
   134  	// Call cleanupDeletedDevices() and after the call take and release
   135  	// DeviceSet Lock. If lock has not been released, this will hang.
   136  	driver.DeviceSet.cleanupDeletedDevices()
   137  
   138  	doneChan := make(chan bool)
   139  
   140  	go func() {
   141  		driver.DeviceSet.Lock()
   142  		defer driver.DeviceSet.Unlock()
   143  		doneChan <- true
   144  	}()
   145  
   146  	select {
   147  	case <-time.After(time.Second * 5):
   148  		// Timer expired. That means lock was not released upon
   149  		// function return and we are deadlocked. Release lock
   150  		// here so that cleanup could succeed and fail the test.
   151  		driver.DeviceSet.Unlock()
   152  		t.Fatal("Could not acquire devices lock after call to cleanupDeletedDevices()")
   153  	case <-doneChan:
   154  	}
   155  }
   156  
   157  // Ensure that mounts aren't leakedriver. It's non-trivial for us to test the full
   158  // reproducer of #34573 in a unit test, but we can at least make sure that a
   159  // simple command run in a new namespace doesn't break things horribly.
   160  func TestDevmapperMountLeaks(t *testing.T) {
   161  	if !kernel.CheckKernelVersion(3, 18, 0) {
   162  		t.Skipf("kernel version <3.18.0 and so is missing torvalds/linux@8ed936b5671bfb33d89bc60bdcc7cf0470ba52fe.")
   163  	}
   164  
   165  	driver := graphtest.GetDriver(t, "devicemapper", "dm.use_deferred_removal=false", "dm.use_deferred_deletion=false").(*graphtest.Driver).Driver.(*graphdriver.NaiveDiffDriver).ProtoDriver.(*Driver)
   166  	defer graphtest.PutDriver(t)
   167  
   168  	// We need to create a new (dummy) device.
   169  	if err := driver.Create("some-layer", "", nil); err != nil {
   170  		t.Fatalf("setting up some-layer: %v", err)
   171  	}
   172  
   173  	// Mount the device.
   174  	_, err := driver.Get("some-layer", "")
   175  	if err != nil {
   176  		t.Fatalf("mounting some-layer: %v", err)
   177  	}
   178  
   179  	// Create a new subprocess which will inherit our mountpoint, then
   180  	// intentionally leak it and stick around. We can't do this entirely within
   181  	// Go because forking and namespaces in Go are really not handled well at
   182  	// all.
   183  	cmd := exec.Cmd{
   184  		Path: "/bin/sh",
   185  		Args: []string{
   186  			"/bin/sh", "-c",
   187  			"mount --make-rprivate / && sleep 1000s",
   188  		},
   189  		SysProcAttr: &syscall.SysProcAttr{
   190  			Unshareflags: syscall.CLONE_NEWNS,
   191  		},
   192  	}
   193  	if err := cmd.Start(); err != nil {
   194  		t.Fatalf("starting sub-command: %v", err)
   195  	}
   196  	defer func() {
   197  		unix.Kill(cmd.Process.Pid, unix.SIGKILL)
   198  		cmd.Wait()
   199  	}()
   200  
   201  	// Now try to "drop" the device.
   202  	if err := driver.Put("some-layer"); err != nil {
   203  		t.Fatalf("unmounting some-layer: %v", err)
   204  	}
   205  }