my $cpuinfo= PVE::ProcFSTools::read_cpuinfo();
-our $COMMON_TAR_FLAGS = [ '--totals', '--sparse', '--numeric-owner', '--acls',
+our $COMMON_TAR_FLAGS = [ '--sparse', '--numeric-owner', '--acls',
'--xattrs',
'--xattrs-include=user.*',
'--xattrs-include=security.capability',
return $list;
}
+sub classify_mountpoint {
+ my ($vol) = @_;
+ if ($vol =~ m!^/!) {
+ return 'device' if $vol =~ m!^/dev/!;
+ return 'bind';
+ }
+ return 'volume';
+}
+
sub parse_ct_mountpoint {
my ($data, $noerr) = @_;
$res->{size} = $size;
}
+ $res->{type} = classify_mountpoint($res->{volume});
+
return $res;
}
sub print_ct_mountpoint {
my ($info, $nomp) = @_;
- my $skip = $nomp ? ['mp'] : [];
+ my $skip = [ 'type' ];
+ push @$skip, 'mp' if $nomp;
return PVE::JSONSchema::print_property_string($info, $mp_desc, $skip);
}
die "implement me";
}
+ $raw .= "lxc.start.unshare = 1\n";
+
# Should we read them from /etc/subuid?
if ($unprivileged && !$custom_idmap) {
$raw .= "lxc.id_map = u 0 100000 65536\n";
my $lxcmem = int($memory*1024*1024);
$raw .= "lxc.cgroup.memory.limit_in_bytes = $lxcmem\n";
+ $raw .= "lxc.cgroup.memory.kmem.limit_in_bytes = $lxcmem\n";
my $lxcswap = int(($memory + $swap)*1024*1024);
$raw .= "lxc.cgroup.memory.memsw.limit_in_bytes = $lxcswap\n";
$mountpoint->{mp} = '/';
$raw .= "lxc.rootfs = $dir/rootfs\n";
+ $raw .= "lxc.hook.stop = /usr/lib/x86_64-linux-gnu/lxc/hooks/unmount-namespace\n";
my $netcount = 0;
foreach my $k (keys %$conf) {
sub add_unused_volume {
my ($config, $volid) = @_;
- # skip bind mounts and block devices
- return if $volid =~ m|^/|;
-
my $key;
for (my $ind = $MAX_UNUSED_DISKS - 1; $ind >= 0; $ind--) {
my $test = "unused$ind";
if (defined($delete)) {
foreach my $opt (@$delete) {
+ if (!exists($conf->{$opt})) {
+ warn "no such option: $opt\n";
+ next;
+ }
+
if ($opt eq 'hostname' || $opt eq 'memory' || $opt eq 'rootfs') {
die "unable to delete required option '$opt'\n";
} elsif ($opt eq 'swap') {
next if $hotplug_error->($opt);
check_protection($conf, "can't remove CT $vmid drive '$opt'");
my $mountpoint = parse_ct_mountpoint($conf->{$opt});
- add_unused_volume($conf, $mountpoint->{volume});
+ if ($mountpoint->{type} eq 'volume') {
+ add_unused_volume($conf, $mountpoint->{volume})
+ }
delete $conf->{$opt};
} elsif ($opt eq 'unprivileged') {
die "unable to delete read-only option: '$opt'\n";
sub delete_mountpoint_volume {
my ($storage_cfg, $vmid, $volume) = @_;
- # skip bind mounts and block devices
- if ($volume =~ m|^/|) {
- return;
- }
+ return if classify_mountpoint($volume) ne 'volume';
my ($vtype, $name, $owner) = PVE::Storage::parse_volname($storage_cfg, $volume);
PVE::Storage::vdisk_free($storage_cfg, $volume) if $vmid == $owner;
}
};
+sub query_loopdev {
+ my ($path) = @_;
+ my $found;
+ my $parser = sub {
+ my $line = shift;
+ if ($line =~ m@^(/dev/loop\d+):@) {
+ $found = $1;
+ }
+ };
+ my $cmd = ['losetup', '--associated', $path];
+ PVE::Tools::run_command($cmd, outfunc => $parser);
+ return $found;
+}
+
# use $rootdir = undef to just return the corresponding mount path
sub mountpoint_mount {
my ($mountpoint, $rootdir, $storage_cfg, $snapname) = @_;
my $volid = $mountpoint->{volume};
my $mount = $mountpoint->{mp};
+ my $type = $mountpoint->{type};
return if !$volid || !$mount;
if ($format eq 'subvol') {
if ($mount_path) {
if ($snapname) {
- if ($scfg->{type} eq 'zfspool') {
- my $path_arg = $path;
- $path_arg =~ s!^/+!!;
- PVE::Tools::run_command(['mount', '-o', 'ro', '-t', 'zfs', $path_arg, $mount_path]);
- } else {
+ if ($scfg->{type} ne 'zfspool') {
die "cannot mount subvol snapshots for storage type '$scfg->{type}'\n";
}
- } else {
- PVE::Tools::run_command(['mount', '-o', 'bind', $path, $mount_path]);
}
+ PVE::Tools::run_command(['mount', '-o', 'bind', $path, $mount_path]);
}
return wantarray ? ($path, 0) : $path;
} elsif ($format eq 'raw' || $format eq 'iso') {
} else {
die "unsupported image format '$format'\n";
}
- } elsif ($volid =~ m|^/dev/.+|) {
+ } elsif ($type eq 'device') {
PVE::Tools::run_command(['mount', $volid, $mount_path]) if $mount_path;
return wantarray ? ($volid, 0) : $volid;
- } elsif ($volid !~ m|^/dev/.+| && $volid =~ m|^/.+| && -d $volid) {
+ } elsif ($type eq 'bind' && -d $volid) {
&$check_mount_path($volid);
PVE::Tools::run_command(['mount', '-o', 'bind', $volid, $mount_path]) if $mount_path;
return wantarray ? ($volid, 0) : $volid;
my $volid = $mountpoint->{volume};
- return if !$volid || $volid =~ m|^/|;
+ return if !$volid || $mountpoint->{type} ne 'volume';
my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
return if !$sid;
}
sub mkfs {
- my ($dev) = @_;
+ my ($dev, $rootuid, $rootgid) = @_;
- PVE::Tools::run_command(['mkfs.ext4', '-O', 'mmp', $dev]);
+ PVE::Tools::run_command(['mkfs.ext4', '-O', 'mmp',
+ '-E', "root_owner=$rootuid:$rootgid",
+ $dev]);
}
sub format_disk {
- my ($storage_cfg, $volid) = @_;
+ my ($storage_cfg, $volid, $rootuid, $rootgid) = @_;
if ($volid =~ m!^/dev/.+!) {
mkfs($volid);
die "cannot format volume '$volid' (format == $format)\n"
if $format ne 'raw';
- mkfs($path);
+ mkfs($path, $rootuid, $rootgid);
}
sub destroy_disks {
my $vollist = [];
eval {
+ my (undef, $rootuid, $rootgid) = PVE::LXC::parse_id_maps($conf);
+ my $chown_vollist = [];
+
foreach_mountpoint($settings, sub {
my ($ms, $mountpoint) = @_;
if ($size_kb > 0) {
$volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'raw',
undef, $size_kb);
- format_disk($storecfg, $volid);
+ format_disk($storecfg, $volid, $rootuid, $rootgid);
} else {
$volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'subvol',
undef, 0);
+ push @$chown_vollist, $volid;
}
} elsif ($scfg->{type} eq 'zfspool') {
$volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'subvol',
undef, $size_kb);
+ push @$chown_vollist, $volid;
} elsif ($scfg->{type} eq 'drbd' || $scfg->{type} eq 'lvm') {
$volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'raw', undef, $size_kb);
- format_disk($storecfg, $volid);
+ format_disk($storecfg, $volid, $rootuid, $rootgid);
} elsif ($scfg->{type} eq 'rbd') {
die "krbd option must be enabled on storage type '$scfg->{type}'\n" if !$scfg->{krbd};
$volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'raw', undef, $size_kb);
- format_disk($storecfg, $volid);
+ format_disk($storecfg, $volid, $rootuid, $rootgid);
} else {
die "unable to create containers on storage type '$scfg->{type}'\n";
}
push @$vollist, $volid;
- my $new_mountpoint = { volume => $volid, size => $size_kb*1024, mp => $mp };
- $conf->{$ms} = print_ct_mountpoint($new_mountpoint, $ms eq 'rootfs');
+ $mountpoint->{volume} = $volid;
+ $mountpoint->{size} = $size_kb * 1024;
+ $conf->{$ms} = print_ct_mountpoint($mountpoint, $ms eq 'rootfs');
} else {
# use specified/existing volid
}
});
+
+ PVE::Storage::activate_volumes($storecfg, $chown_vollist, undef);
+ foreach my $volid (@$chown_vollist) {
+ my $path = PVE::Storage::path($storecfg, $volid, undef);
+ chown($rootuid, $rootgid, $path);
+ }
+ PVE::Storage::deactivate_volumes($storecfg, $chown_vollist, undef);
};
# free allocated images on error
if (my $err = $@) {
return ($id_map, $rootuid, $rootgid);
}
+sub userns_command {
+ my ($id_map) = @_;
+ if (@$id_map) {
+ return ['lxc-usernsexec', (map { ('-m', join(':', @$_)) } @$id_map), '--'];
+ }
+ return [];
+}
+
1;