[Devel] [RFC PATCH vz9 v6 06/62] dm-ploop: reduce the time lock is hold, taking it only to protect data
Alexander Atanasov
alexander.atanasov at virtuozzo.com
Tue Jan 14 15:05:23 MSK 2025
On 14.01.25 4:27, Pavel Tikhomirov wrote:
>
>
> On 1/14/25 00:27, Alexander Atanasov wrote:
>> On 9.01.25 5:52, Pavel Tikhomirov wrote:
>>>
>>>
>>> On 12/6/24 05:55, Alexander Atanasov wrote:
>>>> Currently lock is taken once for all pios submitted(code block),
>>>> move it to protect only the list insertion (data).
>>>> The goal is to reduce lock contention on the deferred lock as
>>>> it is in the top of lock stats.
>>>>
>>>> https://virtuozzo.atlassian.net/browse/VSTOR-91820
>>>> Signed-off-by: Alexander Atanasov <alexander.atanasov at virtuozzo.com>
>>>> ---
>>>> drivers/md/dm-ploop-map.c | 8 ++++----
>>>> 1 file changed, 4 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/drivers/md/dm-ploop-map.c b/drivers/md/dm-ploop-map.c
>>>> index 4b9e000e0f98..a0fe92a592a1 100644
>>>> --- a/drivers/md/dm-ploop-map.c
>>>> +++ b/drivers/md/dm-ploop-map.c
>>>> @@ -340,8 +340,9 @@ static void ploop_dispatch_pio(struct ploop
>>>> *ploop, struct pio *pio,
>>>> bool *is_data, bool *is_flush)
>>>> {
>>>> struct list_head *list = &ploop->pios[pio->queue_list_id];
>>>> + unsigned long flags;
>>>> - lockdep_assert_held(&ploop->deferred_lock);
>>>> + lockdep_assert_not_held(&ploop->deferred_lock);
>>>> WARN_ON_ONCE(pio->queue_list_id >= PLOOP_LIST_COUNT);
>>>> if (pio->queue_list_id == PLOOP_LIST_FLUSH)
>>>> @@ -349,23 +350,22 @@ static void ploop_dispatch_pio(struct ploop
>>>> *ploop, struct pio *pio,
>>>> else
>>>> *is_data = true;
>>>> + spin_lock_irqsave(&ploop->deferred_lock, flags);
>>>> list_add_tail(&pio->list, list);
>>>> + spin_unlock_irqrestore(&ploop->deferred_lock, flags);
>>>
>>> This patch can be merged to "[RFC PATCH vz9 v6 10/62] dm-ploop:
>>> convert the rest of the lists to use llist variant".
>>
>> I try to extra careful with list conversions, they bring hard to find
>> issues. So i prefer conversions to be in small steps.
>>
>>>
>>> Also I think that having one lock around the whole loop introduces
>>> much less lock contention than doing multiple take/release on each
>>> iteration of the loop.
>>
>>
>> This lock is gone later with move to llist.
>
> That is the main reason why it should be merged. There should be no
> reverts inside one series, moving lock unnecessarily and then removing
> it completely only brings unneeded confusion for the future reader of
> the code. [1]
I checked various guides, do you have a reference for this ?
The requirements listed are that:
- each patch is separate logical change
- each patch compiles to a working kernel
For me locking data instead of code is a logical change,
,changing list usage is separate logical change and so on.
If lock and list change are in one place it is easier to see.
https://www.kernel.org/doc/html/v4.11/process/coding-style.html#codingstyle
https://www.ozlabs.org/~akpm/stuff/tpp.txt
https://halobates.de/on-submitting-patches.pdf
>
> Usually there is just one
>> entry in the list most users dispatch single pio - locking the list
>> when it is necessary reduces the time lock is held - locking data
>> instead of locking code .
>
> This kind of optimization does not feel right to me. We should either
> optimize general case or have explicit optimizations for edge cases,
> e.g. in ploop_dispatch_pios "if (likely(pio))
> ploop_dispatch_pio_locked()", explicitly marking function which takes
> lock by itself with _locked suffix.
This is not a optimisation. General case is one pio, exception is many
pios. difference is neglectable, in the end this function is only used
for more than one pio one some abnormal condition. So i do not see a
point to optimise it. Fine graine locking on data is better than locking
a 100 lines function code, just like your example for the locks - you
can loose sense of why a lock is necessary.
>
> But all this is unimportant due to [1], should be just merged.
Ok. i will check.
>
>>
>>>
>>>> }
>>>> void ploop_dispatch_pios(struct ploop *ploop, struct pio *pio,
>>>> struct list_head *pio_list)
>>>> {
>>>> bool is_data = false, is_flush = false;
>>>> - unsigned long flags;
>>>> - spin_lock_irqsave(&ploop->deferred_lock, flags);
>>>> if (pio)
>>>> ploop_dispatch_pio(ploop, pio, &is_data, &is_flush);
>>>> if (pio_list) {
>>>> while ((pio = ploop_pio_list_pop(pio_list)) != NULL)
>>>> ploop_dispatch_pio(ploop, pio, &is_data, &is_flush);
>>>> }
>>>> - spin_unlock_irqrestore(&ploop->deferred_lock, flags);
>>>> if (is_data)
>>>> queue_work(ploop->wq, &ploop->worker);
>>>
>>
>
--
Regards,
Alexander Atanasov
More information about the Devel
mailing list