github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/daemon/graphdriver/devmapper/devmapper_test.go (about)

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