ia64/linux-2.6.18-xen.hg

view arch/sparc64/kernel/sys_sparc32.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
line source
1 /* $Id: sys_sparc32.c,v 1.184 2002/02/09 19:49:31 davem Exp $
2 * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
3 *
4 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
6 *
7 * These routines maintain argument size conversion between 32bit and 64bit
8 * environment.
9 */
11 #include <linux/kernel.h>
12 #include <linux/sched.h>
13 #include <linux/capability.h>
14 #include <linux/fs.h>
15 #include <linux/mm.h>
16 #include <linux/file.h>
17 #include <linux/signal.h>
18 #include <linux/resource.h>
19 #include <linux/times.h>
20 #include <linux/utsname.h>
21 #include <linux/smp.h>
22 #include <linux/smp_lock.h>
23 #include <linux/sem.h>
24 #include <linux/msg.h>
25 #include <linux/shm.h>
26 #include <linux/slab.h>
27 #include <linux/uio.h>
28 #include <linux/nfs_fs.h>
29 #include <linux/quota.h>
30 #include <linux/module.h>
31 #include <linux/sunrpc/svc.h>
32 #include <linux/nfsd/nfsd.h>
33 #include <linux/nfsd/cache.h>
34 #include <linux/nfsd/xdr.h>
35 #include <linux/nfsd/syscall.h>
36 #include <linux/poll.h>
37 #include <linux/personality.h>
38 #include <linux/stat.h>
39 #include <linux/filter.h>
40 #include <linux/highmem.h>
41 #include <linux/highuid.h>
42 #include <linux/mman.h>
43 #include <linux/ipv6.h>
44 #include <linux/in.h>
45 #include <linux/icmpv6.h>
46 #include <linux/syscalls.h>
47 #include <linux/sysctl.h>
48 #include <linux/binfmts.h>
49 #include <linux/dnotify.h>
50 #include <linux/security.h>
51 #include <linux/compat.h>
52 #include <linux/vfs.h>
53 #include <linux/netfilter_ipv4/ip_tables.h>
54 #include <linux/ptrace.h>
55 #include <linux/highuid.h>
57 #include <asm/types.h>
58 #include <asm/ipc.h>
59 #include <asm/uaccess.h>
60 #include <asm/fpumacro.h>
61 #include <asm/semaphore.h>
62 #include <asm/mmu_context.h>
63 #include <asm/a.out.h>
65 asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group)
66 {
67 return sys_chown(filename, low2highuid(user), low2highgid(group));
68 }
70 asmlinkage long sys32_lchown16(const char __user * filename, u16 user, u16 group)
71 {
72 return sys_lchown(filename, low2highuid(user), low2highgid(group));
73 }
75 asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group)
76 {
77 return sys_fchown(fd, low2highuid(user), low2highgid(group));
78 }
80 asmlinkage long sys32_setregid16(u16 rgid, u16 egid)
81 {
82 return sys_setregid(low2highgid(rgid), low2highgid(egid));
83 }
85 asmlinkage long sys32_setgid16(u16 gid)
86 {
87 return sys_setgid((gid_t)gid);
88 }
90 asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
91 {
92 return sys_setreuid(low2highuid(ruid), low2highuid(euid));
93 }
95 asmlinkage long sys32_setuid16(u16 uid)
96 {
97 return sys_setuid((uid_t)uid);
98 }
100 asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
101 {
102 return sys_setresuid(low2highuid(ruid), low2highuid(euid),
103 low2highuid(suid));
104 }
106 asmlinkage long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid)
107 {
108 int retval;
110 if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
111 !(retval = put_user(high2lowuid(current->euid), euid)))
112 retval = put_user(high2lowuid(current->suid), suid);
114 return retval;
115 }
117 asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid)
118 {
119 return sys_setresgid(low2highgid(rgid), low2highgid(egid),
120 low2highgid(sgid));
121 }
123 asmlinkage long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid)
124 {
125 int retval;
127 if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
128 !(retval = put_user(high2lowgid(current->egid), egid)))
129 retval = put_user(high2lowgid(current->sgid), sgid);
131 return retval;
132 }
134 asmlinkage long sys32_setfsuid16(u16 uid)
135 {
136 return sys_setfsuid((uid_t)uid);
137 }
139 asmlinkage long sys32_setfsgid16(u16 gid)
140 {
141 return sys_setfsgid((gid_t)gid);
142 }
144 static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
145 {
146 int i;
147 u16 group;
149 for (i = 0; i < group_info->ngroups; i++) {
150 group = (u16)GROUP_AT(group_info, i);
151 if (put_user(group, grouplist+i))
152 return -EFAULT;
153 }
155 return 0;
156 }
158 static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist)
159 {
160 int i;
161 u16 group;
163 for (i = 0; i < group_info->ngroups; i++) {
164 if (get_user(group, grouplist+i))
165 return -EFAULT;
166 GROUP_AT(group_info, i) = (gid_t)group;
167 }
169 return 0;
170 }
172 asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist)
173 {
174 int i;
176 if (gidsetsize < 0)
177 return -EINVAL;
179 get_group_info(current->group_info);
180 i = current->group_info->ngroups;
181 if (gidsetsize) {
182 if (i > gidsetsize) {
183 i = -EINVAL;
184 goto out;
185 }
186 if (groups16_to_user(grouplist, current->group_info)) {
187 i = -EFAULT;
188 goto out;
189 }
190 }
191 out:
192 put_group_info(current->group_info);
193 return i;
194 }
196 asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
197 {
198 struct group_info *group_info;
199 int retval;
201 if (!capable(CAP_SETGID))
202 return -EPERM;
203 if ((unsigned)gidsetsize > NGROUPS_MAX)
204 return -EINVAL;
206 group_info = groups_alloc(gidsetsize);
207 if (!group_info)
208 return -ENOMEM;
209 retval = groups16_from_user(group_info, grouplist);
210 if (retval) {
211 put_group_info(group_info);
212 return retval;
213 }
215 retval = set_current_groups(group_info);
216 put_group_info(group_info);
218 return retval;
219 }
221 asmlinkage long sys32_getuid16(void)
222 {
223 return high2lowuid(current->uid);
224 }
226 asmlinkage long sys32_geteuid16(void)
227 {
228 return high2lowuid(current->euid);
229 }
231 asmlinkage long sys32_getgid16(void)
232 {
233 return high2lowgid(current->gid);
234 }
236 asmlinkage long sys32_getegid16(void)
237 {
238 return high2lowgid(current->egid);
239 }
241 /* 32-bit timeval and related flotsam. */
243 static long get_tv32(struct timeval *o, struct compat_timeval __user *i)
244 {
245 return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
246 (__get_user(o->tv_sec, &i->tv_sec) |
247 __get_user(o->tv_usec, &i->tv_usec)));
248 }
250 static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
251 {
252 return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
253 (__put_user(i->tv_sec, &o->tv_sec) |
254 __put_user(i->tv_usec, &o->tv_usec)));
255 }
257 #ifdef CONFIG_SYSVIPC
258 asmlinkage long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, u32 fifth)
259 {
260 int version;
262 version = call >> 16; /* hack for backward compatibility */
263 call &= 0xffff;
265 switch (call) {
266 case SEMTIMEDOP:
267 if (fifth)
268 /* sign extend semid */
269 return compat_sys_semtimedop((int)first,
270 compat_ptr(ptr), second,
271 compat_ptr(fifth));
272 /* else fall through for normal semop() */
273 case SEMOP:
274 /* struct sembuf is the same on 32 and 64bit :)) */
275 /* sign extend semid */
276 return sys_semtimedop((int)first, compat_ptr(ptr), second,
277 NULL);
278 case SEMGET:
279 /* sign extend key, nsems */
280 return sys_semget((int)first, (int)second, third);
281 case SEMCTL:
282 /* sign extend semid, semnum */
283 return compat_sys_semctl((int)first, (int)second, third,
284 compat_ptr(ptr));
286 case MSGSND:
287 /* sign extend msqid */
288 return compat_sys_msgsnd((int)first, (int)second, third,
289 compat_ptr(ptr));
290 case MSGRCV:
291 /* sign extend msqid, msgtyp */
292 return compat_sys_msgrcv((int)first, second, (int)fifth,
293 third, version, compat_ptr(ptr));
294 case MSGGET:
295 /* sign extend key */
296 return sys_msgget((int)first, second);
297 case MSGCTL:
298 /* sign extend msqid */
299 return compat_sys_msgctl((int)first, second, compat_ptr(ptr));
301 case SHMAT:
302 /* sign extend shmid */
303 return compat_sys_shmat((int)first, second, third, version,
304 compat_ptr(ptr));
305 case SHMDT:
306 return sys_shmdt(compat_ptr(ptr));
307 case SHMGET:
308 /* sign extend key_t */
309 return sys_shmget((int)first, second, third);
310 case SHMCTL:
311 /* sign extend shmid */
312 return compat_sys_shmctl((int)first, second, compat_ptr(ptr));
314 default:
315 return -ENOSYS;
316 };
318 return -ENOSYS;
319 }
320 #endif
322 asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
323 {
324 if ((int)high < 0)
325 return -EINVAL;
326 else
327 return sys_truncate(path, (high << 32) | low);
328 }
330 asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
331 {
332 if ((int)high < 0)
333 return -EINVAL;
334 else
335 return sys_ftruncate(fd, (high << 32) | low);
336 }
338 int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
339 {
340 int err;
342 if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) ||
343 !old_valid_dev(stat->rdev))
344 return -EOVERFLOW;
346 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
347 err |= put_user(stat->ino, &statbuf->st_ino);
348 err |= put_user(stat->mode, &statbuf->st_mode);
349 err |= put_user(stat->nlink, &statbuf->st_nlink);
350 err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
351 err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
352 err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev);
353 err |= put_user(stat->size, &statbuf->st_size);
354 err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
355 err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
356 err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
357 err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
358 err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
359 err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
360 err |= put_user(stat->blksize, &statbuf->st_blksize);
361 err |= put_user(stat->blocks, &statbuf->st_blocks);
362 err |= put_user(0, &statbuf->__unused4[0]);
363 err |= put_user(0, &statbuf->__unused4[1]);
365 return err;
366 }
368 int cp_compat_stat64(struct kstat *stat, struct compat_stat64 __user *statbuf)
369 {
370 int err;
372 err = put_user(huge_encode_dev(stat->dev), &statbuf->st_dev);
373 err |= put_user(stat->ino, &statbuf->st_ino);
374 err |= put_user(stat->mode, &statbuf->st_mode);
375 err |= put_user(stat->nlink, &statbuf->st_nlink);
376 err |= put_user(stat->uid, &statbuf->st_uid);
377 err |= put_user(stat->gid, &statbuf->st_gid);
378 err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev);
379 err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]);
380 err |= put_user(stat->size, &statbuf->st_size);
381 err |= put_user(stat->blksize, &statbuf->st_blksize);
382 err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[0]);
383 err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[4]);
384 err |= put_user(stat->blocks, &statbuf->st_blocks);
385 err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
386 err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
387 err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
388 err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
389 err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
390 err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
391 err |= put_user(0, &statbuf->__unused4);
392 err |= put_user(0, &statbuf->__unused5);
394 return err;
395 }
397 asmlinkage long compat_sys_stat64(char __user * filename,
398 struct compat_stat64 __user *statbuf)
399 {
400 struct kstat stat;
401 int error = vfs_stat(filename, &stat);
403 if (!error)
404 error = cp_compat_stat64(&stat, statbuf);
405 return error;
406 }
408 asmlinkage long compat_sys_lstat64(char __user * filename,
409 struct compat_stat64 __user *statbuf)
410 {
411 struct kstat stat;
412 int error = vfs_lstat(filename, &stat);
414 if (!error)
415 error = cp_compat_stat64(&stat, statbuf);
416 return error;
417 }
419 asmlinkage long compat_sys_fstat64(unsigned int fd,
420 struct compat_stat64 __user * statbuf)
421 {
422 struct kstat stat;
423 int error = vfs_fstat(fd, &stat);
425 if (!error)
426 error = cp_compat_stat64(&stat, statbuf);
427 return error;
428 }
430 asmlinkage long compat_sys_fstatat64(unsigned int dfd, char __user *filename,
431 struct compat_stat64 __user * statbuf, int flag)
432 {
433 struct kstat stat;
434 int error = -EINVAL;
436 if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
437 goto out;
439 if (flag & AT_SYMLINK_NOFOLLOW)
440 error = vfs_lstat_fd(dfd, filename, &stat);
441 else
442 error = vfs_stat_fd(dfd, filename, &stat);
444 if (!error)
445 error = cp_compat_stat64(&stat, statbuf);
447 out:
448 return error;
449 }
451 asmlinkage long compat_sys_sysfs(int option, u32 arg1, u32 arg2)
452 {
453 return sys_sysfs(option, arg1, arg2);
454 }
456 struct sysinfo32 {
457 s32 uptime;
458 u32 loads[3];
459 u32 totalram;
460 u32 freeram;
461 u32 sharedram;
462 u32 bufferram;
463 u32 totalswap;
464 u32 freeswap;
465 unsigned short procs;
466 unsigned short pad;
467 u32 totalhigh;
468 u32 freehigh;
469 u32 mem_unit;
470 char _f[20-2*sizeof(int)-sizeof(int)];
471 };
473 asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
474 {
475 struct sysinfo s;
476 int ret, err;
477 int bitcount = 0;
478 mm_segment_t old_fs = get_fs ();
480 set_fs(KERNEL_DS);
481 ret = sys_sysinfo((struct sysinfo __user *) &s);
482 set_fs(old_fs);
483 /* Check to see if any memory value is too large for 32-bit and
484 * scale down if needed.
485 */
486 if ((s.totalram >> 32) || (s.totalswap >> 32)) {
487 while (s.mem_unit < PAGE_SIZE) {
488 s.mem_unit <<= 1;
489 bitcount++;
490 }
491 s.totalram >>= bitcount;
492 s.freeram >>= bitcount;
493 s.sharedram >>= bitcount;
494 s.bufferram >>= bitcount;
495 s.totalswap >>= bitcount;
496 s.freeswap >>= bitcount;
497 s.totalhigh >>= bitcount;
498 s.freehigh >>= bitcount;
499 }
501 err = put_user (s.uptime, &info->uptime);
502 err |= __put_user (s.loads[0], &info->loads[0]);
503 err |= __put_user (s.loads[1], &info->loads[1]);
504 err |= __put_user (s.loads[2], &info->loads[2]);
505 err |= __put_user (s.totalram, &info->totalram);
506 err |= __put_user (s.freeram, &info->freeram);
507 err |= __put_user (s.sharedram, &info->sharedram);
508 err |= __put_user (s.bufferram, &info->bufferram);
509 err |= __put_user (s.totalswap, &info->totalswap);
510 err |= __put_user (s.freeswap, &info->freeswap);
511 err |= __put_user (s.procs, &info->procs);
512 err |= __put_user (s.totalhigh, &info->totalhigh);
513 err |= __put_user (s.freehigh, &info->freehigh);
514 err |= __put_user (s.mem_unit, &info->mem_unit);
515 if (err)
516 return -EFAULT;
517 return ret;
518 }
520 asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval)
521 {
522 struct timespec t;
523 int ret;
524 mm_segment_t old_fs = get_fs ();
526 set_fs (KERNEL_DS);
527 ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t);
528 set_fs (old_fs);
529 if (put_compat_timespec(&t, interval))
530 return -EFAULT;
531 return ret;
532 }
534 asmlinkage long compat_sys_rt_sigprocmask(int how,
535 compat_sigset_t __user *set,
536 compat_sigset_t __user *oset,
537 compat_size_t sigsetsize)
538 {
539 sigset_t s;
540 compat_sigset_t s32;
541 int ret;
542 mm_segment_t old_fs = get_fs();
544 if (set) {
545 if (copy_from_user (&s32, set, sizeof(compat_sigset_t)))
546 return -EFAULT;
547 switch (_NSIG_WORDS) {
548 case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
549 case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
550 case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
551 case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
552 }
553 }
554 set_fs (KERNEL_DS);
555 ret = sys_rt_sigprocmask(how,
556 set ? (sigset_t __user *) &s : NULL,
557 oset ? (sigset_t __user *) &s : NULL,
558 sigsetsize);
559 set_fs (old_fs);
560 if (ret) return ret;
561 if (oset) {
562 switch (_NSIG_WORDS) {
563 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
564 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
565 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
566 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
567 }
568 if (copy_to_user (oset, &s32, sizeof(compat_sigset_t)))
569 return -EFAULT;
570 }
571 return 0;
572 }
574 asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
575 compat_size_t sigsetsize)
576 {
577 sigset_t s;
578 compat_sigset_t s32;
579 int ret;
580 mm_segment_t old_fs = get_fs();
582 set_fs (KERNEL_DS);
583 ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
584 set_fs (old_fs);
585 if (!ret) {
586 switch (_NSIG_WORDS) {
587 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
588 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
589 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
590 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
591 }
592 if (copy_to_user (set, &s32, sizeof(compat_sigset_t)))
593 return -EFAULT;
594 }
595 return ret;
596 }
598 asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig,
599 struct compat_siginfo __user *uinfo)
600 {
601 siginfo_t info;
602 int ret;
603 mm_segment_t old_fs = get_fs();
605 if (copy_siginfo_from_user32(&info, uinfo))
606 return -EFAULT;
608 set_fs (KERNEL_DS);
609 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
610 set_fs (old_fs);
611 return ret;
612 }
614 asmlinkage long compat_sys_sigaction(int sig, struct old_sigaction32 __user *act,
615 struct old_sigaction32 __user *oact)
616 {
617 struct k_sigaction new_ka, old_ka;
618 int ret;
620 if (sig < 0) {
621 set_thread_flag(TIF_NEWSIGNALS);
622 sig = -sig;
623 }
625 if (act) {
626 compat_old_sigset_t mask;
627 u32 u_handler, u_restorer;
629 ret = get_user(u_handler, &act->sa_handler);
630 new_ka.sa.sa_handler = compat_ptr(u_handler);
631 ret |= __get_user(u_restorer, &act->sa_restorer);
632 new_ka.sa.sa_restorer = compat_ptr(u_restorer);
633 ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
634 ret |= __get_user(mask, &act->sa_mask);
635 if (ret)
636 return ret;
637 new_ka.ka_restorer = NULL;
638 siginitset(&new_ka.sa.sa_mask, mask);
639 }
641 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
643 if (!ret && oact) {
644 ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
645 ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
646 ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
647 ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
648 }
650 return ret;
651 }
653 asmlinkage long compat_sys_rt_sigaction(int sig,
654 struct sigaction32 __user *act,
655 struct sigaction32 __user *oact,
656 void __user *restorer,
657 compat_size_t sigsetsize)
658 {
659 struct k_sigaction new_ka, old_ka;
660 int ret;
661 compat_sigset_t set32;
663 /* XXX: Don't preclude handling different sized sigset_t's. */
664 if (sigsetsize != sizeof(compat_sigset_t))
665 return -EINVAL;
667 /* All tasks which use RT signals (effectively) use
668 * new style signals.
669 */
670 set_thread_flag(TIF_NEWSIGNALS);
672 if (act) {
673 u32 u_handler, u_restorer;
675 new_ka.ka_restorer = restorer;
676 ret = get_user(u_handler, &act->sa_handler);
677 new_ka.sa.sa_handler = compat_ptr(u_handler);
678 ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t));
679 switch (_NSIG_WORDS) {
680 case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32);
681 case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32);
682 case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32);
683 case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32);
684 }
685 ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
686 ret |= __get_user(u_restorer, &act->sa_restorer);
687 new_ka.sa.sa_restorer = compat_ptr(u_restorer);
688 if (ret)
689 return -EFAULT;
690 }
692 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
694 if (!ret && oact) {
695 switch (_NSIG_WORDS) {
696 case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3];
697 case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2];
698 case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1];
699 case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0];
700 }
701 ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
702 ret |= __copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t));
703 ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
704 ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
705 if (ret)
706 ret = -EFAULT;
707 }
709 return ret;
710 }
712 /*
713 * sparc32_execve() executes a new program after the asm stub has set
714 * things up for us. This should basically do what I want it to.
715 */
716 asmlinkage long sparc32_execve(struct pt_regs *regs)
717 {
718 int error, base = 0;
719 char *filename;
721 /* User register window flush is done by entry.S */
723 /* Check for indirect call. */
724 if ((u32)regs->u_regs[UREG_G1] == 0)
725 base = 1;
727 filename = getname(compat_ptr(regs->u_regs[base + UREG_I0]));
728 error = PTR_ERR(filename);
729 if (IS_ERR(filename))
730 goto out;
732 error = compat_do_execve(filename,
733 compat_ptr(regs->u_regs[base + UREG_I1]),
734 compat_ptr(regs->u_regs[base + UREG_I2]), regs);
736 putname(filename);
738 if (!error) {
739 fprs_write(0);
740 current_thread_info()->xfsr[0] = 0;
741 current_thread_info()->fpsaved[0] = 0;
742 regs->tstate &= ~TSTATE_PEF;
743 task_lock(current);
744 current->ptrace &= ~PT_DTRACE;
745 task_unlock(current);
746 }
747 out:
748 return error;
749 }
751 #ifdef CONFIG_MODULES
753 asmlinkage long sys32_init_module(void __user *umod, u32 len,
754 const char __user *uargs)
755 {
756 return sys_init_module(umod, len, uargs);
757 }
759 asmlinkage long sys32_delete_module(const char __user *name_user,
760 unsigned int flags)
761 {
762 return sys_delete_module(name_user, flags);
763 }
765 #else /* CONFIG_MODULES */
767 asmlinkage long sys32_init_module(const char __user *name_user,
768 struct module __user *mod_user)
769 {
770 return -ENOSYS;
771 }
773 asmlinkage long sys32_delete_module(const char __user *name_user)
774 {
775 return -ENOSYS;
776 }
778 #endif /* CONFIG_MODULES */
780 /* Translations due to time_t size differences. Which affects all
781 sorts of things, like timeval and itimerval. */
783 extern struct timezone sys_tz;
785 asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv,
786 struct timezone __user *tz)
787 {
788 if (tv) {
789 struct timeval ktv;
790 do_gettimeofday(&ktv);
791 if (put_tv32(tv, &ktv))
792 return -EFAULT;
793 }
794 if (tz) {
795 if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
796 return -EFAULT;
797 }
798 return 0;
799 }
801 static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
802 {
803 long usec;
805 if (!access_ok(VERIFY_READ, i, sizeof(*i)))
806 return -EFAULT;
807 if (__get_user(o->tv_sec, &i->tv_sec))
808 return -EFAULT;
809 if (__get_user(usec, &i->tv_usec))
810 return -EFAULT;
811 o->tv_nsec = usec * 1000;
812 return 0;
813 }
815 asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
816 struct timezone __user *tz)
817 {
818 struct timespec kts;
819 struct timezone ktz;
821 if (tv) {
822 if (get_ts32(&kts, tv))
823 return -EFAULT;
824 }
825 if (tz) {
826 if (copy_from_user(&ktz, tz, sizeof(ktz)))
827 return -EFAULT;
828 }
830 return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
831 }
833 asmlinkage long sys32_utimes(char __user *filename,
834 struct compat_timeval __user *tvs)
835 {
836 struct timeval ktvs[2];
838 if (tvs) {
839 if (get_tv32(&ktvs[0], tvs) ||
840 get_tv32(&ktvs[1], 1+tvs))
841 return -EFAULT;
842 }
844 return do_utimes(AT_FDCWD, filename, (tvs ? &ktvs[0] : NULL));
845 }
847 /* These are here just in case some old sparc32 binary calls it. */
848 asmlinkage long sys32_pause(void)
849 {
850 current->state = TASK_INTERRUPTIBLE;
851 schedule();
852 return -ERESTARTNOHAND;
853 }
855 asmlinkage compat_ssize_t sys32_pread64(unsigned int fd,
856 char __user *ubuf,
857 compat_size_t count,
858 unsigned long poshi,
859 unsigned long poslo)
860 {
861 return sys_pread64(fd, ubuf, count, (poshi << 32) | poslo);
862 }
864 asmlinkage compat_ssize_t sys32_pwrite64(unsigned int fd,
865 char __user *ubuf,
866 compat_size_t count,
867 unsigned long poshi,
868 unsigned long poslo)
869 {
870 return sys_pwrite64(fd, ubuf, count, (poshi << 32) | poslo);
871 }
873 asmlinkage long compat_sys_readahead(int fd,
874 unsigned long offhi,
875 unsigned long offlo,
876 compat_size_t count)
877 {
878 return sys_readahead(fd, (offhi << 32) | offlo, count);
879 }
881 long compat_sys_fadvise64(int fd,
882 unsigned long offhi,
883 unsigned long offlo,
884 compat_size_t len, int advice)
885 {
886 return sys_fadvise64_64(fd, (offhi << 32) | offlo, len, advice);
887 }
889 long compat_sys_fadvise64_64(int fd,
890 unsigned long offhi, unsigned long offlo,
891 unsigned long lenhi, unsigned long lenlo,
892 int advice)
893 {
894 return sys_fadvise64_64(fd,
895 (offhi << 32) | offlo,
896 (lenhi << 32) | lenlo,
897 advice);
898 }
900 asmlinkage long compat_sys_sendfile(int out_fd, int in_fd,
901 compat_off_t __user *offset,
902 compat_size_t count)
903 {
904 mm_segment_t old_fs = get_fs();
905 int ret;
906 off_t of;
908 if (offset && get_user(of, offset))
909 return -EFAULT;
911 set_fs(KERNEL_DS);
912 ret = sys_sendfile(out_fd, in_fd,
913 offset ? (off_t __user *) &of : NULL,
914 count);
915 set_fs(old_fs);
917 if (offset && put_user(of, offset))
918 return -EFAULT;
920 return ret;
921 }
923 asmlinkage long compat_sys_sendfile64(int out_fd, int in_fd,
924 compat_loff_t __user *offset,
925 compat_size_t count)
926 {
927 mm_segment_t old_fs = get_fs();
928 int ret;
929 loff_t lof;
931 if (offset && get_user(lof, offset))
932 return -EFAULT;
934 set_fs(KERNEL_DS);
935 ret = sys_sendfile64(out_fd, in_fd,
936 offset ? (loff_t __user *) &lof : NULL,
937 count);
938 set_fs(old_fs);
940 if (offset && put_user(lof, offset))
941 return -EFAULT;
943 return ret;
944 }
946 /* This is just a version for 32-bit applications which does
947 * not force O_LARGEFILE on.
948 */
950 asmlinkage long sparc32_open(const char __user *filename,
951 int flags, int mode)
952 {
953 return do_sys_open(AT_FDCWD, filename, flags, mode);
954 }
956 extern unsigned long do_mremap(unsigned long addr,
957 unsigned long old_len, unsigned long new_len,
958 unsigned long flags, unsigned long new_addr);
960 asmlinkage unsigned long sys32_mremap(unsigned long addr,
961 unsigned long old_len, unsigned long new_len,
962 unsigned long flags, u32 __new_addr)
963 {
964 struct vm_area_struct *vma;
965 unsigned long ret = -EINVAL;
966 unsigned long new_addr = __new_addr;
968 if (old_len > STACK_TOP32 || new_len > STACK_TOP32)
969 goto out;
970 if (addr > STACK_TOP32 - old_len)
971 goto out;
972 down_write(&current->mm->mmap_sem);
973 if (flags & MREMAP_FIXED) {
974 if (new_addr > STACK_TOP32 - new_len)
975 goto out_sem;
976 } else if (addr > STACK_TOP32 - new_len) {
977 unsigned long map_flags = 0;
978 struct file *file = NULL;
980 ret = -ENOMEM;
981 if (!(flags & MREMAP_MAYMOVE))
982 goto out_sem;
984 vma = find_vma(current->mm, addr);
985 if (vma) {
986 if (vma->vm_flags & VM_SHARED)
987 map_flags |= MAP_SHARED;
988 file = vma->vm_file;
989 }
991 /* MREMAP_FIXED checked above. */
992 new_addr = get_unmapped_area(file, addr, new_len,
993 vma ? vma->vm_pgoff : 0,
994 map_flags);
995 ret = new_addr;
996 if (new_addr & ~PAGE_MASK)
997 goto out_sem;
998 flags |= MREMAP_FIXED;
999 }
1000 ret = do_mremap(addr, old_len, new_len, flags, new_addr);
1001 out_sem:
1002 up_write(&current->mm->mmap_sem);
1003 out:
1004 return ret;
1007 struct __sysctl_args32 {
1008 u32 name;
1009 int nlen;
1010 u32 oldval;
1011 u32 oldlenp;
1012 u32 newval;
1013 u32 newlen;
1014 u32 __unused[4];
1015 };
1017 asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
1019 #ifndef CONFIG_SYSCTL
1020 return -ENOSYS;
1021 #else
1022 struct __sysctl_args32 tmp;
1023 int error;
1024 size_t oldlen, __user *oldlenp = NULL;
1025 unsigned long addr = (((unsigned long)&args->__unused[0]) + 7UL) & ~7UL;
1027 if (copy_from_user(&tmp, args, sizeof(tmp)))
1028 return -EFAULT;
1030 if (tmp.oldval && tmp.oldlenp) {
1031 /* Duh, this is ugly and might not work if sysctl_args
1032 is in read-only memory, but do_sysctl does indirectly
1033 a lot of uaccess in both directions and we'd have to
1034 basically copy the whole sysctl.c here, and
1035 glibc's __sysctl uses rw memory for the structure
1036 anyway. */
1037 if (get_user(oldlen, (u32 __user *)(unsigned long)tmp.oldlenp) ||
1038 put_user(oldlen, (size_t __user *)addr))
1039 return -EFAULT;
1040 oldlenp = (size_t __user *)addr;
1043 lock_kernel();
1044 error = do_sysctl((int __user *)(unsigned long) tmp.name,
1045 tmp.nlen,
1046 (void __user *)(unsigned long) tmp.oldval,
1047 oldlenp,
1048 (void __user *)(unsigned long) tmp.newval,
1049 tmp.newlen);
1050 unlock_kernel();
1051 if (oldlenp) {
1052 if (!error) {
1053 if (get_user(oldlen, (size_t __user *)addr) ||
1054 put_user(oldlen, (u32 __user *)(unsigned long) tmp.oldlenp))
1055 error = -EFAULT;
1057 if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)))
1058 error = -EFAULT;
1060 return error;
1061 #endif
1064 long sys32_lookup_dcookie(unsigned long cookie_high,
1065 unsigned long cookie_low,
1066 char __user *buf, size_t len)
1068 return sys_lookup_dcookie((cookie_high << 32) | cookie_low,
1069 buf, len);
1072 long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_low, unsigned long nb_high, unsigned long nb_low, int flags)
1074 return sys_sync_file_range(fd,
1075 (off_high << 32) | off_low,
1076 (nb_high << 32) | nb_low,
1077 flags);