diff mbox series

[v2,1/2] fs: add asserting functions for sb_start_{write,pagefault,intwrite}

Message ID 40cbbef14229eaa34df0cdc576f02a1bd4ba6809.1644469146.git.naohiro.aota@wdc.com (mailing list archive)
State New, archived
Headers show
Series btrfs: zoned: mark relocation as writing | expand

Commit Message

Naohiro Aota Feb. 10, 2022, 5:59 a.m. UTC
Add an assert function sb_assert_write_started() to check if
sb_start_write() is properly called. It is used in the next commit.

Also, add the assert functions for sb_start_pagefault() and
sb_start_intwrite().

Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
---
 include/linux/fs.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

Comments

Dave Chinner Feb. 14, 2022, 9:35 p.m. UTC | #1
On Thu, Feb 10, 2022 at 02:59:04PM +0900, Naohiro Aota wrote:
> Add an assert function sb_assert_write_started() to check if
> sb_start_write() is properly called. It is used in the next commit.
> 
> Also, add the assert functions for sb_start_pagefault() and
> sb_start_intwrite().
> 
> Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
> ---
>  include/linux/fs.h | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index bbf812ce89a8..5d5dc9a276d9 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1820,6 +1820,11 @@ static inline bool __sb_start_write_trylock(struct super_block *sb, int level)
>  #define __sb_writers_release(sb, lev)	\
>  	percpu_rwsem_release(&(sb)->s_writers.rw_sem[(lev)-1], 1, _THIS_IP_)
>  
> +static inline void __sb_assert_write_started(struct super_block *sb, int level)
> +{
> +	lockdep_assert_held_read(sb->s_writers.rw_sem + level - 1);
> +}
> +

So this isn't an assert, it's a WARN_ON(). Asserts stop execution
(i.e. kill the task) rather than just issue a warning, so let's not
name a function that issues a warning "assert"...

Hence I'd much rather see this implemented as:

static inline bool __sb_write_held(struct super_block *sb, int level)
{
	return lockdep_is_held_type(sb->s_writers.rw_sem + level - 1, 1);
}

i.e. named similar to __sb_start_write/__sb_end_write, with similar
wrappers for pagefault/intwrite, and it just returns a bool status
that lets the caller do what it wants with the status (warn, bug,
etc).

Then in the code that needs to check if the right freeze levels are
held simply need to do:

	WARN_ON(!sb_write_held(sb));

in which case it's self documenting in the code that cares about
this and it's also obvious to anyone debugging such a message where
it came from and what constraint got violated...

Cheers,

Dave.
Damien Le Moal Feb. 14, 2022, 10:49 p.m. UTC | #2
On 2/15/22 06:35, Dave Chinner wrote:
> On Thu, Feb 10, 2022 at 02:59:04PM +0900, Naohiro Aota wrote:
>> Add an assert function sb_assert_write_started() to check if
>> sb_start_write() is properly called. It is used in the next commit.
>>
>> Also, add the assert functions for sb_start_pagefault() and
>> sb_start_intwrite().
>>
>> Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
>> ---
>>  include/linux/fs.h | 20 ++++++++++++++++++++
>>  1 file changed, 20 insertions(+)
>>
>> diff --git a/include/linux/fs.h b/include/linux/fs.h
>> index bbf812ce89a8..5d5dc9a276d9 100644
>> --- a/include/linux/fs.h
>> +++ b/include/linux/fs.h
>> @@ -1820,6 +1820,11 @@ static inline bool __sb_start_write_trylock(struct super_block *sb, int level)
>>  #define __sb_writers_release(sb, lev)	\
>>  	percpu_rwsem_release(&(sb)->s_writers.rw_sem[(lev)-1], 1, _THIS_IP_)
>>  
>> +static inline void __sb_assert_write_started(struct super_block *sb, int level)
>> +{
>> +	lockdep_assert_held_read(sb->s_writers.rw_sem + level - 1);
>> +}
>> +
> 
> So this isn't an assert, it's a WARN_ON(). Asserts stop execution
> (i.e. kill the task) rather than just issue a warning, so let's not
> name a function that issues a warning "assert"...
> 
> Hence I'd much rather see this implemented as:
> 
> static inline bool __sb_write_held(struct super_block *sb, int level)
> {
> 	return lockdep_is_held_type(sb->s_writers.rw_sem + level - 1, 1);
> }

Since this would be true when called in between __sb_start_write() and
__sb_end_write(), what about calling it __sb_write_started() ? That
disconnects from the fact that the implementation uses a sem.

