SetupLoop looks for (and possibly creates) a free loop device, and then attaches backingFile to it. When autoclear is true, caller should take care to close it when done with the loop device. The loop device file handle keeps loFlagsAutoclear in effect and we rely on it to clean up the loop device.
(backingFile string, param LoopParams)
| 166 | // |
| 167 | // Upon success, the file handle to the loop device is returned. |
| 168 | func SetupLoop(backingFile string, param LoopParams) (*os.File, error) { |
| 169 | for retry := 1; retry < 100; retry++ { |
| 170 | num, err := getFreeLoopDev() |
| 171 | if err != nil { |
| 172 | return nil, err |
| 173 | } |
| 174 | |
| 175 | loopDev := fmt.Sprintf(loopDevFormat, num) |
| 176 | file, err := setupLoopDev(backingFile, loopDev, param) |
| 177 | if err != nil { |
| 178 | // Per util-linux/sys-utils/losetup.c:create_loop(), |
| 179 | // free loop device can race and we end up failing |
| 180 | // with EBUSY when trying to set it up. |
| 181 | if strings.Contains(err.Error(), ebusyString) { |
| 182 | // Fallback a bit to avoid live lock |
| 183 | time.Sleep(time.Millisecond * time.Duration(randutil.Intn(retry*10))) |
| 184 | continue |
| 185 | } |
| 186 | return nil, err |
| 187 | } |
| 188 | |
| 189 | return file, nil |
| 190 | } |
| 191 | |
| 192 | return nil, errors.New("timeout creating new loopback device") |
| 193 | } |
| 194 | |
| 195 | func setLoopAutoclear(loop *os.File, autoclear bool) error { |
| 196 | info, err := unix.IoctlLoopGetStatus64(int(loop.Fd())) |
searching dependent graphs…