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