Skip to content

Commit c03098d

Browse files
committed
Merge tag 'gfs2-v5.15-rc5-mmap-fault' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2
Pull gfs2 mmap + page fault deadlocks fixes from Andreas Gruenbacher: "Functions gfs2_file_read_iter and gfs2_file_write_iter are both accessing the user buffer to write to or read from while holding the inode glock. In the most basic deadlock scenario, that buffer will not be resident and it will be mapped to the same file. Accessing the buffer will trigger a page fault, and gfs2 will deadlock trying to take the same inode glock again while trying to handle that fault. Fix that and similar, more complex scenarios by disabling page faults while accessing user buffers. To make this work, introduce a small amount of new infrastructure and fix some bugs that didn't trigger so far, with page faults enabled" * tag 'gfs2-v5.15-rc5-mmap-fault' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: gfs2: Fix mmap + page fault deadlocks for direct I/O iov_iter: Introduce nofault flag to disable page faults gup: Introduce FOLL_NOFAULT flag to disable page faults iomap: Add done_before argument to iomap_dio_rw iomap: Support partial direct I/O on user copy failures iomap: Fix iomap_dio_rw return value for user copies gfs2: Fix mmap + page fault deadlocks for buffered I/O gfs2: Eliminate ip->i_gh gfs2: Move the inode glock locking to gfs2_file_buffered_write gfs2: Introduce flag for glock holder auto-demotion gfs2: Clean up function may_grant gfs2: Add wrapper for iomap_file_buffered_write iov_iter: Introduce fault_in_iov_iter_writeable iov_iter: Turn iov_iter_fault_in_readable into fault_in_iov_iter_readable gup: Turn fault_in_pages_{readable,writeable} into fault_in_{readable,writeable} powerpc/kvm: Fix kvm_use_magic_page iov_iter: Fix iov_iter_get_pages{,_alloc} page fault return value
2 parents ab2e7f4 + b01b2d7 commit c03098d

File tree

29 files changed

+791
-283
lines changed

29 files changed

+791
-283
lines changed

arch/powerpc/kernel/kvm.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,8 @@ static void __init kvm_use_magic_page(void)
669669
on_each_cpu(kvm_map_magic_page, &features, 1);
670670

671671
/* Quick self-test to see if the mapping works */
672-
if (!fault_in_pages_readable((const char *)KVM_MAGIC_PAGE, sizeof(u32))) {
672+
if (fault_in_readable((const char __user *)KVM_MAGIC_PAGE,
673+
sizeof(u32))) {
673674
kvm_patching_worked = false;
674675
return;
675676
}

arch/powerpc/kernel/signal_32.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,7 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,
10481048
if (new_ctx == NULL)
10491049
return 0;
10501050
if (!access_ok(new_ctx, ctx_size) ||
1051-
fault_in_pages_readable((u8 __user *)new_ctx, ctx_size))
1051+
fault_in_readable((char __user *)new_ctx, ctx_size))
10521052
return -EFAULT;
10531053

10541054
/*
@@ -1237,7 +1237,7 @@ SYSCALL_DEFINE3(debug_setcontext, struct ucontext __user *, ctx,
12371237
#endif
12381238

12391239
if (!access_ok(ctx, sizeof(*ctx)) ||
1240-
fault_in_pages_readable((u8 __user *)ctx, sizeof(*ctx)))
1240+
fault_in_readable((char __user *)ctx, sizeof(*ctx)))
12411241
return -EFAULT;
12421242

12431243
/*

arch/powerpc/kernel/signal_64.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ SYSCALL_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,
688688
if (new_ctx == NULL)
689689
return 0;
690690
if (!access_ok(new_ctx, ctx_size) ||
691-
fault_in_pages_readable((u8 __user *)new_ctx, ctx_size))
691+
fault_in_readable((char __user *)new_ctx, ctx_size))
692692
return -EFAULT;
693693

694694
/*

arch/x86/kernel/fpu/signal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ static bool restore_fpregs_from_user(void __user *buf, u64 xrestore,
309309
if (ret != X86_TRAP_PF)
310310
return false;
311311

312-
if (!fault_in_pages_readable(buf, size))
312+
if (!fault_in_readable(buf, size))
313313
goto retry;
314314
return false;
315315
}

drivers/gpu/drm/armada/armada_gem.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ int armada_gem_pwrite_ioctl(struct drm_device *dev, void *data,
336336
struct drm_armada_gem_pwrite *args = data;
337337
struct armada_gem_object *dobj;
338338
char __user *ptr;
339-
int ret;
339+
int ret = 0;
340340

341341
DRM_DEBUG_DRIVER("handle %u off %u size %u ptr 0x%llx\n",
342342
args->handle, args->offset, args->size, args->ptr);
@@ -349,9 +349,8 @@ int armada_gem_pwrite_ioctl(struct drm_device *dev, void *data,
349349
if (!access_ok(ptr, args->size))
350350
return -EFAULT;
351351

352-
ret = fault_in_pages_readable(ptr, args->size);
353-
if (ret)
354-
return ret;
352+
if (fault_in_readable(ptr, args->size))
353+
return -EFAULT;
355354

356355
dobj = armada_gem_object_lookup(file, args->handle);
357356
if (dobj == NULL)

fs/btrfs/file.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,7 +1718,7 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
17181718
* Fault pages before locking them in prepare_pages
17191719
* to avoid recursive lock
17201720
*/
1721-
if (unlikely(iov_iter_fault_in_readable(i, write_bytes))) {
1721+
if (unlikely(fault_in_iov_iter_readable(i, write_bytes))) {
17221722
ret = -EFAULT;
17231723
break;
17241724
}
@@ -1965,7 +1965,7 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
19651965
}
19661966

