use warnings;
use Cwd qw();
-use Errno qw(ELOOP ENOTDIR EROFS ECONNREFUSED ENOSYS EEXIST);
+use Errno qw(ELOOP ENOTDIR EROFS ECONNREFUSED EEXIST);
use Fcntl qw(O_RDONLY O_WRONLY O_NOFOLLOW O_DIRECTORY);
use File::Path;
use File::Spec;
__mountpoint_mount($mountpoint, $stage_dir, $storage_cfg, $snapname, $rootuid, $rootgid, 1);
if (!defined($path)) {
- return undef if $! == ENOSYS;
die "failed to mount subvolume: $!\n";
}
# Use $stage_mount, $rootdir is treated as a temporary path to "stage" the file system. The user
# can then open a file descriptor to it which can be used with the `move_mount` syscall.
-# Note that if the kernel does not support the new mount API, this will not perform any action
-# and return `undef` with $! = ENOSYS.
sub __mountpoint_mount {
my ($mountpoint, $rootdir, $storage_cfg, $snapname, $rootuid, $rootgid, $stage_mount) = @_;
- if (defined($stage_mount) && !PVE::LXC::Tools::can_use_new_mount_api()) {
- $! = ENOSYS;
- return undef;
- }
-
# When staging mount points we always mount to $rootdir directly (iow. as if `mp=/`).
# This is required since __mount_prepare_rootdir() will return handles to the parent directory
# which we use in __bindmount_verify()!
return $target;
}
-# Mount /run/pve/mountpoints as tmpfs
+# Mount tmpfs for mount point staging and return the path.
sub get_staging_tempfs() {
# We choose a path in /var/lib/lxc/ here because the lxc-start apparmor profile restricts most
# mounts to that.
use strict;
use warnings;
-use Errno qw(ENOSYS);
-
use PVE::SafeSyslog;
# LXC introduced an `lxc.hook.version` property which allows hooks to be executed in different
return 1;
}
-# Check whether the kernel supports the new mount api. This is used in the pre-start hook and in
-# the hotplugging code.
-my $cached_can_use_new_mount_api = undef;
-sub can_use_new_mount_api() {
- if (!defined($cached_can_use_new_mount_api)) {
- if (PVE::Tools::move_mount(-1, 0, -1, 0, 0)) {
- # This should not be possible...
- die "kernel behaved unexpectedly: move_mount(-1, NULL, -1, NULL) did not fail!\n";
- }
- # On older kernels the syscall doesn't exist and we get ENOSYS. (For newer kernels this call
- # will fail with EFAULT instead, since we pass in a NULL pointer as file system name.)
- $cached_can_use_new_mount_api = ($! != ENOSYS);
- }
- return $cached_can_use_new_mount_api;
-}
-
1;
PVE::Tools::run_command(['umount', '--recursive', $rootdir], outfunc => sub {}, errfunc => sub {});
};
- my $setup_mountpoint;
- if (!PVE::LXC::Tools::can_use_new_mount_api()) {
- # Legacy mode for old kernels:
- $setup_mountpoint = sub {
- my ($opt, $mountpoint) = @_;
-
- my (undef, undef, $dev) = PVE::LXC::mountpoint_mount(
- $mountpoint,
- $rootdir,
- $storage_cfg,
- undef,
- $rootuid,
- $rootgid,
- );
- push @$devices, $dev if $dev && $mountpoint->{quota};
- };
- } else {
- # With newer kernels we stage mount points and then use move_mount().
- my $rootdir_fd = undef;
- $setup_mountpoint = sub {
- my ($opt, $mountpoint) = @_;
-
- my $dir = PVE::LXC::get_staging_mount_path($opt);
- my (undef, undef, $dev, $mount_fd) = PVE::LXC::mountpoint_stage(
- $mountpoint,
- $dir,
- $storage_cfg,
- undef,
- $rootuid,
- $rootgid,
- );
-
- my ($dest_dir, $dest_base_fd);
- if ($rootdir_fd) {
- # Mount relative to the rootdir fd.
- $dest_base_fd = $rootdir_fd;
- $dest_dir = './' . $mountpoint->{mp};
- } else {
- # Assert that 'rootfs' is the first one:
- die "foreach_mount() error\n" if $opt ne 'rootfs';
-
- # Mount the rootfs absolutely.
- # $rootdir is not controlled by the container, so this is fine.
- sysopen($dest_base_fd, '/', O_PATH | O_DIRECTORY)
- or die "failed to open '.': $!\n";
- $dest_dir = $rootdir;
- }
-
- PVE::LXC::mountpoint_insert_staged(
- $mount_fd,
- $dest_base_fd,
- $dest_dir,
- $opt,
- $rootuid,
- $rootgid,
- );
-
- # From now on we mount inside our rootfs:
- if (!$rootdir_fd) {
- $rootdir_fd = $mount_fd;
- }
-
- push @$devices, $dev if $dev && $mountpoint->{quota};
- };
- }
+ my $rootdir_fd = undef;
+ my $setup_mountpoint = sub {
+ my ($opt, $mountpoint) = @_;
+
+ my $dir = PVE::LXC::get_staging_mount_path($opt);
+ my (undef, undef, $dev, $mount_fd) = PVE::LXC::mountpoint_stage(
+ $mountpoint,
+ $dir,
+ $storage_cfg,
+ undef,
+ $rootuid,
+ $rootgid,
+ );
+
+ my ($dest_dir, $dest_base_fd);
+ if ($rootdir_fd) {
+ # Mount relative to the rootdir fd.
+ $dest_base_fd = $rootdir_fd;
+ $dest_dir = './' . $mountpoint->{mp};
+ } else {
+ # Assert that 'rootfs' is the first one:
+ die "foreach_mount() error\n" if $opt ne 'rootfs';
+
+ # Mount the rootfs absolutely.
+ # $rootdir is not controlled by the container, so this is fine.
+ sysopen($dest_base_fd, '/', O_PATH | O_DIRECTORY)
+ or die "failed to open '.': $!\n";
+ $dest_dir = $rootdir;
+ }
+
+ PVE::LXC::mountpoint_insert_staged(
+ $mount_fd,
+ $dest_base_fd,
+ $dest_dir,
+ $opt,
+ $rootuid,
+ $rootgid,
+ );
+
+ # From now on we mount inside our rootfs:
+ if (!$rootdir_fd) {
+ $rootdir_fd = $mount_fd;
+ }
+
+ push @$devices, $dev if $dev && $mountpoint->{quota};
+ };
PVE::LXC::Config->foreach_volume($conf, $setup_mountpoint);