Merge pull request #4991 from kzys/no-auto-clear
mount: setupLoop() doesn't work with with Autoclear
This commit is contained in:
commit
ccbeb550ba
@ -69,7 +69,10 @@ func getFreeLoopDev() (uint32, error) {
|
|||||||
return uint32(num), nil
|
return uint32(num), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupLoopDev(backingFile, loopDev string, param LoopParams) error {
|
// setupLoopDev attaches the backing file to the loop device and returns
|
||||||
|
// the file handle for the loop device. The caller is responsible for
|
||||||
|
// closing the file handle.
|
||||||
|
func setupLoopDev(backingFile, loopDev string, param LoopParams) (*os.File, error) {
|
||||||
// 1. Open backing file and loop device
|
// 1. Open backing file and loop device
|
||||||
flags := os.O_RDWR
|
flags := os.O_RDWR
|
||||||
if param.Readonly {
|
if param.Readonly {
|
||||||
@ -78,19 +81,20 @@ func setupLoopDev(backingFile, loopDev string, param LoopParams) error {
|
|||||||
|
|
||||||
back, err := os.OpenFile(backingFile, flags, 0)
|
back, err := os.OpenFile(backingFile, flags, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not open backing file: %s", backingFile)
|
return nil, errors.Wrapf(err, "could not open backing file: %s", backingFile)
|
||||||
}
|
}
|
||||||
defer back.Close()
|
defer back.Close()
|
||||||
|
|
||||||
|
// To make Autoclear (LO_FLAGS_AUTOCLEAR) work, this function intentionally
|
||||||
|
// doesn't close this file handle on defer.
|
||||||
loop, err := os.OpenFile(loopDev, flags, 0)
|
loop, err := os.OpenFile(loopDev, flags, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not open loop device: %s", loopDev)
|
return nil, errors.Wrapf(err, "could not open loop device: %s", loopDev)
|
||||||
}
|
}
|
||||||
defer loop.Close()
|
|
||||||
|
|
||||||
// 2. Set FD
|
// 2. Set FD
|
||||||
if _, _, err = ioctl(loop.Fd(), unix.LOOP_SET_FD, back.Fd()); err != nil {
|
if _, _, err = ioctl(loop.Fd(), unix.LOOP_SET_FD, back.Fd()); err != nil {
|
||||||
return errors.Wrapf(err, "could not set loop fd for device: %s", loopDev)
|
return nil, errors.Wrapf(err, "could not set loop fd for device: %s", loopDev)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Set Info
|
// 3. Set Info
|
||||||
@ -110,7 +114,7 @@ func setupLoopDev(backingFile, loopDev string, param LoopParams) error {
|
|||||||
|
|
||||||
_, _, err = ioctl(loop.Fd(), unix.LOOP_SET_STATUS64, uintptr(unsafe.Pointer(&info)))
|
_, _, err = ioctl(loop.Fd(), unix.LOOP_SET_STATUS64, uintptr(unsafe.Pointer(&info)))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return loop, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if param.Direct {
|
if param.Direct {
|
||||||
@ -119,13 +123,16 @@ func setupLoopDev(backingFile, loopDev string, param LoopParams) error {
|
|||||||
info.Flags &= ^(uint32(unix.LO_FLAGS_DIRECT_IO))
|
info.Flags &= ^(uint32(unix.LO_FLAGS_DIRECT_IO))
|
||||||
_, _, err = ioctl(loop.Fd(), unix.LOOP_SET_STATUS64, uintptr(unsafe.Pointer(&info)))
|
_, _, err = ioctl(loop.Fd(), unix.LOOP_SET_STATUS64, uintptr(unsafe.Pointer(&info)))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return loop, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup loop fd and return error
|
// Cleanup loop fd and return error.
|
||||||
|
// If this function doesn't return this file handle, it must close the handle to
|
||||||
|
// prevent file descriptor leaks.
|
||||||
|
loop.Close()
|
||||||
_, _, _ = ioctl(loop.Fd(), unix.LOOP_CLR_FD, 0)
|
_, _, _ = ioctl(loop.Fd(), unix.LOOP_CLR_FD, 0)
|
||||||
return errors.Errorf("failed to set loop device info: %v", err)
|
return nil, errors.Errorf("failed to set loop device info: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setupLoop looks for (and possibly creates) a free loop device, and
|
// setupLoop looks for (and possibly creates) a free loop device, and
|
||||||
@ -142,15 +149,16 @@ func setupLoopDev(backingFile, loopDev string, param LoopParams) error {
|
|||||||
// the loop device when done with it.
|
// the loop device when done with it.
|
||||||
//
|
//
|
||||||
// Upon success, the file handle to the loop device is returned.
|
// Upon success, the file handle to the loop device is returned.
|
||||||
func setupLoop(backingFile string, param LoopParams) (string, error) {
|
func setupLoop(backingFile string, param LoopParams) (*os.File, error) {
|
||||||
for retry := 1; retry < 100; retry++ {
|
for retry := 1; retry < 100; retry++ {
|
||||||
num, err := getFreeLoopDev()
|
num, err := getFreeLoopDev()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
loopDev := fmt.Sprintf(loopDevFormat, num)
|
loopDev := fmt.Sprintf(loopDevFormat, num)
|
||||||
if err := setupLoopDev(backingFile, loopDev, param); err != nil {
|
file, err := setupLoopDev(backingFile, loopDev, param)
|
||||||
|
if err != nil {
|
||||||
// Per util-linux/sys-utils/losetup.c:create_loop(),
|
// Per util-linux/sys-utils/losetup.c:create_loop(),
|
||||||
// free loop device can race and we end up failing
|
// free loop device can race and we end up failing
|
||||||
// with EBUSY when trying to set it up.
|
// with EBUSY when trying to set it up.
|
||||||
@ -159,13 +167,13 @@ func setupLoop(backingFile string, param LoopParams) (string, error) {
|
|||||||
time.Sleep(time.Millisecond * time.Duration(rand.Intn(retry*10)))
|
time.Sleep(time.Millisecond * time.Duration(rand.Intn(retry*10)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return loopDev, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", errors.New("timeout creating new loopback device")
|
return nil, errors.New("timeout creating new loopback device")
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeLoop(loopdev string) error {
|
func removeLoop(loopdev string) error {
|
||||||
@ -181,7 +189,12 @@ func removeLoop(loopdev string) error {
|
|||||||
|
|
||||||
// Attach a specified backing file to a loop device
|
// Attach a specified backing file to a loop device
|
||||||
func AttachLoopDevice(backingFile string) (string, error) {
|
func AttachLoopDevice(backingFile string) (string, error) {
|
||||||
return setupLoop(backingFile, LoopParams{})
|
file, err := setupLoop(backingFile, LoopParams{})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return file.Name(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detach a loop device
|
// Detach a loop device
|
||||||
|
@ -64,12 +64,13 @@ func TestRoLoop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
path, err := setupLoop(backingFile, LoopParams{Readonly: true, Autoclear: true})
|
file, err := setupLoop(backingFile, LoopParams{Readonly: true, Autoclear: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
if err := ioutil.WriteFile(path, randomData, os.ModePerm); err == nil {
|
if _, err := file.Write(randomData); err == nil {
|
||||||
t.Fatalf("writing to readonly loop device should fail")
|
t.Fatalf("writing to readonly loop device should fail")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,12 +85,13 @@ func TestRwLoop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
path, err := setupLoop(backingFile, LoopParams{Autoclear: true})
|
file, err := setupLoop(backingFile, LoopParams{Autoclear: false})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
if err := ioutil.WriteFile(path, randomData, os.ModePerm); err != nil {
|
if _, err := file.Write(randomData); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,14 +79,16 @@ func (m *Mount) Mount(target string) (err error) {
|
|||||||
// or remount with changed data
|
// or remount with changed data
|
||||||
source := m.Source
|
source := m.Source
|
||||||
if losetup {
|
if losetup {
|
||||||
devFile, err := setupLoop(m.Source, LoopParams{
|
loFile, err := setupLoop(m.Source, LoopParams{
|
||||||
Readonly: oflags&unix.MS_RDONLY == unix.MS_RDONLY,
|
Readonly: oflags&unix.MS_RDONLY == unix.MS_RDONLY,
|
||||||
Autoclear: true})
|
Autoclear: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer loFile.Close()
|
||||||
|
|
||||||
// Mount the loop device instead
|
// Mount the loop device instead
|
||||||
source = devFile
|
source = loFile.Name()
|
||||||
}
|
}
|
||||||
if err := mountAt(chdir, source, target, m.Type, uintptr(oflags), data); err != nil {
|
if err := mountAt(chdir, source, target, m.Type, uintptr(oflags), data); err != nil {
|
||||||
return err
|
return err
|
||||||
|
Loading…
Reference in New Issue
Block a user