19671967
dio = __iomap_dio_rw(iocb, from, &btrfs_dio_iomap_ops, &btrfs_dio_ops,
1968-
0);
1968+
0, 0);
19691969

19701970
btrfs_inode_unlock(inode, ilock_flags);
19711971

@@ -3668,7 +3668,8 @@ static ssize_t btrfs_direct_read(struct kiocb *iocb, struct iov_iter *to)
36683668
return 0;
36693669

36703670
btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED);
3671-
ret = iomap_dio_rw(iocb, to, &btrfs_dio_iomap_ops, &btrfs_dio_ops, 0);
3671+
ret = iomap_dio_rw(iocb, to, &btrfs_dio_iomap_ops, &btrfs_dio_ops,
3672+
0, 0);
36723673
btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
36733674
return ret;
36743675
}

fs/btrfs/ioctl.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2222,9 +2222,8 @@ static noinline int search_ioctl(struct inode *inode,
22222222
key.offset = sk->min_offset;
22232223

22242224
while (1) {
2225-
ret = fault_in_pages_writeable(ubuf + sk_offset,
2226-
*buf_size - sk_offset);
2227-
if (ret)
2225+
ret = -EFAULT;
2226+
if (fault_in_writeable(ubuf + sk_offset, *buf_size - sk_offset))
22282227
break;
22292228

22302229
ret = btrfs_search_forward(root, &key, path, sk->min_transid);

fs/erofs/data.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
334334

335335
if (!err)
336336
return iomap_dio_rw(iocb, to, &erofs_iomap_ops,
337-
NULL, 0);
337+
NULL, 0, 0);
338338
if (err < 0)
339339
return err;
340340
}

fs/ext4/file.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ static ssize_t ext4_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
7474
return generic_file_read_iter(iocb, to);
7575
}
7676

77-
ret = iomap_dio_rw(iocb, to, &ext4_iomap_ops, NULL, 0);
77+
ret = iomap_dio_rw(iocb, to, &ext4_iomap_ops, NULL, 0, 0);
7878
inode_unlock_shared(inode);
7979

8080
file_accessed(iocb->ki_filp);
@@ -566,7 +566,8 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
566566
if (ilock_shared)
567567
iomap_ops = &ext4_iomap_overwrite_ops;
568568
ret = iomap_dio_rw(iocb, from, iomap_ops, &ext4_dio_write_ops,
569-
(unaligned_io || extend) ? IOMAP_DIO_FORCE_WAIT : 0);
569+
(unaligned_io || extend) ? IOMAP_DIO_FORCE_WAIT : 0,
570+
0);
570571
if (ret == -ENOTBLK)
571572
ret = 0;
572573

fs/f2fs/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4276,7 +4276,7 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
42764276
size_t target_size = 0;
42774277
int err;
42784278

4279-
if (iov_iter_fault_in_readable(from, iov_iter_count(from)))
4279+
if (fault_in_iov_iter_readable(from, iov_iter_count(from)))
42804280
set_inode_flag(inode, FI_NO_PREALLOC);
42814281

42824282
if ((iocb->ki_flags & IOCB_NOWAIT)) {

0 commit comments

Comments
 (0)