[libvirt] [PATCH v2 4/7] lockd_driver_lockd: Implement metadata flag

Michal Prívozník mprivozn at redhat.com
Mon Aug 20 07:25:13 UTC 2018


On 08/17/2018 01:53 AM, John Ferlan wrote:
> 
> 
> On 08/14/2018 07:19 AM, Michal Privoznik wrote:
>> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
>> ---
>>  src/locking/lock_daemon_dispatch.c | 12 ++++++++++--
>>  src/locking/lock_driver_lockd.c    | 31 +++++++++++++++++++++----------
>>  src/locking/lock_driver_lockd.h    |  1 +
>>  3 files changed, 32 insertions(+), 12 deletions(-)
>>
>> diff --git a/src/locking/lock_daemon_dispatch.c b/src/locking/lock_daemon_dispatch.c
>> index 10248ec0b5..c24571ceac 100644
>> --- a/src/locking/lock_daemon_dispatch.c
>> +++ b/src/locking/lock_daemon_dispatch.c
>> @@ -37,6 +37,9 @@ VIR_LOG_INIT("locking.lock_daemon_dispatch");
>>  
>>  #include "lock_daemon_dispatch_stubs.h"
>>  
>> +#define DEFAULT_OFFSET 0
>> +#define METADATA_OFFSET 1
>> +
> 
> Curious, does this lead to the prospect of being able to acquire/use
> offset==0 length==1 and offset==1 length==1 at least conceptually and
> granularity wise?

Yes, this is exactly the purpose. I've taken inspiration from qemu. They
lock bytes from 100 to 100 + N, depending on what operations they want
the disk for (checkout raw_apply_lock_bytes() form block/file-posix.c).
And my idea was for virtlockd to do the same. Currently, it locks 0th
byte of given file and with metadata flag it would lock the first one.

> 
> Related or not, there's a strange NFSv3 collision between QEMU and NFS
> related to some sort of fcntl locking granularity. More details that you
> possibly want to read at:
> 
> https://bugzilla.redhat.com/show_bug.cgi?id=1592582
> https://bugzilla.redhat.com/show_bug.cgi?id=1547095
> 
> I only note it because well it was on my 'short term history' radar and
> suffice to say it's an ugly and not fun issue dealing with these locks.

Oh yeah, NFSv3 and file locks. Well, I'm not making our situation any
worse here. Qemu is already locking disks, and it is doing so for the
while lifetime of the domain whereas my patches would lock for only a
fraction of a second (well, as long as it takes for chown() and
setfilecon_raw() to run). It is very unlikely that connection to the
NFSv3 server will be lost right when metadata lock is held.

