diff mbox

[net-next,1/3] team: remove synchronize_rcu() called during queue override change

Message ID 1370878945-9718-2-git-send-email-jiri@resnulli.us
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Jiri Pirko June 10, 2013, 3:42 p.m. UTC
This patch removes synchronize_rcu() from function
__team_queue_override_port_del(). That can be done because it is ok to
do list_del_rcu() and list_add_tail_rcu() on the same list_head member
without calling synchronize_rcu() in between. A bit of refactoring
needed to be done because INIT_LIST_HEAD needed to be removed (to not
kill the forward pointer) as well.

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
 drivers/net/team/team.c | 63 ++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 47 insertions(+), 16 deletions(-)

Comments

Flavio Leitner June 11, 2013, 12:48 a.m. UTC | #1
On Mon, Jun 10, 2013 at 05:42:23PM +0200, Jiri Pirko wrote:
> This patch removes synchronize_rcu() from function
> __team_queue_override_port_del(). That can be done because it is ok to
> do list_del_rcu() and list_add_tail_rcu() on the same list_head member
> without calling synchronize_rcu() in between. A bit of refactoring
> needed to be done because INIT_LIST_HEAD needed to be removed (to not
> kill the forward pointer) as well.
> 
> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
> ---
>  drivers/net/team/team.c | 63 ++++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 47 insertions(+), 16 deletions(-)
> 
[...]

