• Alex Elder's avatar
    net: ipa: lock when freeing transaction · 064c9c32
    Alex Elder authored
    Transactions sit on one of several lists, depending on their state
    (allocated, pending, complete, or polled).  A spinlock protects
    against concurrent access when transactions are moved between these
    lists.
    
    Transactions are also reference counted.  A newly-allocated
    transaction has an initial count of 1; a transaction is released in
    gsi_trans_free() only if its decremented reference count reaches 0.
    Releasing a transaction includes removing it from the polled (or if
    unused, allocated) list, so the spinlock is acquired when we release
    a transaction.
    
    The reference count is used to allow a caller to synchronously wait
    for a committed transaction to complete.  In this case, the waiter
    takes an extra reference to the transaction *before* committing it
    (so it won't be freed), and releases its reference (calls
    gsi_trans_free()) when it is done with it.
    
    Similarly, gsi_channel_update() takes an extra reference to ensure a
    transaction isn't released before the function is done operating on
    it.  Until the transaction is moved to the completed list (by this
    function) it won't be freed, so this reference is taken "safely."
    
    But in the quiesce path, we want to wait for the "last" transaction,
    which we find in the completed or polled list.  Transactions on
    these lists can be freed at any time, so we (try to) prevent that
    by taking the reference while holding the spinlock.
    
    Currently gsi_trans_free() decrements a transaction's reference
    count unconditionally, acquiring the lock to remove the transaction
    from its list *only* when the count reaches 0.  This does not
    protect the quiesce path, which depends on the lock to ensure its
    extra reference prevents release of the transaction.
    
    Fix this by only dropping the last reference to a transaction
    in gsi_trans_free() while holding the spinlock.
    
    Fixes: 9dd441e4 ("soc: qcom: ipa: GSI transactions")
    Reported-by: default avatarStephen Boyd <swboyd@chromium.org>
    Signed-off-by: default avatarAlex Elder <elder@linaro.org>
    Link: https://lore.kernel.org/r/20201114182017.28270-1-elder@linaro.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
    064c9c32
gsi_trans.c 23.9 KB