[libvirt] [PATCH 1/7] util: Alter virObjectLockRead to return status

John Ferlan posted 7 patches 7 years, 9 months ago
There is a newer version of this series
[libvirt] [PATCH 1/7] util: Alter virObjectLockRead to return status
Posted by John Ferlan 7 years, 9 months ago
Rather than ignore errors, let's have virObjectLockRead check for
the correct usage and issue an error when not properly used so
so that we don't run into situations where the resource we think
we're locking really isn't locked because the void input parameter
wasn't valid.

Signed-off-by: John Ferlan <jferlan@redhat.com>
---
 src/conf/virdomainobjlist.c | 27 ++++++++++++++++++---------
 src/util/virobject.c        |  6 +++++-
 src/util/virobject.h        |  2 +-
 3 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/src/conf/virdomainobjlist.c b/src/conf/virdomainobjlist.c
index 1d027a4..fed4029 100644
--- a/src/conf/virdomainobjlist.c
+++ b/src/conf/virdomainobjlist.c
@@ -118,7 +118,8 @@ virDomainObjListFindByIDInternal(virDomainObjListPtr doms,
                                  bool ref)
 {
     virDomainObjPtr obj;
-    virObjectLockRead(doms);
+    if (virObjectLockRead(doms) < 0)
+        return NULL;
     obj = virHashSearch(doms->objs, virDomainObjListSearchID, &id, NULL);
     if (ref) {
         virObjectRef(obj);
@@ -160,7 +161,8 @@ virDomainObjListFindByUUIDInternal(virDomainObjListPtr doms,
     char uuidstr[VIR_UUID_STRING_BUFLEN];
     virDomainObjPtr obj;
 
-    virObjectLockRead(doms);
+    if (virObjectLockRead(doms) < 0)
+        return NULL;
     virUUIDFormat(uuid, uuidstr);
 
     obj = virHashLookup(doms->objs, uuidstr);
@@ -204,7 +206,8 @@ virDomainObjPtr virDomainObjListFindByName(virDomainObjListPtr doms,
 {
     virDomainObjPtr obj;
 
-    virObjectLockRead(doms);
+    if (virObjectLockRead(doms) < 0)
+        return NULL;
     obj = virHashLookup(doms->objsName, name);
     virObjectRef(obj);
     virObjectUnlock(doms);
@@ -653,7 +656,8 @@ virDomainObjListNumOfDomains(virDomainObjListPtr doms,
                              virConnectPtr conn)
 {
     struct virDomainObjListData data = { filter, conn, active, 0 };
-    virObjectLockRead(doms);
+    if (virObjectLockRead(doms) < 0)
+        return -1;
     virHashForEach(doms->objs, virDomainObjListCount, &data);
     virObjectUnlock(doms);
     return data.count;
@@ -697,7 +701,8 @@ virDomainObjListGetActiveIDs(virDomainObjListPtr doms,
 {
     struct virDomainIDData data = { filter, conn,
                                     0, maxids, ids };
-    virObjectLockRead(doms);
+    if (virObjectLockRead(doms) < 0)
+        return -1;
     virHashForEach(doms->objs, virDomainObjListCopyActiveIDs, &data);
     virObjectUnlock(doms);
     return data.numids;
@@ -751,7 +756,8 @@ virDomainObjListGetInactiveNames(virDomainObjListPtr doms,
     struct virDomainNameData data = { filter, conn,
                                       0, 0, maxnames, names };
     size_t i;
-    virObjectLockRead(doms);
+    if (virObjectLockRead(doms) < 0)
+        return -1;
     virHashForEach(doms->objs, virDomainObjListCopyInactiveNames, &data);
     virObjectUnlock(doms);
     if (data.oom) {
@@ -792,7 +798,8 @@ virDomainObjListForEach(virDomainObjListPtr doms,
     struct virDomainListIterData data = {
         callback, opaque, 0,
     };
-    virObjectLockRead(doms);
+    if (virObjectLockRead(doms) < 0)
+        return -1;
     virHashForEach(doms->objs, virDomainObjListHelper, &data);
     virObjectUnlock(doms);
     return data.ret;
@@ -925,7 +932,8 @@ virDomainObjListCollect(virDomainObjListPtr domlist,
 {
     struct virDomainListData data = { NULL, 0 };
 
-    virObjectLockRead(domlist);
+    if (virObjectLockRead(domlist) < 0)
+        return -1;
     sa_assert(domlist->objs);
     if (VIR_ALLOC_N(data.vms, virHashSize(domlist->objs)) < 0) {
         virObjectUnlock(domlist);
@@ -962,7 +970,8 @@ virDomainObjListConvert(virDomainObjListPtr domlist,
     *nvms = 0;
     *vms = NULL;
 
-    virObjectLockRead(domlist);
+    if (virObjectLockRead(domlist) < 0)
+        return -1;
     for (i = 0; i < ndoms; i++) {
         virDomainPtr dom = doms[i];
 
diff --git a/src/util/virobject.c b/src/util/virobject.c
index b1bb378..73de4d3 100644
--- a/src/util/virobject.c
+++ b/src/util/virobject.c
@@ -410,17 +410,21 @@ virObjectLock(void *anyobj)
  * The object must be unlocked before releasing this
  * reference.
  */
-void
+int
 virObjectLockRead(void *anyobj)
 {
     if (virObjectIsClass(anyobj, virObjectRWLockableClass)) {
         virObjectRWLockablePtr obj = anyobj;
         virRWLockRead(&obj->lock);
+        return 0;
     } else {
         virObjectPtr obj = anyobj;
         VIR_WARN("Object %p (%s) is not a virObjectRWLockable instance",
                  anyobj, obj ? obj->klass->name : "(unknown)");
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unable to obtain rwlock for object=%p"), anyobj);
     }
+    return -1;
 }
 
 
diff --git a/src/util/virobject.h b/src/util/virobject.h
index 5985fad..99910e0 100644
--- a/src/util/virobject.h
+++ b/src/util/virobject.h
@@ -124,7 +124,7 @@ void
 virObjectLock(void *lockableobj)
     ATTRIBUTE_NONNULL(1);
 
-void
+int
 virObjectLockRead(void *lockableobj)
     ATTRIBUTE_NONNULL(1);
 
-- 
2.9.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 1/7] util: Alter virObjectLockRead to return status
Posted by Pavel Hrdina 7 years, 9 months ago
On Fri, Jul 28, 2017 at 12:38:55PM -0400, John Ferlan wrote:
> Rather than ignore errors, let's have virObjectLockRead check for
> the correct usage and issue an error when not properly used so
> so that we don't run into situations where the resource we think
> we're locking really isn't locked because the void input parameter
> wasn't valid.

I agree with Dan that this doesn't give any benefit.  We should rather
consider start using abort() since this is a programming error, not
something that depends on an input from user.  It should not happen if
if it does we have serious issues and abort is a best choice.

Pavel
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 1/7] util: Alter virObjectLockRead to return status
Posted by John Ferlan 7 years, 9 months ago

On 07/28/2017 12:56 PM, Pavel Hrdina wrote:
> On Fri, Jul 28, 2017 at 12:38:55PM -0400, John Ferlan wrote:
>> Rather than ignore errors, let's have virObjectLockRead check for
>> the correct usage and issue an error when not properly used so
>> so that we don't run into situations where the resource we think
>> we're locking really isn't locked because the void input parameter
>> wasn't valid.
> 
> I agree with Dan that this doesn't give any benefit.  We should rather
> consider start using abort() since this is a programming error, not
> something that depends on an input from user.  It should not happen if
> if it does we have serious issues and abort is a best choice.
> 
> Pavel
> 

I'm in the minority, but that's fine. I could also change this patch to
be rename virObjectLockRead to be virObjectRWLockRead as suggested later
on too.

John

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 1/7] util: Alter virObjectLockRead to return status
Posted by Michal Privoznik 7 years, 9 months ago
On 07/28/2017 08:26 PM, John Ferlan wrote:
> 
> 
> On 07/28/2017 12:56 PM, Pavel Hrdina wrote:
>> On Fri, Jul 28, 2017 at 12:38:55PM -0400, John Ferlan wrote:
>>> Rather than ignore errors, let's have virObjectLockRead check for
>>> the correct usage and issue an error when not properly used so
>>> so that we don't run into situations where the resource we think
>>> we're locking really isn't locked because the void input parameter
>>> wasn't valid.
>>
>> I agree with Dan that this doesn't give any benefit.  We should rather
>> consider start using abort() since this is a programming error, not
>> something that depends on an input from user.  It should not happen if
>> if it does we have serious issues and abort is a best choice.
>>
>> Pavel
>>
> 
> I'm in the minority, but that's fine. I could also change this patch to
> be rename virObjectLockRead to be virObjectRWLockRead as suggested later
> on too.

Actually, me choosing virObjectLockRead over virObjectRWLockRead was
arbitrary. The reason is that my text editor can offer me completions:

virObjectLock
virObjectLockWrite
virObjectLockRead

BTW: Following your reasoning here, it should have been called
virObjectLockableLock() instead of virObjectLock() ;-)
IOW, I'm failing to see the need for 'RW' in the name you're suggesting.

Michal

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 1/7] util: Alter virObjectLockRead to return status
Posted by Daniel P. Berrange 7 years, 9 months ago
On Fri, Jul 28, 2017 at 12:38:55PM -0400, John Ferlan wrote:
> Rather than ignore errors, let's have virObjectLockRead check for
> the correct usage and issue an error when not properly used so
> so that we don't run into situations where the resource we think
> we're locking really isn't locked because the void input parameter
> wasn't valid.
> 
> Signed-off-by: John Ferlan <jferlan@redhat.com>
> ---
>  src/conf/virdomainobjlist.c | 27 ++++++++++++++++++---------
>  src/util/virobject.c        |  6 +++++-
>  src/util/virobject.h        |  2 +-
>  3 files changed, 24 insertions(+), 11 deletions(-)
> 
> diff --git a/src/conf/virdomainobjlist.c b/src/conf/virdomainobjlist.c
> index 1d027a4..fed4029 100644
> --- a/src/conf/virdomainobjlist.c
> +++ b/src/conf/virdomainobjlist.c
> @@ -118,7 +118,8 @@ virDomainObjListFindByIDInternal(virDomainObjListPtr doms,
>                                   bool ref)
>  {
>      virDomainObjPtr obj;
> -    virObjectLockRead(doms);
> +    if (virObjectLockRead(doms) < 0)
> +        return NULL;
>      obj = virHashSearch(doms->objs, virDomainObjListSearchID, &id, NULL);
>      if (ref) {
>          virObjectRef(obj);
> @@ -160,7 +161,8 @@ virDomainObjListFindByUUIDInternal(virDomainObjListPtr doms,
>      char uuidstr[VIR_UUID_STRING_BUFLEN];
>      virDomainObjPtr obj;
>  
> -    virObjectLockRead(doms);
> +    if (virObjectLockRead(doms) < 0)
> +        return NULL;
>      virUUIDFormat(uuid, uuidstr);
>  
>      obj = virHashLookup(doms->objs, uuidstr);
> @@ -204,7 +206,8 @@ virDomainObjPtr virDomainObjListFindByName(virDomainObjListPtr doms,
>  {
>      virDomainObjPtr obj;
>  
> -    virObjectLockRead(doms);
> +    if (virObjectLockRead(doms) < 0)
> +        return NULL;
>      obj = virHashLookup(doms->objsName, name);
>      virObjectRef(obj);
>      virObjectUnlock(doms);
> @@ -653,7 +656,8 @@ virDomainObjListNumOfDomains(virDomainObjListPtr doms,
>                               virConnectPtr conn)
>  {
>      struct virDomainObjListData data = { filter, conn, active, 0 };
> -    virObjectLockRead(doms);
> +    if (virObjectLockRead(doms) < 0)
> +        return -1;
>      virHashForEach(doms->objs, virDomainObjListCount, &data);
>      virObjectUnlock(doms);
>      return data.count;
> @@ -697,7 +701,8 @@ virDomainObjListGetActiveIDs(virDomainObjListPtr doms,
>  {
>      struct virDomainIDData data = { filter, conn,
>                                      0, maxids, ids };
> -    virObjectLockRead(doms);
> +    if (virObjectLockRead(doms) < 0)
> +        return -1;
>      virHashForEach(doms->objs, virDomainObjListCopyActiveIDs, &data);
>      virObjectUnlock(doms);
>      return data.numids;
> @@ -751,7 +756,8 @@ virDomainObjListGetInactiveNames(virDomainObjListPtr doms,
>      struct virDomainNameData data = { filter, conn,
>                                        0, 0, maxnames, names };
>      size_t i;
> -    virObjectLockRead(doms);
> +    if (virObjectLockRead(doms) < 0)
> +        return -1;
>      virHashForEach(doms->objs, virDomainObjListCopyInactiveNames, &data);
>      virObjectUnlock(doms);
>      if (data.oom) {
> @@ -792,7 +798,8 @@ virDomainObjListForEach(virDomainObjListPtr doms,
>      struct virDomainListIterData data = {
>          callback, opaque, 0,
>      };
> -    virObjectLockRead(doms);
> +    if (virObjectLockRead(doms) < 0)
> +        return -1;
>      virHashForEach(doms->objs, virDomainObjListHelper, &data);
>      virObjectUnlock(doms);
>      return data.ret;
> @@ -925,7 +932,8 @@ virDomainObjListCollect(virDomainObjListPtr domlist,
>  {
>      struct virDomainListData data = { NULL, 0 };
>  
> -    virObjectLockRead(domlist);
> +    if (virObjectLockRead(domlist) < 0)
> +        return -1;
>      sa_assert(domlist->objs);
>      if (VIR_ALLOC_N(data.vms, virHashSize(domlist->objs)) < 0) {
>          virObjectUnlock(domlist);
> @@ -962,7 +970,8 @@ virDomainObjListConvert(virDomainObjListPtr domlist,
>      *nvms = 0;
>      *vms = NULL;
>  
> -    virObjectLockRead(domlist);
> +    if (virObjectLockRead(domlist) < 0)
> +        return -1;
>      for (i = 0; i < ndoms; i++) {
>          virDomainPtr dom = doms[i];
>  
> diff --git a/src/util/virobject.c b/src/util/virobject.c
> index b1bb378..73de4d3 100644
> --- a/src/util/virobject.c
> +++ b/src/util/virobject.c
> @@ -410,17 +410,21 @@ virObjectLock(void *anyobj)
>   * The object must be unlocked before releasing this
>   * reference.
>   */
> -void
> +int

I'm NACK on this return value change.

>  virObjectLockRead(void *anyobj)
>  {
>      if (virObjectIsClass(anyobj, virObjectRWLockableClass)) {
>          virObjectRWLockablePtr obj = anyobj;
>          virRWLockRead(&obj->lock);
> +        return 0;
>      } else {
>          virObjectPtr obj = anyobj;
>          VIR_WARN("Object %p (%s) is not a virObjectRWLockable instance",
>                   anyobj, obj ? obj->klass->name : "(unknown)");
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("unable to obtain rwlock for object=%p"), anyobj);
>      }
> +    return -1;
>  }

IMHO this should just be simplified to

  virObjectLockRead(void *anyobj)
  {
     virObjectRWLockablePtr obj = anyobj;
     virRWLockRead(&obj->lock);
  }


Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 1/7] util: Alter virObjectLockRead to return status
Posted by John Ferlan 7 years, 9 months ago
[...]

>> --- a/src/util/virobject.c
>> +++ b/src/util/virobject.c
>> @@ -410,17 +410,21 @@ virObjectLock(void *anyobj)
>>   * The object must be unlocked before releasing this
>>   * reference.
>>   */
>> -void
>> +int
> 
> I'm NACK on this return value change.
> 

OK - that's fine.

>>  virObjectLockRead(void *anyobj)
>>  {
>>      if (virObjectIsClass(anyobj, virObjectRWLockableClass)) {
>>          virObjectRWLockablePtr obj = anyobj;
>>          virRWLockRead(&obj->lock);
>> +        return 0;
>>      } else {
>>          virObjectPtr obj = anyobj;
>>          VIR_WARN("Object %p (%s) is not a virObjectRWLockable instance",
>>                   anyobj, obj ? obj->klass->name : "(unknown)");
>> +        virReportError(VIR_ERR_INTERNAL_ERROR,
>> +                       _("unable to obtain rwlock for object=%p"), anyobj);
>>      }
>> +    return -1;
>>  }
> 
> IMHO this should just be simplified to
> 
>   virObjectLockRead(void *anyobj)
>   {
>      virObjectRWLockablePtr obj = anyobj;
>      virRWLockRead(&obj->lock);
>   }
> 
> 

I'm not as sure for this one though, but I do understand the reasoning
especially if @obj == NULL since we'd have a core. Still if @obj is
passed in as a non NULL address, I don't believe we're going to get a
failure - sure pthread_rwlock_{rdlock|wrlock} or pthread_mutex_lock will
fail, but we don't fail on that. Still getting a VIR_WARN somewhere
would hopefully help us debug. It's too bad we couldn't have the extra
checks be for developer builds only and cause the abort then.

In the FWIW department...

Even in the first commit ('b545f65d') for virObject{Lock|Unlock},
rudimentary error checking such as !obj and using an @obj with the right
class was checked and a VIR_WARN issued.

As I was adding a new class for common objects, I made the mistake noted
in patch 7, so it seemed to be a good thing to do to add a few more
checks along the way and perhaps better entrails. Of course doing that
required a multi-step changes... So, commit id '10c2bb2b1' created
virObjectGetLockableObj as a way to combine the existing checks.

The next steps from my v2 weren't NACK'd, but they weren't ACK'd or
discouraged - they just needed some adjustments. The v3 made the
adjustments (along with more patches), but never got any reviews.

With the addition of RWLockable (commit id '77f4593b') those checks got
wiped out in favor of inline code again. I understand why - one API, one
place to check, etc.

If there's going to be 4 API's, then recreating the original check again
is where I was headed, but not it seems like it's not desired even
though checks like that have been around from the start.

We could proceed with no checks, but before posting patches for that I
would like to make sure that's what is really desired given the history
and side effect of doing so.

Tks -

John

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list