Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-26 Thread Eric W. Biederman
"J. Bruce Fields"  writes:

> On Tue, Feb 25, 2014 at 02:03:36PM -0800, Eric W. Biederman wrote:
>> "J. Bruce Fields"  writes:
>> 
>> > On Mon, Feb 24, 2014 at 04:01:29PM -0800, Eric W. Biederman wrote:
>> >> Miklos Szeredi  writes:
>> >> 
>> >> >
>> >> > You can optimize this by including the negative check within the above 
>> >> > d_locked
>> >> > region and calling __d_drop() instead.
>> >> 
>> >> For this patch just moving the code and not changing it is the corret
>> >> thing to do because it helps with review and understanding the code.
>> >> 
>> >> There are two ways I could see going with optimizing the preamble.
>> >> Simply dropping the d_lock from around the d_unhashed test as a pointer
>> >> dereference should be atomic, and the test is racy against
>> >> d_materialise_unique.
>> >
>> > Could you explain?  What's the race, and what are the consequences?
>
> Actually I was just confused as to whether the above was "is racy" was
> claiming the existance of some bug.
>
> I believe I should have read the above as more like "the test is already
> racy against d_materialise_unique, but it's a harmless race, and
> dropping the d_lock wouldn't make it any worse".
>
>> >> (We don't always hold the parent directories inode mutex when 
>> >> d_invalidate is called).
>> 
>> d_unhashed is not a permanent condition because of d_materialise_unique,
>> and d_splice_alias.
>> 
>> d_invalidate can be called on an unhashed dentry in one of two ways
>> (either d_revalidate dropped the dentry or another routine that drops
>> the dentry beat the current invocation of d_invalidate to the job).
>> 
>> 
>> There are 3 places d_revalidate is called.
>> 
>> Once on the rcu path with with the appropriate flag set.
>> 
>> Once without out the parent i_mutex held, just off of the rcu path,
>> on that path d_invalidate is when d_revalidate fails.
>> 
>> Once during lookup with the parent directory i_mutex held.
>> 
>> 
>> Because the parent direcories i_mutex is not always held accross
>> d_revalidate and the following d_invalidate it happens that d_invalidate
>> is not always an atomic operation.
>> 
>> 
>> At worst the race results in a dentry that is dropped when it could be
>> hashed,
>
> Because somebody not holding the i_mutex calls d_invalidate based on old
> information and unhashes something that
> d_materialise_unique/d_splice_alias just hashed?

More likely today somebody not holding i_mutex and not in rcu context
calls d_revalidate.  d_revalidate drops the dentry and before we
d_invalidate d_materialise_unique/d_splice_alias rehashes it.

After my changes it looks like it takes 3 processes two instances
of d_invalidate and a instance of d_materialise_unique/d_spliace_alias
to trigger this case.

In either case the window is very small and the outcome is effectively
harmless.  So I don't see this as a problem.

>> that we will resurrect next time someone attempts to look it
>> up and d_materialise_unique/d_splice_alias is called.
>
> OK.
>
>> None of that really matters for optimizing d_invalidate, but it is part
>> of the background in which d_invalidate lives. All that is significant
>> in d_invalidate is knowing that d_materialise_unique, and possibly
>> d_splice_alias may run concurrently with d_invalidate.  It is unlikely
>> and essentially harmless.
>> 
>> 
>> After my patchset (because I removed all of the d_drop's from
>> .d_revalidate) the only race that should remain is between two parallel
>> calls of d_invalidate.  Which probably means we can remove the test for
>> d_unhashed altogether.
>> 
>> Right now I just want to make this first big step and make certain the
>> code is solid.  After that optimization is easy.
>
> Thanks for the explanation!

Welcome.

Eric

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-26 Thread J. Bruce Fields
On Tue, Feb 25, 2014 at 02:03:36PM -0800, Eric W. Biederman wrote:
> "J. Bruce Fields"  writes:
> 
> > On Mon, Feb 24, 2014 at 04:01:29PM -0800, Eric W. Biederman wrote:
> >> Miklos Szeredi  writes:
> >> 
> >> >
> >> > You can optimize this by including the negative check within the above 
> >> > d_locked
> >> > region and calling __d_drop() instead.
> >> 
> >> For this patch just moving the code and not changing it is the corret
> >> thing to do because it helps with review and understanding the code.
> >> 
> >> There are two ways I could see going with optimizing the preamble.
> >> Simply dropping the d_lock from around the d_unhashed test as a pointer
> >> dereference should be atomic, and the test is racy against
> >> d_materialise_unique.
> >
> > Could you explain?  What's the race, and what are the consequences?

Actually I was just confused as to whether the above was "is racy" was
claiming the existance of some bug.

I believe I should have read the above as more like "the test is already
racy against d_materialise_unique, but it's a harmless race, and
dropping the d_lock wouldn't make it any worse".

> >> (We don't always hold the parent directories inode mutex when d_invalidate 
> >> is called).
> 
> d_unhashed is not a permanent condition because of d_materialise_unique,
> and d_splice_alias.
> 
> d_invalidate can be called on an unhashed dentry in one of two ways
> (either d_revalidate dropped the dentry or another routine that drops
> the dentry beat the current invocation of d_invalidate to the job).
> 
> 
> There are 3 places d_revalidate is called.
> 
> Once on the rcu path with with the appropriate flag set.
> 
> Once without out the parent i_mutex held, just off of the rcu path,
> on that path d_invalidate is when d_revalidate fails.
> 
> Once during lookup with the parent directory i_mutex held.
> 
> 
> Because the parent direcories i_mutex is not always held accross
> d_revalidate and the following d_invalidate it happens that d_invalidate
> is not always an atomic operation.
> 
> 
> At worst the race results in a dentry that is dropped when it could be
> hashed,

