Skip to content

Commit 799c105

Browse files
committed
De-pessimize rds_page_copy_user
Don't try to "optimize" rds_page_copy_user() by using kmap_atomic() and the unsafe atomic user mode accessor functions. It's actually slower than the straightforward code on any reasonable modern CPU. Back when the code was written (although probably not by the time it was actually merged, though), 32-bit x86 may have been the dominant architecture. And there kmap_atomic() can be a lot faster than kmap() (unless you have very good locality, in which case the virtual address caching by kmap() can overcome all the downsides). But these days, x86-64 may not be more populous, but it's getting there (and if you care about performance, it's definitely already there - you'd have upgraded your CPU's already in the last few years). And on x86-64, the non-kmap_atomic() version is faster, simply because the code is simpler and doesn't have the "re-try page fault" case. People with old hardware are not likely to care about RDS anyway, and the optimization for the 32-bit case is simply buggy, since it doesn't verify the user addresses properly. Reported-by: Dan Rosenberg <drosenberg@vsecurity.com> Acked-by: Andrew Morton <akpm@linux-foundation.org> Cc: stable@kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 5a2b3ef commit 799c105

File tree

1 file changed

+7
-20
lines changed

1 file changed

+7
-20
lines changed

net/rds/page.c

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,30 +57,17 @@ int rds_page_copy_user(struct page *page, unsigned long offset,
5757
unsigned long ret;
5858
void *addr;
5959

60-
if (to_user)
60+
addr = kmap(page);
61+
if (to_user) {
6162
rds_stats_add(s_copy_to_user, bytes);
62-
else
63+
ret = copy_to_user(ptr, addr + offset, bytes);
64+
} else {
6365
rds_stats_add(s_copy_from_user, bytes);
64-
65-
addr = kmap_atomic(page, KM_USER0);
66-
if (to_user)
67-
ret = __copy_to_user_inatomic(ptr, addr + offset, bytes);
68-
else
69-
ret = __copy_from_user_inatomic(addr + offset, ptr, bytes);
70-
kunmap_atomic(addr, KM_USER0);
71-
72-
if (ret) {
73-
addr = kmap(page);
74-
if (to_user)
75-
ret = copy_to_user(ptr, addr + offset, bytes);
76-
else
77-
ret = copy_from_user(addr + offset, ptr, bytes);
78-
kunmap(page);
79-
if (ret)
80-
return -EFAULT;
66+
ret = copy_from_user(addr + offset, ptr, bytes);
8167
}
68+
kunmap(page);
8269

83-
return 0;
70+
return ret ? -EFAULT : 0;
8471
}
8572
EXPORT_SYMBOL_GPL(rds_page_copy_user);
8673

0 commit comments

Comments
 (0)