mount: support direct-io for loopback device
Signed-off-by: Wei Fu <fuweid89@gmail.com>
This commit is contained in:
parent
ded713010c
commit
72b7d16505
@ -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)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
_ = unix.IoctlSetInt(int(loop.Fd()), unix.LOOP_CLR_FD, 0)
|
||||
}
|
||||
}()
|
||||
|
||||
// 3. Set Info
|
||||
info := unix.LoopInfo64{}
|
||||
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
|
||||
}
|
||||
|
||||
if param.Direct {
|
||||
info.Flags |= unix.LO_FLAGS_DIRECT_IO
|
||||
}
|
||||
|
||||
err = unix.IoctlLoopSetStatus64(int(loop.Fd()), &info)
|
||||
if err == nil {
|
||||
return loop, nil
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to set loop device info: %w", err)
|
||||
}
|
||||
|
||||
// 4. Set Direct IO
|
||||
if param.Direct {
|
||||
// Retry w/o direct IO flag in case kernel does not support it. The downside is that
|
||||
// it will suffer from double cache problem.
|
||||
info.Flags &= ^(uint32(unix.LO_FLAGS_DIRECT_IO))
|
||||
err = unix.IoctlLoopSetStatus64(int(loop.Fd()), &info)
|
||||
if err == nil {
|
||||
return loop, nil
|
||||
err = unix.IoctlSetInt(int(loop.Fd()), unix.LOOP_SET_DIRECT_IO, 1)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to setup loop with direct: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
_ = unix.IoctlSetInt(int(loop.Fd()), unix.LOOP_CLR_FD, 0)
|
||||
return nil, fmt.Errorf("failed to set loop device info: %v", err)
|
||||
return loop, nil
|
||||
}
|
||||
|
||||
// setupLoop looks for (and possibly creates) a free loop device, and
|
||||
|
@ -63,9 +63,6 @@ func (m *Mount) mount(target string) (err error) {
|
||||
}
|
||||
|
||||
flags, data, losetup := parseMountOptions(options)
|
||||
if len(data) > pagesize {
|
||||
return errors.New("mount options is too long")
|
||||
}
|
||||
|
||||
// propagation types.
|
||||
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.
|
||||
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).
|
||||
if flags&unix.MS_REMOUNT == 0 || data != "" {
|
||||
if flags&unix.MS_REMOUNT == 0 || dataInStr != "" {
|
||||
// Initial call applying all non-propagation flags for mount
|
||||
// or remount with changed data
|
||||
source := m.Source
|
||||
if losetup {
|
||||
loFile, err := setupLoop(m.Source, LoopParams{
|
||||
Readonly: oflags&unix.MS_RDONLY == unix.MS_RDONLY,
|
||||
Autoclear: true})
|
||||
loFile, err := setupLoop(m.Source, loopParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -90,7 +99,7 @@ func (m *Mount) mount(target string) (err error) {
|
||||
// Mount the loop device instead
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -199,7 +208,7 @@ func UnmountAll(mount string, flags int) error {
|
||||
|
||||
// parseMountOptions takes fstab style mount options and parses them for
|
||||
// use with a standard mount() syscall
|
||||
func parseMountOptions(options []string) (int, string, bool) {
|
||||
func parseMountOptions(options []string) (int, []string, bool) {
|
||||
var (
|
||||
flag int
|
||||
losetup bool
|
||||
@ -252,7 +261,16 @@ func parseMountOptions(options []string) (int, string, bool) {
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user