Because somebody not holding the i_mutex calls d_invalidate based on old
information and unhashes something that
d_materialise_unique/d_splice_alias just hashed?

> that we will resurrect next time someone attempts to look it
> up and d_materialise_unique/d_splice_alias is called.

OK.

> None of that really matters for optimizing d_invalidate, but it is part
> of the background in which d_invalidate lives. All that is significant
> in d_invalidate is knowing that d_materialise_unique, and possibly
> d_splice_alias may run concurrently with d_invalidate.  It is unlikely
> and essentially harmless.
> 
> 
> After my patchset (because I removed all of the d_drop's from
> .d_revalidate) the only race that should remain is between two parallel
> calls of d_invalidate.  Which probably means we can remove the test for
> d_unhashed altogether.
> 
> Right now I just want to make this first big step and make certain the
> code is solid.  After that optimization is easy.

Thanks for the explanation!

--b.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-26 Thread J. Bruce Fields
On Tue, Feb 25, 2014 at 02:03:36PM -0800, Eric W. Biederman wrote:
 J. Bruce Fields bfie...@fieldses.org writes:
 
  On Mon, Feb 24, 2014 at 04:01:29PM -0800, Eric W. Biederman wrote:
  Miklos Szeredi mik...@szeredi.hu writes:
  
  
   You can optimize this by including the negative check within the above 
   d_locked
   region and calling __d_drop() instead.
  
  For this patch just moving the code and not changing it is the corret
  thing to do because it helps with review and understanding the code.
  
  There are two ways I could see going with optimizing the preamble.
  Simply dropping the d_lock from around the d_unhashed test as a pointer
  dereference should be atomic, and the test is racy against
  d_materialise_unique.
 
  Could you explain?  What's the race, and what are the consequences?

Actually I was just confused as to whether the above was is racy was
claiming the existance of some bug.

I believe I should have read the above as more like the test is already
racy against d_materialise_unique, but it's a harmless race, and
dropping the d_lock wouldn't make it any worse.

  (We don't always hold the parent directories inode mutex when d_invalidate 
  is called).
 
 d_unhashed is not a permanent condition because of d_materialise_unique,
 and d_splice_alias.
 
 d_invalidate can be called on an unhashed dentry in one of two ways
 (either d_revalidate dropped the dentry or another routine that drops
 the dentry beat the current invocation of d_invalidate to the job).
 
 
 There are 3 places d_revalidate is called.
 
 Once on the rcu path with with the appropriate flag set.
 
 Once without out the parent i_mutex held, just off of the rcu path,
 on that path d_invalidate is when d_revalidate fails.
 
 Once during lookup with the parent directory i_mutex held.
 
 
 Because the parent direcories i_mutex is not always held accross
 d_revalidate and the following d_invalidate it happens that d_invalidate
 is not always an atomic operation.
 
 
 At worst the race results in a dentry that is dropped when it could be
 hashed,

Because somebody not holding the i_mutex calls d_invalidate based on old
information and unhashes something that
d_materialise_unique/d_splice_alias just hashed?

 that we will resurrect next time someone attempts to look it
 up and d_materialise_unique/d_splice_alias is called.

OK.

 None of that really matters for optimizing d_invalidate, but it is part
 of the background in which d_invalidate lives. All that is significant
 in d_invalidate is knowing that d_materialise_unique, and possibly
 d_splice_alias may run concurrently with d_invalidate.  It is unlikely
 and essentially harmless.
 
 
 After my patchset (because I removed all of the d_drop's from
 .d_revalidate) the only race that should remain is between two parallel
 calls of d_invalidate.  Which probably means we can remove the test for
 d_unhashed altogether.
 
 Right now I just want to make this first big step and make certain the
 code is solid.  After that optimization is easy.

Thanks for the explanation!

--b.
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-26 Thread Eric W. Biederman
J. Bruce Fields bfie...@fieldses.org writes:

 On Tue, Feb 25, 2014 at 02:03:36PM -0800, Eric W. Biederman wrote:
 J. Bruce Fields bfie...@fieldses.org writes:
 
  On Mon, Feb 24, 2014 at 04:01:29PM -0800, Eric W. Biederman wrote:
  Miklos Szeredi mik...@szeredi.hu writes:
  
  
   You can optimize this by including the negative check within the above 
   d_locked
   region and calling __d_drop() instead.
  
  For this patch just moving the code and not changing it is the corret
  thing to do because it helps with review and understanding the code.
  
  There are two ways I could see going with optimizing the preamble.
  Simply dropping the d_lock from around the d_unhashed test as a pointer
  dereference should be atomic, and the test is racy against
  d_materialise_unique.
 
  Could you explain?  What's the race, and what are the consequences?

 Actually I was just confused as to whether the above was is racy was
 claiming the existance of some bug.

 I believe I should have read the above as more like the test is already
 racy against d_materialise_unique, but it's a harmless race, and
 dropping the d_lock wouldn't make it any worse.

  (We don't always hold the parent directories inode mutex when 
  d_invalidate is called).
 
 d_unhashed is not a permanent condition because of d_materialise_unique,
 and d_splice_alias.
 
 d_invalidate can be called on an unhashed dentry in one of two ways
 (either d_revalidate dropped the dentry or another routine that drops
 the dentry beat the current invocation of d_invalidate to the job).
 
 
 There are 3 places d_revalidate is called.
 
 Once on the rcu path with with the appropriate flag set.
 
 Once without out the parent i_mutex held, just off of the rcu path,
 on that path d_invalidate is when d_revalidate fails.
 
 Once during lookup with the parent directory i_mutex held.
 
 
 Because the parent direcories i_mutex is not always held accross
 d_revalidate and the following d_invalidate it happens that d_invalidate
 is not always an atomic operation.
 
 
 At worst the race results in a dentry that is dropped when it could be
 hashed,

 Because somebody not holding the i_mutex calls d_invalidate based on old
 information and unhashes something that
 d_materialise_unique/d_splice_alias just hashed?

