* [PATCHSET v2 0/2] xfsprogs: random fixes for 5.19
@ 2022-08-09 21:06 Darrick J. Wong
2022-08-09 21:06 ` [PATCH 1/2] xfs_repair: fix printf format specifiers on 32-bit platforms Darrick J. Wong
2022-08-09 21:06 ` [PATCH 2/2] xfs_repair: retain superblock buffer to avoid write hook deadlock Darrick J. Wong
0 siblings, 2 replies; 8+ messages in thread
From: Darrick J. Wong @ 2022-08-09 21:06 UTC (permalink / raw)
To: sandeen, djwong; +Cc: linux-xfs
Hi all,
This is a rollup of all the random fixes I've collected for xfsprogs
5.19. At this point it's just an assorted collection, no particular
theme. Some of them are leftovers from last week's posting.
v2: note the actual cause (too small filesystem) when we abort due to
impossible log geometry
If you're going to start using this mess, you probably ought to just
pull from my git trees, which are linked below.
This is an extraordinary way to destroy everything. Enjoy!
Comments and questions are, as always, welcome.
--D
kernel git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=random-fixes
xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=random-fixes
fstests git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=random-fixes
---
libxfs/libxfs_api_defs.h | 2 +
libxfs/libxfs_io.h | 1 +
libxfs/rdwr.c | 8 +++++
logprint/log_misc.c | 8 ++---
repair/bmap.c | 8 ++---
repair/phase2.c | 8 +++++
repair/protos.h | 1 +
repair/xfs_repair.c | 75 ++++++++++++++++++++++++++++++++++++++++------
8 files changed, 94 insertions(+), 17 deletions(-)
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] xfs_repair: fix printf format specifiers on 32-bit platforms
2022-08-09 21:06 [PATCHSET v2 0/2] xfsprogs: random fixes for 5.19 Darrick J. Wong
@ 2022-08-09 21:06 ` Darrick J. Wong
2022-08-11 12:37 ` Christoph Hellwig
2022-08-09 21:06 ` [PATCH 2/2] xfs_repair: retain superblock buffer to avoid write hook deadlock Darrick J. Wong
1 sibling, 1 reply; 8+ messages in thread
From: Darrick J. Wong @ 2022-08-09 21:06 UTC (permalink / raw)
To: sandeen, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
armv7l builds spit out the following warnings:
In file included from ../include/platform_defs.h:44,
from ../include/libxfs.h:13,
from bmap.c:7:
bmap.c: In function ‘blkmap_alloc’:
bmap.c:41:11: error: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘xfs_extnum_t’ {aka ‘long long unsigned int’} [-Werror=format=]
41 | _("Number of extents requested in blkmap_alloc (%d) overflows 32 bits.\n"
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bmap.c:41:9: note: in expansion of macro ‘_’
41 | _("Number of extents requested in blkmap_alloc (%d) overflows 32 bits.\n"
| ^
bmap.c:41:58: note: format string is defined here
41 | _("Number of extents requested in blkmap_alloc (%d) overflows 32 bits.\n"
| ~^
| |
| int
| %lld
In file included from ../include/platform_defs.h:44,
from ../include/libxfs.h:13,
from bmap.c:7:
bmap.c:54:35: error: format ‘%zu’ expects argument of type ‘size_t’, but argument 2 has type ‘xfs_extnum_t’ {aka ‘long long unsigned int’} [-Werror=format=]
54 | do_warn(_("malloc failed in blkmap_alloc (%zu bytes)\n"),
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bmap.c:54:33: note: in expansion of macro ‘_’
54 | do_warn(_("malloc failed in blkmap_alloc (%zu bytes)\n"),
| ^
bmap.c:54:69: note: format string is defined here
54 | do_warn(_("malloc failed in blkmap_alloc (%zu bytes)\n"),
| ~~^
| |
| unsigned int
| %llu
Fix these.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
logprint/log_misc.c | 8 ++++----
repair/bmap.c | 8 ++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/logprint/log_misc.c b/logprint/log_misc.c
index 82e1f682..836156e0 100644
--- a/logprint/log_misc.c
+++ b/logprint/log_misc.c
@@ -493,16 +493,16 @@ xlog_print_trans_inode_core(
nextents = ip->di_big_nextents;
else
nextents = ip->di_nextents;
- printf(_("size 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%lx\n"),
+ printf(_("size 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%llx\n"),
(unsigned long long)ip->di_size, (unsigned long long)ip->di_nblocks,
- ip->di_extsize, nextents);
+ ip->di_extsize, (unsigned long long)nextents);
if (ip->di_flags2 & XFS_DIFLAG2_NREXT64)
nextents = ip->di_big_anextents;
else
nextents = ip->di_anextents;
- printf(_("naextents 0x%lx forkoff %d dmevmask 0x%x dmstate 0x%hx\n"),
- nextents, (int)ip->di_forkoff, ip->di_dmevmask, ip->di_dmstate);
+ printf(_("naextents 0x%llx forkoff %d dmevmask 0x%x dmstate 0x%hx\n"),
+ (unsigned long long)nextents, (int)ip->di_forkoff, ip->di_dmevmask, ip->di_dmstate);
printf(_("flags 0x%x gen 0x%x\n"),
ip->di_flags, ip->di_gen);
if (ip->di_version == 3) {
diff --git a/repair/bmap.c b/repair/bmap.c
index 44e43ab4..cd1a8b07 100644
--- a/repair/bmap.c
+++ b/repair/bmap.c
@@ -38,10 +38,10 @@ blkmap_alloc(
#if (BITS_PER_LONG == 32) /* on 64-bit platforms this is never true */
if (nex > BLKMAP_NEXTS_MAX) {
do_warn(
- _("Number of extents requested in blkmap_alloc (%d) overflows 32 bits.\n"
+ _("Number of extents requested in blkmap_alloc (%llu) overflows 32 bits.\n"
"If this is not a corruption, then you will need a 64 bit system\n"
"to repair this filesystem.\n"),
- nex);
+ (unsigned long long)nex);
return NULL;
}
#endif
@@ -51,8 +51,8 @@ blkmap_alloc(
if (!blkmap || blkmap->naexts < nex) {
blkmap = realloc(blkmap, BLKMAP_SIZE(nex));
if (!blkmap) {
- do_warn(_("malloc failed in blkmap_alloc (%zu bytes)\n"),
- BLKMAP_SIZE(nex));
+ do_warn(_("malloc failed in blkmap_alloc (%llu bytes)\n"),
+ (unsigned long long)BLKMAP_SIZE(nex));
return NULL;
}
pthread_setspecific(key, blkmap);
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2] xfs_repair: retain superblock buffer to avoid write hook deadlock
2022-08-09 21:06 [PATCHSET v2 0/2] xfsprogs: random fixes for 5.19 Darrick J. Wong
2022-08-09 21:06 ` [PATCH 1/2] xfs_repair: fix printf format specifiers on 32-bit platforms Darrick J. Wong
@ 2022-08-09 21:06 ` Darrick J. Wong
2022-08-11 12:47 ` Christoph Hellwig
2022-08-11 22:15 ` Dave Chinner
1 sibling, 2 replies; 8+ messages in thread
From: Darrick J. Wong @ 2022-08-09 21:06 UTC (permalink / raw)
To: sandeen, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Every now and then I experience the following deadlock in xfs_repair
when I'm running the offline repair fuzz tests:
#0 futex_wait (private=0, expected=2, futex_word=0x55555566df70) at ../sysdeps/nptl/futex-internal.h:146
#1 __GI___lll_lock_wait (futex=futex@entry=0x55555566df70, private=0) at ./nptl/lowlevellock.c:49
#2 lll_mutex_lock_optimized (mutex=0x55555566df70) at ./nptl/pthread_mutex_lock.c:48
#3 ___pthread_mutex_lock (mutex=mutex@entry=0x55555566df70) at ./nptl/pthread_mutex_lock.c:93
#4 cache_shake (cache=cache@entry=0x55555566de60, priority=priority@entry=2, purge=purge@entry=false) at cache.c:231
#5 cache_node_get (cache=cache@entry=0x55555566de60, key=key@entry=0x7fffe55e01b0, nodep=nodep@entry=0x7fffe55e0168) at cache.c:452
#6 __cache_lookup (key=key@entry=0x7fffe55e01b0, flags=0, bpp=bpp@entry=0x7fffe55e0228) at rdwr.c:405
#7 libxfs_getbuf_flags (btp=0x55555566de00, blkno=0, len=<optimized out>, flags=<optimized out>, bpp=0x7fffe55e0228) at rdwr.c:457
#8 libxfs_buf_read_map (btp=0x55555566de00, map=map@entry=0x7fffe55e0280, nmaps=nmaps@entry=1, flags=flags@entry=0, bpp=bpp@entry=0x7fffe55e0278, ops=0x5555556233e0 <xfs_sb_buf_ops>)
at rdwr.c:704
#9 libxfs_buf_read (ops=<optimized out>, bpp=0x7fffe55e0278, flags=0, numblks=<optimized out>, blkno=0, target=<optimized out>)
at /storage/home/djwong/cdev/work/xfsprogs/build-x86_64/libxfs/libxfs_io.h:195
#10 libxfs_getsb (mp=mp@entry=0x7fffffffd690) at rdwr.c:162
#11 force_needsrepair (mp=0x7fffffffd690) at xfs_repair.c:924
#12 repair_capture_writeback (bp=<optimized out>) at xfs_repair.c:1000
#13 libxfs_bwrite (bp=0x7fffe011e530) at rdwr.c:869
#14 cache_shake (cache=cache@entry=0x55555566de60, priority=priority@entry=2, purge=purge@entry=false) at cache.c:240
#15 cache_node_get (cache=cache@entry=0x55555566de60, key=key@entry=0x7fffe55e0470, nodep=nodep@entry=0x7fffe55e0428) at cache.c:452
#16 __cache_lookup (key=key@entry=0x7fffe55e0470, flags=1, bpp=bpp@entry=0x7fffe55e0538) at rdwr.c:405
#17 libxfs_getbuf_flags (btp=0x55555566de00, blkno=12736, len=<optimized out>, flags=<optimized out>, bpp=0x7fffe55e0538) at rdwr.c:457
#18 __libxfs_buf_get_map (btp=<optimized out>, map=map@entry=0x7fffe55e05b0, nmaps=<optimized out>, flags=flags@entry=1, bpp=bpp@entry=0x7fffe55e0538) at rdwr.c:501
#19 libxfs_buf_get_map (btp=<optimized out>, map=map@entry=0x7fffe55e05b0, nmaps=<optimized out>, flags=flags@entry=1, bpp=bpp@entry=0x7fffe55e0538) at rdwr.c:525
#20 pf_queue_io (args=args@entry=0x5555556722c0, map=map@entry=0x7fffe55e05b0, nmaps=<optimized out>, flag=flag@entry=11) at prefetch.c:124
#21 pf_read_bmbt_reclist (args=0x5555556722c0, rp=<optimized out>, numrecs=78) at prefetch.c:220
#22 pf_scan_lbtree (dbno=dbno@entry=1211, level=level@entry=1, isadir=isadir@entry=1, args=args@entry=0x5555556722c0, func=0x55555557f240 <pf_scanfunc_bmap>) at prefetch.c:298
#23 pf_read_btinode (isadir=1, dino=<optimized out>, args=0x5555556722c0) at prefetch.c:385
#24 pf_read_inode_dirs (args=args@entry=0x5555556722c0, bp=bp@entry=0x7fffdc023790) at prefetch.c:459
#25 pf_read_inode_dirs (bp=<optimized out>, args=0x5555556722c0) at prefetch.c:411
#26 pf_batch_read (args=args@entry=0x5555556722c0, which=which@entry=PF_PRIMARY, buf=buf@entry=0x7fffd001d000) at prefetch.c:609
#27 pf_io_worker (param=0x5555556722c0) at prefetch.c:673
#28 start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#29 clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
From this stack trace, we see that xfs_repair's prefetch module is
getting some xfs_buf objects ahead of initiating a read (#19). The
buffer cache has hit its limit, so it calls cache_shake (#14) to free
some unused xfs_bufs. The buffer it finds is a dirty buffer, so it
calls libxfs_bwrite to flush it out to disk, which in turn invokes the
buffer write hook that xfs_repair set up in 3b7667cb to mark the ondisk
filesystem's superblock as NEEDSREPAIR until repair actually completes.
Unfortunately, the NEEDSREPAIR handler itself needs to grab the
superblock buffer, so it makes another call into the buffer cache (#9),
which sees that the cache is full and tries to shake it(#4). Hence we
deadlock on cm_mutex because shaking is not reentrant.
Fix this by retaining a reference to the superblock buffer when possible
so that the writeback hook doesn't have to access the buffer cache to
set NEEDSREPAIR.
Fixes: 3b7667cb ("xfs_repair: set NEEDSREPAIR the first time we write to a filesystem")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/libxfs_api_defs.h | 2 +
libxfs/libxfs_io.h | 1 +
libxfs/rdwr.c | 8 +++++
repair/phase2.c | 8 +++++
repair/protos.h | 1 +
repair/xfs_repair.c | 75 ++++++++++++++++++++++++++++++++++++++++------
6 files changed, 86 insertions(+), 9 deletions(-)
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 824f2c4d..7c59bd4b 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -53,9 +53,11 @@
#define xfs_buf_delwri_submit libxfs_buf_delwri_submit
#define xfs_buf_get libxfs_buf_get
#define xfs_buf_get_uncached libxfs_buf_get_uncached
+#define xfs_buf_lock libxfs_buf_lock
#define xfs_buf_read libxfs_buf_read
#define xfs_buf_read_uncached libxfs_buf_read_uncached
#define xfs_buf_relse libxfs_buf_relse
+#define xfs_buf_unlock libxfs_buf_unlock
#define xfs_bunmapi libxfs_bunmapi
#define xfs_bwrite libxfs_bwrite
#define xfs_calc_dquots_per_chunk libxfs_calc_dquots_per_chunk
diff --git a/libxfs/libxfs_io.h b/libxfs/libxfs_io.h
index 9c0e2704..fae86427 100644
--- a/libxfs/libxfs_io.h
+++ b/libxfs/libxfs_io.h
@@ -226,6 +226,7 @@ xfs_buf_hold(struct xfs_buf *bp)
}
void xfs_buf_lock(struct xfs_buf *bp);
+void xfs_buf_unlock(struct xfs_buf *bp);
int libxfs_buf_get_uncached(struct xfs_buftarg *targ, size_t bblen, int flags,
struct xfs_buf **bpp);
diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index fe69f9b4..61083dac 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -384,6 +384,14 @@ xfs_buf_lock(
pthread_mutex_lock(&bp->b_lock);
}
+void
+xfs_buf_unlock(
+ struct xfs_buf *bp)
+{
+ if (use_xfs_buf_lock)
+ pthread_mutex_unlock(&bp->b_lock);
+}
+
static int
__cache_lookup(
struct xfs_bufkey *key,
diff --git a/repair/phase2.c b/repair/phase2.c
index 56a39bb4..2ada95ae 100644
--- a/repair/phase2.c
+++ b/repair/phase2.c
@@ -370,6 +370,14 @@ phase2(
} else
do_log(_("Phase 2 - using internal log\n"));
+ /*
+ * Now that we've set up the buffer cache the way we want it, try to
+ * grab our own reference to the primary sb so that the hooks will not
+ * have to call out to the buffer cache.
+ */
+ if (mp->m_buf_writeback_fn)
+ retain_primary_sb(mp);
+
/* Zero log if applicable */
do_log(_(" - zero log...\n"));
diff --git a/repair/protos.h b/repair/protos.h
index 03ebae14..83e471ff 100644
--- a/repair/protos.h
+++ b/repair/protos.h
@@ -16,6 +16,7 @@ int get_sb(xfs_sb_t *sbp,
xfs_off_t off,
int size,
xfs_agnumber_t agno);
+int retain_primary_sb(struct xfs_mount *mp);
void write_primary_sb(xfs_sb_t *sbp,
int size);
diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c
index c94671d8..d46870cc 100644
--- a/repair/xfs_repair.c
+++ b/repair/xfs_repair.c
@@ -749,6 +749,63 @@ check_fs_vs_host_sectsize(
}
}
+/*
+ * If we set up a writeback function to set NEEDSREPAIR while the filesystem is
+ * dirty, there's a chance that calling libxfs_getsb could deadlock the buffer
+ * cache while trying to get the primary sb buffer if the first non-sb write to
+ * the filesystem is the result of a cache shake. Retain a reference to the
+ * primary sb buffer to avoid all that.
+ */
+static struct xfs_buf *primary_sb_bp; /* buffer for superblock */
+
+int
+retain_primary_sb(
+ struct xfs_mount *mp)
+{
+ int error;
+
+ error = -libxfs_buf_read(mp->m_ddev_targp, XFS_SB_DADDR,
+ XFS_FSS_TO_BB(mp, 1), 0, &primary_sb_bp,
+ &xfs_sb_buf_ops);
+ if (error)
+ return error;
+
+ libxfs_buf_unlock(primary_sb_bp);
+ return 0;
+}
+
+static void
+drop_primary_sb(void)
+{
+ if (!primary_sb_bp)
+ return;
+
+ libxfs_buf_lock(primary_sb_bp);
+ libxfs_buf_relse(primary_sb_bp);
+ primary_sb_bp = NULL;
+}
+
+static int
+get_primary_sb(
+ struct xfs_mount *mp,
+ struct xfs_buf **bpp)
+{
+ int error;
+
+ *bpp = NULL;
+
+ if (!primary_sb_bp) {
+ error = retain_primary_sb(mp);
+ if (error)
+ return error;
+ }
+
+ libxfs_buf_lock(primary_sb_bp);
+ xfs_buf_hold(primary_sb_bp);
+ *bpp = primary_sb_bp;
+ return 0;
+}
+
/* Clear needsrepair after a successful repair run. */
void
clear_needsrepair(
@@ -769,15 +826,14 @@ clear_needsrepair(
do_warn(
_("Cannot clear needsrepair due to flush failure, err=%d.\n"),
error);
- return;
+ goto drop;
}
/* Clear needsrepair from the superblock. */
- bp = libxfs_getsb(mp);
- if (!bp || bp->b_error) {
+ error = get_primary_sb(mp, &bp);
+ if (error) {
do_warn(
- _("Cannot clear needsrepair from primary super, err=%d.\n"),
- bp ? bp->b_error : ENOMEM);
+ _("Cannot clear needsrepair from primary super, err=%d.\n"), error);
} else {
mp->m_sb.sb_features_incompat &=
~XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR;
@@ -786,6 +842,8 @@ clear_needsrepair(
}
if (bp)
libxfs_buf_relse(bp);
+drop:
+ drop_primary_sb();
}
static void
@@ -808,11 +866,10 @@ force_needsrepair(
xfs_sb_version_needsrepair(&mp->m_sb))
return;
- bp = libxfs_getsb(mp);
- if (!bp || bp->b_error) {
+ error = get_primary_sb(mp, &bp);
+ if (error) {
do_log(
- _("couldn't get superblock to set needsrepair, err=%d\n"),
- bp ? bp->b_error : ENOMEM);
+ _("couldn't get superblock to set needsrepair, err=%d\n"), error);
} else {
/*
* It's possible that we need to set NEEDSREPAIR before we've
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] xfs_repair: fix printf format specifiers on 32-bit platforms
2022-08-09 21:06 ` [PATCH 1/2] xfs_repair: fix printf format specifiers on 32-bit platforms Darrick J. Wong
@ 2022-08-11 12:37 ` Christoph Hellwig
0 siblings, 0 replies; 8+ messages in thread
From: Christoph Hellwig @ 2022-08-11 12:37 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: sandeen, linux-xfs
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] xfs_repair: retain superblock buffer to avoid write hook deadlock
2022-08-09 21:06 ` [PATCH 2/2] xfs_repair: retain superblock buffer to avoid write hook deadlock Darrick J. Wong
@ 2022-08-11 12:47 ` Christoph Hellwig
2022-08-11 18:46 ` Darrick J. Wong
2022-08-11 22:15 ` Dave Chinner
1 sibling, 1 reply; 8+ messages in thread
From: Christoph Hellwig @ 2022-08-11 12:47 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: sandeen, linux-xfs
Maybe we just simply need to set NEEDSREPAIR for any run that does
not specify the no-modify flag and avoid this magic lazy behavior?
That being said the code looks sane if we can't fix this better by
just working differently.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] xfs_repair: retain superblock buffer to avoid write hook deadlock
2022-08-11 12:47 ` Christoph Hellwig
@ 2022-08-11 18:46 ` Darrick J. Wong
0 siblings, 0 replies; 8+ messages in thread
From: Darrick J. Wong @ 2022-08-11 18:46 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: sandeen, linux-xfs
On Thu, Aug 11, 2022 at 05:47:26AM -0700, Christoph Hellwig wrote:
> Maybe we just simply need to set NEEDSREPAIR for any run that does
> not specify the no-modify flag and avoid this magic lazy behavior?
Heh, which part of the magic lazy behavior? You asked for the bwrite
hook[1], and then Brian asked for a randomly triggered hook[2] in the
buffer cache IO path to enable testing, which now results in periodic
failures in xfs/155...
[1] https://lore.kernel.org/linux-xfs/20210209091336.GG1718132@infradead.org/
[2] https://lore.kernel.org/linux-xfs/20210212133503.GA321056@bfoster/
> That being said the code looks sane if we can't fix this better by
> just working differently.
There are too many patches in my tree for me to be able to take on more
refactoring.
--D
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] xfs_repair: retain superblock buffer to avoid write hook deadlock
2022-08-09 21:06 ` [PATCH 2/2] xfs_repair: retain superblock buffer to avoid write hook deadlock Darrick J. Wong
2022-08-11 12:47 ` Christoph Hellwig
@ 2022-08-11 22:15 ` Dave Chinner
2022-08-16 2:12 ` Darrick J. Wong
1 sibling, 1 reply; 8+ messages in thread
From: Dave Chinner @ 2022-08-11 22:15 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: sandeen, linux-xfs
On Tue, Aug 09, 2022 at 02:06:57PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Every now and then I experience the following deadlock in xfs_repair
> when I'm running the offline repair fuzz tests:
>
> #0 futex_wait (private=0, expected=2, futex_word=0x55555566df70) at ../sysdeps/nptl/futex-internal.h:146
> #1 __GI___lll_lock_wait (futex=futex@entry=0x55555566df70, private=0) at ./nptl/lowlevellock.c:49
> #2 lll_mutex_lock_optimized (mutex=0x55555566df70) at ./nptl/pthread_mutex_lock.c:48
> #3 ___pthread_mutex_lock (mutex=mutex@entry=0x55555566df70) at ./nptl/pthread_mutex_lock.c:93
> #4 cache_shake (cache=cache@entry=0x55555566de60, priority=priority@entry=2, purge=purge@entry=false) at cache.c:231
> #5 cache_node_get (cache=cache@entry=0x55555566de60, key=key@entry=0x7fffe55e01b0, nodep=nodep@entry=0x7fffe55e0168) at cache.c:452
> #6 __cache_lookup (key=key@entry=0x7fffe55e01b0, flags=0, bpp=bpp@entry=0x7fffe55e0228) at rdwr.c:405
> #7 libxfs_getbuf_flags (btp=0x55555566de00, blkno=0, len=<optimized out>, flags=<optimized out>, bpp=0x7fffe55e0228) at rdwr.c:457
> #8 libxfs_buf_read_map (btp=0x55555566de00, map=map@entry=0x7fffe55e0280, nmaps=nmaps@entry=1, flags=flags@entry=0, bpp=bpp@entry=0x7fffe55e0278, ops=0x5555556233e0 <xfs_sb_buf_ops>)
> at rdwr.c:704
> #9 libxfs_buf_read (ops=<optimized out>, bpp=0x7fffe55e0278, flags=0, numblks=<optimized out>, blkno=0, target=<optimized out>)
> at /storage/home/djwong/cdev/work/xfsprogs/build-x86_64/libxfs/libxfs_io.h:195
> #10 libxfs_getsb (mp=mp@entry=0x7fffffffd690) at rdwr.c:162
> #11 force_needsrepair (mp=0x7fffffffd690) at xfs_repair.c:924
> #12 repair_capture_writeback (bp=<optimized out>) at xfs_repair.c:1000
> #13 libxfs_bwrite (bp=0x7fffe011e530) at rdwr.c:869
> #14 cache_shake (cache=cache@entry=0x55555566de60, priority=priority@entry=2, purge=purge@entry=false) at cache.c:240
> #15 cache_node_get (cache=cache@entry=0x55555566de60, key=key@entry=0x7fffe55e0470, nodep=nodep@entry=0x7fffe55e0428) at cache.c:452
> #16 __cache_lookup (key=key@entry=0x7fffe55e0470, flags=1, bpp=bpp@entry=0x7fffe55e0538) at rdwr.c:405
> #17 libxfs_getbuf_flags (btp=0x55555566de00, blkno=12736, len=<optimized out>, flags=<optimized out>, bpp=0x7fffe55e0538) at rdwr.c:457
> #18 __libxfs_buf_get_map (btp=<optimized out>, map=map@entry=0x7fffe55e05b0, nmaps=<optimized out>, flags=flags@entry=1, bpp=bpp@entry=0x7fffe55e0538) at rdwr.c:501
> #19 libxfs_buf_get_map (btp=<optimized out>, map=map@entry=0x7fffe55e05b0, nmaps=<optimized out>, flags=flags@entry=1, bpp=bpp@entry=0x7fffe55e0538) at rdwr.c:525
> #20 pf_queue_io (args=args@entry=0x5555556722c0, map=map@entry=0x7fffe55e05b0, nmaps=<optimized out>, flag=flag@entry=11) at prefetch.c:124
> #21 pf_read_bmbt_reclist (args=0x5555556722c0, rp=<optimized out>, numrecs=78) at prefetch.c:220
> #22 pf_scan_lbtree (dbno=dbno@entry=1211, level=level@entry=1, isadir=isadir@entry=1, args=args@entry=0x5555556722c0, func=0x55555557f240 <pf_scanfunc_bmap>) at prefetch.c:298
> #23 pf_read_btinode (isadir=1, dino=<optimized out>, args=0x5555556722c0) at prefetch.c:385
> #24 pf_read_inode_dirs (args=args@entry=0x5555556722c0, bp=bp@entry=0x7fffdc023790) at prefetch.c:459
> #25 pf_read_inode_dirs (bp=<optimized out>, args=0x5555556722c0) at prefetch.c:411
> #26 pf_batch_read (args=args@entry=0x5555556722c0, which=which@entry=PF_PRIMARY, buf=buf@entry=0x7fffd001d000) at prefetch.c:609
> #27 pf_io_worker (param=0x5555556722c0) at prefetch.c:673
> #28 start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
> #29 clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
>
> From this stack trace, we see that xfs_repair's prefetch module is
> getting some xfs_buf objects ahead of initiating a read (#19). The
> buffer cache has hit its limit, so it calls cache_shake (#14) to free
> some unused xfs_bufs. The buffer it finds is a dirty buffer, so it
> calls libxfs_bwrite to flush it out to disk, which in turn invokes the
> buffer write hook that xfs_repair set up in 3b7667cb to mark the ondisk
> filesystem's superblock as NEEDSREPAIR until repair actually completes.
>
> Unfortunately, the NEEDSREPAIR handler itself needs to grab the
> superblock buffer, so it makes another call into the buffer cache (#9),
> which sees that the cache is full and tries to shake it(#4). Hence we
> deadlock on cm_mutex because shaking is not reentrant.
>
> Fix this by retaining a reference to the superblock buffer when possible
> so that the writeback hook doesn't have to access the buffer cache to
> set NEEDSREPAIR.
If we are going to "retain" a permanent reference to the superblock
buffer, can we just do it the same way as the kernel does at mount
time? i.e. do this for every xfs_mount instance via an uncached
buffer, and attach it to mp->m_sb_bp so that the
superblock can be grabbed at any time in any context without needing
to hit the buffer cache?
If we've got code that exists to do this in a generic manner that
brings userspace closer to kernel behaviour, then that's what we
should use rather than create a special one-off implementation for a
single userspace binary...
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] xfs_repair: retain superblock buffer to avoid write hook deadlock
2022-08-11 22:15 ` Dave Chinner
@ 2022-08-16 2:12 ` Darrick J. Wong
0 siblings, 0 replies; 8+ messages in thread
From: Darrick J. Wong @ 2022-08-16 2:12 UTC (permalink / raw)
To: Dave Chinner; +Cc: sandeen, linux-xfs
On Fri, Aug 12, 2022 at 08:15:41AM +1000, Dave Chinner wrote:
> On Tue, Aug 09, 2022 at 02:06:57PM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Every now and then I experience the following deadlock in xfs_repair
> > when I'm running the offline repair fuzz tests:
> >
> > #0 futex_wait (private=0, expected=2, futex_word=0x55555566df70) at ../sysdeps/nptl/futex-internal.h:146
> > #1 __GI___lll_lock_wait (futex=futex@entry=0x55555566df70, private=0) at ./nptl/lowlevellock.c:49
> > #2 lll_mutex_lock_optimized (mutex=0x55555566df70) at ./nptl/pthread_mutex_lock.c:48
> > #3 ___pthread_mutex_lock (mutex=mutex@entry=0x55555566df70) at ./nptl/pthread_mutex_lock.c:93
> > #4 cache_shake (cache=cache@entry=0x55555566de60, priority=priority@entry=2, purge=purge@entry=false) at cache.c:231
> > #5 cache_node_get (cache=cache@entry=0x55555566de60, key=key@entry=0x7fffe55e01b0, nodep=nodep@entry=0x7fffe55e0168) at cache.c:452
> > #6 __cache_lookup (key=key@entry=0x7fffe55e01b0, flags=0, bpp=bpp@entry=0x7fffe55e0228) at rdwr.c:405
> > #7 libxfs_getbuf_flags (btp=0x55555566de00, blkno=0, len=<optimized out>, flags=<optimized out>, bpp=0x7fffe55e0228) at rdwr.c:457
> > #8 libxfs_buf_read_map (btp=0x55555566de00, map=map@entry=0x7fffe55e0280, nmaps=nmaps@entry=1, flags=flags@entry=0, bpp=bpp@entry=0x7fffe55e0278, ops=0x5555556233e0 <xfs_sb_buf_ops>)
> > at rdwr.c:704
> > #9 libxfs_buf_read (ops=<optimized out>, bpp=0x7fffe55e0278, flags=0, numblks=<optimized out>, blkno=0, target=<optimized out>)
> > at /storage/home/djwong/cdev/work/xfsprogs/build-x86_64/libxfs/libxfs_io.h:195
> > #10 libxfs_getsb (mp=mp@entry=0x7fffffffd690) at rdwr.c:162
> > #11 force_needsrepair (mp=0x7fffffffd690) at xfs_repair.c:924
> > #12 repair_capture_writeback (bp=<optimized out>) at xfs_repair.c:1000
> > #13 libxfs_bwrite (bp=0x7fffe011e530) at rdwr.c:869
> > #14 cache_shake (cache=cache@entry=0x55555566de60, priority=priority@entry=2, purge=purge@entry=false) at cache.c:240
> > #15 cache_node_get (cache=cache@entry=0x55555566de60, key=key@entry=0x7fffe55e0470, nodep=nodep@entry=0x7fffe55e0428) at cache.c:452
> > #16 __cache_lookup (key=key@entry=0x7fffe55e0470, flags=1, bpp=bpp@entry=0x7fffe55e0538) at rdwr.c:405
> > #17 libxfs_getbuf_flags (btp=0x55555566de00, blkno=12736, len=<optimized out>, flags=<optimized out>, bpp=0x7fffe55e0538) at rdwr.c:457
> > #18 __libxfs_buf_get_map (btp=<optimized out>, map=map@entry=0x7fffe55e05b0, nmaps=<optimized out>, flags=flags@entry=1, bpp=bpp@entry=0x7fffe55e0538) at rdwr.c:501
> > #19 libxfs_buf_get_map (btp=<optimized out>, map=map@entry=0x7fffe55e05b0, nmaps=<optimized out>, flags=flags@entry=1, bpp=bpp@entry=0x7fffe55e0538) at rdwr.c:525
> > #20 pf_queue_io (args=args@entry=0x5555556722c0, map=map@entry=0x7fffe55e05b0, nmaps=<optimized out>, flag=flag@entry=11) at prefetch.c:124
> > #21 pf_read_bmbt_reclist (args=0x5555556722c0, rp=<optimized out>, numrecs=78) at prefetch.c:220
> > #22 pf_scan_lbtree (dbno=dbno@entry=1211, level=level@entry=1, isadir=isadir@entry=1, args=args@entry=0x5555556722c0, func=0x55555557f240 <pf_scanfunc_bmap>) at prefetch.c:298
> > #23 pf_read_btinode (isadir=1, dino=<optimized out>, args=0x5555556722c0) at prefetch.c:385
> > #24 pf_read_inode_dirs (args=args@entry=0x5555556722c0, bp=bp@entry=0x7fffdc023790) at prefetch.c:459
> > #25 pf_read_inode_dirs (bp=<optimized out>, args=0x5555556722c0) at prefetch.c:411
> > #26 pf_batch_read (args=args@entry=0x5555556722c0, which=which@entry=PF_PRIMARY, buf=buf@entry=0x7fffd001d000) at prefetch.c:609
> > #27 pf_io_worker (param=0x5555556722c0) at prefetch.c:673
> > #28 start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
> > #29 clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
> >
> > From this stack trace, we see that xfs_repair's prefetch module is
> > getting some xfs_buf objects ahead of initiating a read (#19). The
> > buffer cache has hit its limit, so it calls cache_shake (#14) to free
> > some unused xfs_bufs. The buffer it finds is a dirty buffer, so it
> > calls libxfs_bwrite to flush it out to disk, which in turn invokes the
> > buffer write hook that xfs_repair set up in 3b7667cb to mark the ondisk
> > filesystem's superblock as NEEDSREPAIR until repair actually completes.
> >
> > Unfortunately, the NEEDSREPAIR handler itself needs to grab the
> > superblock buffer, so it makes another call into the buffer cache (#9),
> > which sees that the cache is full and tries to shake it(#4). Hence we
> > deadlock on cm_mutex because shaking is not reentrant.
> >
> > Fix this by retaining a reference to the superblock buffer when possible
> > so that the writeback hook doesn't have to access the buffer cache to
> > set NEEDSREPAIR.
>
> If we are going to "retain" a permanent reference to the superblock
> buffer, can we just do it the same way as the kernel does at mount
> time? i.e. do this for every xfs_mount instance via an uncached
> buffer, and attach it to mp->m_sb_bp so that the
> superblock can be grabbed at any time in any context without needing
> to hit the buffer cache?
That was the first method that I tried, and promptly ran into all sorts
of weird issues, such (a) figuring out that someone's calling
libxfs_mount with no devices open so that it can compute something, and
(b) xfs_repair deciding to resize the buffer cache prior to phase 2.
That seemed like a whole lot of extra complexity to enable *one* use
case in one program while I was trying to help Eric get 5.19 out.
(Frankly, I'm already rather annoyed at the scope creep of NEEDSREPAIR,
and now it's creeping even more...)
> If we've got code that exists to do this in a generic manner that
> brings userspace closer to kernel behaviour, then that's what we
> should use rather than create a special one-off implementation for a
> single userspace binary...
I'd rather focus on getting through online repair's design review than
this, although given how sh*t email is, I have no idea if you (Dave)
stopped after patch 4 or if further replies simply got eaten.
--D
>
> Cheers,
>
> Dave.
> --
> Dave Chinner
> david@fromorbit.com
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2022-08-16 6:55 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-08-09 21:06 [PATCHSET v2 0/2] xfsprogs: random fixes for 5.19 Darrick J. Wong
2022-08-09 21:06 ` [PATCH 1/2] xfs_repair: fix printf format specifiers on 32-bit platforms Darrick J. Wong
2022-08-11 12:37 ` Christoph Hellwig
2022-08-09 21:06 ` [PATCH 2/2] xfs_repair: retain superblock buffer to avoid write hook deadlock Darrick J. Wong
2022-08-11 12:47 ` Christoph Hellwig
2022-08-11 18:46 ` Darrick J. Wong
2022-08-11 22:15 ` Dave Chinner
2022-08-16 2:12 ` Darrick J. Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox