* __copy_tofrom_user fails on unaligned read faults
@ 2002-11-21 21:50 Dale Farnsworth
2002-11-21 22:07 ` Dan Malek
0 siblings, 1 reply; 8+ messages in thread
From: Dale Farnsworth @ 2002-11-21 21:50 UTC (permalink / raw)
To: linuxppc-dev
For performance reasons, __copy_tofrom_user copies
data in 16-bytes chunks. If a read fault occurs in the
middle of one of these chunks, the data which has been
successfully read (up to 15 bytes within the chunk) is
discarded.
Valid data is similarly not copied properly while copying
words and the faulting read address is not word aligned.
Is this a known issue?
While this a rare corner case, I propose that we retry
with byte copies after an unaligned read fault.
I've appended a patch against linuxppc_2_4_devel
-Dale Farnsworth
--- linux/arch/ppc/lib/string.S.orig 2002-11-21 09:26:41.000000000 -0700
+++ linux/arch/ppc/lib/string.S 2002-11-21 11:47:29.000000000 -0700
@@ -512,7 +512,12 @@
li r3,0
b 99f
/* read fault, initial word copy */
-102: li r4,0
+102: andi. r0,r4,3
+ beq 85f
+/* read fault was not word aligned, retry one byte at a time */
+ li r3,2
+ b 86f
+85: li r4,0
b 91f
/* write fault, initial word copy */
103: li r4,1
@@ -539,15 +544,33 @@
#endif
/* read fault in cacheline loop */
-104: li r4,0
+104: addi r0,r4,4
+ andi. r0,r0,15
+ beq 87f
+/* read fault was not 16-byte aligned, retry one byte at a time */
+/* number of bytes remaining is r5 + (ctr << r3) */
+86: mfctr r0
+ slw r3,r0,r3
+ add r3,r3,r5
+ mtctr r3
+ b 40b
+
+87: li r4,0
b 92f
+
/* fault on dcbz (effectively a write fault) */
/* or write fault in cacheline loop */
105: li r4,1
92: li r3,LG_CACHELINE_BYTES
b 99f
/* read fault in final word loop */
-108: li r4,0
+108: andi. r0,r4,3
+ beq 88f
+/* read fault was not word aligned, retry one byte at a time */
+ andi. r5,r5,3
+ li r3,2
+ b 86b
+88: li r4,0
b 93f
/* write fault in final word loop */
109: li r4,1
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: __copy_tofrom_user fails on unaligned read faults
2002-11-21 21:50 __copy_tofrom_user fails on unaligned read faults Dale Farnsworth
@ 2002-11-21 22:07 ` Dan Malek
2002-11-21 22:12 ` Dale Farnsworth
0 siblings, 1 reply; 8+ messages in thread
From: Dan Malek @ 2002-11-21 22:07 UTC (permalink / raw)
To: Dale Farnsworth; +Cc: linuxppc-dev
Dale Farnsworth wrote:
> For performance reasons, __copy_tofrom_user copies
> data in 16-bytes chunks. If a read fault occurs in the
> middle of one of these chunks,
How do you get a read fault in the middle of a 16-byte
aligned data copy?
-- Dan
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: __copy_tofrom_user fails on unaligned read faults
2002-11-21 22:07 ` Dan Malek
@ 2002-11-21 22:12 ` Dale Farnsworth
2002-11-21 22:27 ` Dan Malek
0 siblings, 1 reply; 8+ messages in thread
From: Dale Farnsworth @ 2002-11-21 22:12 UTC (permalink / raw)
To: Dan Malek; +Cc: linuxppc-dev
On Thu, Nov 21, 2002 at 05:07:32PM -0500, Dan Malek wrote:
> Dale Farnsworth wrote:
>
> >For performance reasons, __copy_tofrom_user copies
> >data in 16-bytes chunks. If a read fault occurs in the
> >middle of one of these chunks,
>
> How do you get a read fault in the middle of a 16-byte
> aligned data copy?
The 16-byte copy is aligned on the destination address.
It is unaligned with respect to the source address.
-Dale
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: __copy_tofrom_user fails on unaligned read faults
2002-11-21 22:12 ` Dale Farnsworth
@ 2002-11-21 22:27 ` Dan Malek
2002-11-21 23:18 ` Dale Farnsworth
0 siblings, 1 reply; 8+ messages in thread
From: Dan Malek @ 2002-11-21 22:27 UTC (permalink / raw)
To: Dale Farnsworth; +Cc: linuxppc-dev
Dale Farnsworth wrote:
> The 16-byte copy is aligned on the destination address.
> It is unaligned with respect to the source address.
I see, so do the semantics of a copy_to/from allow this behavior?
If you still return an error, how does the caller know how many
bytes were transferred? I always thought if you handled a SEG/BUS
fault exception the contents of the buffer were undefined.
-- Dan
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: __copy_tofrom_user fails on unaligned read faults
2002-11-21 22:27 ` Dan Malek
@ 2002-11-21 23:18 ` Dale Farnsworth
2002-11-23 1:03 ` Paul Mackerras
0 siblings, 1 reply; 8+ messages in thread
From: Dale Farnsworth @ 2002-11-21 23:18 UTC (permalink / raw)
To: Dan Malek; +Cc: linuxppc-dev
On Thu, Nov 21, 2002 at 05:27:53PM -0500, Dan Malek wrote:
> Dale Farnsworth wrote:
>
> >The 16-byte copy is aligned on the destination address.
> >It is unaligned with respect to the source address.
>
> I see, so do the semantics of a copy_to/from allow this behavior?
> If you still return an error, how does the caller know how many
> bytes were transferred? I always thought if you handled a SEG/BUS
> fault exception the contents of the buffer were undefined.
>
> -- Dan
copy_from_user is supposed to transfer as much data as is
valid and then to return the number of bytes not tranferred.
That's how it works on x86. On ppc it can be as much as 15
bytes short.
I initially saw the problem with the mount system call. Here's
a partial strace:
# strace mount -t jffs2 /dev/mtdblock0 /xx
execve("/bin/mount", ["mount", "-t", "jffs2", "/dev/mtdblock0", "/xx"], [/* 7 vars */]) = 0
<deleted lots of stuff>
stat("/dev/mtdblock0", {st_mode=S_IFBLK|0644, st_rdev=makedev(31, 0), ...}) = 0
brk(0x1005e000) = 0x1005e000
brk(0x1005f000) = 0x1005f000
mount("/dev/mtdblock0", "/xx", "jffs2", 0xc0ed0000, 0x1005eff8) = -1 EFAULT (Bad address)
Note that the fifth argument to mount is an address 8 bytes from the end
of user data space. There is a null byte at that address, since no mount
options are being passed.
In the kernel, sys_mount() allocates a page for the options and
does copy_from_user(new_page, 0x1005eff8, PAGE_SIZE). copy_from_user
should copy 8 bytes and return (PAGE_SIZE-8). Instead, on ppc it reads
8 bytes, faults, writes no bytes, and returns PAGE_SIZE, which causes the
EFAULT to be erroneously reported.
-Dale
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: __copy_tofrom_user fails on unaligned read faults
2002-11-21 23:18 ` Dale Farnsworth
@ 2002-11-23 1:03 ` Paul Mackerras
2002-11-24 2:25 ` Dale Farnsworth
2002-11-25 18:30 ` Dale Farnsworth
0 siblings, 2 replies; 8+ messages in thread
From: Paul Mackerras @ 2002-11-23 1:03 UTC (permalink / raw)
To: Dale Farnsworth; +Cc: linuxppc-dev
Dale Farnsworth writes:
> copy_from_user is supposed to transfer as much data as is
> valid and then to return the number of bytes not tranferred.
> That's how it works on x86. On ppc it can be as much as 15
> bytes short.
>
> I initially saw the problem with the mount system call. Here's
> a partial strace:
I've always disliked the way that the mount system call does that.
However, we just have to deal with it, I guess.
IMO you are right in thinking that we need to try to copy bytes one at
a time after we get a read fault. I think I would do the extra byte
copy loop inline after the 99: label instead of jumping back the way
you do. Could you try this patch, please?
Paul.
diff -urN linuxppc_2_4_devel/arch/ppc/lib/string.S pmac/arch/ppc/lib/string.S
--- linuxppc_2_4_devel/arch/ppc/lib/string.S 2002-08-13 21:52:53.000000000 +1000
+++ pmac/arch/ppc/lib/string.S 2002-11-23 12:01:31.000000000 +1100
@@ -567,10 +567,19 @@
*/
99: mfctr r0
slw r3,r0,r3
- add r3,r3,r5
+ add. r3,r3,r5
+ beq 120f /* shouldn't happen */
cmpwi 0,r4,0
bne 120f
-/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
+/* for a read fault, first try to continue the copy one byte at a time */
+ mtctr r3
+130: lbz r0,4(r4)
+131: stb r0,4(r6)
+ addi r4,r4,1
+ addi r6,r6,1
+ bdnz 130b
+/* then clear out the destination: r3 bytes starting at 4(r6) */
+132: mfctr r3
srwi. r0,r3,2
li r9,0
mtctr r0
@@ -591,6 +600,8 @@
.long 31b,109b
.long 40b,110b
.long 41b,111b
+ .long 130b,132b
+ .long 131b,120b
.long 112b,120b
.long 114b,120b
.text
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: __copy_tofrom_user fails on unaligned read faults
2002-11-23 1:03 ` Paul Mackerras
@ 2002-11-24 2:25 ` Dale Farnsworth
2002-11-25 18:30 ` Dale Farnsworth
1 sibling, 0 replies; 8+ messages in thread
From: Dale Farnsworth @ 2002-11-24 2:25 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
On Sat, Nov 23, 2002 at 12:03:36PM +1100, Paul Mackerras wrote:
> IMO you are right in thinking that we need to try to copy bytes one at
> a time after we get a read fault. I think I would do the extra byte
> copy loop inline after the 99: label instead of jumping back the way
> you do.
By the time we get to 99:, r4 has already been zeroed. We need to
insert the byte copy at 104:. Now, to figure out how to do that without
duplicating code... I won't be able to spend time on it until Monday.
Note that we also need to handle an unaligned fault in the initial
and final word copy loops.
-Dale
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: __copy_tofrom_user fails on unaligned read faults
2002-11-23 1:03 ` Paul Mackerras
2002-11-24 2:25 ` Dale Farnsworth
@ 2002-11-25 18:30 ` Dale Farnsworth
1 sibling, 0 replies; 8+ messages in thread
From: Dale Farnsworth @ 2002-11-25 18:30 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
On Sat, Nov 23, 2002 at 12:03:36PM +1100, Paul Mackerras wrote:
> Could you try this patch, please?
Your patch worked fine after I moved the read/write flag from r4 to r9.
Here's the resultant patch. I'm happy with it.
-Dale
diff -u linuxppc_2_4_devel/arch/ppc/lib/string.S hxeb100/arch/ppc/lib/string.S
--- linuxppc_2_4_devel/arch/ppc/lib/string.S 2002-11-25 10:38:45.000000000 -0700
+++ hxeb100/arch/ppc/lib/string.S 2002-11-25 09:32:00.000000000 -0700
@@ -504,18 +504,18 @@
blr
/* read fault, initial single-byte copy */
-100: li r4,0
+100: li r9,0
b 90f
/* write fault, initial single-byte copy */
-101: li r4,1
+101: li r9,1
90: subf r5,r8,r5
li r3,0
b 99f
/* read fault, initial word copy */
-102: li r4,0
+102: li r9,0
b 91f
/* write fault, initial word copy */
-103: li r4,1
+103: li r9,1
91: li r3,2
b 99f
@@ -539,38 +539,47 @@
#endif
/* read fault in cacheline loop */
-104: li r4,0
+104: li r9,0
b 92f
/* fault on dcbz (effectively a write fault) */
/* or write fault in cacheline loop */
-105: li r4,1
+105: li r9,1
92: li r3,LG_CACHELINE_BYTES
b 99f
/* read fault in final word loop */
-108: li r4,0
+108: li r9,0
b 93f
/* write fault in final word loop */
-109: li r4,1
+109: li r9,1
93: andi. r5,r5,3
li r3,2
b 99f
/* read fault in final byte loop */
-110: li r4,0
+110: li r9,0
b 94f
/* write fault in final byte loop */
-111: li r4,1
+111: li r9,1
94: li r5,0
li r3,0
/*
* At this stage the number of bytes not copied is
- * r5 + (ctr << r3), and r4 is 0 for read or 1 for write.
+ * r5 + (ctr << r3), and r9 is 0 for read or 1 for write.
*/
99: mfctr r0
slw r3,r0,r3
- add r3,r3,r5
- cmpwi 0,r4,0
+ add. r3,r3,r5
+ beq 120f /* shouldn't happen */
+ cmpwi 0,r9,0
bne 120f
-/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
+/* for a read fault, first try to continue the copy one byte at a time */
+ mtctr r3
+130: lbz r0,4(r4)
+131: stb r0,4(r6)
+ addi r4,r4,1
+ addi r6,r6,1
+ bdnz 130b
+/* then clear out the destination: r3 bytes starting at 4(r6) */
+132: mfctr r3
srwi. r0,r3,2
li r9,0
mtctr r0
@@ -591,6 +600,8 @@
.long 31b,109b
.long 40b,110b
.long 41b,111b
+ .long 130b,132b
+ .long 131b,120b
.long 112b,120b
.long 114b,120b
.text
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2002-11-25 18:30 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-11-21 21:50 __copy_tofrom_user fails on unaligned read faults Dale Farnsworth
2002-11-21 22:07 ` Dan Malek
2002-11-21 22:12 ` Dale Farnsworth
2002-11-21 22:27 ` Dan Malek
2002-11-21 23:18 ` Dale Farnsworth
2002-11-23 1:03 ` Paul Mackerras
2002-11-24 2:25 ` Dale Farnsworth
2002-11-25 18:30 ` Dale Farnsworth
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).