Hi Changwei,

On 2017/12/8 17:09, Changwei Ge wrote:
> On 2017/12/7 20:37, piaojun wrote:
>> Hi Changwei,
>>
>> On 2017/12/7 19:59, Changwei Ge wrote:
>>> Hi Jun,
>>>
>>> On 2017/12/7 19:30, piaojun wrote:
>>>>          CPUA                                      CPUB
>>>>
>>>> ocfs2_dentry_convert_worker
>>>> get 'l_lock'
>>>
>>> This lock belongs to ocfs2_dentry_lock::ocfs2_lock_res::l_lock
>>>
>>>>
>>>>                                       get 'dentry_attach_lock'
>>>>
>>>>                                       interruptted by dio_end_io:
>>>>                                         dio_end_io
>>>>                                           dio_bio_end_aio
>>>>                                             dio_complete
>>>>                                               dio->end_io
>>>>                                                 ocfs2_dio_end_io
>>>>                                                   ocfs2_rw_unlock
>>>>                                                   ...
>>>>                                                   try to get 'l_lock'
>>>
>>> This lock belongs to ocfs2_lock_res::l_lock though.
>>>
>>> So I think they are totally two different locks.
>>> So making spin_lock to interruption safe is pointless.
>>>
>>> Thanks,
>>> Changwei
>>>
>>
>> For the same lock, we need use spin_lock_irqsave to ensure irq-safe as
>> you said. But the scenario described above is another kind of deadlock
>> caused by two different locks which stuck each other. To avoid this
>> 'ABBA' deadlock we need follow the rule that 'spin_lock_irqsave' should
>> be called under 'spin_lock_irqsave'.
> 
> Hi Jun,
> I'm not sure if you understood my concern?
> I agree with that we should avoid ABBA dead lock scenario.
> But the dead lock scenario your sequence diagram is demonstrating 
> doesn't even exist.
> 
> Because CPU A is holding lock _X1_ and waiting for _dentry_attach_lock_.
> meanwhile CPU B is holding lock _dentry_attach_lock_ and waiting for _X2_.
> No ABBA deadlock condition is met, CPU B will acquire lock _X2_ without 
> being affected by CPU A.
> 
> In a nutshell, there are three locks(lock memory space) involved in your 
> diagram rather than two.
> 
> Thanks,
> Changwei
> 

Sorry for misunderstanding your point, and I realize no deadlock would
happen as these two 'l_lock' belong to different lockres. But I still
suggest merging this patch, because this would reduce the risk of
introducing new deadlock probably by programming.

thanks,
Jun

