Re: [PATCH 2/2] kernfs: remove mutex in kernfs_dop_revalidate

2020-12-02 Thread Fox Chen
On Thu, Dec 3, 2020 at 2:46 AM Tejun Heo  wrote:
>
> Hello,
>
> On Wed, Dec 02, 2020 at 10:58:37PM +0800, Fox Chen wrote:
> > There is a big mutex in kernfs_dop_revalidate which slows down the
> > concurrent performance of kernfs.
> >
> > Since kernfs_dop_revalidate only does some checks, the lock is
> > largely unnecessary. Also, according to kernel filesystem locking
> > document:
> > https://www.kernel.org/doc/html/latest/filesystems/locking.html
> > locking is not in the protocal for d_revalidate operation.
>
> That's just describing the rules seen from vfs side. It doesn't say anything
> about locking rules internal to each file system implementation.

Oh, Ok, I got it.

> > This patch remove this mutex from
> > kernfs_dop_revalidate, so kernfs_dop_revalidate
> > can run concurrently.
> >
> > Signed-off-by: Fox Chen 
> > ---
> >  fs/kernfs/dir.c | 9 +++--
> >  1 file changed, 3 insertions(+), 6 deletions(-)
> >
> > diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
> > index 9aec80b9d7c6..c2267c93f546 100644
> > --- a/fs/kernfs/dir.c
> > +++ b/fs/kernfs/dir.c
> > @@ -26,7 +26,6 @@ static DEFINE_SPINLOCK(kernfs_idr_lock);/* 
> > root->ino_idr */
> >
> >  static bool kernfs_active(struct kernfs_node *kn)
> >  {
> > - lockdep_assert_held(_mutex);
> >   return atomic_read(>active) >= 0;
> >  }
> >
> > @@ -557,10 +556,9 @@ static int kernfs_dop_revalidate(struct dentry 
> > *dentry, unsigned int flags)
> >
> >   /* Always perform fresh lookup for negatives */
> >   if (d_really_is_negative(dentry))
> > - goto out_bad_unlocked;
> > + goto out_bad;
> >
> >   kn = kernfs_dentry_node(dentry);
> > - mutex_lock(_mutex);
> >
> >   /* The kernfs node has been deactivated */
> >   if (!kernfs_active(kn))
> > @@ -579,11 +577,8 @@ static int kernfs_dop_revalidate(struct dentry 
> > *dentry, unsigned int flags)
> >   kernfs_info(dentry->d_sb)->ns != kn->ns)
> >   goto out_bad;
> >
> > - mutex_unlock(_mutex);
> >   return 1;
> >  out_bad:
> > - mutex_unlock(_mutex);
> > -out_bad_unlocked:
> >   return 0;
> >  }
>
> I don't see how this can be safe. Nothing even protects the dentry from
> turning negative in the middle and it may end up trying to deref NULL. I'm
> sure we can make this not need kernfs_mutex but that'd have to be a lot more
> careful.
>

Sorry Tejun, I don't get it. Even before the patch

if (d_really_is_negative(dentry))
 goto out_bad_unlocked;

kn = kernfs_dentry_node(dentry);
mutex_lock(_mutex);  < we lock here

status of d_really_is_negative is not preserved by the mutex. It could
turn negative between we checked it and we lock kernfs_mutex.
Is it a bug here??


thanks,
fox


Re: [PATCH 2/2] kernfs: remove mutex in kernfs_dop_revalidate

