tracing: Add tracepoints for hotplug
[linux-2.6.git] / kernel / compat.c
index b78328a..e2435ee 100644 (file)
 #include <linux/timex.h>
 #include <linux/migrate.h>
 #include <linux/posix-timers.h>
+#include <linux/times.h>
+#include <linux/ptrace.h>
+#include <linux/gfp.h>
 
 #include <asm/uaccess.h>
 
+/*
+ * Note that the native side is already converted to a timespec, because
+ * that's what we want anyway.
+ */
+static int compat_get_timeval(struct timespec *o,
+               struct compat_timeval __user *i)
+{
+       long usec;
+
+       if (get_user(o->tv_sec, &i->tv_sec) ||
+           get_user(usec, &i->tv_usec))
+               return -EFAULT;
+       o->tv_nsec = usec * 1000;
+       return 0;
+}
+
+static int compat_put_timeval(struct compat_timeval __user *o,
+               struct timeval *i)
+{
+       return (put_user(i->tv_sec, &o->tv_sec) ||
+               put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;
+}
+
+static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp)
+{
+       memset(txc, 0, sizeof(struct timex));
+
+       if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) ||
+                       __get_user(txc->modes, &utp->modes) ||
+                       __get_user(txc->offset, &utp->offset) ||
+                       __get_user(txc->freq, &utp->freq) ||
+                       __get_user(txc->maxerror, &utp->maxerror) ||
+                       __get_user(txc->esterror, &utp->esterror) ||
+                       __get_user(txc->status, &utp->status) ||
+                       __get_user(txc->constant, &utp->constant) ||
+                       __get_user(txc->precision, &utp->precision) ||
+                       __get_user(txc->tolerance, &utp->tolerance) ||
+                       __get_user(txc->time.tv_sec, &utp->time.tv_sec) ||
+                       __get_user(txc->time.tv_usec, &utp->time.tv_usec) ||
+                       __get_user(txc->tick, &utp->tick) ||
+                       __get_user(txc->ppsfreq, &utp->ppsfreq) ||
+                       __get_user(txc->jitter, &utp->jitter) ||
+                       __get_user(txc->shift, &utp->shift) ||
+                       __get_user(txc->stabil, &utp->stabil) ||
+                       __get_user(txc->jitcnt, &utp->jitcnt) ||
+                       __get_user(txc->calcnt, &utp->calcnt) ||
+                       __get_user(txc->errcnt, &utp->errcnt) ||
+                       __get_user(txc->stbcnt, &utp->stbcnt))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int compat_put_timex(struct compat_timex __user *utp, struct timex *txc)
+{
+       if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) ||
+                       __put_user(txc->modes, &utp->modes) ||
+                       __put_user(txc->offset, &utp->offset) ||
+                       __put_user(txc->freq, &utp->freq) ||
+                       __put_user(txc->maxerror, &utp->maxerror) ||
+                       __put_user(txc->esterror, &utp->esterror) ||
+                       __put_user(txc->status, &utp->status) ||
+                       __put_user(txc->constant, &utp->constant) ||
+                       __put_user(txc->precision, &utp->precision) ||
+                       __put_user(txc->tolerance, &utp->tolerance) ||
+                       __put_user(txc->time.tv_sec, &utp->time.tv_sec) ||
+                       __put_user(txc->time.tv_usec, &utp->time.tv_usec) ||
+                       __put_user(txc->tick, &utp->tick) ||
+                       __put_user(txc->ppsfreq, &utp->ppsfreq) ||
+                       __put_user(txc->jitter, &utp->jitter) ||
+                       __put_user(txc->shift, &utp->shift) ||
+                       __put_user(txc->stabil, &utp->stabil) ||
+                       __put_user(txc->jitcnt, &utp->jitcnt) ||
+                       __put_user(txc->calcnt, &utp->calcnt) ||
+                       __put_user(txc->errcnt, &utp->errcnt) ||
+                       __put_user(txc->stbcnt, &utp->stbcnt) ||
+                       __put_user(txc->tai, &utp->tai))
+               return -EFAULT;
+       return 0;
+}
+
+asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
+               struct timezone __user *tz)
+{
+       if (tv) {
+               struct timeval ktv;
+               do_gettimeofday(&ktv);
+               if (compat_put_timeval(tv, &ktv))
+                       return -EFAULT;
+       }
+       if (tz) {
+               if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
+               struct timezone __user *tz)
+{
+       struct timespec kts;
+       struct timezone ktz;
+
+       if (tv) {
+               if (compat_get_timeval(&kts, tv))
+                       return -EFAULT;
+       }
+       if (tz) {
+               if (copy_from_user(&ktz, tz, sizeof(ktz)))
+                       return -EFAULT;
+       }
+
+       return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
+}
+
 int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
 {
        return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
@@ -39,63 +158,63 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user
                        __put_user(ts->tv_sec, &cts->tv_sec) ||
                        __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
 }
+EXPORT_SYMBOL_GPL(put_compat_timespec);
 
 static long compat_nanosleep_restart(struct restart_block *restart)
 {
-       unsigned long expire = restart->arg0, now = jiffies;
        struct compat_timespec __user *rmtp;
+       struct timespec rmt;
+       mm_segment_t oldfs;
+       long ret;
 
-       /* Did it expire while we handled signals? */
-       if (!time_after(expire, now))
-               return 0;
-
-       expire = schedule_timeout_interruptible(expire - now);
-       if (expire == 0)
-               return 0;
+       restart->nanosleep.rmtp = (struct timespec __user *) &rmt;
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = hrtimer_nanosleep_restart(restart);
+       set_fs(oldfs);
 
-       rmtp = (struct compat_timespec __user *)restart->arg1;
-       if (rmtp) {
-               struct compat_timespec ct;
-               struct timespec t;
+       if (ret) {
+               rmtp = restart->nanosleep.compat_rmtp;
 
-               jiffies_to_timespec(expire, &t);
-               ct.tv_sec = t.tv_sec;
-               ct.tv_nsec = t.tv_nsec;
-               if (copy_to_user(rmtp, &ct, sizeof(ct)))
+               if (rmtp && put_compat_timespec(&rmt, rmtp))
                        return -EFAULT;
        }
-       /* The 'restart' block is already filled in */
-       return -ERESTART_RESTARTBLOCK;
+
+       return ret;
 }
 
 asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
-               struct compat_timespec __user *rmtp)
+                                    struct compat_timespec __user *rmtp)
 {
-       struct timespec t;
-       struct restart_block *restart;
-       unsigned long expire;
+       struct timespec tu, rmt;
+       mm_segment_t oldfs;
+       long ret;
 
-       if (get_compat_timespec(&t, rqtp))
+       if (get_compat_timespec(&tu, rqtp))
                return -EFAULT;
 
-       if ((t.tv_nsec >= 1000000000L) || (t.tv_nsec < 0) || (t.tv_sec < 0))
+       if (!timespec_valid(&tu))
                return -EINVAL;
 
-       expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
-       expire = schedule_timeout_interruptible(expire);
-       if (expire == 0)
-               return 0;
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = hrtimer_nanosleep(&tu,
+                               rmtp ? (struct timespec __user *)&rmt : NULL,
+                               HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+       set_fs(oldfs);
 
-       if (rmtp) {
-               jiffies_to_timespec(expire, &t);
-               if (put_compat_timespec(&t, rmtp))
+       if (ret) {
+               struct restart_block *restart
+                       = &current_thread_info()->restart_block;
+
+               restart->fn = compat_nanosleep_restart;
+               restart->nanosleep.compat_rmtp = rmtp;
+
+               if (rmtp && put_compat_timespec(&rmt, rmtp))
                        return -EFAULT;
        }
-       restart = &current_thread_info()->restart_block;
-       restart->fn = compat_nanosleep_restart;
-       restart->arg0 = jiffies + expire;
-       restart->arg1 = (unsigned long) rmtp;
-       return -ERESTART_RESTARTBLOCK;
+
+       return ret;
 }
 
 static inline long get_compat_itimerval(struct itimerval *o,
@@ -151,55 +270,32 @@ asmlinkage long compat_sys_setitimer(int which,
        return 0;
 }
 
+static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
+{
+       return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
+}
+
 asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
 {
-       /*
-        *      In the SMP world we might just be unlucky and have one of
-        *      the times increment as we use it. Since the value is an
-        *      atomically safe type this is just fine. Conceptually its
-        *      as if the syscall took an instant longer to occur.
-        */
        if (tbuf) {
+               struct tms tms;
                struct compat_tms tmp;
-               struct task_struct *tsk = current;
-               struct task_struct *t;
-               cputime_t utime, stime, cutime, cstime;
-
-               read_lock(&tasklist_lock);
-               utime = tsk->signal->utime;
-               stime = tsk->signal->stime;
-               t = tsk;
-               do {
-                       utime = cputime_add(utime, t->utime);
-                       stime = cputime_add(stime, t->stime);
-                       t = next_thread(t);
-               } while (t != tsk);
-
-               /*
-                * While we have tasklist_lock read-locked, no dying thread
-                * can be updating current->signal->[us]time.  Instead,
-                * we got their counts included in the live thread loop.
-                * However, another thread can come in right now and
-                * do a wait call that updates current->signal->c[us]time.
-                * To make sure we always see that pair updated atomically,
-                * we take the siglock around fetching them.
-                */
-               spin_lock_irq(&tsk->sighand->siglock);
-               cutime = tsk->signal->cutime;
-               cstime = tsk->signal->cstime;
-               spin_unlock_irq(&tsk->sighand->siglock);
-               read_unlock(&tasklist_lock);
-
-               tmp.tms_utime = compat_jiffies_to_clock_t(cputime_to_jiffies(utime));
-               tmp.tms_stime = compat_jiffies_to_clock_t(cputime_to_jiffies(stime));
-               tmp.tms_cutime = compat_jiffies_to_clock_t(cputime_to_jiffies(cutime));
-               tmp.tms_cstime = compat_jiffies_to_clock_t(cputime_to_jiffies(cstime));
+
+               do_sys_times(&tms);
+               /* Convert our struct tms to the compat version. */
+               tmp.tms_utime = clock_t_to_compat_clock_t(tms.tms_utime);
+               tmp.tms_stime = clock_t_to_compat_clock_t(tms.tms_stime);
+               tmp.tms_cutime = clock_t_to_compat_clock_t(tms.tms_cutime);
+               tmp.tms_cstime = clock_t_to_compat_clock_t(tms.tms_cstime);
                if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
                        return -EFAULT;
        }
+       force_successful_syscall_return();
        return compat_jiffies_to_clock_t(jiffies);
 }
 
+#ifdef __ARCH_WANT_SYS_SIGPENDING
+
 /*
  * Assumption: old_sigset_t and compat_old_sigset_t are both
  * types that can be passed to put_user()/get_user().
@@ -219,6 +315,10 @@ asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set)
        return ret;
 }
 
+#endif
+
+#ifdef __ARCH_WANT_SYS_SIGPROCMASK
+
 asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set,
                compat_old_sigset_t __user *oset)
 {
@@ -240,15 +340,12 @@ asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set,
        return ret;
 }
 
+#endif
+
 asmlinkage long compat_sys_setrlimit(unsigned int resource,
                struct compat_rlimit __user *rlim)
 {
        struct rlimit r;
-       int ret;
-       mm_segment_t old_fs = get_fs ();
-
-       if (resource >= RLIM_NLIMITS)
-               return -EINVAL;
 
        if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) ||
            __get_user(r.rlim_cur, &rlim->rlim_cur) ||
@@ -259,10 +356,7 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource,
                r.rlim_cur = RLIM_INFINITY;
        if (r.rlim_max == COMPAT_RLIM_INFINITY)
                r.rlim_max = RLIM_INFINITY;
-       set_fs(KERNEL_DS);
-       ret = sys_setrlimit(resource, (struct rlimit __user *) &r);
-       set_fs(old_fs);
-       return ret;
+       return do_prlimit(current, resource, &r, NULL);
 }
 
 #ifdef COMPAT_RLIM_OLD_INFINITY
@@ -294,16 +388,13 @@ asmlinkage long compat_sys_old_getrlimit(unsigned int resource,
 
 #endif
 
-asmlinkage long compat_sys_getrlimit (unsigned int resource,
+asmlinkage long compat_sys_getrlimit(unsigned int resource,
                struct compat_rlimit __user *rlim)
 {
        struct rlimit r;
        int ret;
-       mm_segment_t old_fs = get_fs();
 
-       set_fs(KERNEL_DS);
-       ret = sys_getrlimit(resource, (struct rlimit __user *) &r);
-       set_fs(old_fs);
+       ret = do_prlimit(current, resource, NULL, &r);
        if (!ret) {
                if (r.rlim_cur > COMPAT_RLIM_INFINITY)
                        r.rlim_cur = COMPAT_RLIM_INFINITY;
@@ -422,16 +513,16 @@ asmlinkage long compat_sys_waitid(int which, compat_pid_t pid,
 }
 
 static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
-                                   unsigned len, cpumask_t *new_mask)
+                                   unsigned len, struct cpumask *new_mask)
 {
        unsigned long *k;
 
-       if (len < sizeof(cpumask_t))
-               memset(new_mask, 0, sizeof(cpumask_t));
-       else if (len > sizeof(cpumask_t))
-               len = sizeof(cpumask_t);
+       if (len < cpumask_size())
+               memset(new_mask, 0, cpumask_size());
+       else if (len > cpumask_size())
+               len = cpumask_size();
 
-       k = cpus_addr(*new_mask);
+       k = cpumask_bits(new_mask);
        return compat_get_bitmap(k, user_mask_ptr, len * 8);
 }
 
@@ -439,40 +530,48 @@ asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid,
                                             unsigned int len,
                                             compat_ulong_t __user *user_mask_ptr)
 {
-       cpumask_t new_mask;
+       cpumask_var_t new_mask;
        int retval;
 
-       retval = compat_get_user_cpu_mask(user_mask_ptr, len, &new_mask);
+       if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       retval = compat_get_user_cpu_mask(user_mask_ptr, len, new_mask);
        if (retval)
-               return retval;
+               goto out;
 
-       return sched_setaffinity(pid, new_mask);
+       retval = sched_setaffinity(pid, new_mask);
+out:
+       free_cpumask_var(new_mask);
+       return retval;
 }
 
 asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
                                             compat_ulong_t __user *user_mask_ptr)
 {
        int ret;
-       cpumask_t mask;
-       unsigned long *k;
-       unsigned int min_length = sizeof(cpumask_t);
+       cpumask_var_t mask;
 
-       if (NR_CPUS <= BITS_PER_COMPAT_LONG)
-               min_length = sizeof(compat_ulong_t);
-
-       if (len < min_length)
+       if ((len * BITS_PER_BYTE) < nr_cpu_ids)
+               return -EINVAL;
+       if (len & (sizeof(compat_ulong_t)-1))
                return -EINVAL;
 
-       ret = sched_getaffinity(pid, &mask);
-       if (ret < 0)
-               return ret;
+       if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+               return -ENOMEM;
 
-       k = cpus_addr(mask);
-       ret = compat_put_bitmap(user_mask_ptr, k, min_length * 8);
-       if (ret)
-               return ret;
+       ret = sched_getaffinity(pid, mask);
+       if (ret == 0) {
+               size_t retlen = min_t(size_t, len, cpumask_size());
+
+               if (compat_put_bitmap(user_mask_ptr, cpumask_bits(mask), retlen * 8))
+                       ret = -EFAULT;
+               else
+                       ret = retlen;
+       }
+       free_cpumask_var(mask);
 
-       return min_length;
+       return ret;
 }
 
 int get_compat_itimerspec(struct itimerspec *dst,
@@ -585,6 +684,29 @@ long compat_sys_clock_gettime(clockid_t which_clock,
        return err;
 }
 
+long compat_sys_clock_adjtime(clockid_t which_clock,
+               struct compat_timex __user *utp)
+{
+       struct timex txc;
+       mm_segment_t oldfs;
+       int err, ret;
+
+       err = compat_get_timex(&txc, utp);
+       if (err)
+               return err;
+
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = sys_clock_adjtime(which_clock, (struct timex __user *) &txc);
+       set_fs(oldfs);
+
+       err = compat_put_timex(utp, &txc);
+       if (err)
+               return err;
+
+       return ret;
+}
+
 long compat_sys_clock_getres(clockid_t which_clock,
                struct compat_timespec __user *tp)
 {
@@ -607,9 +729,9 @@ static long compat_clock_nanosleep_restart(struct restart_block *restart)
        long err;
        mm_segment_t oldfs;
        struct timespec tu;
-       struct compat_timespec *rmtp = (struct compat_timespec *)(restart->arg1);
+       struct compat_timespec *rmtp = restart->nanosleep.compat_rmtp;
 
-       restart->arg1 = (unsigned long) &tu;
+       restart->nanosleep.rmtp = (struct timespec __user *) &tu;
        oldfs = get_fs();
        set_fs(KERNEL_DS);
        err = clock_nanosleep_restart(restart);
@@ -621,7 +743,7 @@ static long compat_clock_nanosleep_restart(struct restart_block *restart)
 
        if (err == -ERESTART_RESTARTBLOCK) {
                restart->fn = compat_clock_nanosleep_restart;
-               restart->arg1 = (unsigned long) rmtp;
+               restart->nanosleep.compat_rmtp = rmtp;
        }
        return err;
 }
@@ -652,7 +774,7 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
        if (err == -ERESTART_RESTARTBLOCK) {
                restart = &current_thread_info()->restart_block;
                restart->fn = compat_clock_nanosleep_restart;
-               restart->arg1 = (unsigned long) rmtp;
+               restart->nanosleep.compat_rmtp = rmtp;
        }
        return err;
 }
@@ -769,6 +891,7 @@ sigset_from_compat (sigset_t *set, compat_sigset_t *compat)
        case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 );
        }
 }
+EXPORT_SYMBOL_GPL(sigset_from_compat);
 
 asmlinkage long
 compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese,
@@ -777,10 +900,9 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese,
 {
        compat_sigset_t s32;
        sigset_t s;
-       int sig;
        struct timespec t;
        siginfo_t info;
-       long ret, timeout = 0;
+       long ret;
 
        if (sigsetsize != sizeof(sigset_t))
                return -EINVAL;
@@ -788,55 +910,34 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese,
        if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
                return -EFAULT;
        sigset_from_compat(&s, &s32);
-       sigdelsetmask(&s,sigmask(SIGKILL)|sigmask(SIGSTOP));
-       signotset(&s);
 
        if (uts) {
-               if (get_compat_timespec (&t, uts))
+               if (get_compat_timespec(&t, uts))
                        return -EFAULT;
-               if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0
-                               || t.tv_sec < 0)
-                       return -EINVAL;
        }
 
-       spin_lock_irq(&current->sighand->siglock);
-       sig = dequeue_signal(current, &s, &info);
-       if (!sig) {
-               timeout = MAX_SCHEDULE_TIMEOUT;
-               if (uts)
-                       timeout = timespec_to_jiffies(&t)
-                               +(t.tv_sec || t.tv_nsec);
-               if (timeout) {
-                       current->real_blocked = current->blocked;
-                       sigandsets(&current->blocked, &current->blocked, &s);
-
-                       recalc_sigpending();
-                       spin_unlock_irq(&current->sighand->siglock);
-
-                       timeout = schedule_timeout_interruptible(timeout);
-
-                       spin_lock_irq(&current->sighand->siglock);
-                       sig = dequeue_signal(current, &s, &info);
-                       current->blocked = current->real_blocked;
-                       siginitset(&current->real_blocked, 0);
-                       recalc_sigpending();
-               }
-       }
-       spin_unlock_irq(&current->sighand->siglock);
+       ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
 
-       if (sig) {
-               ret = sig;
-               if (uinfo) {
-                       if (copy_siginfo_to_user32(uinfo, &info))
-                               ret = -EFAULT;
-               }
-       }else {
-               ret = timeout?-EINTR:-EAGAIN;
+       if (ret > 0 && uinfo) {
+               if (copy_siginfo_to_user32(uinfo, &info))
+                       ret = -EFAULT;
        }
+
        return ret;
 
 }
 
+asmlinkage long
+compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid, compat_pid_t pid, int sig,
+                            struct compat_siginfo __user *uinfo)
+{
+       siginfo_t info;
+
+       if (copy_siginfo_from_user32(&info, uinfo))
+               return -EFAULT;
+       return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
+}
+
 #ifdef __ARCH_WANT_COMPAT_SYS_TIME
 
 /* compat_time_t is a 32 bit "long" and needs to get converted. */
@@ -851,8 +952,9 @@ asmlinkage long compat_sys_time(compat_time_t __user * tloc)
 
        if (tloc) {
                if (put_user(i,tloc))
-                       i = -EFAULT;
+                       return -EFAULT;
        }
+       force_successful_syscall_return();
        return i;
 }
 
@@ -891,15 +993,12 @@ asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat
        sigset_from_compat(&newset, &newset32);
        sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
 
-       spin_lock_irq(&current->sighand->siglock);
        current->saved_sigmask = current->blocked;
-       current->blocked = newset;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+       set_current_blocked(&newset);
 
        current->state = TASK_INTERRUPTIBLE;
        schedule();
-       set_thread_flag(TIF_RESTORE_SIGMASK);
+       set_restore_sigmask();
        return -ERESTARTNOHAND;
 }
 #endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
@@ -907,57 +1006,17 @@ asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat
 asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
 {
        struct timex txc;
-       int ret;
-
-       memset(&txc, 0, sizeof(struct timex));
+       int err, ret;
 
-       if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) ||
-                       __get_user(txc.modes, &utp->modes) ||
-                       __get_user(txc.offset, &utp->offset) ||
-                       __get_user(txc.freq, &utp->freq) ||
-                       __get_user(txc.maxerror, &utp->maxerror) ||
-                       __get_user(txc.esterror, &utp->esterror) ||
-                       __get_user(txc.status, &utp->status) ||
-                       __get_user(txc.constant, &utp->constant) ||
-                       __get_user(txc.precision, &utp->precision) ||
-                       __get_user(txc.tolerance, &utp->tolerance) ||
-                       __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-                       __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-                       __get_user(txc.tick, &utp->tick) ||
-                       __get_user(txc.ppsfreq, &utp->ppsfreq) ||
-                       __get_user(txc.jitter, &utp->jitter) ||
-                       __get_user(txc.shift, &utp->shift) ||
-                       __get_user(txc.stabil, &utp->stabil) ||
-                       __get_user(txc.jitcnt, &utp->jitcnt) ||
-                       __get_user(txc.calcnt, &utp->calcnt) ||
-                       __get_user(txc.errcnt, &utp->errcnt) ||
-                       __get_user(txc.stbcnt, &utp->stbcnt))
-               return -EFAULT;
+       err = compat_get_timex(&txc, utp);
+       if (err)
+               return err;
 
        ret = do_adjtimex(&txc);
 