>>
>> thanks,
>> Jun
>>
>>>>                                                   but CPUA has got it.
>>>>
>>>> try to get 'dentry_attach_lock',
>>>> but CPUB has got 'dentry_attach_lock',
>>>> and would not release it.
>>>>
>>>> so we need use spin_lock_irqsave for 'dentry_attach_lock' to prevent
>>>> interruptted by softirq.
>>>>
>>>> Signed-off-by: Jun Piao <piao...@huawei.com>
>>>> Reviewed-by: Alex Chen <alex.c...@huawei.com>
>>>> ---
>>>>    fs/ocfs2/dcache.c  | 14 ++++++++------
>>>>    fs/ocfs2/dlmglue.c | 14 +++++++-------
>>>>    fs/ocfs2/namei.c   |  5 +++--
>>>>    3 files changed, 18 insertions(+), 15 deletions(-)
>>>>
>>>> diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c
>>>> index 2903730..6555fbf 100644
>>>> --- a/fs/ocfs2/dcache.c
>>>> +++ b/fs/ocfs2/dcache.c
>>>> @@ -230,6 +230,7 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
>>>>            int ret;
>>>>            struct dentry *alias;
>>>>            struct ocfs2_dentry_lock *dl = dentry->d_fsdata;
>>>> +  unsigned long flags;
>>>>
>>>>            trace_ocfs2_dentry_attach_lock(dentry->d_name.len, 
>>>> dentry->d_name.name,
>>>>                                           (unsigned long 
>>>> long)parent_blkno, dl);
>>>> @@ -309,10 +310,10 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
>>>>            ocfs2_dentry_lock_res_init(dl, parent_blkno, inode);
>>>>
>>>>    out_attach:
>>>> -  spin_lock(&dentry_attach_lock);
>>>> +  spin_lock_irqsave(&dentry_attach_lock, flags);
>>>>            dentry->d_fsdata = dl;
>>>>            dl->dl_count++;
>>>> -  spin_unlock(&dentry_attach_lock);
>>>> +  spin_unlock_irqrestore(&dentry_attach_lock, flags);
>>>>
>>>>            /*
>>>>             * This actually gets us our PRMODE level lock. From now on,
>>>> @@ -333,9 +334,9 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
>>>>            if (ret < 0 && !alias) {
>>>>                    ocfs2_lock_res_free(&dl->dl_lockres);
>>>>                    BUG_ON(dl->dl_count != 1);
>>>> -          spin_lock(&dentry_attach_lock);
>>>> +          spin_lock_irqsave(&dentry_attach_lock, flags);
>>>>                    dentry->d_fsdata = NULL;
>>>> -          spin_unlock(&dentry_attach_lock);
>>>> +          spin_unlock_irqrestore(&dentry_attach_lock, flags);
>>>>                    kfree(dl);
>>>>                    iput(inode);
>>>>            }
>>>> @@ -379,13 +380,14 @@ void ocfs2_dentry_lock_put(struct ocfs2_super *osb,
>>>>                               struct ocfs2_dentry_lock *dl)
>>>>    {
>>>>            int unlock = 0;
>>>> +  unsigned long flags;
>>>>
>>>>            BUG_ON(dl->dl_count == 0);
>>>>
>>>> -  spin_lock(&dentry_attach_lock);
>>>> +  spin_lock_irqsave(&dentry_attach_lock, flags);
>>>>            dl->dl_count--;
>>>>            unlock = !dl->dl_count;
>>>> -  spin_unlock(&dentry_attach_lock);
>>>> +  spin_unlock_irqrestore(&dentry_attach_lock, flags);
>>>>
>>>>            if (unlock)
>>>>                    ocfs2_drop_dentry_lock(osb, dl);
>>>> diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
>>>> index 4689940..9bff3d2 100644
>>>> --- a/fs/ocfs2/dlmglue.c
>>>> +++ b/fs/ocfs2/dlmglue.c
>>>> @@ -3801,7 +3801,7 @@ static int ocfs2_dentry_convert_worker(struct 
>>>> ocfs2_lock_res *lockres,
>>>>            struct ocfs2_dentry_lock *dl = ocfs2_lock_res_dl(lockres);
>>>>            struct ocfs2_inode_info *oi = OCFS2_I(dl->dl_inode);
>>>>            struct dentry *dentry;
>>>> -  unsigned long flags;
>>>> +  unsigned long flags, d_flags;
>>>>            int extra_ref = 0;
>>>>
>>>>            /*
>>>> @@ -3831,13 +3831,13 @@ static int ocfs2_dentry_convert_worker(struct 
>>>> ocfs2_lock_res *lockres,
>>>>             * flag.
>>>>             */
>>>>            spin_lock_irqsave(&lockres->l_lock, flags);
>>>> -  spin_lock(&dentry_attach_lock);
>>>> +  spin_lock_irqsave(&dentry_attach_lock, d_flags);
>>>>            if (!(lockres->l_flags & OCFS2_LOCK_FREEING)
>>>>                && dl->dl_count) {
>>>>                    dl->dl_count++;
>>>>                    extra_ref = 1;
>>>>            }
>>>> -  spin_unlock(&dentry_attach_lock);
>>>> +  spin_unlock_irqrestore(&dentry_attach_lock, d_flags);
>>>>            spin_unlock_irqrestore(&lockres->l_lock, flags);
>>>>
>>>>            mlog(0, "extra_ref = %d\n", extra_ref);
>>>> @@ -3850,13 +3850,13 @@ static int ocfs2_dentry_convert_worker(struct 
>>>> ocfs2_lock_res *lockres,
>>>>            if (!extra_ref)
>>>>                    return UNBLOCK_CONTINUE;
>>>>
>>>> -  spin_lock(&dentry_attach_lock);
>>>> +  spin_lock_irqsave(&dentry_attach_lock, d_flags);
>>>>            while (1) {
>>>>                    dentry = ocfs2_find_local_alias(dl->dl_inode,
>>>>                                                    dl->dl_parent_blkno, 1);
>>>>                    if (!dentry)
>>>>                            break;
>>>> -          spin_unlock(&dentry_attach_lock);
>>>> +          spin_unlock_irqrestore(&dentry_attach_lock, d_flags);
>>>>
>>>>                    if (S_ISDIR(dl->dl_inode->i_mode))
>>>>                            shrink_dcache_parent(dentry);
>>>> @@ -3874,9 +3874,9 @@ static int ocfs2_dentry_convert_worker(struct 
>>>> ocfs2_lock_res *lockres,
>>>>                    d_delete(dentry);
>>>>                    dput(dentry);
>>>>
>>>> -          spin_lock(&dentry_attach_lock);
>>>> +          spin_lock_irqsave(&dentry_attach_lock, d_flags);
>>>>            }
>>>> -  spin_unlock(&dentry_attach_lock);
>>>> +  spin_unlock_irqrestore(&dentry_attach_lock, d_flags);
>>>>
>>>>            /*
>>>>             * If we are the last holder of this dentry lock, there is no
>>>> diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
>>>> index 3b0a10d..a17454e 100644
>>>> --- a/fs/ocfs2/namei.c
>>>> +++ b/fs/ocfs2/namei.c
>>>> @@ -223,13 +223,14 @@ static void ocfs2_cleanup_add_entry_failure(struct 
>>>> ocfs2_super *osb,
>>>>                    struct dentry *dentry, struct inode *inode)
>>>>    {
>>>>            struct ocfs2_dentry_lock *dl = dentry->d_fsdata;
>>>> +  unsigned long flags;
>>>>
>>>>            ocfs2_simple_drop_lockres(osb, &dl->dl_lockres);
>>>>            ocfs2_lock_res_free(&dl->dl_lockres);
>>>>            BUG_ON(dl->dl_count != 1);
>>>> -  spin_lock(&dentry_attach_lock);
>>>> +  spin_lock_irqsave(&dentry_attach_lock, flags);
>>>>            dentry->d_fsdata = NULL;
>>>> -  spin_unlock(&dentry_attach_lock);
>>>> +  spin_unlock_irqrestore(&dentry_attach_lock, flags);
>>>>            kfree(dl);
>>>>            iput(inode);
>>>>    }
>>>>
>>>
>>> .
>>>
>>
> 
> .
> 

_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel@oss.oracle.com
https://oss.oracle.com/mailman/listinfo/ocfs2-devel

Reply via email to