diff mbox series

ext4: properly check for dirty state in ext4_inode_datasync_dirty()

Message ID 20201024140115.GA35973@xps-13-7390
State Superseded
Headers show
Series ext4: properly check for dirty state in ext4_inode_datasync_dirty() | expand

Commit Message

Andrea Righi Oct. 24, 2020, 2:01 p.m. UTC
ext4_inode_datasync_dirty() needs to return 'true' if the inode is
dirty, 'false' otherwise, but the logic seems to be incorrectly changed
by commit aa75f4d3daae ("ext4: main fast-commit commit path").

This introduces a problem with swap files that are always failing to be
activated, showing this error in dmesg:

 [   34.406479] swapon: file is not committed

Simple test case to reproduce the problem:

  # fallocate -l 8G swapfile
  # chmod 0600 swapfile
  # mkswap swapfile
  # swapon swapfile

Fix the logic to return the proper state of the inode.

Link: https://lore.kernel.org/lkml/20201024131333.GA32124@xps-13-7390
Fixes: aa75f4d3daae ("ext4: main fast-commit commit path")
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
---
 fs/ext4/inode.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Comments

harshad shirwadkar Oct. 26, 2020, 10:28 p.m. UTC | #1
Thanks Andrea for catching and sending out a fix for this.

On Sat, Oct 24, 2020 at 7:01 AM Andrea Righi <andrea.righi@canonical.com> wrote:
>
> ext4_inode_datasync_dirty() needs to return 'true' if the inode is
> dirty, 'false' otherwise, but the logic seems to be incorrectly changed
> by commit aa75f4d3daae ("ext4: main fast-commit commit path").
>
> This introduces a problem with swap files that are always failing to be
> activated, showing this error in dmesg:
>
>  [   34.406479] swapon: file is not committed
>
> Simple test case to reproduce the problem:
>
>   # fallocate -l 8G swapfile
>   # chmod 0600 swapfile
>   # mkswap swapfile
>   # swapon swapfile
>
> Fix the logic to return the proper state of the inode.
>
> Link: https://lore.kernel.org/lkml/20201024131333.GA32124@xps-13-7390
> Fixes: aa75f4d3daae ("ext4: main fast-commit commit path")
> Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
> ---
>  fs/ext4/inode.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index 03c2253005f0..a890a17ab7e1 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -3308,8 +3308,8 @@ static bool ext4_inode_datasync_dirty(struct inode *inode)
>         if (journal) {
>                 if (jbd2_transaction_committed(journal,
>                                         EXT4_I(inode)->i_datasync_tid))
> -                       return true;
> -               return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) >=
> +                       return false;
> +               return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) <
>                         EXT4_I(inode)->i_fc_committed_subtid;
In addition, the above condition should only be checked if fast
commits are enabled. So, in effect this overall condition will look
like this:

if (journal) {
    if (jbd2_transaction_committed(journal, EXT4_I(inode)->i_datasync_tid))
        return false;
    if (test_opt2(sb, JOURNAL_FAST_COMMIT))
        return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) <
EXT4_I(inode)->i_fc_committed_subtid;
    return true;
}

Thanks,
Harshad

>         }
>
> --
> 2.27.0
>
Ritesh Harjani Oct. 28, 2020, 3:27 a.m. UTC | #2
On 10/27/20 3:58 AM, harshad shirwadkar wrote:
> Thanks Andrea for catching and sending out a fix for this.
> 
> On Sat, Oct 24, 2020 at 7:01 AM Andrea Righi <andrea.righi@canonical.com> wrote:
>>
>> ext4_inode_datasync_dirty() needs to return 'true' if the inode is
>> dirty, 'false' otherwise, but the logic seems to be incorrectly changed
>> by commit aa75f4d3daae ("ext4: main fast-commit commit path").
>>
>> This introduces a problem with swap files that are always failing to be
>> activated, showing this error in dmesg:
>>
>>   [   34.406479] swapon: file is not committed
>>

Well, I too noticed this yesterday while I was testing xfstests -g swap.
Those tests were returning _notrun, hence that could be the reason why
it didn't get notice in XFSTESTing from Ted.

- I did notice that this code was introduced in v10 only.
This wasn't there in v9 though.


