mount: support direct-io for loopback device

Signed-off-by: Wei Fu <fuweid89@gmail.com>
This commit is contained in:
Wei Fu 2023-06-15 06:04:19 +00:00
parent ded713010c
commit 72b7d16505
2 changed files with 41 additions and 24 deletions

View File

@ -89,6 +89,12 @@ func setupLoopDev(backingFile, loopDev string, param LoopParams) (_ *os.File, re
return nil, fmt.Errorf("could not set loop fd for device: %s: %w", loopDev, err) return nil, fmt.Errorf("could not set loop fd for device: %s: %w", loopDev, err)
} }
defer func() {
if retErr != nil {
_ = unix.IoctlSetInt(int(loop.Fd()), unix.LOOP_CLR_FD, 0)
}
}()
// 3. Set Info // 3. Set Info
info := unix.LoopInfo64{} info := unix.LoopInfo64{}
copy(info.File_name[:], backingFile) copy(info.File_name[:], backingFile)
@ -100,27 +106,20 @@ func setupLoopDev(backingFile, loopDev string, param LoopParams) (_ *os.File, re
info.Flags |= unix.LO_FLAGS_AUTOCLEAR info.Flags |= unix.LO_FLAGS_AUTOCLEAR
} }
if param.Direct {
info.Flags |= unix.LO_FLAGS_DIRECT_IO
}
err = unix.IoctlLoopSetStatus64(int(loop.Fd()), &info) err = unix.IoctlLoopSetStatus64(int(loop.Fd()), &info)
if err == nil { if err != nil {
return loop, nil return nil, fmt.Errorf("failed to set loop device info: %w", err)
} }
// 4. Set Direct IO
if param.Direct { if param.Direct {
// Retry w/o direct IO flag in case kernel does not support it. The downside is that err = unix.IoctlSetInt(int(loop.Fd()), unix.LOOP_SET_DIRECT_IO, 1)
// it will suffer from double cache problem. if err != nil {
info.Flags &= ^(uint32(unix.LO_FLAGS_DIRECT_IO)) return nil, fmt.Errorf("failed to setup loop with direct: %w", err)
err = unix.IoctlLoopSetStatus64(int(loop.Fd()), &info)
if err == nil {
return loop, nil
} }
} }
_ = unix.IoctlSetInt(int(loop.Fd()), unix.LOOP_CLR_FD, 0) return loop, nil
return nil, fmt.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

View File

@ -63,9 +63,6 @@ func (m *Mount) mount(target string) (err error) {
} }
flags, data, losetup := parseMountOptions(options) flags, data, losetup := parseMountOptions(options)
if len(data) > pagesize {
return errors.New("mount options is too long")
}
// propagation types. // propagation types.
const ptypes = unix.MS_SHARED | unix.MS_PRIVATE | unix.MS_SLAVE | unix.MS_UNBINDABLE const ptypes = unix.MS_SHARED | unix.MS_PRIVATE | unix.MS_SLAVE | unix.MS_UNBINDABLE
@ -73,15 +70,27 @@ func (m *Mount) mount(target string) (err error) {
// Ensure propagation type change flags aren't included in other calls. // Ensure propagation type change flags aren't included in other calls.
oflags := flags &^ ptypes oflags := flags &^ ptypes
var loopParams LoopParams
if losetup {
loopParams = LoopParams{
Readonly: oflags&unix.MS_RDONLY == unix.MS_RDONLY,
Autoclear: true,
}
loopParams.Direct, data = hasDirectIO(data)
}
dataInStr := strings.Join(data, ",")
if len(dataInStr) > pagesize {
return errors.New("mount options is too long")
}
// In the case of remounting with changed data (data != ""), need to call mount (moby/moby#34077). // In the case of remounting with changed data (data != ""), need to call mount (moby/moby#34077).
if flags&unix.MS_REMOUNT == 0 || data != "" { if flags&unix.MS_REMOUNT == 0 || dataInStr != "" {
// Initial call applying all non-propagation flags for mount // Initial call applying all non-propagation flags for mount
// or remount with changed data // or remount with changed data
source := m.Source source := m.Source
if losetup { if losetup {
loFile, err := setupLoop(m.Source, LoopParams{ loFile, err := setupLoop(m.Source, loopParams)
Readonly: oflags&unix.MS_RDONLY == unix.MS_RDONLY,
Autoclear: true})
if err != nil { if err != nil {
return err return err
} }
@ -90,7 +99,7 @@ func (m *Mount) mount(target string) (err error) {
// Mount the loop device instead // Mount the loop device instead
source = loFile.Name() 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), dataInStr); err != nil {
return err return err
} }
} }
@ -199,7 +208,7 @@ func UnmountAll(mount string, flags int) error {
// parseMountOptions takes fstab style mount options and parses them for // parseMountOptions takes fstab style mount options and parses them for
// use with a standard mount() syscall // use with a standard mount() syscall
func parseMountOptions(options []string) (int, string, bool) { func parseMountOptions(options []string) (int, []string, bool) {
var ( var (
flag int flag int
losetup bool losetup bool
@ -252,7 +261,16 @@ func parseMountOptions(options []string) (int, string, bool) {
data = append(data, o) data = append(data, o)
} }
} }
return flag, strings.Join(data, ","), losetup return flag, data, losetup
}
func hasDirectIO(opts []string) (bool, []string) {
for idx, opt := range opts {
if opt == "direct-io" {
return true, append(opts[:idx], opts[idx+1:]...)
}
}
return false, opts
} }
// compactLowerdirOption updates overlay lowdir option and returns the common // compactLowerdirOption updates overlay lowdir option and returns the common