linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* __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).