podman

Форк
0
/
volume_internal_common.go 
193 строки · 5.6 Кб
1
//go:build !remote && (linux || freebsd)
2

3
package libpod
4

5
import (
6
	"errors"
7
	"fmt"
8
	"os/exec"
9
	"strings"
10

11
	"github.com/containers/podman/v5/libpod/define"
12
	pluginapi "github.com/docker/go-plugins-helpers/volume"
13
	"github.com/sirupsen/logrus"
14
	"golang.org/x/sys/unix"
15
)
16

17
// This is a pseudo-container ID to use when requesting a mount or unmount from
18
// the volume plugins.
19
// This is the shas256 of the string "placeholder\n".
20
const pseudoCtrID = "2f73349cfc4630255319c6c8dfc1b46a8996ace9d14d8e07563b165915918ec2"
21

22
// mount mounts the volume if necessary.
23
// A mount is necessary if a volume has any options set.
24
// If a mount is necessary, v.state.MountCount will be incremented.
25
// If it was 0 when the increment occurred, the volume will be mounted on the
26
// host. Otherwise, we assume it is already mounted.
27
// Must be done while the volume is locked.
28
// Is a no-op on volumes that do not require a mount (as defined by
29
// volumeNeedsMount()).
30
func (v *Volume) mount() error {
31
	if !v.needsMount() {
32
		return nil
33
	}
34

35
	// Update the volume from the DB to get an accurate mount counter.
36
	if err := v.update(); err != nil {
37
		return err
38
	}
39

40
	// If the count is non-zero, the volume is already mounted.
41
	// Nothing to do.
42
	if v.state.MountCount > 0 {
43
		v.state.MountCount++
44
		logrus.Debugf("Volume %s mount count now at %d", v.Name(), v.state.MountCount)
45
		return v.save()
46
	}
47

48
	// Volume plugins implement their own mount counter, based on the ID of
49
	// the mounting container. But we already have one, and honestly I trust
50
	// ours more. So hardcode container ID to something reasonable, and use
51
	// the same one for everything.
52
	if v.UsesVolumeDriver() {
53
		if v.plugin == nil {
54
			return fmt.Errorf("volume plugin %s (needed by volume %s) missing: %w", v.Driver(), v.Name(), define.ErrMissingPlugin)
55
		}
56

57
		req := new(pluginapi.MountRequest)
58
		req.Name = v.Name()
59
		req.ID = pseudoCtrID
60
		mountPoint, err := v.plugin.MountVolume(req)
61
		if err != nil {
62
			return err
63
		}
64

65
		v.state.MountCount++
66
		v.state.MountPoint = mountPoint
67
		return v.save()
68
	} else if v.config.Driver == define.VolumeDriverImage {
69
		mountPoint, err := v.runtime.storageService.MountContainerImage(v.config.StorageID)
70
		if err != nil {
71
			return fmt.Errorf("mounting volume %s image failed: %w", v.Name(), err)
72
		}
73

74
		v.state.MountCount++
75
		v.state.MountPoint = mountPoint
76
		return v.save()
77
	}
78

79
	volDevice := v.config.Options["device"]
80
	volType := v.config.Options["type"]
81
	volOptions := v.config.Options["o"]
82

83
	// Some filesystems (tmpfs) don't have a device, but we still need to
84
	// give the kernel something.
85
	if volDevice == "" && volType != "" {
86
		volDevice = volType
87
	}
88

89
	// We need to use the actual mount command.
90
	// Convincing unix.Mount to use the same semantics as the mount command
91
	// itself seems prohibitively difficult.
92
	// TODO: might want to cache this path in the runtime?
93
	mountPath, err := exec.LookPath("mount")
94
	if err != nil {
95
		return fmt.Errorf("locating 'mount' binary: %w", err)
96
	}
97
	mountArgs := []string{}
98
	if volOptions != "" {
99
		mountArgs = append(mountArgs, "-o", volOptions)
100
	}
101
	switch volType {
102
	case "":
103
	case define.TypeBind:
104
		mountArgs = append(mountArgs, "-o", volType)
105
	default:
106
		mountArgs = append(mountArgs, "-t", volType)
107
	}
108

109
	mountArgs = append(mountArgs, volDevice, v.config.MountPoint)
110
	mountCmd := exec.Command(mountPath, mountArgs...)
111

112
	logrus.Debugf("Running mount command: %s %s", mountPath, strings.Join(mountArgs, " "))
113
	if output, err := mountCmd.CombinedOutput(); err != nil {
114
		logrus.Debugf("Mount %v failed with %v", mountCmd, err)
115
		return errors.New(string(output))
116
	}
117

118
	logrus.Debugf("Mounted volume %s", v.Name())
119

120
	// Increment the mount counter
121
	v.state.MountCount++
122
	logrus.Debugf("Volume %s mount count now at %d", v.Name(), v.state.MountCount)
123
	return v.save()
124
}
125

126
// unmount unmounts the volume if necessary.
127
// Unmounting a volume that is not mounted is a no-op.
128
// Unmounting a volume that does not require a mount is a no-op.
129
// The volume must be locked for this to occur.
130
// The mount counter will be decremented if non-zero. If the counter reaches 0,
131
// the volume will really be unmounted, as no further containers are using the
132
// volume.
133
// If force is set, the volume will be unmounted regardless of mount counter.
134
func (v *Volume) unmount(force bool) error {
135
	if !v.needsMount() {
136
		return nil
137
	}
138

139
	// Update the volume from the DB to get an accurate mount counter.
140
	if err := v.update(); err != nil {
141
		return err
142
	}
143

144
	if v.state.MountCount == 0 {
145
		logrus.Debugf("Volume %s already unmounted", v.Name())
146
		return nil
147
	}
148

149
	if !force {
150
		v.state.MountCount--
151
	} else {
152
		v.state.MountCount = 0
153
	}
154

155
	logrus.Debugf("Volume %s mount count now at %d", v.Name(), v.state.MountCount)
156

157
	if v.state.MountCount == 0 {
158
		if v.UsesVolumeDriver() {
159
			if v.plugin == nil {
160
				return fmt.Errorf("volume plugin %s (needed by volume %s) missing: %w", v.Driver(), v.Name(), define.ErrMissingPlugin)
161
			}
162

163
			req := new(pluginapi.UnmountRequest)
164
			req.Name = v.Name()
165
			req.ID = pseudoCtrID
166
			if err := v.plugin.UnmountVolume(req); err != nil {
167
				return err
168
			}
169

170
			v.state.MountPoint = ""
171
			return v.save()
172
		} else if v.config.Driver == define.VolumeDriverImage {
173
			if _, err := v.runtime.storageService.UnmountContainerImage(v.config.StorageID, force); err != nil {
174
				return fmt.Errorf("unmounting volume %s image: %w", v.Name(), err)
175
			}
176

177
			v.state.MountPoint = ""
178
			return v.save()
179
		}
180

181
		// Unmount the volume
182
		if err := detachUnmount(v.config.MountPoint); err != nil {
183
			if err == unix.EINVAL {
184
				// Ignore EINVAL - the mount no longer exists.
185
				return nil
186
			}
187
			return fmt.Errorf("unmounting volume %s: %w", v.Name(), err)
188
		}
189
		logrus.Debugf("Unmounted volume %s", v.Name())
190
	}
191

192
	return v.save()
193
}
194

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.