[Ocfs2-devel] [PATCH] ocfs2: kill EBUSY from dlmfs_evict_inode

heming.zhao at suse.com heming.zhao at suse.com
Sun Jun 5 01:12:20 UTC 2022


On 6/5/22 08:48, Junxiao Bi wrote:
> 
> 
>> 在 2022年6月4日,下午4:17,heming.zhao at suse.com 写道:
>>
>> On 6/5/22 06:27, Junxiao Bi wrote:
>>>> On 6/4/22 3:10 AM, heming.zhao at suse.com wrote:
>>>> Hello Junxiao,
>>>>
>>>> On 6/4/22 06:31, Junxiao Bi via Ocfs2-devel wrote:
>>>>> When unlink a dlmfs, first it will invoke dlmfs_unlink(), and then invoke
>>>>> dlmfs_evict_inode(), user_dlm_destroy_lock() is invoked in both places,
>>>>> the second one from dlmfs_evict_inode() will get EBUSY error because
>>>>> USER_LOCK_IN_TEARDOWN is already set in lockres. This doesn't affect
>>>>> any function, just the error log is anonying.
>>>>>
>>>>> Signed-off-by: Junxiao Bi <junxiao.bi at oracle.com>
>>>>> ---
>>>>>    fs/ocfs2/dlmfs/dlmfs.c | 14 +++++++++++---
>>>>>    1 file changed, 11 insertions(+), 3 deletions(-)
>>>>>
>>>>> diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
>>>>> index e360543ad7e7..a120610dff7e 100644
>>>>> --- a/fs/ocfs2/dlmfs/dlmfs.c
>>>>> +++ b/fs/ocfs2/dlmfs/dlmfs.c
>>>>> @@ -296,17 +296,25 @@ static void dlmfs_evict_inode(struct inode *inode)
>>>>>    {
>>>>>        int status;
>>>>>        struct dlmfs_inode_private *ip;
>>>>> +    struct user_lock_res *lockres;
>>>>> +    int destroyed;
>>>>>          clear_inode(inode);
>>>>>          mlog(0, "inode %lu\n", inode->i_ino);
>>>>>          ip = DLMFS_I(inode);
>>>>> +    lockres = &ip->ip_lockres;
>>>>>          if (S_ISREG(inode->i_mode)) {
>>>>> -        status = user_dlm_destroy_lock(&ip->ip_lockres);
>>>>> -        if (status < 0)
>>>>> -            mlog_errno(status);
>>>>> +        spin_lock(&lockres->l_lock);
>>>>> +        destroyed = !!(lockres->l_flags & USER_LOCK_IN_TEARDOWN);
>>>>> +        spin_unlock(&lockres->l_lock);
>>>>
>>>> This area code does the same work in user_dlm_destroy_lock(). Why not to give another
>>>> errno (e.g -EAGAIN) for user_dlm_destroy_lock when l_flags contains USER_LOCK_IN_TEARDOWN.
>>>> then change 'if (status < 0)' to 'if (status < 0 && status != -EAGAIN)'
>>> I don't think we should do that. It's reasonable for user_dlm_destroy_lock() to return EBUSY in that case. EAGAIN is for the case, you invoke it second time you may succeed. That's not the case here.
>>
>> I agree the EAGAIN is not good, but do you think the errno idea is reasonable?
>> user_dlm_destroy_lock only has two callers: dlmfs_evict_inode & dlmfs_unlink.
>> the code logic is clear, we can choose another errno, or even create a new one.
>> it costs too much to use spin_lock to avoid print an error log.
> Regarding cost, the suggested way has even higher cost, the spin lock can’t be avoided unless you don’t access the lockres and an extra function call was also added.
> Actually that function shouldn’t be invoked because it was already invoked once in this flow. I don’t think we should change return value of that function, EBUSY looks most reasonable return value for me.

I can't see why my idea cost more. the patch ('NEW_ERRNO' should be changed) with my idea:

diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c

index e360543ad7e7..dd47556b07fa 100644

--- a/fs/ocfs2/dlmfs/dlmfs.c

+++ b/fs/ocfs2/dlmfs/dlmfs.c

@@ -305,7 +305,7 @@ static void dlmfs_evict_inode(struct inode *inode)

  

      if (S_ISREG(inode->i_mode)) {

          status = user_dlm_destroy_lock(&ip->ip_lockres);

-        if (status < 0)

+        if (status < 0 && status != NEW_ERRNO)

              mlog_errno(status);

          iput(ip->ip_parent);

          goto clear_fields;

diff --git a/fs/ocfs2/dlmfs/userdlm.c b/fs/ocfs2/dlmfs/userdlm.c

index 617c92e7b925..93b8d7bad96e 100644

--- a/fs/ocfs2/dlmfs/userdlm.c

+++ b/fs/ocfs2/dlmfs/userdlm.c

@@ -600,6 +600,7 @@ int user_dlm_destroy_lock(struct user_lock_res *lockres)

      spin_lock(&lockres->l_lock);

      if (lockres->l_flags & USER_LOCK_IN_TEARDOWN) {

          spin_unlock(&lockres->l_lock);

+        status = -NEW_ERRNO;

          goto bail;

      }

your patch added many codes and add another 'if' branch.
- the many codes: cpu will spend more time to complete the same work.
- the new added 'if' branch will breaks cpu pipeline.

my patch only changes 2 lines, maybe add 2 lines cpu instruct without adding
new breaking cpu pipeline case.

/Heming

>>
>>>>
>>>>> +        if (!destroyed) {
>>>>> +            status = user_dlm_destroy_lock(lockres);
>>>>> +            if (status < 0)
>>>>> +                mlog_errno(status);
>>>>> +        }
>>>>>            iput(ip->ip_parent);
>>>>>            goto clear_fields;
>>>>>        }
>>>>
>>




More information about the Ocfs2-devel mailing list