mirror of https://github.com/k3s-io/k3s
Apply _netdev mount option in bind mount if available
_netdev mount option is a userspace mount option and isn't copied over when bind mount is created and remount also does not copies it over and hence must be explicitly used with bind mountpull/58/head
parent
426ef9d349
commit
e881a29107
|
@ -68,6 +68,7 @@ go_test(
|
||||||
srcs = [
|
srcs = [
|
||||||
"exec_mount_test.go",
|
"exec_mount_test.go",
|
||||||
"mount_linux_test.go",
|
"mount_linux_test.go",
|
||||||
|
"mount_test.go",
|
||||||
"mount_windows_test.go",
|
"mount_windows_test.go",
|
||||||
"nsenter_mount_test.go",
|
"nsenter_mount_test.go",
|
||||||
"safe_format_and_mount_test.go",
|
"safe_format_and_mount_test.go",
|
||||||
|
|
|
@ -44,10 +44,10 @@ var _ Interface = &execMounter{}
|
||||||
|
|
||||||
// Mount runs mount(8) using given exec interface.
|
// Mount runs mount(8) using given exec interface.
|
||||||
func (m *execMounter) Mount(source string, target string, fstype string, options []string) error {
|
func (m *execMounter) Mount(source string, target string, fstype string, options []string) error {
|
||||||
bind, bindRemountOpts := isBind(options)
|
bind, bindOpts, bindRemountOpts := isBind(options)
|
||||||
|
|
||||||
if bind {
|
if bind {
|
||||||
err := m.doExecMount(source, target, fstype, []string{"bind"})
|
err := m.doExecMount(source, target, fstype, bindOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,7 +286,7 @@ func IsNotMountPoint(mounter Interface, file string) (bool, error) {
|
||||||
// use in case of bind mount, due to the fact that bind mount doesn't respect mount options.
|
// use in case of bind mount, due to the fact that bind mount doesn't respect mount options.
|
||||||
// The list equals:
|
// The list equals:
|
||||||
// options - 'bind' + 'remount' (no duplicate)
|
// options - 'bind' + 'remount' (no duplicate)
|
||||||
func isBind(options []string) (bool, []string) {
|
func isBind(options []string) (bool, []string, []string) {
|
||||||
// Because we have an FD opened on the subpath bind mount, the "bind" option
|
// Because we have an FD opened on the subpath bind mount, the "bind" option
|
||||||
// needs to be included, otherwise the mount target will error as busy if you
|
// needs to be included, otherwise the mount target will error as busy if you
|
||||||
// remount as readonly.
|
// remount as readonly.
|
||||||
|
@ -295,8 +295,14 @@ func isBind(options []string) (bool, []string) {
|
||||||
// volume mount to be read only.
|
// volume mount to be read only.
|
||||||
bindRemountOpts := []string{"bind", "remount"}
|
bindRemountOpts := []string{"bind", "remount"}
|
||||||
bind := false
|
bind := false
|
||||||
|
bindOpts := []string{"bind"}
|
||||||
|
|
||||||
|
// _netdev is a userspace mount option and does not automatically get added when
|
||||||
|
// bind mount is created and hence we must carry it over.
|
||||||
|
if checkForNetDev(options) {
|
||||||
|
bindOpts = append(bindOpts, "_netdev")
|
||||||
|
}
|
||||||
|
|
||||||
if len(options) != 0 {
|
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
switch option {
|
switch option {
|
||||||
case "bind":
|
case "bind":
|
||||||
|
@ -308,9 +314,17 @@ func isBind(options []string) (bool, []string) {
|
||||||
bindRemountOpts = append(bindRemountOpts, option)
|
bindRemountOpts = append(bindRemountOpts, option)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return bind, bindRemountOpts
|
return bind, bindOpts, bindRemountOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkForNetDev(options []string) bool {
|
||||||
|
for _, option := range options {
|
||||||
|
if option == "_netdev" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this is a workaround for the unmount device issue caused by gci mounter.
|
// TODO: this is a workaround for the unmount device issue caused by gci mounter.
|
||||||
|
|
|
@ -89,9 +89,9 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
|
||||||
// Path to mounter binary if containerized mounter is needed. Otherwise, it is set to empty.
|
// Path to mounter binary if containerized mounter is needed. Otherwise, it is set to empty.
|
||||||
// All Linux distros are expected to be shipped with a mount utility that a support bind mounts.
|
// All Linux distros are expected to be shipped with a mount utility that a support bind mounts.
|
||||||
mounterPath := ""
|
mounterPath := ""
|
||||||
bind, bindRemountOpts := isBind(options)
|
bind, bindOpts, bindRemountOpts := isBind(options)
|
||||||
if bind {
|
if bind {
|
||||||
err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, []string{"bind"})
|
err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
Copyright 2018 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsBind(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
mountOption []string
|
||||||
|
isBind bool
|
||||||
|
expectedBindOpts []string
|
||||||
|
expectedRemountOpts []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
[]string{"vers=2", "ro", "_netdev"},
|
||||||
|
false,
|
||||||
|
[]string{},
|
||||||
|
[]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
|
||||||
|
[]string{"bind", "vers=2", "ro", "_netdev"},
|
||||||
|
true,
|
||||||
|
[]string{"bind", "_netdev"},
|
||||||
|
[]string{"bind", "remount", "vers=2", "ro", "_netdev"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
bind, bindOpts, bindRemountOpts := isBind(test.mountOption)
|
||||||
|
if bind != test.isBind {
|
||||||
|
t.Errorf("Expected bind to be %v but got %v", test.isBind, bind)
|
||||||
|
}
|
||||||
|
if test.isBind {
|
||||||
|
if !reflect.DeepEqual(test.expectedBindOpts, bindOpts) {
|
||||||
|
t.Errorf("Expected bind mount options to be %+v got %+v", test.expectedBindOpts, bindOpts)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(test.expectedRemountOpts, bindRemountOpts) {
|
||||||
|
t.Errorf("Expected remount options to be %+v got %+v", test.expectedRemountOpts, bindRemountOpts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -68,7 +68,7 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
|
||||||
bindSource := ""
|
bindSource := ""
|
||||||
|
|
||||||
// tell it's going to mount azure disk or azure file according to options
|
// tell it's going to mount azure disk or azure file according to options
|
||||||
if bind, _ := isBind(options); bind {
|
if bind, _, _ := isBind(options); bind {
|
||||||
// mount azure disk
|
// mount azure disk
|
||||||
bindSource = normalizeWindowsPath(source)
|
bindSource = normalizeWindowsPath(source)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -61,10 +61,10 @@ var _ = Interface(&NsenterMounter{})
|
||||||
// Mount runs mount(8) in the host's root mount namespace. Aside from this
|
// Mount runs mount(8) in the host's root mount namespace. Aside from this
|
||||||
// aspect, Mount has the same semantics as the mounter returned by mount.New()
|
// aspect, Mount has the same semantics as the mounter returned by mount.New()
|
||||||
func (n *NsenterMounter) Mount(source string, target string, fstype string, options []string) error {
|
func (n *NsenterMounter) Mount(source string, target string, fstype string, options []string) error {
|
||||||
bind, bindRemountOpts := isBind(options)
|
bind, bindOpts, bindRemountOpts := isBind(options)
|
||||||
|
|
||||||
if bind {
|
if bind {
|
||||||
err := n.doNsenterMount(source, target, fstype, []string{"bind"})
|
err := n.doNsenterMount(source, target, fstype, bindOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue