[libvirt] [PATCH v5 1/3] nwfilter: Convert _virNWFilterObj to use virObjectRWLockable
Stefan Berger
stefanb at linux.vnet.ibm.com
Thu Feb 8 21:00:02 UTC 2018
On 02/08/2018 08:30 AM, Daniel P. Berrangé wrote:
> On Thu, Feb 08, 2018 at 02:13:58PM +0100, Michal Privoznik wrote:
>> On 02/06/2018 08:20 PM, John Ferlan wrote:
>>> Unlike it's counterparts, the nwfilter object code needs to be able
>>> to support recursive read locks while processing and checking new
>>> filters against the existing environment. Thus instead of using a
>>> virObjectLockable which uses pure mutexes, use the virObjectRWLockable
>>> and primarily use RWLockRead when obtaining the object lock since
>>> RWLockRead locks can be recursively obtained (up to a limit) as long
>>> as there's a corresponding unlock.
>>>
>>> Since all the object management is within the virnwfilterobj code, we
>>> can limit the number of Write locks on the object to very small areas
>>> of code to ensure we don't run into deadlock's with other threads and
>>> domain code that will check/use the filters (it's a very delicate
>>> balance). This limits the write locks to AssignDef and Remove processing.
>>>
>>> This patch will introduce a new API virNWFilterObjEndAPI to unlock
>>> and deref the object.
>>>
>>> This patch introduces two helpers to promote/demote the read/write lock.
>>>
>>> Signed-off-by: John Ferlan <jferlan at redhat.com>
>>> ---
>>> src/conf/virnwfilterobj.c | 193 +++++++++++++++++++++++----------
>>> src/conf/virnwfilterobj.h | 9 +-
>>> src/libvirt_private.syms | 3 +-
>>> src/nwfilter/nwfilter_driver.c | 15 +--
>>> src/nwfilter/nwfilter_gentech_driver.c | 11 +-
>>> 5 files changed, 153 insertions(+), 78 deletions(-)
>>>
>>> diff --git a/src/conf/virnwfilterobj.c b/src/conf/virnwfilterobj.c
>>> index 87d7e7270..cd52706ec 100644
>>> --- a/src/conf/virnwfilterobj.c
>>> +++ b/src/conf/virnwfilterobj.c
>>> @@ -34,7 +34,7 @@
>>> VIR_LOG_INIT("conf.virnwfilterobj");
>>>
>>> struct _virNWFilterObj {
>>> - virMutex lock;
>>> + virObjectRWLockable parent;
>>>
>>> bool wantRemoved;
>>>
>>> @@ -47,27 +47,69 @@ struct _virNWFilterObjList {
>>> virNWFilterObjPtr *objs;
>>> };
>>>
>>> +static virClassPtr virNWFilterObjClass;
>>> +static void virNWFilterObjDispose(void *opaque);
>>> +
>>> +
>>> +static int
>>> +virNWFilterObjOnceInit(void)
>>> +{
>>> + if (!(virNWFilterObjClass = virClassNew(virClassForObjectRWLockable(),
>>> + "virNWFilterObj",
>>> + sizeof(virNWFilterObj),
>>> + virNWFilterObjDispose)))
>>> + return -1;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +VIR_ONCE_GLOBAL_INIT(virNWFilterObj)
>>> +
>>>
>>> static virNWFilterObjPtr
>>> virNWFilterObjNew(void)
>>> {
>>> virNWFilterObjPtr obj;
>>>
>>> - if (VIR_ALLOC(obj) < 0)
>>> + if (virNWFilterObjInitialize() < 0)
>>> return NULL;
>>>
>>> - if (virMutexInitRecursive(&obj->lock) < 0) {
>>> - virReportError(VIR_ERR_INTERNAL_ERROR,
>>> - "%s", _("cannot initialize mutex"));
>>> - VIR_FREE(obj);
>>> + if (!(obj = virObjectRWLockableNew(virNWFilterObjClass)))
>>> return NULL;
>>> - }
>>>
>>> - virNWFilterObjLock(obj);
>>> + virObjectRWLockWrite(obj);
>>> return obj;
>>> }
>>>
>>>
>>> +static void
>>> +virNWFilterObjPromoteToWrite(virNWFilterObjPtr obj)
>>> +{
>>> + virObjectRWUnlock(obj);
>>> + virObjectRWLockWrite(obj);
>>> +}
>> How can this not deadlock? This will work only if @obj is locked exactly
>> once. But since we allow recursive locks any lock() that happens in the
>> 2nd level must deadlock with this. On the other hand, there's no such
>> case in the code currently. But that doesn't stop anybody from calling
>> PromoteWrite() without understanding its limitations.
>>
>> Maybe the fact that we need recursive lock for NWFilterObj means it's
>> not a good candidate for virObjectRWLocable? It is still a good
>> candidate for virObject though.
>>
>> Or if you want to spend extra time on this, maybe introducing
>> virObjectRecursiveLockable may be worth it (terrible name, I know).
> I can't remember exactly call trace scenarios that meant we required
> recursive locking. I vaguely recall is was related to fact that we
> have an alternative entry point into the nwfilter code that's triggered
> by the virt drivers. I'm thus vaguely hoping that when we split nwfilter
> off into a separate daemon from virt driver, the need for recursive
> lockingn would magically disappear. I could be completely wrong though :-)
The nwfilter code tries to detect circular references of filters, like
a->b->c->a, and while testing for that needs to grab a read lock twice.
Stefan
>
>
> Regards,
> Daniel
More information about the libvir-list
mailing list