> 
> i.e. named similar to __sb_start_write/__sb_end_write, with similar
> wrappers for pagefault/intwrite, and it just returns a bool status
> that lets the caller do what it wants with the status (warn, bug,
> etc).
> 
> Then in the code that needs to check if the right freeze levels are
> held simply need to do:
> 
> 	WARN_ON(!sb_write_held(sb));
> 
> in which case it's self documenting in the code that cares about
> this and it's also obvious to anyone debugging such a message where
> it came from and what constraint got violated...
> 
> Cheers,
> 
> Dave.
Dave Chinner Feb. 15, 2022, 12:05 a.m. UTC | #3
On Tue, Feb 15, 2022 at 07:49:27AM +0900, Damien Le Moal wrote:
> On 2/15/22 06:35, Dave Chinner wrote:
> > On Thu, Feb 10, 2022 at 02:59:04PM +0900, Naohiro Aota wrote:
> >> Add an assert function sb_assert_write_started() to check if
> >> sb_start_write() is properly called. It is used in the next commit.
> >>
> >> Also, add the assert functions for sb_start_pagefault() and
> >> sb_start_intwrite().
> >>
> >> Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
> >> ---
> >>  include/linux/fs.h | 20 ++++++++++++++++++++
> >>  1 file changed, 20 insertions(+)
> >>
> >> diff --git a/include/linux/fs.h b/include/linux/fs.h
> >> index bbf812ce89a8..5d5dc9a276d9 100644
> >> --- a/include/linux/fs.h
> >> +++ b/include/linux/fs.h
> >> @@ -1820,6 +1820,11 @@ static inline bool __sb_start_write_trylock(struct super_block *sb, int level)
> >>  #define __sb_writers_release(sb, lev)	\
> >>  	percpu_rwsem_release(&(sb)->s_writers.rw_sem[(lev)-1], 1, _THIS_IP_)
> >>  
> >> +static inline void __sb_assert_write_started(struct super_block *sb, int level)
> >> +{
> >> +	lockdep_assert_held_read(sb->s_writers.rw_sem + level - 1);
> >> +}
> >> +
> > 
> > So this isn't an assert, it's a WARN_ON(). Asserts stop execution
> > (i.e. kill the task) rather than just issue a warning, so let's not
> > name a function that issues a warning "assert"...
> > 
> > Hence I'd much rather see this implemented as:
> > 
> > static inline bool __sb_write_held(struct super_block *sb, int level)
> > {
> > 	return lockdep_is_held_type(sb->s_writers.rw_sem + level - 1, 1);
> > }
> 
> Since this would be true when called in between __sb_start_write() and
> __sb_end_write(), what about calling it __sb_write_started() ? That
> disconnects from the fact that the implementation uses a sem.

Makes no difference to me; I initially was going to suggest
*_inprogress() but that seemed a bit verbose. We don't need to
bikeshed this to death - all I want is it to be a check that can be
used for generic purposes rather than being an explicit assert.

Cheers,

Dave.
Damien Le Moal Feb. 15, 2022, 12:07 a.m. UTC | #4
On 2/15/22 09:05, Dave Chinner wrote:
> On Tue, Feb 15, 2022 at 07:49:27AM +0900, Damien Le Moal wrote:
>> On 2/15/22 06:35, Dave Chinner wrote:
>>> On Thu, Feb 10, 2022 at 02:59:04PM +0900, Naohiro Aota wrote:
>>>> Add an assert function sb_assert_write_started() to check if
>>>> sb_start_write() is properly called. It is used in the next commit.
>>>>
>>>> Also, add the assert functions for sb_start_pagefault() and
>>>> sb_start_intwrite().
>>>>
>>>> Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
>>>> ---
>>>>  include/linux/fs.h | 20 ++++++++++++++++++++
>>>>  1 file changed, 20 insertions(+)
>>>>
>>>> diff --git a/include/linux/fs.h b/include/linux/fs.h
>>>> index bbf812ce89a8..5d5dc9a276d9 100644
>>>> --- a/include/linux/fs.h
>>>> +++ b/include/linux/fs.h
>>>> @@ -1820,6 +1820,11 @@ static inline bool __sb_start_write_trylock(struct super_block *sb, int level)
>>>>  #define __sb_writers_release(sb, lev)	\
>>>>  	percpu_rwsem_release(&(sb)->s_writers.rw_sem[(lev)-1], 1, _THIS_IP_)
>>>>  
>>>> +static inline void __sb_assert_write_started(struct super_block *sb, int level)
>>>> +{
>>>> +	lockdep_assert_held_read(sb->s_writers.rw_sem + level - 1);
>>>> +}
>>>> +
>>>
>>> So this isn't an assert, it's a WARN_ON(). Asserts stop execution
>>> (i.e. kill the task) rather than just issue a warning, so let's not
>>> name a function that issues a warning "assert"...
>>>
>>> Hence I'd much rather see this implemented as:
>>>
>>> static inline bool __sb_write_held(struct super_block *sb, int level)
>>> {
>>> 	return lockdep_is_held_type(sb->s_writers.rw_sem + level - 1, 1);
>>> }
>>
>> Since this would be true when called in between __sb_start_write() and
>> __sb_end_write(), what about calling it __sb_write_started() ? That
>> disconnects from the fact that the implementation uses a sem.
> 
> Makes no difference to me; I initially was going to suggest
> *_inprogress() but that seemed a bit verbose. We don't need to
> bikeshed this to death - all I want is it to be a check that can be
> used for generic purposes rather than being an explicit assert.

