mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 03:11:40 +00:00
Merge pull request #100894 from clickyotomy/sk/loop-dev-sysfs
Handle invalid `losetup' options
This commit is contained in:
commit
6768ac8115
@ -19,6 +19,7 @@ package storageos
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@ -346,7 +347,7 @@ func pathDeviceType(path string) (deviceType, error) {
|
|||||||
// attachFileDevice takes a path to a regular file and makes it available as an
|
// attachFileDevice takes a path to a regular file and makes it available as an
|
||||||
// attached block device.
|
// attached block device.
|
||||||
func attachFileDevice(path string, exec utilexec.Interface) (string, error) {
|
func attachFileDevice(path string, exec utilexec.Interface) (string, error) {
|
||||||
blockDevicePath, err := getLoopDevice(path, exec)
|
blockDevicePath, err := getLoopDevice(path)
|
||||||
if err != nil && err.Error() != ErrDeviceNotFound {
|
if err != nil && err.Error() != ErrDeviceNotFound {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -363,7 +364,7 @@ func attachFileDevice(path string, exec utilexec.Interface) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the full path to the loop device associated with the given path.
|
// Returns the full path to the loop device associated with the given path.
|
||||||
func getLoopDevice(path string, exec utilexec.Interface) (string, error) {
|
func getLoopDevice(path string) (string, error) {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return "", errors.New(ErrNotAvailable)
|
return "", errors.New(ErrNotAvailable)
|
||||||
@ -372,23 +373,18 @@ func getLoopDevice(path string, exec utilexec.Interface) (string, error) {
|
|||||||
return "", fmt.Errorf("not attachable: %v", err)
|
return "", fmt.Errorf("not attachable: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
args := []string{"-j", path}
|
return getLoopDeviceFromSysfs(path)
|
||||||
out, err := exec.Command(losetupPath, args...).CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
klog.V(2).Infof("Failed device discover command for path %s: %v", path, err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return parseLosetupOutputForDevice(out)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeLoopDevice(path string, exec utilexec.Interface) (string, error) {
|
func makeLoopDevice(path string, exec utilexec.Interface) (string, error) {
|
||||||
args := []string{"-f", "-P", "--show", path}
|
args := []string{"-f", "-P", path}
|
||||||
out, err := exec.Command(losetupPath, args...).CombinedOutput()
|
out, err := exec.Command(losetupPath, args...).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(2).Infof("Failed device create command for path %s: %v", path, err)
|
klog.V(2).Infof("Failed device create command for path %s: %v %s", path, err, out)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return parseLosetupOutputForDevice(out)
|
|
||||||
|
return getLoopDeviceFromSysfs(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeLoopDevice(device string, exec utilexec.Interface) error {
|
func removeLoopDevice(device string, exec utilexec.Interface) error {
|
||||||
@ -406,16 +402,35 @@ func isLoopDevice(device string) bool {
|
|||||||
return strings.HasPrefix(device, "/dev/loop")
|
return strings.HasPrefix(device, "/dev/loop")
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLosetupOutputForDevice(output []byte) (string, error) {
|
// getLoopDeviceFromSysfs finds the backing file for a loop
|
||||||
if len(output) == 0 {
|
// device from sysfs via "/sys/block/loop*/loop/backing_file".
|
||||||
|
func getLoopDeviceFromSysfs(path string) (string, error) {
|
||||||
|
// If the file is a symlink.
|
||||||
|
realPath, err := filepath.EvalSymlinks(path)
|
||||||
|
if err != nil {
|
||||||
return "", errors.New(ErrDeviceNotFound)
|
return "", errors.New(ErrDeviceNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// losetup returns device in the format:
|
devices, err := filepath.Glob("/sys/block/loop*")
|
||||||
// /dev/loop1: [0073]:148662 (/var/lib/storageos/volumes/308f14af-cf0a-08ff-c9c3-b48104318e05)
|
if err != nil {
|
||||||
device := strings.TrimSpace(strings.SplitN(string(output), ":", 2)[0])
|
|
||||||
if len(device) == 0 {
|
|
||||||
return "", errors.New(ErrDeviceNotFound)
|
return "", errors.New(ErrDeviceNotFound)
|
||||||
}
|
}
|
||||||
return device, nil
|
|
||||||
|
for _, device := range devices {
|
||||||
|
backingFile := fmt.Sprintf("%s/loop/backing_file", device)
|
||||||
|
|
||||||
|
// The contents of this file is the absolute path of "path".
|
||||||
|
data, err := ioutil.ReadFile(backingFile)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the first match.
|
||||||
|
backingFilePath := strings.TrimSpace(string(data))
|
||||||
|
if backingFilePath == path || backingFilePath == realPath {
|
||||||
|
return fmt.Sprintf("/dev/%s", filepath.Base(device)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New(ErrDeviceNotFound)
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@ limitations under the License.
|
|||||||
package volumepathhandler
|
package volumepathhandler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -83,32 +83,20 @@ func (v VolumePathHandler) GetLoopDevice(path string) (string, error) {
|
|||||||
return "", fmt.Errorf("not attachable: %v", err)
|
return "", fmt.Errorf("not attachable: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
args := []string{"-j", path}
|
return getLoopDeviceFromSysfs(path)
|
||||||
cmd := exec.Command(losetupPath, args...)
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
klog.V(2).Infof("Failed device discover command for path %s: %v %s", path, err, out)
|
|
||||||
return "", fmt.Errorf("losetup -j %s failed: %v", path, err)
|
|
||||||
}
|
|
||||||
return parseLosetupOutputForDevice(out, path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeLoopDevice(path string) (string, error) {
|
func makeLoopDevice(path string) (string, error) {
|
||||||
args := []string{"-f", "--show", path}
|
args := []string{"-f", path}
|
||||||
cmd := exec.Command(losetupPath, args...)
|
cmd := exec.Command(losetupPath, args...)
|
||||||
|
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(2).Infof("Failed device create command for path: %s %v %s ", path, err, out)
|
klog.V(2).Infof("Failed device create command for path: %s %v %s", path, err, out)
|
||||||
return "", fmt.Errorf("losetup -f --show %s failed: %v", path, err)
|
return "", fmt.Errorf("losetup %s failed: %v", strings.Join(args, " "), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// losetup -f --show {path} returns device in the format:
|
return getLoopDeviceFromSysfs(path)
|
||||||
// /dev/loop1
|
|
||||||
if len(out) == 0 {
|
|
||||||
return "", errors.New(ErrDeviceNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.TrimSpace(string(out)), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeLoopDevice removes specified loopback device
|
// removeLoopDevice removes specified loopback device
|
||||||
@ -126,51 +114,37 @@ func removeLoopDevice(device string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLosetupOutputForDevice(output []byte, path string) (string, error) {
|
// getLoopDeviceFromSysfs finds the backing file for a loop
|
||||||
if len(output) == 0 {
|
// device from sysfs via "/sys/block/loop*/loop/backing_file".
|
||||||
return "", errors.New(ErrDeviceNotFound)
|
func getLoopDeviceFromSysfs(path string) (string, error) {
|
||||||
}
|
// If the file is a symlink.
|
||||||
|
|
||||||
realPath, err := filepath.EvalSymlinks(path)
|
realPath, err := filepath.EvalSymlinks(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to evaluate path %s: %s", path, err)
|
return "", fmt.Errorf("failed to evaluate path %s: %s", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// losetup -j {path} returns device in the format:
|
devices, err := filepath.Glob("/sys/block/loop*")
|
||||||
// /dev/loop1: [0073]:148662 ({path})
|
if err != nil {
|
||||||
// /dev/loop2: [0073]:148662 (/dev/sdX)
|
return "", fmt.Errorf("failed to list loop devices in sysfs: %s", err)
|
||||||
//
|
|
||||||
// losetup -j shows all the loop device for the same device that has the same
|
|
||||||
// major/minor number, by resolving symlink and matching major/minor number.
|
|
||||||
// Therefore, there will be other path than {path} in output, as shown in above output.
|
|
||||||
s := string(output)
|
|
||||||
// Find the line that exact matches to the path, or "({path})"
|
|
||||||
var matched string
|
|
||||||
scanner := bufio.NewScanner(strings.NewReader(s))
|
|
||||||
for scanner.Scan() {
|
|
||||||
// losetup output has symlinks expanded
|
|
||||||
if strings.HasSuffix(scanner.Text(), "("+realPath+")") {
|
|
||||||
matched = scanner.Text()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// Just in case losetup changes, check for the original path too
|
|
||||||
if strings.HasSuffix(scanner.Text(), "("+path+")") {
|
|
||||||
matched = scanner.Text()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if len(matched) == 0 {
|
|
||||||
return "", errors.New(ErrDeviceNotFound)
|
|
||||||
}
|
|
||||||
s = matched
|
|
||||||
|
|
||||||
// Get device name, or the 0th field of the output separated with ":".
|
for _, device := range devices {
|
||||||
// We don't need 1st field or later to be splitted, so passing 2 to SplitN.
|
backingFile := fmt.Sprintf("%s/loop/backing_file", device)
|
||||||
device := strings.TrimSpace(strings.SplitN(s, ":", 2)[0])
|
|
||||||
if len(device) == 0 {
|
// The contents of this file is the absolute path of "path".
|
||||||
return "", errors.New(ErrDeviceNotFound)
|
data, err := ioutil.ReadFile(backingFile)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the first match.
|
||||||
|
backingFilePath := strings.TrimSpace(string(data))
|
||||||
|
if backingFilePath == path || backingFilePath == realPath {
|
||||||
|
return fmt.Sprintf("/dev/%s", filepath.Base(device)), nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return device, nil
|
|
||||||
|
return "", errors.New(ErrDeviceNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindGlobalMapPathUUIDFromPod finds {pod uuid} bind mount under globalMapPath
|
// FindGlobalMapPathUUIDFromPod finds {pod uuid} bind mount under globalMapPath
|
||||||
|
Loading…
Reference in New Issue
Block a user