2020-12-02 Thread Fox Chen
On Thu, Dec 3, 2020 at 2:26 AM Greg KH  wrote:
>
> On Wed, Dec 02, 2020 at 10:58:37PM +0800, Fox Chen wrote:
> > There is a big mutex in kernfs_dop_revalidate which slows down the
> > concurrent performance of kernfs.
> >
> > Since kernfs_dop_revalidate only does some checks, the lock is
> > largely unnecessary. Also, according to kernel filesystem locking
> > document:
> > https://www.kernel.org/doc/html/latest/filesystems/locking.html
> > locking is not in the protocal for d_revalidate operation.
> >
> > This patch remove this mutex from
> > kernfs_dop_revalidate, so kernfs_dop_revalidate
> > can run concurrently.
> >
> > Signed-off-by: Fox Chen 
> > ---
> >  fs/kernfs/dir.c | 9 +++--
> >  1 file changed, 3 insertions(+), 6 deletions(-)
> >
> > diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
> > index 9aec80b9d7c6..c2267c93f546 100644
> > --- a/fs/kernfs/dir.c
> > +++ b/fs/kernfs/dir.c
> > @@ -26,7 +26,6 @@ static DEFINE_SPINLOCK(kernfs_idr_lock);/* 
> > root->ino_idr */
> >
> >  static bool kernfs_active(struct kernfs_node *kn)
> >  {
> > - lockdep_assert_held(_mutex);
> >   return atomic_read(>active) >= 0;
> >  }
> >
> > @@ -557,10 +556,9 @@ static int kernfs_dop_revalidate(struct dentry 
> > *dentry, unsigned int flags)
> >
> >   /* Always perform fresh lookup for negatives */
> >   if (d_really_is_negative(dentry))
> > - goto out_bad_unlocked;
> > + goto out_bad;
> >
> >   kn = kernfs_dentry_node(dentry);
> > - mutex_lock(_mutex);
> >
> >   /* The kernfs node has been deactivated */
> >   if (!kernfs_active(kn))
> > @@ -579,11 +577,8 @@ static int kernfs_dop_revalidate(struct dentry 
> > *dentry, unsigned int flags)
> >   kernfs_info(dentry->d_sb)->ns != kn->ns)
> >   goto out_bad;
> >
> > - mutex_unlock(_mutex);
> >   return 1;
> >  out_bad:
> > - mutex_unlock(_mutex);
> > -out_bad_unlocked:
> >   return 0;
> >  }
> >
> > @@ -650,6 +645,8 @@ static struct kernfs_node *__kernfs_new_node(struct 
> > kernfs_root *root,
> >   kn->mode = mode;
> >   kn->flags = flags;
> >
> > + rwlock_init(>iattr_rwlock);
>
> Ah, now you initialize this, it should go into patch 1, right? :)
>
Yes, it's my fault. It should be in patch 1. Sorry.


Re: [PATCH 2/2] kernfs: remove mutex in kernfs_dop_revalidate

2020-12-02 Thread Tejun Heo
Hello,

On Wed, Dec 02, 2020 at 10:58:37PM +0800, Fox Chen wrote:
> There is a big mutex in kernfs_dop_revalidate which slows down the
> concurrent performance of kernfs.
> 
> Since kernfs_dop_revalidate only does some checks, the lock is
> largely unnecessary. Also, according to kernel filesystem locking
> document:
> https://www.kernel.org/doc/html/latest/filesystems/locking.html
> locking is not in the protocal for d_revalidate operation.

That's just describing the rules seen from vfs side. It doesn't say anything
about locking rules internal to each file system implementation.

> This patch remove this mutex from
> kernfs_dop_revalidate, so kernfs_dop_revalidate
> can run concurrently.
> 
> Signed-off-by: Fox Chen 
> ---
>  fs/kernfs/dir.c | 9 +++--
>  1 file changed, 3 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
> index 9aec80b9d7c6..c2267c93f546 100644
> --- a/fs/kernfs/dir.c
> +++ b/fs/kernfs/dir.c
> @@ -26,7 +26,6 @@ static DEFINE_SPINLOCK(kernfs_idr_lock);/* 
> root->ino_idr */
>  
>  static bool kernfs_active(struct kernfs_node *kn)
>  {
> - lockdep_assert_held(_mutex);
>   return atomic_read(>active) >= 0;
>  }
>  
> @@ -557,10 +556,9 @@ static int kernfs_dop_revalidate(struct dentry *dentry, 
> unsigned int flags)
>  
>   /* Always perform fresh lookup for negatives */
>   if (d_really_is_negative(dentry))
> - goto out_bad_unlocked;
> + goto out_bad;
>  
>   kn = kernfs_dentry_node(dentry);
> - mutex_lock(_mutex);
>  
>   /* The kernfs node has been deactivated */
>   if (!kernfs_active(kn))
> @@ -579,11 +577,8 @@ static int kernfs_dop_revalidate(struct dentry *dentry, 
> unsigned int flags)
>   kernfs_info(dentry->d_sb)->ns != kn->ns)
>   goto out_bad;
>  
> - mutex_unlock(_mutex);
>   return 1;
>  out_bad:
> - mutex_unlock(_mutex);
> -out_bad_unlocked:
>   return 0;
>  }

I don't see how this can be safe. Nothing even protects the dentry from
turning negative in the middle and it may end up trying to deref NULL. I'm
sure we can make this not need kernfs_mutex but that'd have to be a lot more
careful.

Thanks.

-- 
tejun


Re: [PATCH 2/2] kernfs: remove mutex in kernfs_dop_revalidate