> 
>>  static int
>>  virLockSpaceProtocolDispatchAcquireResource(virNetServerPtr server ATTRIBUTE_UNUSED,
>>                                              virNetServerClientPtr client,
>> @@ -50,13 +53,14 @@ virLockSpaceProtocolDispatchAcquireResource(virNetServerPtr server ATTRIBUTE_UNU
>>          virNetServerClientGetPrivateData(client);
>>      virLockSpacePtr lockspace;
>>      unsigned int newFlags;
>> -    off_t start = 0;
>> +    off_t start = DEFAULT_OFFSET;
>>      off_t len = 1;
>>  
>>      virMutexLock(&priv->lock);
>>  
>>      virCheckFlagsGoto(VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED |
>> -                      VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE, cleanup);
>> +                      VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE |
>> +                      VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_METADATA, cleanup);
>>  
>>      if (priv->restricted) {
>>          virReportError(VIR_ERR_OPERATION_DENIED, "%s",
>> @@ -82,6 +86,10 @@ virLockSpaceProtocolDispatchAcquireResource(virNetServerPtr server ATTRIBUTE_UNU
>>          newFlags |= VIR_LOCK_SPACE_ACQUIRE_SHARED;
>>      if (flags & VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE)
>>          newFlags |= VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE;
>> +    if (flags & VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_METADATA) {
>> +        start = METADATA_OFFSET;
>> +        newFlags |= VIR_LOCK_SPACE_ACQUIRE_WAIT;
>> +    }
> 
> If this is documented in more detail, then it should be noted that a
> METADATA lock forces usage of the wait API's. I can only imagine
> someone, some day will ask for a wait w/ timeout to avoid waiting too long.

That should never happen (TM). The metadata lock is acquired only for
time that seclabels are set on some domain paths (and as we will see in
6/7 we are not going to lock all the paths). As soon as they are set the
lock is released.

> 
>>  
>>      if (virLockSpaceAcquireResource(lockspace,
>>                                      args->name,
>> diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c
>> index 957a963a7b..bd14ed8930 100644
>> --- a/src/locking/lock_driver_lockd.c
>> +++ b/src/locking/lock_driver_lockd.c
>> @@ -475,9 +475,11 @@ static int virLockManagerLockDaemonAddResource(virLockManagerPtr lock,
>>      bool autoCreate = false;
>>  
>>      virCheckFlags(VIR_LOCK_MANAGER_RESOURCE_READONLY |
>> -                  VIR_LOCK_MANAGER_RESOURCE_SHARED, -1);
>> +                  VIR_LOCK_MANAGER_RESOURCE_SHARED |
>> +                  VIR_LOCK_MANAGER_RESOURCE_METADATA, -1);
>>  
>> -    if (flags & VIR_LOCK_MANAGER_RESOURCE_READONLY)
>> +    if (flags & VIR_LOCK_MANAGER_RESOURCE_READONLY &&
>> +        !(flags & VIR_LOCK_MANAGER_RESOURCE_METADATA))
>>          return 0;
> 
> Could someone pass READONLY & METADATA and not return 0 here?  Yes,
> doesn't make sense, but combining them leads to the logic matrix question.

So far there isn't such caller, but sure I can add an explicit check
that errors out if both READONLY and METADATA are set at the same time.

> 
>>  
>>      switch (type) {
>> @@ -489,7 +491,8 @@ static int virLockManagerLockDaemonAddResource(virLockManagerPtr lock,
>>          }
>>          if (!driver->autoDiskLease) {
>>              if (!(flags & (VIR_LOCK_MANAGER_RESOURCE_SHARED |
>> -                           VIR_LOCK_MANAGER_RESOURCE_READONLY)))
>> +                           VIR_LOCK_MANAGER_RESOURCE_READONLY |
>> +                           VIR_LOCK_MANAGER_RESOURCE_METADATA)))
>>                  priv->hasRWDisks = true;
>>              return 0;
>>          }
>> @@ -602,6 +605,10 @@ static int virLockManagerLockDaemonAddResource(virLockManagerPtr lock,
>>          priv->resources[priv->nresources-1].flags |=
>>              VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE;
>>  
>> +    if (flags & VIR_LOCK_MANAGER_RESOURCE_METADATA)
>> +        priv->resources[priv->nresources-1].flags |=
>> +            VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_METADATA;
>> +
>>      return 0;
>>  
>>   error:
>> @@ -626,12 +633,15 @@ static int virLockManagerLockDaemonAcquire(virLockManagerPtr lock,
>>      virCheckFlags(VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY |
>>                    VIR_LOCK_MANAGER_ACQUIRE_RESTRICT, -1);
>>  
>> -    if (priv->nresources == 0 &&
>> -        priv->hasRWDisks &&
>> -        driver->requireLeaseForDisks) {
>> -        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
>> -                       _("Read/write, exclusive access, disks were present, but no leases specified"));
>> -        return -1;
>> +    if (priv->nresources == 0) {
> 
> I'm assuming there's a relationship between metadata and nresources == 0
> which really isn't apparent especially since the subsequent error
> message is about leases.  Do we need to check for resource type?
> 
> Or in the top level API do we need to only allow METADATA for DISK type?

Well, nresources == 0 can happen regardless of METADATA flag if
autoDiskLease is turned off. In that case no domain disk is added into
@resources and thus nresources can be zero. This is the situation where
we require users to put <lease/> into domain XML which will then protect
them.


By the same token, when locking for METADATA, we can not ignore
autoDiskLease setting (because if user has turned off disk leases they
probably did not set any lockspace dir and certainly did not put it onto
shared NFS, as required by our docs
https://libvirt.org/locking-lockd.html#lockdplugin) and we can't lock
files automatically. We must rely on <lease/>. However, we shouldn't
fail because from METADATA POV we don't care if a disk is RO or RW.

Long story short, if users want to rely on <lease/> solely we should
honour that.

> 
>> +        if (priv->hasRWDisks &&
>> +            driver->requireLeaseForDisks) {
>> +            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
>> +                           _("Read/write, exclusive access, disks were present, but no leases specified"));
>> +            return -1;
>> +        }
>> +
>> +        return 0;
>>      }
>>  
>>      if (!(client = virLockManagerLockDaemonConnect(lock, &program, &counter)))
>> @@ -711,7 +721,8 @@ static int virLockManagerLockDaemonRelease(virLockManagerPtr lock,
>>  
>>          args.flags &=
>>              ~(VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED |
>> -              VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE);
>> +              VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE |
>> +              VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_METADATA);
>>  
>>          if (virNetClientProgramCall(program,
>>                                      client,
>> diff --git a/src/locking/lock_driver_lockd.h b/src/locking/lock_driver_lockd.h
>> index 6931fe7425..9882793260 100644
>> --- a/src/locking/lock_driver_lockd.h
>> +++ b/src/locking/lock_driver_lockd.h
>> @@ -25,6 +25,7 @@
>>  enum virLockSpaceProtocolAcquireResourceFlags {
>>          VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED = (1 << 0),
>>          VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE = (1 << 1),
>> +        VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_METADATA = (1 << 2),
> 
> Use of RESOURCE_METADATA would be more consistent wouldn't it?
> 

Oh, okay.

Michal




More information about the libvir-list mailing list