-       if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) ||
-                       __put_user(txc.modes, &utp->modes) ||
-                       __put_user(txc.offset, &utp->offset) ||
-                       __put_user(txc.freq, &utp->freq) ||
-                       __put_user(txc.maxerror, &utp->maxerror) ||
-                       __put_user(txc.esterror, &utp->esterror) ||
-                       __put_user(txc.status, &utp->status) ||
-                       __put_user(txc.constant, &utp->constant) ||
-                       __put_user(txc.precision, &utp->precision) ||
-                       __put_user(txc.tolerance, &utp->tolerance) ||
-                       __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-                       __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-                       __put_user(txc.tick, &utp->tick) ||
-                       __put_user(txc.ppsfreq, &utp->ppsfreq) ||
-                       __put_user(txc.jitter, &utp->jitter) ||
-                       __put_user(txc.shift, &utp->shift) ||
-                       __put_user(txc.stabil, &utp->stabil) ||
-                       __put_user(txc.jitcnt, &utp->jitcnt) ||
-                       __put_user(txc.calcnt, &utp->calcnt) ||
-                       __put_user(txc.errcnt, &utp->errcnt) ||
-                       __put_user(txc.stbcnt, &utp->stbcnt))
-               ret = -EFAULT;
+       err = compat_put_timex(utp, &txc);
+       if (err)
+               return err;
 
        return ret;
 }
@@ -1082,3 +1141,23 @@ compat_sys_sysinfo(struct compat_sysinfo __user *info)
        return 0;
 }
 
+/*
+ * Allocate user-space memory for the duration of a single system call,
+ * in order to marshall parameters inside a compat thunk.
+ */
+void __user *compat_alloc_user_space(unsigned long len)
+{
+       void __user *ptr;
+
+       /* If len would occupy more than half of the entire compat space... */
+       if (unlikely(len > (((compat_uptr_t)~0) >> 1)))
+               return NULL;
+
+       ptr = arch_compat_alloc_user_space(len);
+
+       if (unlikely(!access_ok(VERIFY_WRITE, ptr, len)))
+               return NULL;
+
+       return ptr;
+}
+EXPORT_SYMBOL_GPL(compat_alloc_user_space);