Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 294c7a9f authored by Ben Hutchings's avatar Ben Hutchings Committed by Greg Kroah-Hartman
Browse files

mips,s390,sh,sparc: gup: Work around the "COW can break either way" issue



In Linux 4.14 and 4.19 these architectures still have their own
implementations of get_user_pages_fast().  These also need to force
the write flag on when taking the fast path.

Fixes: 407faed92b4a ("gup: document and work around "COW can break either way" issue")
Fixes: 5e240297 ("gup: document and work around "COW can break either way" issue")
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 1550a97e
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -274,7 +274,14 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
		next = pgd_addr_end(addr, end);
		if (pgd_none(pgd))
			goto slow;
		if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
		/*
		 * The FAST_GUP case requires FOLL_WRITE even for pure reads,
		 * because get_user_pages() may need to cause an early COW in
		 * order to avoid confusing the normal COW routines. So only
		 * targets that are already writable are safe to do by just
		 * looking at the page tables.
		 */
		if (!gup_pud_range(pgd, addr, next, 1, pages, &nr))
			goto slow;
	} while (pgdp++, addr = next, addr != end);
	local_irq_enable();
+8 −1
Original line number Diff line number Diff line
@@ -287,7 +287,14 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,

	might_sleep();
	start &= PAGE_MASK;
	nr = __get_user_pages_fast(start, nr_pages, write, pages);
	/*
	 * The FAST_GUP case requires FOLL_WRITE even for pure reads,
	 * because get_user_pages() may need to cause an early COW in
	 * order to avoid confusing the normal COW routines. So only
	 * targets that are already writable are safe to do by just
	 * looking at the page tables.
	 */
	nr = __get_user_pages_fast(start, nr_pages, 1, pages);
	if (nr == nr_pages)
		return nr;

+8 −1
Original line number Diff line number Diff line
@@ -242,7 +242,14 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
		next = pgd_addr_end(addr, end);
		if (pgd_none(pgd))
			goto slow;
		if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
		/*
		 * The FAST_GUP case requires FOLL_WRITE even for pure reads,
		 * because get_user_pages() may need to cause an early COW in
		 * order to avoid confusing the normal COW routines. So only
		 * targets that are already writable are safe to do by just
		 * looking at the page tables.
		 */
		if (!gup_pud_range(pgd, addr, next, 1, pages, &nr))
			goto slow;
	} while (pgdp++, addr = next, addr != end);
	local_irq_enable();
+8 −1
Original line number Diff line number Diff line
@@ -303,7 +303,14 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
		next = pgd_addr_end(addr, end);
		if (pgd_none(pgd))
			goto slow;
		if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
		/*
		 * The FAST_GUP case requires FOLL_WRITE even for pure reads,
		 * because get_user_pages() may need to cause an early COW in
		 * order to avoid confusing the normal COW routines. So only
		 * targets that are already writable are safe to do by just
		 * looking at the page tables.
		 */
		if (!gup_pud_range(pgd, addr, next, 1, pages, &nr))
			goto slow;
	} while (pgdp++, addr = next, addr != end);