mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-25 03:37:45 +03:00
arc: avoid possible deadlock in arc_read
In l2arc_evict(), the config lock may be acquired in reverse order (e.g., first the config lock (writer), then a hash lock) unlike in arc_read() during scenarios like L2ARC device removal. To avoid deadlocks, if the attempt to acquire the config lock (reader) fails in arc_read(), release the hash lock, wait for the config lock, and retry from the beginning. Reviewed-by: Alexander Motin <mav@FreeBSD.org> Signed-off-by: Ameer Hamza <ahamza@ixsystems.com> Closes #17071
This commit is contained in:
+12
-7
@@ -1164,7 +1164,7 @@ zfs_blkptr_verify_log(spa_t *spa, const blkptr_t *bp,
|
||||
* it only contains known object types, checksum/compression identifiers,
|
||||
* block sizes within the maximum allowed limits, valid DVAs, etc.
|
||||
*
|
||||
* If everything checks out B_TRUE is returned. The zfs_blkptr_verify
|
||||
* If everything checks out 0 is returned. The zfs_blkptr_verify
|
||||
* argument controls the behavior when an invalid field is detected.
|
||||
*
|
||||
* Values for blk_verify_flag:
|
||||
@@ -1179,7 +1179,7 @@ zfs_blkptr_verify_log(spa_t *spa, const blkptr_t *bp,
|
||||
* BLK_CONFIG_SKIP: skip checks which require SCL_VDEV, for better
|
||||
* performance
|
||||
*/
|
||||
boolean_t
|
||||
int
|
||||
zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp,
|
||||
enum blk_config_flag blk_config, enum blk_verify_flag blk_verify)
|
||||
{
|
||||
@@ -1211,7 +1211,7 @@ zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp,
|
||||
"blkptr at %px has invalid PSIZE %llu",
|
||||
bp, (longlong_t)BPE_GET_PSIZE(bp));
|
||||
}
|
||||
return (errors == 0);
|
||||
return (errors ? ECKSUM : 0);
|
||||
}
|
||||
if (unlikely(BP_GET_CHECKSUM(bp) >= ZIO_CHECKSUM_FUNCTIONS)) {
|
||||
errors += zfs_blkptr_verify_log(spa, bp, blk_verify,
|
||||
@@ -1229,7 +1229,7 @@ zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp,
|
||||
* will be done once the zio is executed in vdev_mirror_map_alloc.
|
||||
*/
|
||||
if (unlikely(!spa->spa_trust_config))
|
||||
return (errors == 0);
|
||||
return (errors ? ECKSUM : 0);
|
||||
|
||||
switch (blk_config) {
|
||||
case BLK_CONFIG_HELD:
|
||||
@@ -1238,8 +1238,12 @@ zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp,
|
||||
case BLK_CONFIG_NEEDED:
|
||||
spa_config_enter(spa, SCL_VDEV, bp, RW_READER);
|
||||
break;
|
||||
case BLK_CONFIG_NEEDED_TRY:
|
||||
if (!spa_config_tryenter(spa, SCL_VDEV, bp, RW_READER))
|
||||
return (EBUSY);
|
||||
break;
|
||||
case BLK_CONFIG_SKIP:
|
||||
return (errors == 0);
|
||||
return (errors ? ECKSUM : 0);
|
||||
default:
|
||||
panic("invalid blk_config %u", blk_config);
|
||||
}
|
||||
@@ -1294,10 +1298,11 @@ zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp,
|
||||
bp, i, (longlong_t)offset);
|
||||
}
|
||||
}
|
||||
if (blk_config == BLK_CONFIG_NEEDED)
|
||||
if (blk_config == BLK_CONFIG_NEEDED || blk_config ==
|
||||
BLK_CONFIG_NEEDED_TRY)
|
||||
spa_config_exit(spa, SCL_VDEV, bp);
|
||||
|
||||
return (errors == 0);
|
||||
return (errors ? ECKSUM : 0);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
|
||||
Reference in New Issue
Block a user