>> Simple test case to reproduce the problem:
>>
>>    # fallocate -l 8G swapfile
>>    # chmod 0600 swapfile
>>    # mkswap swapfile
>>    # swapon swapfile
>>
>> Fix the logic to return the proper state of the inode.
>>
>> Link: https://lore.kernel.org/lkml/20201024131333.GA32124@xps-13-7390
>> Fixes: aa75f4d3daae ("ext4: main fast-commit commit path")
>> Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
>> ---
>>   fs/ext4/inode.c | 4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
>> index 03c2253005f0..a890a17ab7e1 100644
>> --- a/fs/ext4/inode.c
>> +++ b/fs/ext4/inode.c
>> @@ -3308,8 +3308,8 @@ static bool ext4_inode_datasync_dirty(struct inode *inode)
>>          if (journal) {
>>                  if (jbd2_transaction_committed(journal,
>>                                          EXT4_I(inode)->i_datasync_tid))
>> -                       return true;
>> -               return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) >=
>> +                       return false;
>> +               return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) <
>>                          EXT4_I(inode)->i_fc_committed_subtid;
> In addition, the above condition should only be checked if fast
> commits are enabled. So, in effect this overall condition will look
> like this:
> 
> if (journal) {
>      if (jbd2_transaction_committed(journal, EXT4_I(inode)->i_datasync_tid))
>          return false;
>      if (test_opt2(sb, JOURNAL_FAST_COMMIT))
>          return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) <
> EXT4_I(inode)->i_fc_committed_subtid;
>      return true;
> }

Yup - I too had made a similar patch. But then I also noticed that below
condition will always remain false. Since we never update
"i_fc_committed_subtid" other than at these 2 places
(one during init where we set it to 0 and other during ext4_fc_commit()
where we set it to sbi->s_fc_subtid).

<condition>
atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid < 
EXT4_I(inode)->i_fc_committed_subtid


Maybe I need more reading around this.

-ritesh





> 
> Thanks,
> Harshad
> 
>>          }
>>
>> --
>> 2.27.0
>>
harshad shirwadkar Oct. 28, 2020, 3:48 a.m. UTC | #3
Actually the simpler fix for this in case of fast commits is to check
if the inode is on the fast commit list or not. Since we clear the
fast commit list after every fast and / or full commit, it's always
true that if the inode is not on the list, that means it isn't dirty.
This will simplify the logic here and then we can probably get rid of
i_fc_committed_subtid field altogether. I'll test this and send out a
patch.

Thanks,
Harshad

On Tue, Oct 27, 2020 at 8:27 PM Ritesh Harjani <riteshh@linux.ibm.com> wrote:
>
>
>
> On 10/27/20 3:58 AM, harshad shirwadkar wrote:
> > Thanks Andrea for catching and sending out a fix for this.
> >
> > On Sat, Oct 24, 2020 at 7:01 AM Andrea Righi <andrea.righi@canonical.com> wrote:
> >>
> >> ext4_inode_datasync_dirty() needs to return 'true' if the inode is
> >> dirty, 'false' otherwise, but the logic seems to be incorrectly changed
> >> by commit aa75f4d3daae ("ext4: main fast-commit commit path").
> >>
> >> This introduces a problem with swap files that are always failing to be
> >> activated, showing this error in dmesg:
> >>
> >>   [   34.406479] swapon: file is not committed
> >>
>
> Well, I too noticed this yesterday while I was testing xfstests -g swap.
> Those tests were returning _notrun, hence that could be the reason why
> it didn't get notice in XFSTESTing from Ted.
>
> - I did notice that this code was introduced in v10 only.
> This wasn't there in v9 though.
>
>
> >> Simple test case to reproduce the problem:
> >>
> >>    # fallocate -l 8G swapfile
> >>    # chmod 0600 swapfile
> >>    # mkswap swapfile
> >>    # swapon swapfile
> >>
> >> Fix the logic to return the proper state of the inode.
> >>
> >> Link: https://lore.kernel.org/lkml/20201024131333.GA32124@xps-13-7390
> >> Fixes: aa75f4d3daae ("ext4: main fast-commit commit path")
> >> Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
> >> ---
> >>   fs/ext4/inode.c | 4 ++--
> >>   1 file changed, 2 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> >> index 03c2253005f0..a890a17ab7e1 100644
> >> --- a/fs/ext4/inode.c
> >> +++ b/fs/ext4/inode.c
> >> @@ -3308,8 +3308,8 @@ static bool ext4_inode_datasync_dirty(struct inode *inode)
> >>          if (journal) {
> >>                  if (jbd2_transaction_committed(journal,
> >>                                          EXT4_I(inode)->i_datasync_tid))
> >> -                       return true;
> >> -               return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) >=
> >> +                       return false;
> >> +               return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) <
> >>                          EXT4_I(inode)->i_fc_committed_subtid;
> > In addition, the above condition should only be checked if fast
> > commits are enabled. So, in effect this overall condition will look
> > like this:
> >
> > if (journal) {
> >      if (jbd2_transaction_committed(journal, EXT4_I(inode)->i_datasync_tid))
> >          return false;
> >      if (test_opt2(sb, JOURNAL_FAST_COMMIT))
> >          return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) <
> > EXT4_I(inode)->i_fc_committed_subtid;
> >      return true;
> > }
>
> Yup - I too had made a similar patch. But then I also noticed that below
> condition will always remain false. Since we never update
> "i_fc_committed_subtid" other than at these 2 places
> (one during init where we set it to 0 and other during ext4_fc_commit()
> where we set it to sbi->s_fc_subtid).
>
> <condition>
> atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid <
> EXT4_I(inode)->i_fc_committed_subtid
>
>
> Maybe I need more reading around this.
>
> -ritesh
>
>
>
>
>
> >
> > Thanks,
> > Harshad
> >
> >>          }
> >>
> >> --
> >> 2.27.0
> >>
Ritesh Harjani Oct. 28, 2020, 4:33 a.m. UTC | #4
On 10/28/20 9:18 AM, harshad shirwadkar wrote:
> Actually the simpler fix for this in case of fast commits is to check
> if the inode is on the fast commit list or not. Since we clear the
> fast commit list after every fast and / or full commit, it's always
> true that if the inode is not on the list, that means it isn't dirty.
> This will simplify the logic here and then we can probably get rid of
> i_fc_committed_subtid field altogether. I'll test this and send out a
> patch.

