summaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2011-02-22 13:02:26 +0000
committerAurelien Jarno <aurelien@aurel32.net>2011-03-06 19:06:27 +0100
commit0c1592d93585ddce572a71a77534ca765c5f5d34 (patch)
tree16845c422b05e50130611c851d4e7ac2f115b046 /linux-user
parent26883c699eee60c6f2dd63818a9dd470f2c567fc (diff)
downloadqemu-0c1592d93585ddce572a71a77534ca765c5f5d34.tar.gz
linux-user: Fix large seeks by 32 bit guest on 64 bit host
When emulating a 32 bit Linux user-mode program on a 64 bit target we implement the llseek syscall in terms of lseek. Correct a bug which meant we were silently casting the result of host lseek() to a 32 bit integer as it passed through get_errno() and thus throwing away the top half. We also don't try to store the result back to userspace unless the seek succeeded; this matches the kernel behaviour. Thanks to Eoghan Sherry for identifying the problem and suggesting a solution. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/syscall.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index cf8a4c3876..23d7a630f5 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6127,16 +6127,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR__llseek /* Not on alpha */
case TARGET_NR__llseek:
{
+ int64_t res;
#if !defined(__NR_llseek)
- ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5));
- if (put_user_s64(ret, arg4))
- goto efault;
+ res = lseek(arg1, ((uint64_t)arg2 << 32) | arg3, arg5);
+ if (res == -1) {
+ ret = get_errno(res);
+ } else {
+ ret = 0;
+ }
#else
- int64_t res;
ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
- if (put_user_s64(res, arg4))
- goto efault;
#endif
+ if ((ret == 0) && put_user_s64(res, arg4)) {
+ goto efault;
+ }
}
break;
#endif