]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mlxsw: spectrum_acl_tcam: Fix race during rehash delayed work
authorIdo Schimmel <idosch@nvidia.com>
Mon, 22 Apr 2024 15:25:55 +0000 (17:25 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 25 Apr 2024 02:32:59 +0000 (19:32 -0700)
The purpose of the rehash delayed work is to reduce the number of masks
(eRPs) used by an ACL region as the eRP bank is a global and limited
resource.

This is done in three steps:

1. Creating a new set of masks and a new ACL region which will use the
   new masks and to which the existing filters will be migrated to. The
   new region is assigned to 'vregion->region' and the region from which
   the filters are migrated from is assigned to 'vregion->region2'.

2. Migrating all the filters from the old region to the new region.

3. Destroying the old region and setting 'vregion->region2' to NULL.

Only the second steps is performed under the 'vregion->lock' mutex
although its comments says that among other things it "Protects
consistency of region, region2 pointers".

This is problematic as the first step can race with filter insertion
from user space that uses 'vregion->region', but under the mutex.

Fix by holding the mutex across the entirety of the delayed work and not
only during the second step.

Fixes: 2bffc5322fd8 ("mlxsw: spectrum_acl: Don't take mutex in mlxsw_sp_acl_tcam_vregion_rehash_work()")
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Tested-by: Alexander Zubkov <green@qrator.net>
Reviewed-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://lore.kernel.org/r/1ec1d54edf2bad0a369e6b4fa030aba64e1f124b.1713797103.git.petrm@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c

index b6a4652a6475a283f6b86a607b59bd9c7919f592..9c0c728bb42dc519ef2c8ad5b00080c0e900f9a0 100644 (file)
@@ -718,7 +718,9 @@ static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work)
                             rehash.dw.work);
        int credits = MLXSW_SP_ACL_TCAM_VREGION_REHASH_CREDITS;
 
+       mutex_lock(&vregion->lock);
        mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion, &credits);
+       mutex_unlock(&vregion->lock);
        if (credits < 0)
                /* Rehash gone out of credits so it was interrupted.
                 * Schedule the work as soon as possible to continue.
@@ -1323,7 +1325,6 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
        int err, err2;
 
        trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion);
-       mutex_lock(&vregion->lock);
        err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion,
                                                   ctx, credits);
        if (err) {
@@ -1343,7 +1344,6 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
                        /* Let the rollback to be continued later on. */
                }
        }
-       mutex_unlock(&vregion->lock);
        trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion);
        return err;
 }