diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-10-18 13:50:52 -0700 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-10-18 13:50:52 -0700 |
commit | cff6bf970965c98c62007fc8a36527fd147fe233 (patch) | |
tree | 2791f2208b54ade86625af416ff5342f11282f0c /arch/sparc64/lib/user_fixup.c | |
parent | 6cd7525a00f3b926e8bd2e402954ed3e09a8e924 (diff) | |
parent | 39ca371c45b04cd50d0974030ae051906fc516b6 (diff) | |
download | blackbird-op-linux-cff6bf970965c98c62007fc8a36527fd147fe233.tar.gz blackbird-op-linux-cff6bf970965c98c62007fc8a36527fd147fe233.zip |
Merge /home/trondmy/scm/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'arch/sparc64/lib/user_fixup.c')
-rw-r--r-- | arch/sparc64/lib/user_fixup.c | 63 |
1 files changed, 29 insertions, 34 deletions
diff --git a/arch/sparc64/lib/user_fixup.c b/arch/sparc64/lib/user_fixup.c index 0278e34125db..19d1fdb17d0e 100644 --- a/arch/sparc64/lib/user_fixup.c +++ b/arch/sparc64/lib/user_fixup.c @@ -11,61 +11,56 @@ /* Calculating the exact fault address when using * block loads and stores can be very complicated. + * * Instead of trying to be clever and handling all * of the cases, just fix things up simply here. */ -unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size) +static unsigned long compute_size(unsigned long start, unsigned long size, unsigned long *offset) { - char *dst = to; - const char __user *src = from; + unsigned long fault_addr = current_thread_info()->fault_address; + unsigned long end = start + size; - while (size) { - if (__get_user(*dst, src)) - break; - dst++; - src++; - size--; + if (fault_addr < start || fault_addr >= end) { + *offset = 0; + } else { + *offset = start - fault_addr; + size = end - fault_addr; } + return size; +} - if (size) - memset(dst, 0, size); +unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size) +{ + unsigned long offset; + + size = compute_size((unsigned long) from, size, &offset); + if (likely(size)) + memset(to + offset, 0, size); return size; } unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size) { - char __user *dst = to; - const char *src = from; - - while (size) { - if (__put_user(*src, dst)) - break; - dst++; - src++; - size--; - } + unsigned long offset; - return size; + return compute_size((unsigned long) to, size, &offset); } unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size) { - char __user *dst = to; - char __user *src = from; + unsigned long fault_addr = current_thread_info()->fault_address; + unsigned long start = (unsigned long) to; + unsigned long end = start + size; - while (size) { - char tmp; + if (fault_addr >= start && fault_addr < end) + return end - fault_addr; - if (__get_user(tmp, src)) - break; - if (__put_user(tmp, dst)) - break; - dst++; - src++; - size--; - } + start = (unsigned long) from; + end = start + size; + if (fault_addr >= start && fault_addr < end) + return end - fault_addr; return size; } |