> @@ -1278,17 +1310,16 @@ static int team_queue_id_option_set(struct team *team,
>  				    struct team_gsetter_ctx *ctx)
>  {
>  	struct team_port *port = ctx->info->port;
> +	u16 new_queue_id = ctx->data.u32_val;
>  
> -	if (port->queue_id == ctx->data.u32_val)
> +	if (port->queue_id == new_queue_id)

Since you're passing new_queue_id to port->queue_id and
in the other parts you test against !port->queue_id to see
if it's enable or not, that means queue 0 can't be used.

Maybe I am missing something, but wouldn't be better to
initialize with -1 and allow 0 to be used as well?

fbl

>  		return 0;
> -	if (ctx->data.u32_val >= team->dev->real_num_tx_queues)
> +	if (new_queue_id >= team->dev->real_num_tx_queues)
>  		return -EINVAL;
> -	port->queue_id = ctx->data.u32_val;
> -	team_queue_override_port_refresh(team, port);
> +	team_queue_override_port_change_queue_id(team, port, new_queue_id);
>  	return 0;
>  }
>  

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jiri Pirko June 11, 2013, 5:40 a.m. UTC | #2
Tue, Jun 11, 2013 at 02:48:45AM CEST, fbl@redhat.com wrote:
>On Mon, Jun 10, 2013 at 05:42:23PM +0200, Jiri Pirko wrote:
>> This patch removes synchronize_rcu() from function
>> __team_queue_override_port_del(). That can be done because it is ok to
>> do list_del_rcu() and list_add_tail_rcu() on the same list_head member
>> without calling synchronize_rcu() in between. A bit of refactoring
>> needed to be done because INIT_LIST_HEAD needed to be removed (to not
>> kill the forward pointer) as well.
>> 
>> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
>> ---
>>  drivers/net/team/team.c | 63 ++++++++++++++++++++++++++++++++++++-------------
>>  1 file changed, 47 insertions(+), 16 deletions(-)
>> 
>[...]
>
>> @@ -1278,17 +1310,16 @@ static int team_queue_id_option_set(struct team *team,
>>  				    struct team_gsetter_ctx *ctx)
>>  {
>>  	struct team_port *port = ctx->info->port;
>> +	u16 new_queue_id = ctx->data.u32_val;
>>  
>> -	if (port->queue_id == ctx->data.u32_val)
>> +	if (port->queue_id == new_queue_id)
>
>Since you're passing new_queue_id to port->queue_id and
>in the other parts you test against !port->queue_id to see
>if it's enable or not, that means queue 0 can't be used.
>
>Maybe I am missing something, but wouldn't be better to
>initialize with -1 and allow 0 to be used as well?

0 means default queue. It's done the same was as in bonding code.

>
>fbl
>
>>  		return 0;
>> -	if (ctx->data.u32_val >= team->dev->real_num_tx_queues)
>> +	if (new_queue_id >= team->dev->real_num_tx_queues)
>>  		return -EINVAL;
>> -	port->queue_id = ctx->data.u32_val;
>> -	team_queue_override_port_refresh(team, port);
>> +	team_queue_override_port_change_queue_id(team, port, new_queue_id);
>>  	return 0;
>>  }
>>  
>
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jiri Pirko June 11, 2013, 8:01 a.m. UTC | #3
Tue, Jun 11, 2013 at 07:40:46AM CEST, jiri@resnulli.us wrote:
>Tue, Jun 11, 2013 at 02:48:45AM CEST, fbl@redhat.com wrote:
>>On Mon, Jun 10, 2013 at 05:42:23PM +0200, Jiri Pirko wrote:
>>> This patch removes synchronize_rcu() from function
>>> __team_queue_override_port_del(). That can be done because it is ok to
>>> do list_del_rcu() and list_add_tail_rcu() on the same list_head member
>>> without calling synchronize_rcu() in between. A bit of refactoring
>>> needed to be done because INIT_LIST_HEAD needed to be removed (to not
>>> kill the forward pointer) as well.
>>> 
>>> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
>>> ---
>>>  drivers/net/team/team.c | 63 ++++++++++++++++++++++++++++++++++++-------------
>>>  1 file changed, 47 insertions(+), 16 deletions(-)
>>> 
>>[...]
>>
>>> @@ -1278,17 +1310,16 @@ static int team_queue_id_option_set(struct team *team,
>>>  				    struct team_gsetter_ctx *ctx)
>>>  {
>>>  	struct team_port *port = ctx->info->port;
>>> +	u16 new_queue_id = ctx->data.u32_val;
>>>  
>>> -	if (port->queue_id == ctx->data.u32_val)
>>> +	if (port->queue_id == new_queue_id)
>>
>>Since you're passing new_queue_id to port->queue_id and
>>in the other parts you test against !port->queue_id to see
>>if it's enable or not, that means queue 0 can't be used.
>>
>>Maybe I am missing something, but wouldn't be better to
>>initialize with -1 and allow 0 to be used as well?
>
>0 means default queue. It's done the same was as in bonding code.

+ this patch does not change original behaviour...

>
>>
>>fbl
>>
>>>  		return 0;
>>> -	if (ctx->data.u32_val >= team->dev->real_num_tx_queues)
>>> +	if (new_queue_id >= team->dev->real_num_tx_queues)
>>>  		return -EINVAL;
>>> -	port->queue_id = ctx->data.u32_val;
>>> -	team_queue_override_port_refresh(team, port);
>>> +	team_queue_override_port_change_queue_id(team, port, new_queue_id);
>>>  	return 0;
>>>  }
>>>  
>>
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Flavio Leitner June 11, 2013, 1:18 p.m. UTC | #4
On Tue, Jun 11, 2013 at 10:01:07AM +0200, Jiri Pirko wrote:
> Tue, Jun 11, 2013 at 07:40:46AM CEST, jiri@resnulli.us wrote:
> >Tue, Jun 11, 2013 at 02:48:45AM CEST, fbl@redhat.com wrote:
> >>On Mon, Jun 10, 2013 at 05:42:23PM +0200, Jiri Pirko wrote:
> >>> This patch removes synchronize_rcu() from function
> >>> __team_queue_override_port_del(). That can be done because it is ok to
> >>> do list_del_rcu() and list_add_tail_rcu() on the same list_head member
> >>> without calling synchronize_rcu() in between. A bit of refactoring
> >>> needed to be done because INIT_LIST_HEAD needed to be removed (to not
> >>> kill the forward pointer) as well.
> >>> 
> >>> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
> >>> ---
> >>>  drivers/net/team/team.c | 63 ++++++++++++++++++++++++++++++++++++-------------
> >>>  1 file changed, 47 insertions(+), 16 deletions(-)
> >>> 
> >>[...]
> >>
> >>> @@ -1278,17 +1310,16 @@ static int team_queue_id_option_set(struct team *team,
> >>>  				    struct team_gsetter_ctx *ctx)
> >>>  {
> >>>  	struct team_port *port = ctx->info->port;
> >>> +	u16 new_queue_id = ctx->data.u32_val;
> >>>  
> >>> -	if (port->queue_id == ctx->data.u32_val)
> >>> +	if (port->queue_id == new_queue_id)
> >>
> >>Since you're passing new_queue_id to port->queue_id and
> >>in the other parts you test against !port->queue_id to see
> >>if it's enable or not, that means queue 0 can't be used.
> >>
> >>Maybe I am missing something, but wouldn't be better to
> >>initialize with -1 and allow 0 to be used as well?
> >
> >0 means default queue. It's done the same was as in bonding code.
> 
> + this patch does not change original behaviour...

Jiri explained this bits off list to me, so

Acked-by: Flavio Leitner <fbl@redhat.com>

Thanks,
diff mbox

Patch

diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 4ac10f2..f00446e 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -725,9 +725,9 @@  static bool team_queue_override_transmit(struct team *team, struct sk_buff *skb)
 static void __team_queue_override_port_del(struct team *team,
 					   struct team_port *port)
 {
+	if (!port->queue_id)
+		return;
 	list_del_rcu(&port->qom_list);
-	synchronize_rcu();
-	INIT_LIST_HEAD(&port->qom_list);
 }
 
 static bool team_queue_override_port_has_gt_prio_than(struct team_port *port,
@@ -749,9 +749,8 @@  static void __team_queue_override_port_add(struct team *team,
 	struct list_head *qom_list;
 	struct list_head *node;
 
-	if (!port->queue_id || !team_port_enabled(port))
+	if (!port->queue_id)
 		return;
-
 	qom_list = __team_get_qom_list(team, port->queue_id);
 	node = qom_list;
 	list_for_each_entry(cur, qom_list, qom_list) {
@@ -768,7 +767,7 @@  static void __team_queue_override_enabled_check(struct team *team)
 	bool enabled = false;
 
 	list_for_each_entry(port, &team->port_list, list) {
-		if (!list_empty(&port->qom_list)) {
+		if (port->queue_id) {
 			enabled = true;
 			break;
 		}
@@ -780,14 +779,44 @@  static void __team_queue_override_enabled_check(struct team *team)
 	team->queue_override_enabled = enabled;
 }
 
-static void team_queue_override_port_refresh(struct team *team,
-					     struct team_port *port)
+static void team_queue_override_port_prio_changed(struct team *team,
+						  struct team_port *port)
 {
+	if (!port->queue_id || team_port_enabled(port))
+		return;
 	__team_queue_override_port_del(team, port);
 	__team_queue_override_port_add(team, port);
 	__team_queue_override_enabled_check(team);
 }
 
+static void team_queue_override_port_change_queue_id(struct team *team,
+						     struct team_port *port,
+						     u16 new_queue_id)
+{
+	if (team_port_enabled(port)) {
+		__team_queue_override_port_del(team, port);
+		port->queue_id = new_queue_id;
+		__team_queue_override_port_add(team, port);
+		__team_queue_override_enabled_check(team);
+	} else {
+		port->queue_id = new_queue_id;
+	}
+}
+
+static void team_queue_override_port_add(struct team *team,
+					 struct team_port *port)
+{
+	__team_queue_override_port_add(team, port);
+	__team_queue_override_enabled_check(team);
+}
+
+static void team_queue_override_port_del(struct team *team,
+					 struct team_port *port)
+{
+	__team_queue_override_port_del(team, port);
+	__team_queue_override_enabled_check(team);
+}
+
 
 /****************
  * Port handling
@@ -819,7 +848,7 @@  static void team_port_enable(struct team *team,
 	hlist_add_head_rcu(&port->hlist,
 			   team_port_index_hash(team, port->index));
 	team_adjust_ops(team);
-	team_queue_override_port_refresh(team, port);
+	team_queue_override_port_add(team, port);
 	if (team->ops.port_enabled)
 		team->ops.port_enabled(team, port);
 }
@@ -848,7 +877,7 @@  static void team_port_disable(struct team *team,
 	hlist_del_rcu(&port->hlist);
 	__reconstruct_port_hlist(team, port->index);
 	port->index = -1;
-	team_queue_override_port_refresh(team, port);
+	team_queue_override_port_del(team, port);
 	__team_adjust_ops(team, team->en_port_count - 1);
 	/*
 	 * Wait until readers see adjusted ops. This ensures that
@@ -1259,9 +1288,12 @@  static int team_priority_option_set(struct team *team,
 				    struct team_gsetter_ctx *ctx)
 {
 	struct team_port *port = ctx->info->port;
+	s32 priority = ctx->data.s32_val;
 
-	port->priority = ctx->data.s32_val;
-	team_queue_override_port_refresh(team, port);
+	if (port->priority == priority)
+		return 0;
+	port->priority = priority;
+	team_queue_override_port_prio_changed(team, port);
 	return 0;
 }
 
@@ -1278,17 +1310,16 @@  static int team_queue_id_option_set(struct team *team,
 				    struct team_gsetter_ctx *ctx)
 {
 	struct team_port *port = ctx->info->port;
+	u16 new_queue_id = ctx->data.u32_val;
 
-	if (port->queue_id == ctx->data.u32_val)
+	if (port->queue_id == new_queue_id)
 		return 0;
-	if (ctx->data.u32_val >= team->dev->real_num_tx_queues)
+	if (new_queue_id >= team->dev->real_num_tx_queues)
 		return -EINVAL;
-	port->queue_id = ctx->data.u32_val;
-	team_queue_override_port_refresh(team, port);
+	team_queue_override_port_change_queue_id(team, port, new_queue_id);
 	return 0;
 }
 
-
 static const struct team_option team_options[] = {
 	{
 		.name = "mode",