Yes, sounds like a better solution. Thanks!

-ritesh
Theodore Y. Ts'o Oct. 28, 2020, 3:29 p.m. UTC | #5
On Wed, Oct 28, 2020 at 08:57:03AM +0530, Ritesh Harjani wrote:
> 
> Well, I too noticed this yesterday while I was testing xfstests -g swap.
> Those tests were returning _notrun, hence that could be the reason why
> it didn't get notice in XFSTESTing from Ted.

Yeah, one of the things I discussed with Harshad is we really need a
test that looks like generic/472, but which is in shared/NNN, and
which unconditionally tries to use swapon for those file systems where
swapfiles are expected to work.  This is actually the second
regression caused by our breaking swapfile support (the other being
the iomap bmap change), which escaped our testing because we didn't
notice that generic/472 was skipped.

(Mental note; perhaps we should have a way of flagging tests that are
skipped when previously they would run in the {kvm,gce}-xfstests
framework.)

						- Ted
Ritesh Harjani Oct. 28, 2020, 5:26 p.m. UTC | #6
On 10/28/20 8:59 PM, Theodore Y. Ts'o wrote:
> On Wed, Oct 28, 2020 at 08:57:03AM +0530, Ritesh Harjani wrote:
>>
>> Well, I too noticed this yesterday while I was testing xfstests -g swap.
>> Those tests were returning _notrun, hence that could be the reason why
>> it didn't get notice in XFSTESTing from Ted.
> 
> Yeah, one of the things I discussed with Harshad is we really need a
> test that looks like generic/472, but which is in shared/NNN, and
> which unconditionally tries to use swapon for those file systems where
> swapfiles are expected to work.  This is actually the second
> regression caused by our breaking swapfile support (the other being
> the iomap bmap change), which escaped our testing because we didn't
> notice that generic/472 was skipped.

Yes, agreed this is second in a row.
So with fast-commit, swap tests returned _not_run, since
swapon syscall returned -EINVAL in _require_scratch_swapfile() itself.
This is due to some old commit in fstests to make swap tests work on
btrfs on both kernels (with and w/o support of swapon in btrfs), it
first checks in _require_scratch_swapfile() to see if swapon even works
or not. Hence it skips to run further if _require_scratch_swapfile()
fails.

Secondly with bmap to iomap interface, I guess it should pass
all tests except for case with fallocate files, which I think is
tests/generic/496. But here too it assumes that if 1st time it fails
with falloc then swapon may not be supported for that fs and hence does
_notrun.

I am actually working on this to make these swap tests return some
definitive pass or failure status. Will be sending some patches soon.
I could use your idea to add a test in shared/NNN for testing swap with
fallocate files for ext4 and xfs (for bmap to iomap ext4 regression
category of tests)

Thanks
-ritesh
diff mbox series

Patch

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 03c2253005f0..a890a17ab7e1 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3308,8 +3308,8 @@  static bool ext4_inode_datasync_dirty(struct inode *inode)
 	if (journal) {
 		if (jbd2_transaction_committed(journal,
 					EXT4_I(inode)->i_datasync_tid))
-			return true;
-		return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) >=
+			return false;
+		return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) <
 			EXT4_I(inode)->i_fc_committed_subtid;
 	}