Commit d43ca343 authored by Mike Hibler's avatar Mike Hibler

Fixed for simultaneous RO/RW instances of persistent datasets.

We were creating snapshots at the wrong time and not maintaining
them correctly.
parent fc0ee218
#!/usr/bin/perl -wT
#
# Copyright (c) 2013-2015 University of Utah and the Flux Group.
# Copyright (c) 2013-2016 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -464,7 +464,17 @@ sub freenasVolumeList($;$)
if ($snapinfo) {
my $sref = $snaps{$zvol->{'path'}};
if ($sref && @$sref > 0) {
$vol->{'snapshots'} = join(',', @$sref);
#
# For convenience of the caller, who typically only cares
# about the most recent snapshot, we sort the snapshot
# list from newest to oldest.
#
# XXX note that we can just (reverse) sort lexically since
# the timestamp suffix is fixed in length. Well technically
# it is not fixed-length, but it won't go to 11 digits for
# another 270 years or so...
#
$vol->{'snapshots'} = join(',', sort {$b cmp $a} @$sref);
}
my $sname = $clones{$zvol->{'path'}};
if ($sname) {
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2013-2015 University of Utah and the Flux Group.
# Copyright (c) 2013-2016 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -621,16 +621,15 @@ sub allocSlice($$$$) {
return -1;
}
#
# For possible later cloning, find the highest numbered snapshot
# Note that the 'snapshots' list returned by freenasVolumeList is
# already sorted from newest to oldest, so we just grab the first one.
#
if (exists($vref->{'snapshots'})) {
my $lastsnap = 0;
foreach my $snap (split(',', $vref->{'snapshots'})) {
if ($snap =~ /@(\d+)$/ && $1 > $lastsnap) {
$lastsnap = $1;
}
}
if ($lastsnap) {
$priv->{'lastsnapshot'} = $lastsnap;
my $snap = (split(',', $vref->{'snapshots'}))[0];
if ($snap =~ /@(\d+)$/) {
$priv->{'lastsnapshot'} = $1;
}
}
......@@ -1434,18 +1433,30 @@ sub deallocSlice($$$$) {
# Check for clone volumes. A clone will have our (vnode_id)
# name and be a "cloneof" a snapshot of this lease.
#
# N.B. we now call Destroy rather than Declone, leaving our
# caller responsible for cleaning up snapshots.
#
if (exists($volumes->{$vnode_id})) {
my $vref = $volumes->{$vnode_id};
my $pool = $vref->{'pool'};
if (exists($vref->{'cloneof'}) &&
$vref->{'cloneof'} =~ /^$bsid\@\d+/) {
return freenasVolumeDestroy($pool, $vnode_id);
my $cloneof = $vref->{'cloneof'};
if (defined($cloneof) && $cloneof =~ /^$bsid\@\d+/ &&
exists($volumes->{$bsid})) {
my $snaps = $volumes->{$bsid}->{'snapshots'};
#
# If we are a clone of the most recent snapshot, just Destroy
# which leaves the clone; otherwise Declone and attempt to
# remove the old snapshot.
#
# Note that we do not use the cached 'lastsnapshot' in our
# private data since that was saved back when we were created
# which could be a long time ago (and hence very stale).
#
if (defined($snaps) && $cloneof eq (split(',', $snaps))[0]) {
return freenasVolumeDestroy($pool, $vnode_id);
}
return freenasVolumeDeclone($pool, $vnode_id);
}
warn("*** WARNING: blockstore_deallocSlice: $volname: ".
"Found stale ephemeral volume '$pool/$vnode_id'");
"Found stale clone volume '$pool/$vnode_id'");
}
if (exists($volumes->{$bsid})) {
......@@ -1457,10 +1468,12 @@ sub deallocSlice($$$$) {
}
#
# We use Declone here which will remove the origin snapshot
# as well (if we are the last user) when invoked on a cloned volume.
# Ephemeral volume. We use Declone here rather than Destroy since someday
# we will have clones of ephemeral volumes. In that case we will not have
# to worry about keeping the latest snapshot as there will only be one
# and it should go away on last use.
#
return freenasVolumeDestroy($bsid, $vnode_id);
return freenasVolumeDeclone($bsid, $vnode_id);
}
# Required perl foo
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2012-2015 University of Utah and the Flux Group.
# Copyright (c) 2012-2016 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -513,21 +513,20 @@ sub Reserve($$$$$)
if ($current_size);
}
# Leases do not require any further size accounting updates.
goto done
if ($self->lease_idx() > 0);
#
# Now do an atomic update that changes both tables.
#
if (!DBQueryWarn("update blockstore_state,reserved_blockstores set ".
" remaining_capacity=remaining_capacity-${bs_size}, ".
" size='$bs_size' ".
"where blockstore_state.bsidx=reserved_blockstores.bsidx and ".
" blockstore_state.bs_id=reserved_blockstores.bs_id and ".
" reserved_blockstores.bsidx='$bsidx' and ".
" reserved_blockstores.exptidx='$exptidx' and ".
" reserved_blockstores.vnode_id='$vnode_id'")) {
# Note: leases do not require this.
#
if ($self->lease_idx() == 0 &&
!DBQueryWarn("update blockstore_state,reserved_blockstores set ".
" remaining_capacity=remaining_capacity-${bs_size}, ".
" size='$bs_size' ".
"where ".
" blockstore_state.bsidx=reserved_blockstores.bsidx and".
" blockstore_state.bs_id=reserved_blockstores.bs_id and".
" reserved_blockstores.bsidx='$bsidx' and ".
" reserved_blockstores.exptidx='$exptidx' and ".
" reserved_blockstores.vnode_id='$vnode_id'")) {
goto bad;
}
done:
......@@ -766,6 +765,7 @@ sub IsReadOnly($) {
#
sub HowUsed($) {
my ($self) = @_;
require VirtExperiment;
my $rethash = {
'readonly' => 0,
......@@ -845,18 +845,32 @@ sub Release($)
}
#
# We want to atomically uupdate update remaining_capacity and
# See if there is an associated lease.
#
my $lease_idx = 0;
$query_result =
DBQueryWarn("select lease_idx from blockstores ".
"where bsidx='$bsidx'");
if ($query_result && $query_result->numrows) {
$lease_idx = $query_result->fetchrow_array();
}
#
# We want to atomically update remaining_capacity and
# set the size in the reservation to zero, so that if we fail,
# nothing has changed.
#
if (!DBQueryWarn("update blockstore_state,reserved_blockstores set ".
" remaining_capacity=remaining_capacity+size, ".
" size=0 ".
"where blockstore_state.bsidx=reserved_blockstores.bsidx and ".
" blockstore_state.bs_id=reserved_blockstores.bs_id and ".
" reserved_blockstores.bsidx='$bsidx' and ".
" reserved_blockstores.exptidx='$exptidx' and ".
" reserved_blockstores.vnode_id='$vnode_id'")) {
# Note: leases do not require this.
#
if ($lease_idx == 0 &&
!DBQueryWarn("update blockstore_state,reserved_blockstores set ".
" remaining_capacity=remaining_capacity+size, ".
" size=0 ".
"where ".
" blockstore_state.bsidx=reserved_blockstores.bsidx and".
" blockstore_state.bs_id=reserved_blockstores.bs_id and".
" reserved_blockstores.bsidx='$bsidx' and".
" reserved_blockstores.exptidx='$exptidx' and".
" reserved_blockstores.vnode_id='$vnode_id'")) {
goto bad;
}
# That worked, so now we can delete the reservation row.
......@@ -874,19 +888,15 @@ sub Release($)
# of the lease.
#
# XXX currently, we also create a new snapshot of the blockstore
# if the blockstore is marked as "multiuse".
# if the blockstore is marked as "multiuse" and is mapped RW.
#
$query_result =
DBQueryWarn("select lease_idx from blockstores ".
"where bsidx='$bsidx'");
if ($query_result && $query_result->numrows) {
if ($lease_idx != 0) {
require Lease;
my ($lidx) = $query_result->fetchrow_array();
my $lease = Lease->Lookup($lidx);
my $lease = Lease->Lookup($lease_idx);
if ($lease) {
$lease->BumpLastUsed();
if (!$lease->IsExclusiveUse() &&
if (!$lease->IsExclusiveUse() && !$self->IsReadOnly() &&
$lease->CreateResourceSnapshot(1)) {
print STDERR "Blockstore->Release: ".
"Could not create snapshot for $bsidx ($lease); ".
......
#!/usr/bin/perl -wT
#
# Copyright (c) 2012-2015 University of Utah and the Flux Group.
# Copyright (c) 2012-2016 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -475,10 +475,13 @@ sub InUseReadWrite() {
if (!ref($self));
my $resvref = $self->GetReservations();
if ($resvref && @$resvref) {
# We only need to check the first reservation in the list since no
# concurrent mix of RO and RW is allowed.
$rw = $resvref->[0]->IsReadOnly() ? 0 : 1;
if ($resvref) {
foreach my $ref (@$resvref) {
if (!$ref->IsReadOnly()) {
$rw = 1;
last;
}
}
}
return $rw;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment