public inbox for gfs2@lists.linux.dev
 help / color / mirror / Atom feed
* [PATCH 0/2] GFS2: Fix wrong call of new trans for jdata
@ 2025-06-06  9:47 Su Yue
  2025-06-06  9:47 ` [PATCH 1/2] gfs2: rename gfs2_write_jdata_folio to gfs2_write_jdata_full_folio Su Yue
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Su Yue @ 2025-06-06  9:47 UTC (permalink / raw)
  To: gfs2; +Cc: l, agruenba, willy, Su Yue

Patch 1 is trivial.
Please see commit message of patch 2/2.

Su Yue (2):
  gfs2: rename gfs2_write_jdata_folio to gfs2_write_jdata_full_folio
  gfs2: do not call gfs2_jdata_writepages for jdata

 fs/gfs2/aops.c | 46 +++++++++++++++++++++++++++++++++++++++++++---
 fs/gfs2/aops.h |  1 +
 fs/gfs2/log.c  |  6 +++++-
 3 files changed, 49 insertions(+), 4 deletions(-)

-- 
2.48.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] gfs2: rename gfs2_write_jdata_folio to gfs2_write_jdata_full_folio
  2025-06-06  9:47 [PATCH 0/2] GFS2: Fix wrong call of new trans for jdata Su Yue
@ 2025-06-06  9:47 ` Su Yue
  2025-06-06  9:47 ` [PATCH 2/2] gfs2: do not call gfs2_jdata_writepages for jdata Su Yue
  2025-06-09  0:20 ` [PATCH 0/2] GFS2: Fix wrong call of new trans " Su Yue
  2 siblings, 0 replies; 6+ messages in thread
From: Su Yue @ 2025-06-06  9:47 UTC (permalink / raw)
  To: gfs2; +Cc: l, agruenba, willy, Su Yue

As the functions calls block_write_full_folio(), gfs2_write_jdata_full_folio
is more proper. Reserve name gfs2_write_jdata_folio for futher use.

Signed-off-by: Su Yue <glass.su@suse.com>
---
 fs/gfs2/aops.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 68fc8af14700..1a9e4ed33911 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -82,14 +82,14 @@ static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
 }
 
 /**
- * gfs2_write_jdata_folio - gfs2 jdata-specific version of block_write_full_folio
+ * gfs2_write_jdata_full_folio - gfs2 jdata-specific version of block_write_full_folio
  * @folio: The folio to write
  * @wbc: The writeback control
  *
  * This is the same as calling block_write_full_folio, but it also
  * writes pages outside of i_size
  */
-static int gfs2_write_jdata_folio(struct folio *folio,
+static int gfs2_write_jdata_full_folio(struct folio *folio,
 				 struct writeback_control *wbc)
 {
 	struct inode * const inode = folio->mapping->host;
@@ -135,7 +135,7 @@ static int __gfs2_jdata_write_folio(struct folio *folio,
 		}
 		gfs2_trans_add_databufs(ip, folio, 0, folio_size(folio));
 	}
-	return gfs2_write_jdata_folio(folio, wbc);
+	return gfs2_write_jdata_full_folio(folio, wbc);
 }
 
 /**
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] gfs2: do not call gfs2_jdata_writepages for jdata
  2025-06-06  9:47 [PATCH 0/2] GFS2: Fix wrong call of new trans for jdata Su Yue
  2025-06-06  9:47 ` [PATCH 1/2] gfs2: rename gfs2_write_jdata_folio to gfs2_write_jdata_full_folio Su Yue
@ 2025-06-06  9:47 ` Su Yue
  2025-06-06 12:27   ` Matthew Wilcox
  2025-06-09  0:20 ` [PATCH 0/2] GFS2: Fix wrong call of new trans " Su Yue
  2 siblings, 1 reply; 6+ messages in thread
From: Su Yue @ 2025-06-06  9:47 UTC (permalink / raw)
  To: gfs2; +Cc: l, agruenba, willy, Su Yue

The script can triger hang of umount:

==========================================================================
  dev="/dev/vdb2"
  mnt="/mnt"
  user=root

  yes | mkfs.gfs2 $dev -p lock_nolock
  mount -o quota=account $dev $mnt
  echo 1 > /sys/kernel/debug/tracing/tracing_on
  quotacheck -ug $mnt
  quotaon -ug $mnt
  quotaon --project $mnt
  chmod ugo+rwx $mnt
  setquota -u $user $((250 * 4096 / 1024)) $((500 * 4096 / 1024)) 3 5 $mnt
  umount $mnt # hangs
==========================================================================

  [  247.018171 ] INFO: task umount:1004 blocked for more than 122 seconds.
  [  247.018398 ]       Not tainted 6.11.0-09378-gfbb86b0d5f38 #235
  [  247.018598 ] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
  [  247.018866 ] task:umount          state:D stack:0     pid:1004  tgid:1004  ppid:988    flags:0x00004006
  [  247.019191 ] Call Trace:
  [  247.019282 ]  <TASK>
  [  247.019358 ]  __schedule+0x404/0x1410
  [  247.019485 ]  schedule+0x27/0xf0
  [  247.019600 ]  schedule_preempt_disabled+0x15/0x30
  [  247.019761 ]  rwsem_down_read_slowpath+0x26f/0x4e0
  [  247.019925 ]  ? sched_balance_find_src_group+0x51/0x580
  [  247.020106 ]  down_read+0x48/0xa0
  [  247.020232 ]  __gfs2_trans_begin+0x119/0x290   [gfs2 0d63e36c3a51bc921f68927c362d00048655daca]
  [  247.020535 ]  gfs2_trans_begin+0x4b/0x90   [gfs2 0d63e36c3a51bc921f68927c362d00048655daca]
  [  247.020816 ]  gfs2_write_cache_jdata+0x163/0x680   [gfs2 0d63e36c3a51bc921f68927c362d00048655daca]
  [  247.021138 ]  gfs2_jdata_writepages+0x29/0x70   [gfs2 0d63e36c3a51bc921f68927c362d00048655daca]
  [  247.021449 ]  gfs2_ail1_flush+0x1c9/0x4c0   [gfs2 0d63e36c3a51bc921f68927c362d00048655daca]
  [  247.021731 ]  ? psi_group_change+0x12a/0x300
  [  247.021882 ]  gfs2_ail1_start+0x4b/0x70   [gfs2 0d63e36c3a51bc921f68927c362d00048655daca]
  [  247.022175 ]  gfs2_log_flush+0x9fd/0xb70   [gfs2 0d63e36c3a51bc921f68927c362d00048655daca]
  [  247.022458 ]  gfs2_kill_sb+0x39/0x170   [gfs2 0d63e36c3a51bc921f68927c362d00048655daca]
  [  247.022731 ]  deactivate_locked_super+0x33/0xb0
  [  247.022890 ]  cleanup_mnt+0xba/0x150
  [  247.023018 ]  task_work_run+0x5c/0x90
  [  247.023148 ]  syscall_exit_to_user_mode+0x1b2/0x1c0
  [  247.023316 ]  do_syscall_64+0x8e/0x190
  [  247.023449 ]  ? syscall_exit_to_user_mode+0x37/0x1c0
  [  247.023618 ]  ? do_syscall_64+0x8e/0x190
  [  247.023751 ]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
  [  247.023931 ] RIP: 0033:0x7f1730c2756b
  [  247.024068 ] RSP: 002b:00007fff3db03018 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
  [  247.024334 ] RAX: 0000000000000000 RBX: 0000562517583560 RCX: 00007f1730c2756b
  [  247.024582 ] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000562517583970
  [  247.024828 ] RBP: 00007fff3db030f0 R08: 0000000000000000 R09: 0000000000000000
  [  247.025073 ] R10: 0000000000000800 R11: 0000000000000246 R12: 0000562517583668
  [  247.025320 ] R13: 0000000000000000 R14: 0000562517583970 R15: 0000000000000000
  [  247.025568 ]  </TASK>
==========================================================================

While in gfs2_ail1_flush(),  gfs2_log_flush() has already down_write sdp->sd_log_flush_lock
but gfs2_jdata_writepages() stil calls gfs2_trans_begin() to down_read the semaphore.

The commit 8d391972ae2d ("gfs2: Remove __gfs2_writepage()") overlooked differences between
gfs2_jdata_writepage() and gfs2_jdata_writepages(). The later calls gfs2_write_cache_jdata()
which 'start transactions before we grab page locks'.

The commit partly revert commit 8d391972ae2d ("gfs2: Remove __gfs2_writepage()").
__gfs2_writepage() is back as gfs2_write_jdata_folio() which is called by
exported gfs2_write_jdata_folios().
In gfs2_log_shutdown(), if the inode is jdata then call gfs2_write_jdata_folios()
to write all folios without new transaction started just like old behavior
before 8d391972ae2d.

Fixes: 8d391972ae2d ("gfs2: Remove __gfs2_writepage()")
Signed-off-by: Su Yue <glass.su@suse.com>
---
 fs/gfs2/aops.c | 40 ++++++++++++++++++++++++++++++++++++++++
 fs/gfs2/aops.h |  1 +
 fs/gfs2/log.c  |  6 +++++-
 3 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 1a9e4ed33911..26ed68e9529a 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -138,6 +138,46 @@ static int __gfs2_jdata_write_folio(struct folio *folio,
 	return gfs2_write_jdata_full_folio(folio, wbc);
 }
 
+/**
+ * gfs2_write_jdata_folio - Write folio
+ * @folio: folio to write
+ * @wbc: The writeback control
+ *
+ * Returns: errno
+ *
+ */
+
+static int gfs2_write_jdata_folio(struct folio *folio, struct writeback_control *wbc)
+{
+	struct inode *inode = folio->mapping->host;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+
+	if (gfs2_assert_withdraw(sdp, ip->i_gl->gl_state == LM_ST_EXCLUSIVE))
+		goto out;
+	if (folio_test_checked(folio) || current->journal_info)
+		goto out_ignore;
+	return __gfs2_jdata_write_folio(folio, wbc);
+
+out_ignore:
+	folio_redirty_for_writepage(wbc, folio);
+out:
+	folio_unlock(folio);
+	return 0;
+}
+
+int gfs2_write_jdata_folios(struct address_space *mapping, struct writeback_control *wbc)
+{
+	struct folio *folio = NULL;
+	int error;
+
+	while ((folio = writeback_iter(mapping, wbc, folio, &error)))
+		error = gfs2_write_jdata_folio(folio, wbc);
+
+	return error;
+}
+
+
 /**
  * gfs2_writepages - Write a bunch of dirty pages back to disk
  * @mapping: The mapping to write
diff --git a/fs/gfs2/aops.h b/fs/gfs2/aops.h
index a10c4334d248..4364693486ab 100644
--- a/fs/gfs2/aops.h
+++ b/fs/gfs2/aops.h
@@ -11,5 +11,6 @@
 void adjust_fs_space(struct inode *inode);
 void gfs2_trans_add_databufs(struct gfs2_inode *ip, struct folio *folio,
 			     size_t from, size_t len);
+int gfs2_write_jdata_folios(struct address_space *mapping, struct writeback_control *wbc);
 
 #endif /* __AOPS_DOT_H__ */
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index f9c5089783d2..586f103f01c2 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -31,6 +31,7 @@
 #include "dir.h"
 #include "trace_gfs2.h"
 #include "trans.h"
+#include "aops.h"
 
 static void gfs2_log_shutdown(struct gfs2_sbd *sdp);
 
@@ -131,7 +132,10 @@ __acquires(&sdp->sd_ail_lock)
 		if (!mapping)
 			continue;
 		spin_unlock(&sdp->sd_ail_lock);
-		ret = mapping->a_ops->writepages(mapping, wbc);
+		if (gfs2_is_jdata(GFS2_I(mapping->host)))
+			ret = gfs2_write_jdata_folios(mapping, wbc);
+		else
+			ret = mapping->a_ops->writepages(mapping, wbc);
 		if (need_resched()) {
 			blk_finish_plug(plug);
 			cond_resched();
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] gfs2: do not call gfs2_jdata_writepages for jdata
  2025-06-06  9:47 ` [PATCH 2/2] gfs2: do not call gfs2_jdata_writepages for jdata Su Yue
@ 2025-06-06 12:27   ` Matthew Wilcox
  2025-06-09  0:18     ` Su Yue
  0 siblings, 1 reply; 6+ messages in thread
From: Matthew Wilcox @ 2025-06-06 12:27 UTC (permalink / raw)
  To: Su Yue; +Cc: gfs2, l, agruenba

On Fri, Jun 06, 2025 at 05:47:56PM +0800, Su Yue wrote:
> +++ b/fs/gfs2/aops.c
> @@ -138,6 +138,46 @@ static int __gfs2_jdata_write_folio(struct folio *folio,
>  	return gfs2_write_jdata_full_folio(folio, wbc);
>  }
>  
> +/**
> + * gfs2_write_jdata_folio - Write folio
> + * @folio: folio to write
> + * @wbc: The writeback control
> + *
> + * Returns: errno
> + *
> + */
> +
> +static int gfs2_write_jdata_folio(struct folio *folio, struct writeback_control *wbc)
> +{
> +	struct inode *inode = folio->mapping->host;
> +	struct gfs2_inode *ip = GFS2_I(inode);
> +	struct gfs2_sbd *sdp = GFS2_SB(inode);
> +
> +	if (gfs2_assert_withdraw(sdp, ip->i_gl->gl_state == LM_ST_EXCLUSIVE))
> +		goto out;
> +	if (folio_test_checked(folio) || current->journal_info)
> +		goto out_ignore;
> +	return __gfs2_jdata_write_folio(folio, wbc);
> +
> +out_ignore:
> +	folio_redirty_for_writepage(wbc, folio);
> +out:
> +	folio_unlock(folio);
> +	return 0;
> +}
> +
> +int gfs2_write_jdata_folios(struct address_space *mapping, struct writeback_control *wbc)
> +{
> +	struct folio *folio = NULL;
> +	int error;
> +
> +	while ((folio = writeback_iter(mapping, wbc, folio, &error)))
> +		error = gfs2_write_jdata_folio(folio, wbc);
> +
> +	return error;
> +}

The great thing about using an iterator pattern rather than a callback
pattern is that we don't need this stupid extra function.  So you can
drop patch 1 and just do this:

+	struct inode *inode = mapping->host;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+
+	if (gfs2_assert_withdraw(sdp, ip->i_gl->gl_state == LM_ST_EXCLUSIVE))
+		return -Ewhatever;
+
+	while ((folio = writeback_iter(mapping, wbc, folio, &error))) {
+		if (folio_test_checked(folio) || current->journal_info)
+			goto ignore;
+		error = __gfs2_jdata_write_folio(folio, wbc);
+		continue;
+
+ignore:
+		folio_redirty_for_writepage(wbc, folio);
+		folio_unlock(folio);
+	}
+
+	return error;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] gfs2: do not call gfs2_jdata_writepages for jdata
  2025-06-06 12:27   ` Matthew Wilcox
