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 }