[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <b7c5da61-6c17-fe19-957c-4c8b6d6e86fe@linux.alibaba.com>
Date: Tue, 22 Dec 2020 00:51:27 +0800
From: Liangyan <liangyan.peng@...ux.alibaba.com>
To: Al Viro <viro@...iv.linux.org.uk>,
Joseph Qi <joseph.qi@...ux.alibaba.com>
Cc: Miklos Szeredi <miklos@...redi.hu>, linux-unionfs@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: Re: [PATCH v2] ovl: fix dentry leak in ovl_get_redirect
This is the race scenario based on call trace we captured which cause
the dentry leak.
CPU 0 CPU 1
ovl_set_redirect lookup_fast
ovl_get_redirect __d_lookup
dget_dlock
//no lock protection here spin_lock(&dentry->d_lock)
dentry->d_lockref.count++ dentry->d_lockref.count++
If we use dget_parent instead, we may have this race.
CPU 0 CPU 1
ovl_set_redirect lookup_fast
ovl_get_redirect __d_lookup
dget_parent
raw_seqcount_begin(&dentry->d_seq) spin_lock(&dentry->d_lock)
lockref_get_not_zero(&ret->d_lockref) dentry->d_lockref.count++
On 20/12/21 下午8:11, Al Viro wrote:
> On Mon, Dec 21, 2020 at 07:14:44PM +0800, Joseph Qi wrote:
>> Hi Viro,
>>
>> On 12/21/20 2:26 PM, Al Viro wrote:
>>> On Sun, Dec 20, 2020 at 08:09:27PM +0800, Liangyan wrote:
>>>
>>>> +++ b/fs/overlayfs/dir.c
>>>> @@ -973,6 +973,7 @@ static char *ovl_get_redirect(struct dentry *dentry, bool abs_redirect)
>>>> for (d = dget(dentry); !IS_ROOT(d);) {
>>>> const char *name;
>>>> int thislen;
>>>> + struct dentry *parent = NULL;
>>>>
>>>> spin_lock(&d->d_lock);
>>>> name = ovl_dentry_get_redirect(d);
>>>> @@ -992,7 +993,22 @@ static char *ovl_get_redirect(struct dentry *dentry, bool abs_redirect)
>>>>
>>>> buflen -= thislen;
>>>> memcpy(&buf[buflen], name, thislen);
>>>> - tmp = dget_dlock(d->d_parent);
>>>> + parent = d->d_parent;
>>>> + if (unlikely(!spin_trylock(&parent->d_lock))) {
>>>> + rcu_read_lock();
>>>> + spin_unlock(&d->d_lock);
>>>> +again:
>>>> + parent = READ_ONCE(d->d_parent);
>>>> + spin_lock(&parent->d_lock);
>>>> + if (unlikely(parent != d->d_parent)) {
>>>> + spin_unlock(&parent->d_lock);
>>>> + goto again;
>>>> + }
>>>> + rcu_read_unlock();
>>>> + spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
>>>> + }
>>>> + tmp = dget_dlock(parent);
>>>> + spin_unlock(&parent->d_lock);
>>>> spin_unlock(&d->d_lock);
>>>
>>> Yecchhhh.... What's wrong with just doing
>>> spin_unlock(&d->d_lock);
>>> parent = dget_parent(d);
>>> dput(d);
>>> d = parent;
>>> instead of that?
>>>
>>
>> Now race happens on non-RCU path in lookup_fast(), I'm afraid d_seq can
>> not close the race window.
>
> Explain, please. What exactly are you observing?
>
Powered by blists - more mailing lists