2020-12-02 Thread Greg KH
On Wed, Dec 02, 2020 at 10:58:37PM +0800, Fox Chen wrote:
> There is a big mutex in kernfs_dop_revalidate which slows down the
> concurrent performance of kernfs.
> 
> Since kernfs_dop_revalidate only does some checks, the lock is
> largely unnecessary. Also, according to kernel filesystem locking
> document:
> https://www.kernel.org/doc/html/latest/filesystems/locking.html
> locking is not in the protocal for d_revalidate operation.
> 
> This patch remove this mutex from
> kernfs_dop_revalidate, so kernfs_dop_revalidate
> can run concurrently.
> 
> Signed-off-by: Fox Chen 
> ---
>  fs/kernfs/dir.c | 9 +++--
>  1 file changed, 3 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
> index 9aec80b9d7c6..c2267c93f546 100644
> --- a/fs/kernfs/dir.c
> +++ b/fs/kernfs/dir.c
> @@ -26,7 +26,6 @@ static DEFINE_SPINLOCK(kernfs_idr_lock);/* 
> root->ino_idr */
>  
>  static bool kernfs_active(struct kernfs_node *kn)
>  {
> - lockdep_assert_held(_mutex);
>   return atomic_read(>active) >= 0;
>  }
>  
> @@ -557,10 +556,9 @@ static int kernfs_dop_revalidate(struct dentry *dentry, 
> unsigned int flags)
>  
>   /* Always perform fresh lookup for negatives */
>   if (d_really_is_negative(dentry))
> - goto out_bad_unlocked;
> + goto out_bad;
>  
>   kn = kernfs_dentry_node(dentry);
> - mutex_lock(_mutex);
>  
>   /* The kernfs node has been deactivated */
>   if (!kernfs_active(kn))
> @@ -579,11 +577,8 @@ static int kernfs_dop_revalidate(struct dentry *dentry, 
> unsigned int flags)
>   kernfs_info(dentry->d_sb)->ns != kn->ns)
>   goto out_bad;
>  
> - mutex_unlock(_mutex);
>   return 1;
>  out_bad:
> - mutex_unlock(_mutex);
> -out_bad_unlocked:
>   return 0;
>  }
>  
> @@ -650,6 +645,8 @@ static struct kernfs_node *__kernfs_new_node(struct 
> kernfs_root *root,
>   kn->mode = mode;
>   kn->flags = flags;
>  
> + rwlock_init(>iattr_rwlock);

Ah, now you initialize this, it should go into patch 1, right? :)

greg k-h


[PATCH 2/2] kernfs: remove mutex in kernfs_dop_revalidate

2020-12-02 Thread Fox Chen
There is a big mutex in kernfs_dop_revalidate which slows down the
concurrent performance of kernfs.

Since kernfs_dop_revalidate only does some checks, the lock is
largely unnecessary. Also, according to kernel filesystem locking
document:
https://www.kernel.org/doc/html/latest/filesystems/locking.html
locking is not in the protocal for d_revalidate operation.

This patch remove this mutex from
kernfs_dop_revalidate, so kernfs_dop_revalidate
can run concurrently.

Signed-off-by: Fox Chen 
---
 fs/kernfs/dir.c | 9 +++--
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 9aec80b9d7c6..c2267c93f546 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -26,7 +26,6 @@ static DEFINE_SPINLOCK(kernfs_idr_lock);  /* 
root->ino_idr */
 
 static bool kernfs_active(struct kernfs_node *kn)
 {
-   lockdep_assert_held(_mutex);
return atomic_read(>active) >= 0;
 }
 
@@ -557,10 +556,9 @@ static int kernfs_dop_revalidate(struct dentry *dentry, 
unsigned int flags)
 
/* Always perform fresh lookup for negatives */
if (d_really_is_negative(dentry))
-   goto out_bad_unlocked;
+   goto out_bad;
 
kn = kernfs_dentry_node(dentry);
-   mutex_lock(_mutex);
 
/* The kernfs node has been deactivated */
if (!kernfs_active(kn))
@@ -579,11 +577,8 @@ static int kernfs_dop_revalidate(struct dentry *dentry, 
unsigned int flags)
kernfs_info(dentry->d_sb)->ns != kn->ns)
goto out_bad;
 
-   mutex_unlock(_mutex);
return 1;
 out_bad:
-   mutex_unlock(_mutex);
-out_bad_unlocked:
return 0;
 }
 
@@ -650,6 +645,8 @@ static struct kernfs_node *__kernfs_new_node(struct 
kernfs_root *root,
kn->mode = mode;
kn->flags = flags;
 
+   rwlock_init(>iattr_rwlock);
+
if (!uid_eq(uid, GLOBAL_ROOT_UID) || !gid_eq(gid, GLOBAL_ROOT_GID)) {
struct iattr iattr = {
.ia_valid = ATTR_UID | ATTR_GID,
-- 
2.29.2