@ 2025-06-09  0:18     ` Su Yue
  0 siblings, 0 replies; 6+ messages in thread
From: Su Yue @ 2025-06-09  0:18 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: Su Yue, gfs2, agruenba

On Fri 06 Jun 2025 at 13:27, Matthew Wilcox <willy@infradead.org> 
wrote:

> On Fri, Jun 06, 2025 at 05:47:56PM +0800, Su Yue wrote:
>> +++ b/fs/gfs2/aops.c
>> @@ -138,6 +138,46 @@ static int __gfs2_jdata_write_folio(struct 
>> folio *folio,
>>  	return gfs2_write_jdata_full_folio(folio, wbc);
>>  }
>>
>> +/**
>> + * gfs2_write_jdata_folio - Write folio
>> + * @folio: folio to write
>> + * @wbc: The writeback control
>> + *
>> + * Returns: errno
>> + *
>> + */
>> +
>> +static int gfs2_write_jdata_folio(struct folio *folio, struct 
>> writeback_control *wbc)
>> +{
>> +	struct inode *inode = folio->mapping->host;
>> +	struct gfs2_inode *ip = GFS2_I(inode);
>> +	struct gfs2_sbd *sdp = GFS2_SB(inode);
>> +
>> +	if (gfs2_assert_withdraw(sdp, ip->i_gl->gl_state == 
>> LM_ST_EXCLUSIVE))
>> +		goto out;
>> +	if (folio_test_checked(folio) || current->journal_info)
>> +		goto out_ignore;
>> +	return __gfs2_jdata_write_folio(folio, wbc);
>> +
>> +out_ignore:
>> +	folio_redirty_for_writepage(wbc, folio);
>> +out:
>> +	folio_unlock(folio);
>> +	return 0;
>> +}
>> +
>> +int gfs2_write_jdata_folios(struct address_space *mapping, 
>> struct writeback_control *wbc)
>> +{
>> +	struct folio *folio = NULL;
>> +	int error;
>> +
>> +	while ((folio = writeback_iter(mapping, wbc, folio, 
>> &error)))
>> +		error = gfs2_write_jdata_folio(folio, wbc);
>> +
>> +	return error;
>> +}
>
> The great thing about using an iterator pattern rather than a 
> callback
> pattern is that we don't need this stupid extra function.  So 
> you can
> drop patch 1 and just do this:
>
Thanks. That's what Andreas wrote in his patch 5a90f8d49922  :)

--
Su
> +	struct inode *inode = mapping->host;
> +	struct gfs2_inode *ip = GFS2_I(inode);
> +	struct gfs2_sbd *sdp = GFS2_SB(inode);
> +
> +	if (gfs2_assert_withdraw(sdp, ip->i_gl->gl_state == 
> LM_ST_EXCLUSIVE))
> +		return -Ewhatever;
> +
> +	while ((folio = writeback_iter(mapping, wbc, folio, &error))) 
> {
> +		if (folio_test_checked(folio) || current->journal_info)
> +			goto ignore;
> +		error = __gfs2_jdata_write_folio(folio, wbc);
> +		continue;
> +
> +ignore:
> +		folio_redirty_for_writepage(wbc, folio);
> +		folio_unlock(folio);
> +	}
> +
> +	return error;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/2] GFS2: Fix wrong call of new trans for jdata
  2025-06-06  9:47 [PATCH 0/2] GFS2: Fix wrong call of new trans for jdata Su Yue
  2025-06-06  9:47 ` [PATCH 1/2] gfs2: rename gfs2_write_jdata_folio to gfs2_write_jdata_full_folio Su Yue
  2025-06-06  9:47 ` [PATCH 2/2] gfs2: do not call gfs2_jdata_writepages for jdata Su Yue
@ 2025-06-09  0:20 ` Su Yue
  2 siblings, 0 replies; 6+ messages in thread
