X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=kernel%2Fcompat.c;h=42a1ed4b61b172afe1693234a4c68e5cfb695610;hb=53761746ec98c526c7d82dcf8246cbde9f09e743;hp=b4fbd838cd775ac9007af6e7d566652e1ad629de;hpb=07f3f05c1e3052b8656129b2a5aca9f888241a34;p=linux-2.6-omap-h63xx.git diff --git a/kernel/compat.c b/kernel/compat.c index b4fbd838cd7..42a1ed4b61b 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -26,8 +26,6 @@ #include -extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); - int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts) { return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || @@ -42,62 +40,27 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; } -static long compat_nanosleep_restart(struct restart_block *restart) -{ - unsigned long expire = restart->arg0, now = jiffies; - struct compat_timespec __user *rmtp; - - /* 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; - - rmtp = (struct compat_timespec __user *)restart->arg1; - if (rmtp) { - struct compat_timespec ct; - struct timespec t; - - 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))) - return -EFAULT; - } - /* The 'restart' block is already filled in */ - return -ERESTART_RESTARTBLOCK; -} - 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; + 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; + ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, HRTIMER_MODE_REL, + CLOCK_MONOTONIC); - if (rmtp) { - jiffies_to_timespec(expire, &t); - if (put_compat_timespec(&t, rmtp)) + if (ret && rmtp) { + if (put_compat_timespec(&rmt, rmtp)) return -EFAULT; } - restart = ¤t_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, @@ -249,8 +212,8 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource, int ret; mm_segment_t old_fs = get_fs (); - if (resource >= RLIM_NLIMITS) - return -EINVAL; + if (resource >= RLIM_NLIMITS) + return -EINVAL; if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) || __get_user(r.rlim_cur, &rlim->rlim_cur) || @@ -477,23 +440,23 @@ asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len, return min_length; } -static int get_compat_itimerspec(struct itimerspec *dst, - struct compat_itimerspec __user *src) -{ +int get_compat_itimerspec(struct itimerspec *dst, + const struct compat_itimerspec __user *src) +{ if (get_compat_timespec(&dst->it_interval, &src->it_interval) || get_compat_timespec(&dst->it_value, &src->it_value)) return -EFAULT; return 0; -} +} -static int put_compat_itimerspec(struct compat_itimerspec __user *dst, - struct itimerspec *src) -{ +int put_compat_itimerspec(struct compat_itimerspec __user *dst, + const struct itimerspec *src) +{ if (put_compat_timespec(&src->it_interval, &dst->it_interval) || put_compat_timespec(&src->it_value, &dst->it_value)) return -EFAULT; return 0; -} +} long compat_sys_timer_create(clockid_t which_clock, struct compat_sigevent __user *timer_event_spec, @@ -514,9 +477,9 @@ long compat_sys_timer_create(clockid_t which_clock, } long compat_sys_timer_settime(timer_t timer_id, int flags, - struct compat_itimerspec __user *new, + struct compat_itimerspec __user *new, struct compat_itimerspec __user *old) -{ +{ long err; mm_segment_t oldfs; struct itimerspec newts, oldts; @@ -524,58 +487,58 @@ long compat_sys_timer_settime(timer_t timer_id, int flags, if (!new) return -EINVAL; if (get_compat_itimerspec(&newts, new)) - return -EFAULT; + return -EFAULT; oldfs = get_fs(); set_fs(KERNEL_DS); err = sys_timer_settime(timer_id, flags, (struct itimerspec __user *) &newts, (struct itimerspec __user *) &oldts); - set_fs(oldfs); + set_fs(oldfs); if (!err && old && put_compat_itimerspec(old, &oldts)) return -EFAULT; return err; -} +} long compat_sys_timer_gettime(timer_t timer_id, struct compat_itimerspec __user *setting) -{ +{ long err; mm_segment_t oldfs; - struct itimerspec ts; + struct itimerspec ts; oldfs = get_fs(); set_fs(KERNEL_DS); err = sys_timer_gettime(timer_id, - (struct itimerspec __user *) &ts); - set_fs(oldfs); + (struct itimerspec __user *) &ts); + set_fs(oldfs); if (!err && put_compat_itimerspec(setting, &ts)) return -EFAULT; return err; -} +} long compat_sys_clock_settime(clockid_t which_clock, struct compat_timespec __user *tp) { long err; mm_segment_t oldfs; - struct timespec ts; + struct timespec ts; if (get_compat_timespec(&ts, tp)) - return -EFAULT; + return -EFAULT; oldfs = get_fs(); - set_fs(KERNEL_DS); + set_fs(KERNEL_DS); err = sys_clock_settime(which_clock, (struct timespec __user *) &ts); set_fs(oldfs); return err; -} +} long compat_sys_clock_gettime(clockid_t which_clock, struct compat_timespec __user *tp) { long err; mm_segment_t oldfs; - struct timespec ts; + struct timespec ts; oldfs = get_fs(); set_fs(KERNEL_DS); @@ -583,16 +546,16 @@ long compat_sys_clock_gettime(clockid_t which_clock, (struct timespec __user *) &ts); set_fs(oldfs); if (!err && put_compat_timespec(&ts, tp)) - return -EFAULT; + return -EFAULT; return err; -} +} long compat_sys_clock_getres(clockid_t which_clock, struct compat_timespec __user *tp) { long err; mm_segment_t oldfs; - struct timespec ts; + struct timespec ts; oldfs = get_fs(); set_fs(KERNEL_DS); @@ -600,9 +563,9 @@ long compat_sys_clock_getres(clockid_t which_clock, (struct timespec __user *) &ts); set_fs(oldfs); if (!err && tp && put_compat_timespec(&ts, tp)) - return -EFAULT; + return -EFAULT; return err; -} +} static long compat_clock_nanosleep_restart(struct restart_block *restart) { @@ -634,10 +597,10 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, { long err; mm_segment_t oldfs; - struct timespec in, out; + struct timespec in, out; struct restart_block *restart; - if (get_compat_timespec(&in, rqtp)) + if (get_compat_timespec(&in, rqtp)) return -EFAULT; oldfs = get_fs(); @@ -656,8 +619,8 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, restart->fn = compat_clock_nanosleep_restart; restart->arg1 = (unsigned long) rmtp; } - return err; -} + return err; +} /* * We currently only need the following fields from the sigevent @@ -680,7 +643,7 @@ int get_compat_sigevent(struct sigevent *event, ? -EFAULT : 0; } -long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask, +long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, unsigned long bitmap_size) { int i, j; @@ -984,4 +947,103 @@ asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages, } return sys_move_pages(pid, nr_pages, pages, nodes, status, flags); } + +asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, + compat_ulong_t maxnode, + const compat_ulong_t __user *old_nodes, + const compat_ulong_t __user *new_nodes) +{ + unsigned long __user *old = NULL; + unsigned long __user *new = NULL; + nodemask_t tmp_mask; + unsigned long nr_bits; + unsigned long size; + + nr_bits = min_t(unsigned long, maxnode - 1, MAX_NUMNODES); + size = ALIGN(nr_bits, BITS_PER_LONG) / 8; + if (old_nodes) { + if (compat_get_bitmap(nodes_addr(tmp_mask), old_nodes, nr_bits)) + return -EFAULT; + old = compat_alloc_user_space(new_nodes ? size * 2 : size); + if (new_nodes) + new = old + size / sizeof(unsigned long); + if (copy_to_user(old, nodes_addr(tmp_mask), size)) + return -EFAULT; + } + if (new_nodes) { + if (compat_get_bitmap(nodes_addr(tmp_mask), new_nodes, nr_bits)) + return -EFAULT; + if (new == NULL) + new = compat_alloc_user_space(size); + if (copy_to_user(new, nodes_addr(tmp_mask), size)) + return -EFAULT; + } + return sys_migrate_pages(pid, nr_bits + 1, old, new); +} #endif + +struct compat_sysinfo { + s32 uptime; + u32 loads[3]; + u32 totalram; + u32 freeram; + u32 sharedram; + u32 bufferram; + u32 totalswap; + u32 freeswap; + u16 procs; + u16 pad; + u32 totalhigh; + u32 freehigh; + u32 mem_unit; + char _f[20-2*sizeof(u32)-sizeof(int)]; +}; + +asmlinkage long +compat_sys_sysinfo(struct compat_sysinfo __user *info) +{ + struct sysinfo s; + + do_sysinfo(&s); + + /* Check to see if any memory value is too large for 32-bit and scale + * down if needed + */ + if ((s.totalram >> 32) || (s.totalswap >> 32)) { + int bitcount = 0; + + while (s.mem_unit < PAGE_SIZE) { + s.mem_unit <<= 1; + bitcount++; + } + + s.totalram >>= bitcount; + s.freeram >>= bitcount; + s.sharedram >>= bitcount; + s.bufferram >>= bitcount; + s.totalswap >>= bitcount; + s.freeswap >>= bitcount; + s.totalhigh >>= bitcount; + s.freehigh >>= bitcount; + } + + if (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo)) || + __put_user (s.uptime, &info->uptime) || + __put_user (s.loads[0], &info->loads[0]) || + __put_user (s.loads[1], &info->loads[1]) || + __put_user (s.loads[2], &info->loads[2]) || + __put_user (s.totalram, &info->totalram) || + __put_user (s.freeram, &info->freeram) || + __put_user (s.sharedram, &info->sharedram) || + __put_user (s.bufferram, &info->bufferram) || + __put_user (s.totalswap, &info->totalswap) || + __put_user (s.freeswap, &info->freeswap) || + __put_user (s.procs, &info->procs) || + __put_user (s.totalhigh, &info->totalhigh) || + __put_user (s.freehigh, &info->freehigh) || + __put_user (s.mem_unit, &info->mem_unit)) + return -EFAULT; + + return 0; +} +