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