Skip to content

Commit

Permalink
Fix a deadlock in the FreeBSD getpages VOP
Browse files Browse the repository at this point in the history
FreeBSD has a per-page "busy" lock which is held when handling a page
fault on a mapped file.  This lock is also acquired when copying data
from the DMU to the page cache in zfs_write().  File range locks are
also acquired in both of these paths, in the opposite order with respect
to the busy lock.

In the getpages VOP, the range lock is only used to determine the extent
of optional read-ahead and read-behind operations.  To resolve the lock
order reversal, modify the getpages VOP to avoid blocking on the range
lock.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Ryan Moeller <ryan@ixsystems.com>
Signed-off-by: Mark Johnston <markj@FreeBSD.org>
Closes #10519
  • Loading branch information
markjdb authored and behlendorf committed Jul 6, 2020
1 parent 6e00561 commit cd32b4f
Showing 1 changed file with 12 additions and 1 deletion.
13 changes: 12 additions & 1 deletion module/os/freebsd/zfs/zfs_vnops.c
Expand Up @@ -4809,9 +4809,20 @@ zfs_getpages(struct vnode *vp, vm_page_t *ma, int count, int *rbehind,
*/
for (;;) {
blksz = zp->z_blksz;
lr = zfs_rangelock_enter(&zp->z_rangelock,
lr = zfs_rangelock_tryenter(&zp->z_rangelock,
rounddown(start, blksz),
roundup(end, blksz) - rounddown(start, blksz), RL_READER);
if (lr == NULL) {
if (rahead != NULL) {
*rahead = 0;
rahead = NULL;
}
if (rbehind != NULL) {
*rbehind = 0;
rbehind = NULL;
}
break;
}
if (blksz == zp->z_blksz)
break;
zfs_rangelock_exit(lr);
Expand Down

0 comments on commit cd32b4f

Please sign in to comment.