More likely today somebody not holding i_mutex and not in rcu context
calls d_revalidate.  d_revalidate drops the dentry and before we
d_invalidate d_materialise_unique/d_splice_alias rehashes it.

After my changes it looks like it takes 3 processes two instances
of d_invalidate and a instance of d_materialise_unique/d_spliace_alias
to trigger this case.

In either case the window is very small and the outcome is effectively
harmless.  So I don't see this as a problem.

 that we will resurrect next time someone attempts to look it
 up and d_materialise_unique/d_splice_alias is called.

 OK.

 None of that really matters for optimizing d_invalidate, but it is part
 of the background in which d_invalidate lives. All that is significant
 in d_invalidate is knowing that d_materialise_unique, and possibly
 d_splice_alias may run concurrently with d_invalidate.  It is unlikely
 and essentially harmless.
 
 
 After my patchset (because I removed all of the d_drop's from
 .d_revalidate) the only race that should remain is between two parallel
 calls of d_invalidate.  Which probably means we can remove the test for
 d_unhashed altogether.
 
 Right now I just want to make this first big step and make certain the
 code is solid.  After that optimization is easy.

 Thanks for the explanation!

Welcome.

Eric

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-25 Thread Eric W. Biederman
"J. Bruce Fields"  writes:

> On Mon, Feb 24, 2014 at 04:01:29PM -0800, Eric W. Biederman wrote:
>> Miklos Szeredi  writes:
>> 
>> >
>> > You can optimize this by including the negative check within the above 
>> > d_locked
>> > region and calling __d_drop() instead.
>> 
>> For this patch just moving the code and not changing it is the corret
>> thing to do because it helps with review and understanding the code.
>> 
>> There are two ways I could see going with optimizing the preamble.
>> Simply dropping the d_lock from around the d_unhashed test as a pointer
>> dereference should be atomic, and the test is racy against
>> d_materialise_unique.
>
> Could you explain?  What's the race, and what are the consequences?

>> (We don't always hold the parent directories inode mutex when d_invalidate 
>> is called).

d_unhashed is not a permanent condition because of d_materialise_unique,
and d_splice_alias.

d_invalidate can be called on an unhashed dentry in one of two ways
(either d_revalidate dropped the dentry or another routine that drops
the dentry beat the current invocation of d_invalidate to the job).


There are 3 places d_revalidate is called.

Once on the rcu path with with the appropriate flag set.

Once without out the parent i_mutex held, just off of the rcu path,
on that path d_invalidate is when d_revalidate fails.

Once during lookup with the parent directory i_mutex held.


Because the parent direcories i_mutex is not always held accross
d_revalidate and the following d_invalidate it happens that d_invalidate
is not always an atomic operation.


At worst the race results in a dentry that is dropped when it could be
hashed, that we will resurrect next time someone attempts to look it
up and d_materialise_unique/d_splice_alias is called.


None of that really matters for optimizing d_invalidate, but it is part
of the background in which d_invalidate lives. All that is significant
in d_invalidate is knowing that d_materialise_unique, and possibly
d_splice_alias may run concurrently with d_invalidate.  It is unlikely
and essentially harmless.


After my patchset (because I removed all of the d_drop's from
.d_revalidate) the only race that should remain is between two parallel
calls of d_invalidate.  Which probably means we can remove the test for
d_unhashed altogether.

Right now I just want to make this first big step and make certain the
code is solid.  After that optimization is easy.

Eric
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-25 Thread J. Bruce Fields
On Mon, Feb 24, 2014 at 04:01:29PM -0800, Eric W. Biederman wrote:
> Miklos Szeredi  writes:
> 
> > On Sat, Feb 15, 2014 at 01:39:22PM -0800, Eric W. Biederman wrote:
> >> 
> >> Now that d_invalidate is the only caller of check_submounts_and_drop,
> >> expand check_submounts_and_drop inline in d_invalidate.
> >> 
> >> Signed-off-by: "Eric W. Biederman" 
> >> ---
> >>  fs/dcache.c|   55 
> >> +++
> >>  include/linux/dcache.h |1 -
> >>  2 files changed, 22 insertions(+), 34 deletions(-)
> >> 
> >> diff --git a/fs/dcache.c b/fs/dcache.c
> >> index 27585b1dd6f1..5b41205cbf33 100644
> >> --- a/fs/dcache.c
> >> +++ b/fs/dcache.c
> 
> >> -int check_submounts_and_drop(struct dentry *dentry)
> >> +int d_invalidate(struct dentry *dentry)
> >>  {
> >>int ret = 0;
> >>  
> >> +  /*
> >> +   * If it's already been dropped, return OK.
> >> +   */
> >> +  spin_lock(>d_lock);
> >> +  if (d_unhashed(dentry)) {
> >> +  spin_unlock(>d_lock);
> >> +  return 0;
> >> +  }
> >> +  spin_unlock(>d_lock);
> >> +
> >>/* Negative dentries can be dropped without further checks */
> >>if (!dentry->d_inode) {
> >>d_drop(dentry);
> >
> >
> > You can optimize this by including the negative check within the above 
> > d_locked
> > region and calling __d_drop() instead.
> 
> For this patch just moving the code and not changing it is the corret
> thing to do because it helps with review and understanding the code.
> 
> There are two ways I could see going with optimizing the preamble.
> Simply dropping the d_lock from around the d_unhashed test as a pointer
> dereference should be atomic, and the test is racy against
> d_materialise_unique.

Could you explain?  What's the race, and what are the consequences?

--b.

> (We don't always hold the parent
> directories inode mutex when d_invalidate is called).  So the d_lock
> buys us very little.  Alternatively we could move the work into the
> d_walk callbacks.
> 
> That kind of optimization deserves it's own patch that can be reviewed
> independently.
> 
> Eric
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-25 Thread J. Bruce Fields
On Mon, Feb 24, 2014 at 04:01:29PM -0800, Eric W. Biederman wrote:
 Miklos Szeredi mik...@szeredi.hu writes:
 
  On Sat, Feb 15, 2014 at 01:39:22PM -0800, Eric W. Biederman wrote:
  
  Now that d_invalidate is the only caller of check_submounts_and_drop,
  expand check_submounts_and_drop inline in d_invalidate.
  
  Signed-off-by: Eric W. Biederman ebied...@xmission.com
  ---
   fs/dcache.c|   55 
  +++
   include/linux/dcache.h |1 -
   2 files changed, 22 insertions(+), 34 deletions(-)
  
  diff --git a/fs/dcache.c b/fs/dcache.c
  index 27585b1dd6f1..5b41205cbf33 100644
  --- a/fs/dcache.c
  +++ b/fs/dcache.c
 
  -int check_submounts_and_drop(struct dentry *dentry)
  +int d_invalidate(struct dentry *dentry)
   {
 int ret = 0;
   
  +  /*
  +   * If it's already been dropped, return OK.
  +   */
  +  spin_lock(dentry-d_lock);
  +  if (d_unhashed(dentry)) {
  +  spin_unlock(dentry-d_lock);
  +  return 0;
  +  }
  +  spin_unlock(dentry-d_lock);
  +
 /* Negative dentries can be dropped without further checks */
 if (!dentry-d_inode) {
 d_drop(dentry);
 
 
  You can optimize this by including the negative check within the above 
  d_locked
  region and calling __d_drop() instead.
 
 For this patch just moving the code and not changing it is the corret
 thing to do because it helps with review and understanding the code.
 
 There are two ways I could see going with optimizing the preamble.
 Simply dropping the d_lock from around the d_unhashed test as a pointer
 dereference should be atomic, and the test is racy against
 d_materialise_unique.

Could you explain?  What's the race, and what are the consequences?

--b.

 (We don't always hold the parent
 directories inode mutex when d_invalidate is called).  So the d_lock
 buys us very little.  Alternatively we could move the work into the
 d_walk callbacks.
 
 That kind of optimization deserves it's own patch that can be reviewed
 independently.
 
 Eric
 --
 To unsubscribe from this list: send the line unsubscribe linux-fsdevel in
 the body of a message to majord...@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-25 Thread Eric W. Biederman
J. Bruce Fields bfie...@fieldses.org writes:

 On Mon, Feb 24, 2014 at 04:01:29PM -0800, Eric W. Biederman wrote:
 Miklos Szeredi mik...@szeredi.hu writes:
 
 
  You can optimize this by including the negative check within the above 
  d_locked
  region and calling __d_drop() instead.
 
 For this patch just moving the code and not changing it is the corret
 thing to do because it helps with review and understanding the code.
 
 There are two ways I could see going with optimizing the preamble.
 Simply dropping the d_lock from around the d_unhashed test as a pointer
 dereference should be atomic, and the test is racy against
 d_materialise_unique.

 Could you explain?  What's the race, and what are the consequences?

 (We don't always hold the parent directories inode mutex when d_invalidate 
 is called).

d_unhashed is not a permanent condition because of d_materialise_unique,
and d_splice_alias.

d_invalidate can be called on an unhashed dentry in one of two ways
(either d_revalidate dropped the dentry or another routine that drops
the dentry beat the current invocation of d_invalidate to the job).


There are 3 places d_revalidate is called.

Once on the rcu path with with the appropriate flag set.

Once without out the parent i_mutex held, just off of the rcu path,
on that path d_invalidate is when d_revalidate fails.

Once during lookup with the parent directory i_mutex held.


Because the parent direcories i_mutex is not always held accross
d_revalidate and the following d_invalidate it happens that d_invalidate
is not always an atomic operation.


At worst the race results in a dentry that is dropped when it could be
hashed, that we will resurrect next time someone attempts to look it
up and d_materialise_unique/d_splice_alias is called.


None of that really matters for optimizing d_invalidate, but it is part
of the background in which d_invalidate lives. All that is significant
in d_invalidate is knowing that d_materialise_unique, and possibly
d_splice_alias may run concurrently with d_invalidate.  It is unlikely
and essentially harmless.


After my patchset (because I removed all of the d_drop's from
.d_revalidate) the only race that should remain is between two parallel
calls of d_invalidate.  Which probably means we can remove the test for
d_unhashed altogether.

Right now I just want to make this first big step and make certain the
code is solid.  After that optimization is easy.

Eric
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-24 Thread Eric W. Biederman
Miklos Szeredi  writes:

> On Sat, Feb 15, 2014 at 01:39:22PM -0800, Eric W. Biederman wrote:
>> 
>> Now that d_invalidate is the only caller of check_submounts_and_drop,
>> expand check_submounts_and_drop inline in d_invalidate.
>> 
>> Signed-off-by: "Eric W. Biederman" 
>> ---
>>  fs/dcache.c|   55 
>> +++
>>  include/linux/dcache.h |1 -
>>  2 files changed, 22 insertions(+), 34 deletions(-)
>> 
>> diff --git a/fs/dcache.c b/fs/dcache.c
>> index 27585b1dd6f1..5b41205cbf33 100644
>> --- a/fs/dcache.c
>> +++ b/fs/dcache.c

>> -int check_submounts_and_drop(struct dentry *dentry)
>> +int d_invalidate(struct dentry *dentry)
>>  {
>>  int ret = 0;
>>  
>> +/*
>> + * If it's already been dropped, return OK.
>> + */
>> +spin_lock(>d_lock);
>> +if (d_unhashed(dentry)) {
>> +spin_unlock(>d_lock);
>> +return 0;
>> +}
>> +spin_unlock(>d_lock);
>> +
>>  /* Negative dentries can be dropped without further checks */
>>  if (!dentry->d_inode) {
>>  d_drop(dentry);
>
>
> You can optimize this by including the negative check within the above 
> d_locked
> region and calling __d_drop() instead.

For this patch just moving the code and not changing it is the corret
thing to do because it helps with review and understanding the code.

There are two ways I could see going with optimizing the preamble.
Simply dropping the d_lock from around the d_unhashed test as a pointer
dereference should be atomic, and the test is racy against
d_materialise_unique. (We don't always hold the parent
directories inode mutex when d_invalidate is called).  So the d_lock
buys us very little.  Alternatively we could move the work into the
d_walk callbacks.

That kind of optimization deserves it's own patch that can be reviewed
independently.

Eric
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-24 Thread Eric W. Biederman
Miklos Szeredi mik...@szeredi.hu writes:

 On Sat, Feb 15, 2014 at 01:39:22PM -0800, Eric W. Biederman wrote:
 
 Now that d_invalidate is the only caller of check_submounts_and_drop,
 expand check_submounts_and_drop inline in d_invalidate.
 
 Signed-off-by: Eric W. Biederman ebied...@xmission.com
 ---
  fs/dcache.c|   55 
 +++
  include/linux/dcache.h |1 -
  2 files changed, 22 insertions(+), 34 deletions(-)
 
 diff --git a/fs/dcache.c b/fs/dcache.c
 index 27585b1dd6f1..5b41205cbf33 100644
 --- a/fs/dcache.c
 +++ b/fs/dcache.c

 -int check_submounts_and_drop(struct dentry *dentry)
 +int d_invalidate(struct dentry *dentry)
  {
  int ret = 0;
  
 +/*
 + * If it's already been dropped, return OK.
 + */
 +spin_lock(dentry-d_lock);
 +if (d_unhashed(dentry)) {
 +spin_unlock(dentry-d_lock);
 +return 0;
 +}
 +spin_unlock(dentry-d_lock);
 +
  /* Negative dentries can be dropped without further checks */
  if (!dentry-d_inode) {
  d_drop(dentry);


 You can optimize this by including the negative check within the above 
 d_locked
 region and calling __d_drop() instead.

For this patch just moving the code and not changing it is the corret
thing to do because it helps with review and understanding the code.

There are two ways I could see going with optimizing the preamble.
Simply dropping the d_lock from around the d_unhashed test as a pointer
dereference should be atomic, and the test is racy against
d_materialise_unique. (We don't always hold the parent
directories inode mutex when d_invalidate is called).  So the d_lock
buys us very little.  Alternatively we could move the work into the
d_walk callbacks.

That kind of optimization deserves it's own patch that can be reviewed
independently.

Eric
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-18 Thread Miklos Szeredi
On Sat, Feb 15, 2014 at 01:39:22PM -0800, Eric W. Biederman wrote:
> 
> Now that d_invalidate is the only caller of check_submounts_and_drop,
> expand check_submounts_and_drop inline in d_invalidate.
> 
> Signed-off-by: "Eric W. Biederman" 
> ---
>  fs/dcache.c|   55 +++
>  include/linux/dcache.h |1 -
>  2 files changed, 22 insertions(+), 34 deletions(-)
> 
> diff --git a/fs/dcache.c b/fs/dcache.c
> index 27585b1dd6f1..5b41205cbf33 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -608,32 +608,6 @@ kill_it:
>  }
>  EXPORT_SYMBOL(dput);
>  
> -/**
> - * d_invalidate - invalidate a dentry
> - * @dentry: dentry to invalidate
> - *
> - * Try to invalidate the dentry if it turns out to be
> - * possible. If there are reasons not to delete it
> - * return -EBUSY. On success return 0.
> - *
> - * no dcache lock.
> - */
> - 
> -int d_invalidate(struct dentry * dentry)
> -{
> - /*
> -  * If it's already been dropped, return OK.
> -  */
> - spin_lock(>d_lock);
> - if (d_unhashed(dentry)) {
> - spin_unlock(>d_lock);
> - return 0;
> - }
> - spin_unlock(>d_lock);
> -
> - return check_submounts_and_drop(dentry);
> -}
> -EXPORT_SYMBOL(d_invalidate);
>  
>  /* This must be called with d_lock held */
>  static inline void __dget_dlock(struct dentry *dentry)
> @@ -1175,7 +1149,7 @@ EXPORT_SYMBOL(have_submounts);
>   * reachable (e.g. NFS can unhash a directory dentry and then the complete
>   * subtree can become unreachable).
>   *
> - * Only one of check_submounts_and_drop() and d_set_mounted() must succeed.  
> For
> + * Only one of d_invalidate() and d_set_mounted() must succeed.  For
>   * this reason take rename_lock and d_lock on dentry and ancestors.
>   */
>  int d_set_mounted(struct dentry *dentry)
> @@ -1184,7 +1158,7 @@ int d_set_mounted(struct dentry *dentry)
>   int ret = -ENOENT;
>   write_seqlock(_lock);
>   for (p = dentry->d_parent; !IS_ROOT(p); p = p->d_parent) {
> - /* Need exclusion wrt. check_submounts_and_drop() */
> + /* Need exclusion wrt. d_invalidate() */
>   spin_lock(>d_lock);
>   if (unlikely(d_unhashed(p))) {
>   spin_unlock(>d_lock);
> @@ -1400,18 +1374,33 @@ static void check_and_drop(void *_data)
>  }
>  
>  /**
> - * check_submounts_and_drop - detach submounts, prune dcache, and drop
> + * d_invalidate - detach submounts, prune dcache, and drop
> + * @dentry: dentry to invalidate (aka detach, prune and drop)
> + *
> + * Try to invalidate the dentry if it turns out to be
> + * possible. If there are reasons not to delete it
> + * return -EBUSY. On success return 0.
> + *
> + * no dcache lock.
>   *
>   * The final d_drop is done as an atomic operation relative to
>   * rename_lock ensuring there are no races with d_set_mounted.  This
>   * ensures there are no unhashed dentries on the path to a mountpoint.
> - *
> - * @dentry: dentry to detach, prune and drop
>   */
> -int check_submounts_and_drop(struct dentry *dentry)
> +int d_invalidate(struct dentry *dentry)
>  {
>   int ret = 0;
>  
> + /*
> +  * If it's already been dropped, return OK.
> +  */
> + spin_lock(>d_lock);
> + if (d_unhashed(dentry)) {
> + spin_unlock(>d_lock);
> + return 0;
> + }
> + spin_unlock(>d_lock);
> +
>   /* Negative dentries can be dropped without further checks */
>   if (!dentry->d_inode) {
>   d_drop(dentry);


You can optimize this by including the negative check within the above d_locked
region and calling __d_drop() instead.

> @@ -1445,7 +1434,7 @@ int check_submounts_and_drop(struct dentry *dentry)
>  out:
>   return ret;
>  }
> -EXPORT_SYMBOL(check_submounts_and_drop);
> +EXPORT_SYMBOL(d_invalidate);
>  
>  /**
>   * __d_alloc -   allocate a dcache entry
> diff --git a/include/linux/dcache.h b/include/linux/dcache.h
> index bf72e9ac6de0..ae77222c3e86 100644
> --- a/include/linux/dcache.h
> +++ b/include/linux/dcache.h
> @@ -265,7 +265,6 @@ extern void d_prune_aliases(struct inode *);
>  
>  /* test whether we have any submounts in a subdir tree */
>  extern int have_submounts(struct dentry *);
> -extern int check_submounts_and_drop(struct dentry *);
>  
>  /*
>   * This adds the entry to the hash queues.
> -- 
> 1.7.5.4
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-18 Thread Miklos Szeredi
On Sat, Feb 15, 2014 at 01:39:22PM -0800, Eric W. Biederman wrote:
 
 Now that d_invalidate is the only caller of check_submounts_and_drop,
 expand check_submounts_and_drop inline in d_invalidate.
 
 Signed-off-by: Eric W. Biederman ebied...@xmission.com
 ---
  fs/dcache.c|   55 +++
  include/linux/dcache.h |1 -
  2 files changed, 22 insertions(+), 34 deletions(-)
 
 diff --git a/fs/dcache.c b/fs/dcache.c
 index 27585b1dd6f1..5b41205cbf33 100644
 --- a/fs/dcache.c
 +++ b/fs/dcache.c
 @@ -608,32 +608,6 @@ kill_it:
  }
  EXPORT_SYMBOL(dput);
  
 -/**
 - * d_invalidate - invalidate a dentry
 - * @dentry: dentry to invalidate
 - *
 - * Try to invalidate the dentry if it turns out to be
 - * possible. If there are reasons not to delete it
 - * return -EBUSY. On success return 0.
 - *
 - * no dcache lock.
 - */
 - 
 -int d_invalidate(struct dentry * dentry)
 -{
 - /*
 -  * If it's already been dropped, return OK.
 -  */
 - spin_lock(dentry-d_lock);
 - if (d_unhashed(dentry)) {
 - spin_unlock(dentry-d_lock);
 - return 0;
 - }
 - spin_unlock(dentry-d_lock);
 -
 - return check_submounts_and_drop(dentry);
 -}
 -EXPORT_SYMBOL(d_invalidate);
  
  /* This must be called with d_lock held */
  static inline void __dget_dlock(struct dentry *dentry)
 @@ -1175,7 +1149,7 @@ EXPORT_SYMBOL(have_submounts);
   * reachable (e.g. NFS can unhash a directory dentry and then the complete
   * subtree can become unreachable).
   *
 - * Only one of check_submounts_and_drop() and d_set_mounted() must succeed.  
 For
 + * Only one of d_invalidate() and d_set_mounted() must succeed.  For
   * this reason take rename_lock and d_lock on dentry and ancestors.
   */
  int d_set_mounted(struct dentry *dentry)
 @@ -1184,7 +1158,7 @@ int d_set_mounted(struct dentry *dentry)
   int ret = -ENOENT;
   write_seqlock(rename_lock);
   for (p = dentry-d_parent; !IS_ROOT(p); p = p-d_parent) {
 - /* Need exclusion wrt. check_submounts_and_drop() */
 + /* Need exclusion wrt. d_invalidate() */
   spin_lock(p-d_lock);
   if (unlikely(d_unhashed(p))) {
   spin_unlock(p-d_lock);
 @@ -1400,18 +1374,33 @@ static void check_and_drop(void *_data)
  }
  
  /**
 - * check_submounts_and_drop - detach submounts, prune dcache, and drop
 + * d_invalidate - detach submounts, prune dcache, and drop
 + * @dentry: dentry to invalidate (aka detach, prune and drop)
 + *
 + * Try to invalidate the dentry if it turns out to be
 + * possible. If there are reasons not to delete it
 + * return -EBUSY. On success return 0.
 + *
 + * no dcache lock.
   *
   * The final d_drop is done as an atomic operation relative to
   * rename_lock ensuring there are no races with d_set_mounted.  This
   * ensures there are no unhashed dentries on the path to a mountpoint.
 - *
 - * @dentry: dentry to detach, prune and drop
   */
 -int check_submounts_and_drop(struct dentry *dentry)
 +int d_invalidate(struct dentry *dentry)
  {
   int ret = 0;
  
 + /*
 +  * If it's already been dropped, return OK.
 +  */
 + spin_lock(dentry-d_lock);
 + if (d_unhashed(dentry)) {
 + spin_unlock(dentry-d_lock);
 + return 0;
 + }
 + spin_unlock(dentry-d_lock);
 +
   /* Negative dentries can be dropped without further checks */
   if (!dentry-d_inode) {
   d_drop(dentry);


You can optimize this by including the negative check within the above d_locked
region and calling __d_drop() instead.

 @@ -1445,7 +1434,7 @@ int check_submounts_and_drop(struct dentry *dentry)
  out:
   return ret;
  }
 -EXPORT_SYMBOL(check_submounts_and_drop);
 +EXPORT_SYMBOL(d_invalidate);
  
  /**
   * __d_alloc -   allocate a dcache entry
 diff --git a/include/linux/dcache.h b/include/linux/dcache.h
 index bf72e9ac6de0..ae77222c3e86 100644
 --- a/include/linux/dcache.h
 +++ b/include/linux/dcache.h
 @@ -265,7 +265,6 @@ extern void d_prune_aliases(struct inode *);
  
  /* test whether we have any submounts in a subdir tree */
  extern int have_submounts(struct dentry *);
 -extern int check_submounts_and_drop(struct dentry *);
  
  /*
   * This adds the entry to the hash queues.
 -- 
 1.7.5.4
 
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-15 Thread Eric W. Biederman

Now that d_invalidate is the only caller of check_submounts_and_drop,
expand check_submounts_and_drop inline in d_invalidate.

Signed-off-by: "Eric W. Biederman" 
---
 fs/dcache.c|   55 +++
 include/linux/dcache.h |1 -
 2 files changed, 22 insertions(+), 34 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index 27585b1dd6f1..5b41205cbf33 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -608,32 +608,6 @@ kill_it:
 }
 EXPORT_SYMBOL(dput);
 
-/**
- * d_invalidate - invalidate a dentry
- * @dentry: dentry to invalidate
- *
- * Try to invalidate the dentry if it turns out to be
- * possible. If there are reasons not to delete it
- * return -EBUSY. On success return 0.
- *
- * no dcache lock.
- */
- 
-int d_invalidate(struct dentry * dentry)
-{
-   /*
-* If it's already been dropped, return OK.
-*/
-   spin_lock(>d_lock);
-   if (d_unhashed(dentry)) {
-   spin_unlock(>d_lock);
-   return 0;
-   }
-   spin_unlock(>d_lock);
-
-   return check_submounts_and_drop(dentry);
-}
-EXPORT_SYMBOL(d_invalidate);
 
 /* This must be called with d_lock held */
 static inline void __dget_dlock(struct dentry *dentry)
@@ -1175,7 +1149,7 @@ EXPORT_SYMBOL(have_submounts);
  * reachable (e.g. NFS can unhash a directory dentry and then the complete
  * subtree can become unreachable).
  *
- * Only one of check_submounts_and_drop() and d_set_mounted() must succeed.  
For
+ * Only one of d_invalidate() and d_set_mounted() must succeed.  For
  * this reason take rename_lock and d_lock on dentry and ancestors.
  */
 int d_set_mounted(struct dentry *dentry)
@@ -1184,7 +1158,7 @@ int d_set_mounted(struct dentry *dentry)
int ret = -ENOENT;
write_seqlock(_lock);
for (p = dentry->d_parent; !IS_ROOT(p); p = p->d_parent) {
-   /* Need exclusion wrt. check_submounts_and_drop() */
+   /* Need exclusion wrt. d_invalidate() */
spin_lock(>d_lock);
if (unlikely(d_unhashed(p))) {
spin_unlock(>d_lock);
@@ -1400,18 +1374,33 @@ static void check_and_drop(void *_data)
 }
 
 /**
- * check_submounts_and_drop - detach submounts, prune dcache, and drop
+ * d_invalidate - detach submounts, prune dcache, and drop
+ * @dentry: dentry to invalidate (aka detach, prune and drop)
+ *
+ * Try to invalidate the dentry if it turns out to be
+ * possible. If there are reasons not to delete it
+ * return -EBUSY. On success return 0.
+ *
+ * no dcache lock.
  *
  * The final d_drop is done as an atomic operation relative to
  * rename_lock ensuring there are no races with d_set_mounted.  This
  * ensures there are no unhashed dentries on the path to a mountpoint.
- *
- * @dentry: dentry to detach, prune and drop
  */
-int check_submounts_and_drop(struct dentry *dentry)
+int d_invalidate(struct dentry *dentry)
 {
int ret = 0;
 
+   /*
+* If it's already been dropped, return OK.
+*/
+   spin_lock(>d_lock);
+   if (d_unhashed(dentry)) {
+   spin_unlock(>d_lock);
+   return 0;
+   }
+   spin_unlock(>d_lock);
+
/* Negative dentries can be dropped without further checks */
if (!dentry->d_inode) {
d_drop(dentry);
@@ -1445,7 +1434,7 @@ int check_submounts_and_drop(struct dentry *dentry)
 out:
return ret;
 }
-EXPORT_SYMBOL(check_submounts_and_drop);
+EXPORT_SYMBOL(d_invalidate);
 
 /**
  * __d_alloc   -   allocate a dcache entry
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index bf72e9ac6de0..ae77222c3e86 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -265,7 +265,6 @@ extern void d_prune_aliases(struct inode *);
 
 /* test whether we have any submounts in a subdir tree */
 extern int have_submounts(struct dentry *);
-extern int check_submounts_and_drop(struct dentry *);
 
 /*
  * This adds the entry to the hash queues.
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 08/11] vfs: Merge check_submounts_and_drop and d_invalidate

2014-02-15 Thread Eric W. Biederman

Now that d_invalidate is the only caller of check_submounts_and_drop,
expand check_submounts_and_drop inline in d_invalidate.

Signed-off-by: Eric W. Biederman ebied...@xmission.com
---
 fs/dcache.c|   55 +++
 include/linux/dcache.h |1 -
 2 files changed, 22 insertions(+), 34 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index 27585b1dd6f1..5b41205cbf33 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -608,32 +608,6 @@ kill_it:
 }
 EXPORT_SYMBOL(dput);
 
-/**
- * d_invalidate - invalidate a dentry
- * @dentry: dentry to invalidate
- *
- * Try to invalidate the dentry if it turns out to be
- * possible. If there are reasons not to delete it
- * return -EBUSY. On success return 0.
- *
- * no dcache lock.
- */
- 
-int d_invalidate(struct dentry * dentry)
-{
-   /*
-* If it's already been dropped, return OK.
-*/
-   spin_lock(dentry-d_lock);
-   if (d_unhashed(dentry)) {
-   spin_unlock(dentry-d_lock);
-   return 0;
-   }
-   spin_unlock(dentry-d_lock);
-
-   return check_submounts_and_drop(dentry);
-}
-EXPORT_SYMBOL(d_invalidate);
 
 /* This must be called with d_lock held */
 static inline void __dget_dlock(struct dentry *dentry)
@@ -1175,7 +1149,7 @@ EXPORT_SYMBOL(have_submounts);
  * reachable (e.g. NFS can unhash a directory dentry and then the complete
  * subtree can become unreachable).
  *
- * Only one of check_submounts_and_drop() and d_set_mounted() must succeed.  
For
+ * Only one of d_invalidate() and d_set_mounted() must succeed.  For
  * this reason take rename_lock and d_lock on dentry and ancestors.
  */
 int d_set_mounted(struct dentry *dentry)
@@ -1184,7 +1158,7 @@ int d_set_mounted(struct dentry *dentry)
int ret = -ENOENT;
write_seqlock(rename_lock);
for (p = dentry-d_parent; !IS_ROOT(p); p = p-d_parent) {
-   /* Need exclusion wrt. check_submounts_and_drop() */
+   /* Need exclusion wrt. d_invalidate() */
spin_lock(p-d_lock);
if (unlikely(d_unhashed(p))) {
spin_unlock(p-d_lock);
@@ -1400,18 +1374,33 @@ static void check_and_drop(void *_data)
 }
 
 /**
- * check_submounts_and_drop - detach submounts, prune dcache, and drop
+ * d_invalidate - detach submounts, prune dcache, and drop
+ * @dentry: dentry to invalidate (aka detach, prune and drop)
+ *
+ * Try to invalidate the dentry if it turns out to be
+ * possible. If there are reasons not to delete it
+ * return -EBUSY. On success return 0.
+ *
+ * no dcache lock.
  *
  * The final d_drop is done as an atomic operation relative to
  * rename_lock ensuring there are no races with d_set_mounted.  This
  * ensures there are no unhashed dentries on the path to a mountpoint.
- *
- * @dentry: dentry to detach, prune and drop
  */
-int check_submounts_and_drop(struct dentry *dentry)
+int d_invalidate(struct dentry *dentry)
 {
int ret = 0;
 
+   /*
+* If it's already been dropped, return OK.
+*/
+   spin_lock(dentry-d_lock);
+   if (d_unhashed(dentry)) {
+   spin_unlock(dentry-d_lock);
+   return 0;
+   }
+   spin_unlock(dentry-d_lock);
+
/* Negative dentries can be dropped without further checks */
if (!dentry-d_inode) {
d_drop(dentry);
@@ -1445,7 +1434,7 @@ int check_submounts_and_drop(struct dentry *dentry)
 out:
return ret;
 }
-EXPORT_SYMBOL(check_submounts_and_drop);
+EXPORT_SYMBOL(d_invalidate);
 
 /**
  * __d_alloc   -   allocate a dcache entry
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index bf72e9ac6de0..ae77222c3e86 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -265,7 +265,6 @@ extern void d_prune_aliases(struct inode *);
 
 /* test whether we have any submounts in a subdir tree */
 extern int have_submounts(struct dentry *);
-extern int check_submounts_and_drop(struct dentry *);
 
 /*
  * This adds the entry to the hash queues.
-- 
1.7.5.4

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/