diff mbox series

[XEN,RFC,v4,11/16] common/device_tree: Add rwlock for dt_host

Message ID 20221207061815.7404-5-vikram.garhwal@amd.com (mailing list archive)
State New, archived
Headers show
Series dynamic node programming using overlay dtbo | expand

Commit Message

Vikram Garhwal Dec. 7, 2022, 6:18 a.m. UTC
Dynamic programming ops will modify the dt_host and there might be other
 function which are browsing the dt_host at the same time. To avoid the race
 conditions, adding rwlock for browsing the dt_host.

Signed-off-by: Vikram Garhwal <vikram.garhwal@amd.com>
---
 xen/common/device_tree.c      | 27 +++++++++++++++++++++++++++
 xen/include/xen/device_tree.h |  6 ++++++
 2 files changed, 33 insertions(+)

Comments

Julien Grall Dec. 7, 2022, 4:31 p.m. UTC | #1
Hi Vikram,

On 07/12/2022 06:18, Vikram Garhwal wrote:
>   Dynamic programming ops will modify the dt_host and there might be other
>   function which are browsing the dt_host at the same time. To avoid the race
>   conditions, adding rwlock for browsing the dt_host.

Looking at the user below, it is not entirely clear what the lock is 
actually protecting. For instance...

> 
> Signed-off-by: Vikram Garhwal <vikram.garhwal@amd.com>
> ---
>   xen/common/device_tree.c      | 27 +++++++++++++++++++++++++++
>   xen/include/xen/device_tree.h |  6 ++++++
>   2 files changed, 33 insertions(+)
> 
> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
> index acf26a411d..51ee2a5edf 100644
> --- a/xen/common/device_tree.c
> +++ b/xen/common/device_tree.c
> @@ -140,6 +140,8 @@ const struct dt_property *dt_find_property(const struct dt_device_node *np,
>       if ( !np )
>           return NULL;
>   
> +    read_lock(&dt_host->lock);
> +
>       for ( pp = np->properties; pp; pp = pp->next )
>       {
>           if ( dt_prop_cmp(pp->name, name) == 0 )
> @@ -150,6 +152,7 @@ const struct dt_property *dt_find_property(const struct dt_device_node *np,
>           }
>       }
>   
> +    read_unlock(&dt_host->lock);
>       return pp;
>   }
>   
> @@ -336,11 +339,14 @@ struct dt_device_node *dt_find_node_by_name(struct dt_device_node *from,
>       struct dt_device_node *np;
>       struct dt_device_node *dt;
>   
> +    read_lock(&dt_host->lock);
> +
>       dt = from ? from->allnext : dt_host;
>       dt_for_each_device_node(dt, np)
>           if ( np->name && (dt_node_cmp(np->name, name) == 0) )
>               break;
>   
> +    read_unlock(&dt_host->lock);
>       return np;

... I was expecting the read lock to also protect the value returned 
from being freed. But this is not the case.

Cheers,
Vikram Garhwal Feb. 1, 2023, 5:05 p.m. UTC | #2
Hi Julien,

On 12/7/22 8:31 AM, Julien Grall wrote:
> Hi Vikram,
>
> On 07/12/2022 06:18, Vikram Garhwal wrote:
>>   Dynamic programming ops will modify the dt_host and there might be 
>> other
>>   function which are browsing the dt_host at the same time. To avoid 
>> the race
>>   conditions, adding rwlock for browsing the dt_host.
>
> Looking at the user below, it is not entirely clear what the lock is 
> actually protecting. For instance...

Purpose of the lock was to protect the read/scanning of dt_host while we 
remove the add/nodes. This lock is also used when nodes are 
added/removed in "[XEN][RFC PATCH v4 12/16]: static int 
remove_nodes(const struct overlay_track *tracker)".


>
>>
>> Signed-off-by: Vikram Garhwal <vikram.garhwal@amd.com>
>> ---
>>   xen/common/device_tree.c      | 27 +++++++++++++++++++++++++++
>>   xen/include/xen/device_tree.h |  6 ++++++
>>   2 files changed, 33 insertions(+)
>>
>> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
>> index acf26a411d..51ee2a5edf 100644
>> --- a/xen/common/device_tree.c
>> +++ b/xen/common/device_tree.c
>> @@ -140,6 +140,8 @@ const struct dt_property *dt_find_property(const 
>> struct dt_device_node *np,
>>       if ( !np )
>>           return NULL;
>>   +    read_lock(&dt_host->lock);
>> +
>>       for ( pp = np->properties; pp; pp = pp->next )
>>       {
>>           if ( dt_prop_cmp(pp->name, name) == 0 )
>> @@ -150,6 +152,7 @@ const struct dt_property *dt_find_property(const 
>> struct dt_device_node *np,
>>           }
>>       }
>>   +    read_unlock(&dt_host->lock);
>>       return pp;
>>   }
>>   @@ -336,11 +339,14 @@ struct dt_device_node 
>> *dt_find_node_by_name(struct dt_device_node *from,
>>       struct dt_device_node *np;
>>       struct dt_device_node *dt;
>>   +    read_lock(&dt_host->lock);
>> +
>>       dt = from ? from->allnext : dt_host;
>>       dt_for_each_device_node(dt, np)
>>           if ( np->name && (dt_node_cmp(np->name, name) == 0) )
>>               break;
>>   +    read_unlock(&dt_host->lock);
>>       return np;
>
> ... I was expecting the read lock to also protect the value returned 
> from being freed. But this is not the case.
>
Okay. Shall I remove the lock from here and perhaps add it when 
dt_find_node_by_name() and other related functions are called?
> Cheers,
>
Julien Grall Feb. 10, 2023, 6:48 p.m. UTC | #3
Hi,

On 01/02/2023 17:05, Vikram Garhwal wrote:
> On 12/7/22 8:31 AM, Julien Grall wrote:
>>> Signed-off-by: Vikram Garhwal <vikram.garhwal@amd.com>
>>> ---
>>>   xen/common/device_tree.c      | 27 +++++++++++++++++++++++++++
>>>   xen/include/xen/device_tree.h |  6 ++++++
>>>   2 files changed, 33 insertions(+)
>>>
>>> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
>>> index acf26a411d..51ee2a5edf 100644
>>> --- a/xen/common/device_tree.c
>>> +++ b/xen/common/device_tree.c
>>> @@ -140,6 +140,8 @@ const struct dt_property *dt_find_property(const 
>>> struct dt_device_node *np,
>>>       if ( !np )
>>>           return NULL;
>>>   +    read_lock(&dt_host->lock);
>>> +
>>>       for ( pp = np->properties; pp; pp = pp->next )
>>>       {
>>>           if ( dt_prop_cmp(pp->name, name) == 0 )
>>> @@ -150,6 +152,7 @@ const struct dt_property *dt_find_property(const 
>>> struct dt_device_node *np,
>>>           }
>>>       }
>>>   +    read_unlock(&dt_host->lock);
>>>       return pp;
>>>   }
>>>   @@ -336,11 +339,14 @@ struct dt_device_node 
>>> *dt_find_node_by_name(struct dt_device_node *from,
>>>       struct dt_device_node *np;
>>>       struct dt_device_node *dt;
>>>   +    read_lock(&dt_host->lock);
>>> +
>>>       dt = from ? from->allnext : dt_host;
>>>       dt_for_each_device_node(dt, np)
>>>           if ( np->name && (dt_node_cmp(np->name, name) == 0) )
>>>               break;
>>>   +    read_unlock(&dt_host->lock);
>>>       return np;
>>
>> ... I was expecting the read lock to also protect the value returned 
>> from being freed. But this is not the case.
>>
> Okay. Shall I remove the lock from here and perhaps add it when 
> dt_find_node_by_name() and other related functions are called?

It is a possibility. I would need to see the end result to be sure a 
lock is actually suitable.

Maybe we will end up to need a refcounting instead if we keep the DT 
node for longer.

Cheers,
diff mbox series

Patch

diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
index acf26a411d..51ee2a5edf 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -140,6 +140,8 @@  const struct dt_property *dt_find_property(const struct dt_device_node *np,
     if ( !np )
         return NULL;
 
+    read_lock(&dt_host->lock);
+
     for ( pp = np->properties; pp; pp = pp->next )
     {
         if ( dt_prop_cmp(pp->name, name) == 0 )
@@ -150,6 +152,7 @@  const struct dt_property *dt_find_property(const struct dt_device_node *np,
         }
     }
 
+    read_unlock(&dt_host->lock);
     return pp;
 }
 
@@ -336,11 +339,14 @@  struct dt_device_node *dt_find_node_by_name(struct dt_device_node *from,
     struct dt_device_node *np;
     struct dt_device_node *dt;
 
+    read_lock(&dt_host->lock);
+
     dt = from ? from->allnext : dt_host;
     dt_for_each_device_node(dt, np)
         if ( np->name && (dt_node_cmp(np->name, name) == 0) )
             break;
 
+    read_unlock(&dt_host->lock);
     return np;
 }
 
@@ -350,11 +356,14 @@  struct dt_device_node *dt_find_node_by_type(struct dt_device_node *from,
     struct dt_device_node *np;
     struct dt_device_node *dt;
 
+    read_lock(&dt_host->lock);
+
     dt = from ? from->allnext : dt_host;
     dt_for_each_device_node(dt, np)
         if ( np->type && (dt_node_cmp(np->type, type) == 0) )
             break;
 
+    read_unlock(&dt_host->lock);
     return np;
 }
 
@@ -363,10 +372,13 @@  struct dt_device_node *device_tree_find_node_by_path(struct dt_device_node *dt,
 {
     struct dt_device_node *np;
 
+    read_lock(&dt_host->lock);
+
     dt_for_each_device_node(dt, np)
         if ( np->full_name && (dt_node_cmp(np->full_name, path) == 0) )
             break;
 
+    read_unlock(&dt_host->lock);
     return np;
 }
 
@@ -450,6 +462,8 @@  dt_find_compatible_node(struct dt_device_node *from,
     struct dt_device_node *np;
     struct dt_device_node *dt;
 
+    read_lock(&dt_host->lock);
+
     dt = from ? from->allnext : dt_host;
     dt_for_each_device_node(dt, np)
     {
@@ -460,6 +474,7 @@  dt_find_compatible_node(struct dt_device_node *from,
             break;
     }
 
+    read_unlock(&dt_host->lock);
     return np;
 }
 
@@ -470,13 +485,19 @@  dt_find_matching_node(struct dt_device_node *from,
     struct dt_device_node *np;
     struct dt_device_node *dt;
 
+    read_lock(&dt_host->lock);
+
     dt = from ? from->allnext : dt_host;
     dt_for_each_device_node(dt, np)
     {
         if ( dt_match_node(matches, np) )
+        {
+            read_unlock(&dt_host->lock);
             return np;
+        }
     }
 
+    read_unlock(&dt_host->lock);
     return NULL;
 }
 
@@ -1052,10 +1073,13 @@  struct dt_device_node *dt_find_node_by_phandle(dt_phandle handle)
 {
     struct dt_device_node *np;
 
+    read_lock(&dt_host->lock);
+
     dt_for_each_device_node(dt_host, np)
         if ( np->phandle == handle )
             break;
 
+    read_unlock(&dt_host->lock);
     return np;
 }
 
@@ -2102,6 +2126,9 @@  int unflatten_device_tree(const void *fdt, struct dt_device_node **mynodes)
 
     dt_dprintk(" <- unflatten_device_tree()\n");
 
+    /* Init r/w lock for host device tree. */
+    rwlock_init(&dt_host->lock);
+
     return 0;
 }
 
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
index 51e251b0b4..bafc898f1c 100644
--- a/xen/include/xen/device_tree.h
+++ b/xen/include/xen/device_tree.h
@@ -18,6 +18,7 @@ 
 #include <xen/string.h>
 #include <xen/types.h>
 #include <xen/list.h>
+#include <xen/rwlock.h>
 
 #define DEVICE_TREE_MAX_DEPTH 16
 
@@ -106,6 +107,11 @@  struct dt_device_node {
     struct list_head domain_list;
 
     struct device dev;
+
+    /*
+     * Lock that protects r/w updates to unflattened device tree i.e. dt_host.
+     */
+    rwlock_t lock;
 };
 
 #define dt_to_dev(dt_node)  (&(dt_node)->dev)