zfspool: new format 'subvol' to handle filesystems inside datasets
We use this for containers.
This commit is contained in:
@ -2,6 +2,7 @@ package PVE::API2::Storage::Content;
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
use PVE::SafeSyslog;
|
use PVE::SafeSyslog;
|
||||||
use PVE::Cluster qw(cfs_read_file);
|
use PVE::Cluster qw(cfs_read_file);
|
||||||
@ -123,7 +124,7 @@ __PACKAGE__->register_method ({
|
|||||||
},
|
},
|
||||||
'format' => {
|
'format' => {
|
||||||
type => 'string',
|
type => 'string',
|
||||||
enum => ['raw', 'qcow2'],
|
enum => ['raw', 'qcow2', 'subvol'],
|
||||||
requires => 'size',
|
requires => 'size',
|
||||||
optional => 1,
|
optional => 1,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -16,7 +16,8 @@ sub type {
|
|||||||
|
|
||||||
sub plugindata {
|
sub plugindata {
|
||||||
return {
|
return {
|
||||||
content => [ {images => 1}, { images => 1 }],
|
content => [ {images => 1, rootdir => 1}, {images => 1 , rootdir => 1}],
|
||||||
|
format => [ { raw => 1, subvol => 1 } , 'raw' ],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,25 +93,36 @@ sub zfs_parse_zvol_list {
|
|||||||
|
|
||||||
my @lines = split /\n/, $text;
|
my @lines = split /\n/, $text;
|
||||||
foreach my $line (@lines) {
|
foreach my $line (@lines) {
|
||||||
if ($line =~ /^(.+)\s+([a-zA-Z0-9\.]+|\-)\s+(.+)$/) {
|
my ($dataset, $size, $origin, $type, $refquota) = split(/\s+/, $line);
|
||||||
my $zvol = {};
|
next if !($type eq 'volume' || $type eq 'filesystem');
|
||||||
my $size = $2;
|
|
||||||
my $origin = $3;
|
|
||||||
my @parts = split /\//, $1;
|
|
||||||
my $name = pop @parts;
|
|
||||||
my $pool = join('/', @parts);
|
|
||||||
|
|
||||||
next unless $name =~ m!^(\w+)-(\d+)-(\w+)-(\d+)$!;
|
my $zvol = {};
|
||||||
$name = $pool . '/' . $name;
|
my @parts = split /\//, $dataset;
|
||||||
|
my $name = pop @parts;
|
||||||
|
my $pool = join('/', @parts);
|
||||||
|
|
||||||
$zvol->{pool} = $pool;
|
next unless $name =~ m!^(vm|base|subvol)-(\d+)-(\S+)$!;
|
||||||
$zvol->{name} = $name;
|
$zvol->{owner} = $2;
|
||||||
$zvol->{size} = zfs_parse_size($size);
|
|
||||||
if ($3 !~ /^-$/) {
|
$name = $pool . '/' . $name;
|
||||||
$zvol->{origin} = $origin;
|
|
||||||
|
$zvol->{pool} = $pool;
|
||||||
|
$zvol->{name} = $name;
|
||||||
|
if ($type eq 'filesystem') {
|
||||||
|
if ($refquota eq 'none') {
|
||||||
|
$zvol->{size} = 0;
|
||||||
|
} else {
|
||||||
|
$zvol->{size} = zfs_parse_size($refquota);
|
||||||
}
|
}
|
||||||
push @$list, $zvol;
|
$zvol->{format} = 'subvol';
|
||||||
|
} else {
|
||||||
|
$zvol->{size} = zfs_parse_size($size);
|
||||||
|
$zvol->{format} = 'raw';
|
||||||
}
|
}
|
||||||
|
if ($origin !~ /^-$/) {
|
||||||
|
$zvol->{origin} = $origin;
|
||||||
|
}
|
||||||
|
push @$list, $zvol;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $list;
|
return $list;
|
||||||
@ -119,7 +131,7 @@ sub zfs_parse_zvol_list {
|
|||||||
sub parse_volname {
|
sub parse_volname {
|
||||||
my ($class, $volname) = @_;
|
my ($class, $volname) = @_;
|
||||||
|
|
||||||
if ($volname =~ m/^(((base|vm)-(\d+)-\S+)\/)?((base)?(vm)?-(\d+)-\S+)$/) {
|
if ($volname =~ m/^(((base|vm)-(\d+)-\S+)\/)?((base)?(vm|subvol)?-(\d+)-\S+)$/) {
|
||||||
return ('images', $5, $8, $2, $4, $6);
|
return ('images', $5, $8, $2, $4, $6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,8 +147,13 @@ sub path {
|
|||||||
|
|
||||||
my $path = '';
|
my $path = '';
|
||||||
|
|
||||||
if($vtype eq "images"){
|
if ($vtype eq "images") {
|
||||||
$path = "/dev/zvol/$scfg->{pool}/$volname";
|
if ($volname =~ m/^subvol-/) {
|
||||||
|
# fixme: we currently assume standard mount point?!
|
||||||
|
$path = "$scfg->{pool}/$volname";
|
||||||
|
} else {
|
||||||
|
$path = "/dev/zvol/$scfg->{pool}/$volname";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
die "$vtype is not allowed in ZFSPool!";
|
die "$vtype is not allowed in ZFSPool!";
|
||||||
}
|
}
|
||||||
@ -174,21 +191,32 @@ sub zfs_request {
|
|||||||
sub alloc_image {
|
sub alloc_image {
|
||||||
my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
|
my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
|
||||||
|
|
||||||
die "unsupported format '$fmt'" if $fmt ne 'raw';
|
|
||||||
|
|
||||||
die "illegal name '$name' - sould be 'vm-$vmid-*'\n"
|
|
||||||
if $name && $name !~ m/^vm-$vmid-/;
|
|
||||||
|
|
||||||
my $volname = $name;
|
my $volname = $name;
|
||||||
|
|
||||||
$volname = $class->zfs_find_free_diskname($storeid, $scfg, $vmid) if !$volname;
|
if ($fmt eq 'raw') {
|
||||||
|
|
||||||
$class->zfs_create_zvol($scfg, $volname, $size);
|
die "illegal name '$volname' - sould be 'vm-$vmid-*'\n"
|
||||||
|
if $volname && $volname !~ m/^vm-$vmid-/;
|
||||||
|
$volname = $class->zfs_find_free_diskname($storeid, $scfg, $vmid)
|
||||||
|
if !$volname;
|
||||||
|
|
||||||
my $devname = "/dev/zvol/$scfg->{pool}/$volname";
|
$class->zfs_create_zvol($scfg, $volname, $size);
|
||||||
|
my $devname = "/dev/zvol/$scfg->{pool}/$volname";
|
||||||
|
|
||||||
run_command("udevadm trigger --subsystem-match block");
|
run_command("udevadm trigger --subsystem-match block");
|
||||||
system("udevadm settle --timeout 10 --exit-if-exists=${devname}");
|
system("udevadm settle --timeout 10 --exit-if-exists=${devname}");
|
||||||
|
|
||||||
|
} elsif ( $fmt eq 'subvol') {
|
||||||
|
|
||||||
|
die "subvolume allocation without name\n" if !$volname;
|
||||||
|
die "illegal name '$volname' - sould be 'subvol-$vmid-*'\n"
|
||||||
|
if $volname !~ m/^subvol-$vmid-/;
|
||||||
|
|
||||||
|
$class->zfs_create_subvol($scfg, $volname, $size);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
die "unsupported format '$fmt'";
|
||||||
|
}
|
||||||
|
|
||||||
return $volname;
|
return $volname;
|
||||||
}
|
}
|
||||||
@ -238,7 +266,6 @@ sub list_images {
|
|||||||
push @$res, $info;
|
push @$res, $info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,6 +317,16 @@ sub zfs_create_zvol {
|
|||||||
$class->zfs_request($scfg, undef, @$cmd);
|
$class->zfs_request($scfg, undef, @$cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub zfs_create_subvol {
|
||||||
|
my ($class, $scfg, $volname, $size) = @_;
|
||||||
|
|
||||||
|
my $dataset = "$scfg->{pool}/$volname";
|
||||||
|
|
||||||
|
my $cmd = ['create', '-o', "refquota=${size}k", $dataset];
|
||||||
|
|
||||||
|
$class->zfs_request($scfg, undef, @$cmd);
|
||||||
|
}
|
||||||
|
|
||||||
sub zfs_delete_zvol {
|
sub zfs_delete_zvol {
|
||||||
my ($class, $scfg, $zvol) = @_;
|
my ($class, $scfg, $zvol) = @_;
|
||||||
|
|
||||||
@ -315,31 +352,25 @@ sub zfs_delete_zvol {
|
|||||||
sub zfs_list_zvol {
|
sub zfs_list_zvol {
|
||||||
my ($class, $scfg) = @_;
|
my ($class, $scfg) = @_;
|
||||||
|
|
||||||
my $text = $class->zfs_request($scfg, 10, 'list', '-o', 'name,volsize,origin', '-t', 'volume', '-Hr');
|
my $text = $class->zfs_request($scfg, 10, 'list', '-o', 'name,volsize,origin,type,refquota', '-t', 'volume,filesystem', '-Hr');
|
||||||
my $zvols = zfs_parse_zvol_list($text);
|
my $zvols = zfs_parse_zvol_list($text);
|
||||||
return undef if !$zvols;
|
return undef if !$zvols;
|
||||||
|
|
||||||
my $list = ();
|
my $list = ();
|
||||||
foreach my $zvol (@$zvols) {
|
foreach my $zvol (@$zvols) {
|
||||||
my @values = split('/', $zvol->{name});
|
my $pool = $zvol->{pool};
|
||||||
|
my $name = $zvol->{name};
|
||||||
my $image = pop @values;
|
|
||||||
my $pool = join('/', @values);
|
|
||||||
|
|
||||||
next if $image !~ m/^((vm|base)-(\d+)-\S+)$/;
|
|
||||||
my $owner = $3;
|
|
||||||
|
|
||||||
my $parent = $zvol->{origin};
|
my $parent = $zvol->{origin};
|
||||||
if($zvol->{origin} && $zvol->{origin} =~ m/^$scfg->{pool}\/(\S+)$/){
|
if($zvol->{origin} && $zvol->{origin} =~ m/^$scfg->{pool}\/(\S+)$/){
|
||||||
$parent = $1;
|
$parent = $1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$list->{$pool}->{$image} = {
|
$list->{$pool}->{$name} = {
|
||||||
name => $image,
|
name => $name,
|
||||||
size => $zvol->{size},
|
size => $zvol->{size},
|
||||||
parent => $parent,
|
parent => $parent,
|
||||||
format => 'raw',
|
format => $zvol->{format},
|
||||||
vmid => $owner
|
vmid => $zvol->{owner},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user