From: Su Yue @ 2025-06-09  0:20 UTC (permalink / raw)
  To: Su Yue; +Cc: gfs2, agruenba, willy

On Fri 06 Jun 2025 at 17:47, Su Yue <glass.su@suse.com> wrote:

> Patch 1 is trivial.
> Please see commit message of patch 2/2.
>
Please ignore the patchset. The issue was fixed by
commit 5a90f8d49922 ("gfs2: Don't start unnecessary transactions 
during log flush").

--
Su
> Su Yue (2):
>   gfs2: rename gfs2_write_jdata_folio to 
>   gfs2_write_jdata_full_folio
>   gfs2: do not call gfs2_jdata_writepages for jdata
>
>  fs/gfs2/aops.c | 46 
>  +++++++++++++++++++++++++++++++++++++++++++---
>  fs/gfs2/aops.h |  1 +
>  fs/gfs2/log.c  |  6 +++++-
>  3 files changed, 49 insertions(+), 4 deletions(-)

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2025-06-09  0:26 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-06  9:47 [PATCH 0/2] GFS2: Fix wrong call of new trans for jdata Su Yue
2025-06-06  9:47 ` [PATCH 1/2] gfs2: rename gfs2_write_jdata_folio to gfs2_write_jdata_full_folio Su Yue
2025-06-06  9:47 ` [PATCH 2/2] gfs2: do not call gfs2_jdata_writepages for jdata Su Yue
2025-06-06 12:27   ` Matthew Wilcox
2025-06-09  0:18     ` Su Yue
2025-06-09  0:20 ` [PATCH 0/2] GFS2: Fix wrong call of new trans " Su Yue

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox