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 }