Thread (34 messages) 34 messages, 6 authors, 2021-11-29

Re: [PATCH 3/3] btrfs: Avoid live-lock in search_ioctl() on hardware with sub-page faults

From: Catalin Marinas <catalin.marinas@arm.com>
Date: 2021-11-25 21:31:08
Also in: linux-btrfs, linux-fsdevel, lkml

On Thu, Nov 25, 2021 at 09:02:29PM +0000, Matthew Wilcox wrote:
quoted hunk ↗ jump to hunk
On Thu, Nov 25, 2021 at 08:43:57PM +0000, Catalin Marinas wrote:
quoted
quoted
I really believe that the fix is to make the read/write probing just
be more aggressive.

Make the read/write probing require that AT LEAST <n> bytes be
readable/writable at the beginning, where 'n' is 'min(len,ALIGN)', and
ALIGN is whatever size that copy_from/to_user_xyz() might require just
because it might do multi-byte accesses.

In fact, make ALIGN be perhaps something reasonable like 512 bytes or
whatever, and then you know you can handle the btrfs "copy a whole
structure and reset if that fails" case too.
IIUC what you are suggesting, we still need changes to the btrfs loop
similar to willy's but that should work fine together with a slightly
more aggressive fault_in_writable().

A probing of at least sizeof(struct btrfs_ioctl_search_key) should
suffice without any loop changes and 512 would cover it but it doesn't
look generic enough. We could pass a 'probe_prefix' argument to
fault_in_exact_writeable() to only probe this and btrfs would just
specify the above sizeof().
How about something like this?
+++ b/mm/gup.c
@@ -1672,6 +1672,13 @@ size_t fault_in_writeable(char __user *uaddr, size_t size)

        if (unlikely(size == 0))
                return 0;
+       if (SUBPAGE_PROBE_INTERVAL) {
+               while (uaddr < PAGE_ALIGN((unsigned long)uaddr)) {
+                       if (unlikely(__put_user(0, uaddr) != 0))
+                               goto out;
+                       uaddr += SUBPAGE_PROBE_INTERVAL;
+               }
+       }
        if (!PAGE_ALIGNED(uaddr)) {
                if (unlikely(__put_user(0, uaddr) != 0))
                        return size;
ARM then defines SUBPAGE_PROBE_INTERVAL to be 16 and the rest of us
leave it as 0.  That way we probe all the way to the end of the current
page and the start of the next page.
It doesn't help if the copy_to_user() fault happens 16 bytes into the
second page for example. The fault_in() passes, copy_to_user() fails and
the loop restarts from the same place. With sub-page faults, the page
boundary doesn't have any relevance. We want to probe the beginning of
the buffer that's at least as big as the loop rewind size even if it
goes past a page boundary.

-- 
Catalin

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help