agree.

> 
> Cheers,
> 
> Dave.
Naohiro Aota Feb. 16, 2022, 3:02 a.m. UTC | #5
On Tue, Feb 15, 2022 at 11:05:15AM +1100, Dave Chinner wrote:
> On Tue, Feb 15, 2022 at 07:49:27AM +0900, Damien Le Moal wrote:
> > On 2/15/22 06:35, Dave Chinner wrote:
> > > On Thu, Feb 10, 2022 at 02:59:04PM +0900, Naohiro Aota wrote:
> > >> Add an assert function sb_assert_write_started() to check if
> > >> sb_start_write() is properly called. It is used in the next commit.
> > >>
> > >> Also, add the assert functions for sb_start_pagefault() and
> > >> sb_start_intwrite().
> > >>
> > >> Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
> > >> ---
> > >>  include/linux/fs.h | 20 ++++++++++++++++++++
> > >>  1 file changed, 20 insertions(+)
> > >>
> > >> diff --git a/include/linux/fs.h b/include/linux/fs.h
> > >> index bbf812ce89a8..5d5dc9a276d9 100644
> > >> --- a/include/linux/fs.h
> > >> +++ b/include/linux/fs.h
> > >> @@ -1820,6 +1820,11 @@ static inline bool __sb_start_write_trylock(struct super_block *sb, int level)
> > >>  #define __sb_writers_release(sb, lev)	\
> > >>  	percpu_rwsem_release(&(sb)->s_writers.rw_sem[(lev)-1], 1, _THIS_IP_)
> > >>  
> > >> +static inline void __sb_assert_write_started(struct super_block *sb, int level)
> > >> +{
> > >> +	lockdep_assert_held_read(sb->s_writers.rw_sem + level - 1);
> > >> +}
> > >> +
> > > 
> > > So this isn't an assert, it's a WARN_ON(). Asserts stop execution
> > > (i.e. kill the task) rather than just issue a warning, so let's not
> > > name a function that issues a warning "assert"...
> > > 
> > > Hence I'd much rather see this implemented as:
> > > 
> > > static inline bool __sb_write_held(struct super_block *sb, int level)
> > > {
> > > 	return lockdep_is_held_type(sb->s_writers.rw_sem + level - 1, 1);
> > > }
> > 
> > Since this would be true when called in between __sb_start_write() and
> > __sb_end_write(), what about calling it __sb_write_started() ? That
> > disconnects from the fact that the implementation uses a sem.
> 
> Makes no difference to me; I initially was going to suggest
> *_inprogress() but that seemed a bit verbose. We don't need to
> bikeshed this to death - all I want is it to be a check that can be
> used for generic purposes rather than being an explicit assert.

Agree. I'd like to use __sb_write_started() as it is conforming to
other functions.

> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com
diff mbox series

Patch

diff --git a/include/linux/fs.h b/include/linux/fs.h
index bbf812ce89a8..5d5dc9a276d9 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1820,6 +1820,11 @@  static inline bool __sb_start_write_trylock(struct super_block *sb, int level)
 #define __sb_writers_release(sb, lev)	\
 	percpu_rwsem_release(&(sb)->s_writers.rw_sem[(lev)-1], 1, _THIS_IP_)
 
+static inline void __sb_assert_write_started(struct super_block *sb, int level)
+{
+	lockdep_assert_held_read(sb->s_writers.rw_sem + level - 1);
+}
+
 /**
  * sb_end_write - drop write access to a superblock
  * @sb: the super we wrote to
@@ -1885,6 +1890,11 @@  static inline bool sb_start_write_trylock(struct super_block *sb)
 	return __sb_start_write_trylock(sb, SB_FREEZE_WRITE);
 }
 
+static inline void sb_assert_write_started(struct super_block *sb)
+{
+	__sb_assert_write_started(sb, SB_FREEZE_WRITE);
+}
+
 /**
  * sb_start_pagefault - get write access to a superblock from a page fault
  * @sb: the super we write to
@@ -1909,6 +1919,11 @@  static inline void sb_start_pagefault(struct super_block *sb)
 	__sb_start_write(sb, SB_FREEZE_PAGEFAULT);
 }
 
+static inline void sb_assert_pagefault_started(struct super_block *sb)
+{
+	__sb_assert_write_started(sb, SB_FREEZE_PAGEFAULT);
+}
+
 /**
  * sb_start_intwrite - get write access to a superblock for internal fs purposes
  * @sb: the super we write to
@@ -1932,6 +1947,11 @@  static inline bool sb_start_intwrite_trylock(struct super_block *sb)
 	return __sb_start_write_trylock(sb, SB_FREEZE_FS);
 }
 
+static inline void sb_assert_intwrite_started(struct super_block *sb)
+{
+	__sb_assert_write_started(sb, SB_FREEZE_FS);
+}
+
 bool inode_owner_or_capable(struct user_namespace *mnt_userns,
 			    const struct inode *inode);