ia64/linux-2.6.18-xen.hg

view arch/sparc64/kernel/sys_sunos32.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_sunos32.c,v 1.64 2002/02/09 19:49:31 davem Exp $
2 * sys_sunos32.c: SunOS binary compatibility layer on sparc64.
3 *
4 * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
6 *
7 * Based upon preliminary work which is:
8 *
9 * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
10 */
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/types.h>
15 #include <linux/capability.h>
16 #include <linux/compat.h>
17 #include <linux/mman.h>
18 #include <linux/mm.h>
19 #include <linux/swap.h>
20 #include <linux/fs.h>
21 #include <linux/file.h>
22 #include <linux/resource.h>
23 #include <linux/ipc.h>
24 #include <linux/shm.h>
25 #include <linux/msg.h>
26 #include <linux/sem.h>
27 #include <linux/signal.h>
28 #include <linux/uio.h>
29 #include <linux/utsname.h>
30 #include <linux/major.h>
31 #include <linux/stat.h>
32 #include <linux/slab.h>
33 #include <linux/pagemap.h>
34 #include <linux/errno.h>
35 #include <linux/smp.h>
36 #include <linux/smp_lock.h>
37 #include <linux/syscalls.h>
39 #include <asm/uaccess.h>
40 #include <asm/page.h>
41 #include <asm/pgtable.h>
42 #include <asm/pconf.h>
43 #include <asm/idprom.h> /* for gethostid() */
44 #include <asm/unistd.h>
45 #include <asm/system.h>
47 /* For the nfs mount emulation */
48 #include <linux/socket.h>
49 #include <linux/in.h>
50 #include <linux/nfs.h>
51 #include <linux/nfs2.h>
52 #include <linux/nfs_mount.h>
54 /* for sunos_select */
55 #include <linux/time.h>
56 #include <linux/personality.h>
58 /* For SOCKET_I */
59 #include <linux/socket.h>
60 #include <net/sock.h>
61 #include <net/compat.h>
63 #define SUNOS_NR_OPEN 256
65 asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
66 {
67 struct file *file = NULL;
68 unsigned long retval, ret_type;
70 if (flags & MAP_NORESERVE) {
71 static int cnt;
72 if (cnt++ < 10)
73 printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n",
74 current->comm);
75 flags &= ~MAP_NORESERVE;
76 }
77 retval = -EBADF;
78 if (!(flags & MAP_ANONYMOUS)) {
79 struct inode * inode;
80 if (fd >= SUNOS_NR_OPEN)
81 goto out;
82 file = fget(fd);
83 if (!file)
84 goto out;
85 inode = file->f_dentry->d_inode;
86 if (imajor(inode) == MEM_MAJOR && iminor(inode) == 5) {
87 flags |= MAP_ANONYMOUS;
88 fput(file);
89 file = NULL;
90 }
91 }
93 retval = -EINVAL;
94 if (!(flags & MAP_FIXED))
95 addr = 0;
96 else if (len > 0xf0000000 || addr > 0xf0000000 - len)
97 goto out_putf;
98 ret_type = flags & _MAP_NEW;
99 flags &= ~_MAP_NEW;
101 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
102 down_write(&current->mm->mmap_sem);
103 retval = do_mmap(file,
104 (unsigned long) addr, (unsigned long) len,
105 (unsigned long) prot, (unsigned long) flags,
106 (unsigned long) off);
107 up_write(&current->mm->mmap_sem);
108 if (!ret_type)
109 retval = ((retval < 0xf0000000) ? 0 : retval);
110 out_putf:
111 if (file)
112 fput(file);
113 out:
114 return (u32) retval;
115 }
117 asmlinkage int sunos_mctl(u32 addr, u32 len, int function, u32 arg)
118 {
119 return 0;
120 }
122 asmlinkage int sunos_brk(u32 baddr)
123 {
124 int freepages, retval = -ENOMEM;
125 unsigned long rlim;
126 unsigned long newbrk, oldbrk, brk = (unsigned long) baddr;
128 down_write(&current->mm->mmap_sem);
129 if (brk < current->mm->end_code)
130 goto out;
131 newbrk = PAGE_ALIGN(brk);
132 oldbrk = PAGE_ALIGN(current->mm->brk);
133 retval = 0;
134 if (oldbrk == newbrk) {
135 current->mm->brk = brk;
136 goto out;
137 }
138 /* Always allow shrinking brk. */
139 if (brk <= current->mm->brk) {
140 current->mm->brk = brk;
141 do_munmap(current->mm, newbrk, oldbrk-newbrk);
142 goto out;
143 }
144 /* Check against rlimit and stack.. */
145 retval = -ENOMEM;
146 rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
147 if (rlim >= RLIM_INFINITY)
148 rlim = ~0;
149 if (brk - current->mm->end_code > rlim)
150 goto out;
151 /* Check against existing mmap mappings. */
152 if (find_vma_intersection(current->mm, oldbrk, newbrk+PAGE_SIZE))
153 goto out;
154 /* stupid algorithm to decide if we have enough memory: while
155 * simple, it hopefully works in most obvious cases.. Easy to
156 * fool it, but this should catch most mistakes.
157 */
158 freepages = global_page_state(NR_FILE_PAGES);
159 freepages >>= 1;
160 freepages += nr_free_pages();
161 freepages += nr_swap_pages;
162 freepages -= num_physpages >> 4;
163 freepages -= (newbrk-oldbrk) >> PAGE_SHIFT;
164 if (freepages < 0)
165 goto out;
166 /* Ok, we have probably got enough memory - let it rip. */
167 current->mm->brk = brk;
168 do_brk(oldbrk, newbrk-oldbrk);
169 retval = 0;
170 out:
171 up_write(&current->mm->mmap_sem);
172 return retval;
173 }
175 asmlinkage u32 sunos_sbrk(int increment)
176 {
177 int error, oldbrk;
179 /* This should do it hopefully... */
180 oldbrk = (int)current->mm->brk;
181 error = sunos_brk(((int) current->mm->brk) + increment);
182 if (!error)
183 error = oldbrk;
184 return error;
185 }
187 asmlinkage u32 sunos_sstk(int increment)
188 {
189 printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n",
190 current->comm, increment);
192 return (u32)-1;
193 }
195 /* Give hints to the kernel as to what paging strategy to use...
196 * Completely bogus, don't remind me.
197 */
198 #define VA_NORMAL 0 /* Normal vm usage expected */
199 #define VA_ABNORMAL 1 /* Abnormal/random vm usage probable */
200 #define VA_SEQUENTIAL 2 /* Accesses will be of a sequential nature */
201 #define VA_INVALIDATE 3 /* Page table entries should be flushed ??? */
202 static char *vstrings[] = {
203 "VA_NORMAL",
204 "VA_ABNORMAL",
205 "VA_SEQUENTIAL",
206 "VA_INVALIDATE",
207 };
209 asmlinkage void sunos_vadvise(u32 strategy)
210 {
211 static int count;
213 /* I wanna see who uses this... */
214 if (count++ < 5)
215 printk("%s: Advises us to use %s paging strategy\n",
216 current->comm,
217 strategy <= 3 ? vstrings[strategy] : "BOGUS");
218 }
220 /* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE
221 * resource limit and is for backwards compatibility with older sunos
222 * revs.
223 */
224 asmlinkage int sunos_getdtablesize(void)
225 {
226 return SUNOS_NR_OPEN;
227 }
230 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
232 asmlinkage u32 sunos_sigblock(u32 blk_mask)
233 {
234 u32 old;
236 spin_lock_irq(&current->sighand->siglock);
237 old = (u32) current->blocked.sig[0];
238 current->blocked.sig[0] |= (blk_mask & _BLOCKABLE);
239 recalc_sigpending();
240 spin_unlock_irq(&current->sighand->siglock);
241 return old;
242 }
244 asmlinkage u32 sunos_sigsetmask(u32 newmask)
245 {
246 u32 retval;
248 spin_lock_irq(&current->sighand->siglock);
249 retval = (u32) current->blocked.sig[0];
250 current->blocked.sig[0] = (newmask & _BLOCKABLE);
251 recalc_sigpending();
252 spin_unlock_irq(&current->sighand->siglock);
253 return retval;
254 }
256 /* SunOS getdents is very similar to the newer Linux (iBCS2 compliant) */
257 /* getdents system call, the format of the structure just has a different */
258 /* layout (d_off+d_ino instead of d_ino+d_off) */
259 struct sunos_dirent {
260 s32 d_off;
261 u32 d_ino;
262 u16 d_reclen;
263 u16 d_namlen;
264 char d_name[1];
265 };
267 struct sunos_dirent_callback {
268 struct sunos_dirent __user *curr;
269 struct sunos_dirent __user *previous;
270 int count;
271 int error;
272 };
274 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
275 #define ROUND_UP(x) (((x)+sizeof(s32)-1) & ~(sizeof(s32)-1))
277 static int sunos_filldir(void * __buf, const char * name, int namlen,
278 loff_t offset, ino_t ino, unsigned int d_type)
279 {
280 struct sunos_dirent __user *dirent;
281 struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf;
282 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
284 buf->error = -EINVAL; /* only used if we fail.. */
285 if (reclen > buf->count)
286 return -EINVAL;
287 dirent = buf->previous;
288 if (dirent)
289 put_user(offset, &dirent->d_off);
290 dirent = buf->curr;
291 buf->previous = dirent;
292 put_user(ino, &dirent->d_ino);
293 put_user(namlen, &dirent->d_namlen);
294 put_user(reclen, &dirent->d_reclen);
295 if (copy_to_user(dirent->d_name, name, namlen))
296 return -EFAULT;
297 put_user(0, dirent->d_name + namlen);
298 dirent = (void __user *) dirent + reclen;
299 buf->curr = dirent;
300 buf->count -= reclen;
301 return 0;
302 }
304 asmlinkage int sunos_getdents(unsigned int fd, void __user *dirent, int cnt)
305 {
306 struct file * file;
307 struct sunos_dirent __user *lastdirent;
308 struct sunos_dirent_callback buf;
309 int error = -EBADF;
311 if (fd >= SUNOS_NR_OPEN)
312 goto out;
314 file = fget(fd);
315 if (!file)
316 goto out;
318 error = -EINVAL;
319 if (cnt < (sizeof(struct sunos_dirent) + 255))
320 goto out_putf;
322 buf.curr = (struct sunos_dirent __user *) dirent;
323 buf.previous = NULL;
324 buf.count = cnt;
325 buf.error = 0;
327 error = vfs_readdir(file, sunos_filldir, &buf);
328 if (error < 0)
329 goto out_putf;
331 lastdirent = buf.previous;
332 error = buf.error;
333 if (lastdirent) {
334 put_user(file->f_pos, &lastdirent->d_off);
335 error = cnt - buf.count;
336 }
338 out_putf:
339 fput(file);
340 out:
341 return error;
342 }
344 /* Old sunos getdirentries, severely broken compatibility stuff here. */
345 struct sunos_direntry {
346 u32 d_ino;
347 u16 d_reclen;
348 u16 d_namlen;
349 char d_name[1];
350 };
352 struct sunos_direntry_callback {
353 struct sunos_direntry __user *curr;
354 struct sunos_direntry __user *previous;
355 int count;
356 int error;
357 };
359 static int sunos_filldirentry(void * __buf, const char * name, int namlen,
360 loff_t offset, ino_t ino, unsigned int d_type)
361 {
362 struct sunos_direntry __user *dirent;
363 struct sunos_direntry_callback * buf =
364 (struct sunos_direntry_callback *) __buf;
365 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
367 buf->error = -EINVAL; /* only used if we fail.. */
368 if (reclen > buf->count)
369 return -EINVAL;
370 dirent = buf->previous;
371 dirent = buf->curr;
372 buf->previous = dirent;
373 put_user(ino, &dirent->d_ino);
374 put_user(namlen, &dirent->d_namlen);
375 put_user(reclen, &dirent->d_reclen);
376 if (copy_to_user(dirent->d_name, name, namlen))
377 return -EFAULT;
378 put_user(0, dirent->d_name + namlen);
379 dirent = (void __user *) dirent + reclen;
380 buf->curr = dirent;
381 buf->count -= reclen;
382 return 0;
383 }
385 asmlinkage int sunos_getdirentries(unsigned int fd,
386 void __user *dirent,
387 int cnt,
388 unsigned int __user *basep)
389 {
390 struct file * file;
391 struct sunos_direntry __user *lastdirent;
392 int error = -EBADF;
393 struct sunos_direntry_callback buf;
395 if (fd >= SUNOS_NR_OPEN)
396 goto out;
398 file = fget(fd);
399 if (!file)
400 goto out;
402 error = -EINVAL;
403 if (cnt < (sizeof(struct sunos_direntry) + 255))
404 goto out_putf;
406 buf.curr = (struct sunos_direntry __user *) dirent;
407 buf.previous = NULL;
408 buf.count = cnt;
409 buf.error = 0;
411 error = vfs_readdir(file, sunos_filldirentry, &buf);
412 if (error < 0)
413 goto out_putf;
415 lastdirent = buf.previous;
416 error = buf.error;
417 if (lastdirent) {
418 put_user(file->f_pos, basep);
419 error = cnt - buf.count;
420 }
422 out_putf:
423 fput(file);
424 out:
425 return error;
426 }
428 struct sunos_utsname {
429 char sname[9];
430 char nname[9];
431 char nnext[56];
432 char rel[9];
433 char ver[9];
434 char mach[9];
435 };
437 asmlinkage int sunos_uname(struct sunos_utsname __user *name)
438 {
439 int ret;
441 down_read(&uts_sem);
442 ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0],
443 sizeof(name->sname) - 1);
444 ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0],
445 sizeof(name->nname) - 1);
446 ret |= put_user('\0', &name->nname[8]);
447 ret |= copy_to_user(&name->rel[0], &system_utsname.release[0],
448 sizeof(name->rel) - 1);
449 ret |= copy_to_user(&name->ver[0], &system_utsname.version[0],
450 sizeof(name->ver) - 1);
451 ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0],
452 sizeof(name->mach) - 1);
453 up_read(&uts_sem);
454 return (ret ? -EFAULT : 0);
455 }
457 asmlinkage int sunos_nosys(void)
458 {
459 struct pt_regs *regs;
460 siginfo_t info;
461 static int cnt;
463 regs = current_thread_info()->kregs;
464 if (test_thread_flag(TIF_32BIT)) {
465 regs->tpc &= 0xffffffff;
466 regs->tnpc &= 0xffffffff;
467 }
468 info.si_signo = SIGSYS;
469 info.si_errno = 0;
470 info.si_code = __SI_FAULT|0x100;
471 info.si_addr = (void __user *)regs->tpc;
472 info.si_trapno = regs->u_regs[UREG_G1];
473 send_sig_info(SIGSYS, &info, current);
474 if (cnt++ < 4) {
475 printk("Process makes ni_syscall number %d, register dump:\n",
476 (int) regs->u_regs[UREG_G1]);
477 show_regs(regs);
478 }
479 return -ENOSYS;
480 }
482 /* This is not a real and complete implementation yet, just to keep
483 * the easy SunOS binaries happy.
484 */
485 asmlinkage int sunos_fpathconf(int fd, int name)
486 {
487 int ret;
489 switch(name) {
490 case _PCONF_LINK:
491 ret = LINK_MAX;
492 break;
493 case _PCONF_CANON:
494 ret = MAX_CANON;
495 break;
496 case _PCONF_INPUT:
497 ret = MAX_INPUT;
498 break;
499 case _PCONF_NAME:
500 ret = NAME_MAX;
501 break;
502 case _PCONF_PATH:
503 ret = PATH_MAX;
504 break;
505 case _PCONF_PIPE:
506 ret = PIPE_BUF;
507 break;
508 case _PCONF_CHRESTRICT: /* XXX Investigate XXX */
509 ret = 1;
510 break;
511 case _PCONF_NOTRUNC: /* XXX Investigate XXX */
512 case _PCONF_VDISABLE:
513 ret = 0;
514 break;
515 default:
516 ret = -EINVAL;
517 break;
518 }
519 return ret;
520 }
522 asmlinkage int sunos_pathconf(u32 u_path, int name)
523 {
524 int ret;
526 ret = sunos_fpathconf(0, name); /* XXX cheese XXX */
527 return ret;
528 }
530 asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp_x)
531 {
532 int ret;
534 /* SunOS binaries expect that select won't change the tvp contents */
535 ret = compat_sys_select(width, compat_ptr(inp), compat_ptr(outp),
536 compat_ptr(exp), compat_ptr(tvp_x));
537 if (ret == -EINTR && tvp_x) {
538 struct compat_timeval __user *tvp = compat_ptr(tvp_x);
539 time_t sec, usec;
541 __get_user(sec, &tvp->tv_sec);
542 __get_user(usec, &tvp->tv_usec);
543 if (sec == 0 && usec == 0)
544 ret = 0;
545 }
546 return ret;
547 }
549 asmlinkage void sunos_nop(void)
550 {
551 return;
552 }
554 #if 0 /* This code doesn't translate user pointers correctly,
555 * disable for now. -DaveM
556 */
558 /* XXXXXXXXXX SunOS mount/umount. XXXXXXXXXXX */
559 #define SMNT_RDONLY 1
560 #define SMNT_NOSUID 2
561 #define SMNT_NEWTYPE 4
562 #define SMNT_GRPID 8
563 #define SMNT_REMOUNT 16
564 #define SMNT_NOSUB 32
565 #define SMNT_MULTI 64
566 #define SMNT_SYS5 128
568 struct sunos_fh_t {
569 char fh_data [NFS_FHSIZE];
570 };
572 struct sunos_nfs_mount_args {
573 struct sockaddr_in *addr; /* file server address */
574 struct nfs_fh *fh; /* File handle to be mounted */
575 int flags; /* flags */
576 int wsize; /* write size in bytes */
577 int rsize; /* read size in bytes */
578 int timeo; /* initial timeout in .1 secs */
579 int retrans; /* times to retry send */
580 char *hostname; /* server's hostname */
581 int acregmin; /* attr cache file min secs */
582 int acregmax; /* attr cache file max secs */
583 int acdirmin; /* attr cache dir min secs */
584 int acdirmax; /* attr cache dir max secs */
585 char *netname; /* server's netname */
586 };
589 /* Bind the socket on a local reserved port and connect it to the
590 * remote server. This on Linux/i386 is done by the mount program,
591 * not by the kernel.
592 */
593 /* XXXXXXXXXXXXXXXXXXXX */
594 static int
595 sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
596 {
597 struct sockaddr_in local;
598 struct sockaddr_in server;
599 int try_port;
600 int ret;
601 struct socket *socket;
602 struct inode *inode;
603 struct file *file;
605 file = fget(fd);
606 if (!file)
607 return 0;
609 inode = file->f_dentry->d_inode;
611 socket = SOCKET_I(inode);
612 local.sin_family = AF_INET;
613 local.sin_addr.s_addr = INADDR_ANY;
615 /* IPPORT_RESERVED = 1024, can't find the definition in the kernel */
616 try_port = 1024;
617 do {
618 local.sin_port = htons (--try_port);
619 ret = socket->ops->bind(socket, (struct sockaddr*)&local,
620 sizeof(local));
621 } while (ret && try_port > (1024 / 2));
623 if (ret) {
624 fput(file);
625 return 0;
626 }
628 server.sin_family = AF_INET;
629 server.sin_addr = addr->sin_addr;
630 server.sin_port = NFS_PORT;
632 /* Call sys_connect */
633 ret = socket->ops->connect (socket, (struct sockaddr *) &server,
634 sizeof (server), file->f_flags);
635 fput(file);
636 if (ret < 0)
637 return 0;
638 return 1;
639 }
641 /* XXXXXXXXXXXXXXXXXXXX */
642 static int get_default (int value, int def_value)
643 {
644 if (value)
645 return value;
646 else
647 return def_value;
648 }
650 /* XXXXXXXXXXXXXXXXXXXX */
651 static int sunos_nfs_mount(char *dir_name, int linux_flags, void __user *data)
652 {
653 int server_fd, err;
654 char *the_name, *mount_page;
655 struct nfs_mount_data linux_nfs_mount;
656 struct sunos_nfs_mount_args sunos_mount;
658 /* Ok, here comes the fun part: Linux's nfs mount needs a
659 * socket connection to the server, but SunOS mount does not
660 * require this, so we use the information on the destination
661 * address to create a socket and bind it to a reserved
662 * port on this system
663 */
664 if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount)))
665 return -EFAULT;
667 server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
668 if (server_fd < 0)
669 return -ENXIO;
671 if (copy_from_user(&linux_nfs_mount.addr, sunos_mount.addr,
672 sizeof(*sunos_mount.addr)) ||
673 copy_from_user(&linux_nfs_mount.root, sunos_mount.fh,
674 sizeof(*sunos_mount.fh))) {
675 sys_close (server_fd);
676 return -EFAULT;
677 }
679 if (!sunos_nfs_get_server_fd (server_fd, &linux_nfs_mount.addr)){
680 sys_close (server_fd);
681 return -ENXIO;
682 }
684 /* Now, bind it to a locally reserved port */
685 linux_nfs_mount.version = NFS_MOUNT_VERSION;
686 linux_nfs_mount.flags = sunos_mount.flags;
687 linux_nfs_mount.fd = server_fd;
689 linux_nfs_mount.rsize = get_default (sunos_mount.rsize, 8192);
690 linux_nfs_mount.wsize = get_default (sunos_mount.wsize, 8192);
691 linux_nfs_mount.timeo = get_default (sunos_mount.timeo, 10);
692 linux_nfs_mount.retrans = sunos_mount.retrans;
694 linux_nfs_mount.acregmin = sunos_mount.acregmin;
695 linux_nfs_mount.acregmax = sunos_mount.acregmax;
696 linux_nfs_mount.acdirmin = sunos_mount.acdirmin;
697 linux_nfs_mount.acdirmax = sunos_mount.acdirmax;
699 the_name = getname(sunos_mount.hostname);
700 if (IS_ERR(the_name))
701 return PTR_ERR(the_name);
703 strlcpy(linux_nfs_mount.hostname, the_name,
704 sizeof(linux_nfs_mount.hostname));
705 putname (the_name);
707 mount_page = (char *) get_zeroed_page(GFP_KERNEL);
708 if (!mount_page)
709 return -ENOMEM;
711 memcpy(mount_page, &linux_nfs_mount, sizeof(linux_nfs_mount));
713 err = do_mount("", dir_name, "nfs", linux_flags, mount_page);
715 free_page((unsigned long) mount_page);
716 return err;
717 }
719 /* XXXXXXXXXXXXXXXXXXXX */
720 asmlinkage int
721 sunos_mount(char *type, char *dir, int flags, void *data)
722 {
723 int linux_flags = 0;
724 int ret = -EINVAL;
725 char *dev_fname = 0;
726 char *dir_page, *type_page;
728 if (!capable (CAP_SYS_ADMIN))
729 return -EPERM;
731 /* We don't handle the integer fs type */
732 if ((flags & SMNT_NEWTYPE) == 0)
733 goto out;
735 /* Do not allow for those flags we don't support */
736 if (flags & (SMNT_GRPID|SMNT_NOSUB|SMNT_MULTI|SMNT_SYS5))
737 goto out;
739 if (flags & SMNT_REMOUNT)
740 linux_flags |= MS_REMOUNT;
741 if (flags & SMNT_RDONLY)
742 linux_flags |= MS_RDONLY;
743 if (flags & SMNT_NOSUID)
744 linux_flags |= MS_NOSUID;
746 dir_page = getname(dir);
747 ret = PTR_ERR(dir_page);
748 if (IS_ERR(dir_page))
749 goto out;
751 type_page = getname(type);
752 ret = PTR_ERR(type_page);
753 if (IS_ERR(type_page))
754 goto out1;
756 if (strcmp(type_page, "ext2") == 0) {
757 dev_fname = getname(data);
758 } else if (strcmp(type_page, "iso9660") == 0) {
759 dev_fname = getname(data);
760 } else if (strcmp(type_page, "minix") == 0) {
761 dev_fname = getname(data);
762 } else if (strcmp(type_page, "nfs") == 0) {
763 ret = sunos_nfs_mount (dir_page, flags, data);
764 goto out2;
765 } else if (strcmp(type_page, "ufs") == 0) {
766 printk("Warning: UFS filesystem mounts unsupported.\n");
767 ret = -ENODEV;
768 goto out2;
769 } else if (strcmp(type_page, "proc")) {
770 ret = -ENODEV;
771 goto out2;
772 }
773 ret = PTR_ERR(dev_fname);
774 if (IS_ERR(dev_fname))
775 goto out2;
776 lock_kernel();
777 ret = do_mount(dev_fname, dir_page, type_page, linux_flags, NULL);
778 unlock_kernel();
779 if (dev_fname)
780 putname(dev_fname);
781 out2:
782 putname(type_page);
783 out1:
784 putname(dir_page);
785 out:
786 return ret;
787 }
788 #endif
790 asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid)
791 {
792 int ret;
794 /* So stupid... */
795 if ((!pid || pid == current->pid) &&
796 !pgid) {
797 sys_setsid();
798 ret = 0;
799 } else {
800 ret = sys_setpgid(pid, pgid);
801 }
802 return ret;
803 }
805 /* So stupid... */
806 extern long compat_sys_wait4(compat_pid_t, compat_uint_t __user *, int,
807 struct compat_rusage __user *);
809 asmlinkage int sunos_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options, struct compat_rusage __user *ru)
810 {
811 int ret;
813 ret = compat_sys_wait4((pid ? pid : ((compat_pid_t)-1)),
814 stat_addr, options, ru);
815 return ret;
816 }
818 extern int kill_pg(int, int, int);
819 asmlinkage int sunos_killpg(int pgrp, int sig)
820 {
821 return kill_pg(pgrp, sig, 0);
822 }
824 asmlinkage int sunos_audit(void)
825 {
826 printk ("sys_audit\n");
827 return -1;
828 }
830 asmlinkage u32 sunos_gethostid(void)
831 {
832 u32 ret;
834 ret = (((u32)idprom->id_machtype << 24) | ((u32)idprom->id_sernum));
836 return ret;
837 }
839 /* sysconf options, for SunOS compatibility */
840 #define _SC_ARG_MAX 1
841 #define _SC_CHILD_MAX 2
842 #define _SC_CLK_TCK 3
843 #define _SC_NGROUPS_MAX 4
844 #define _SC_OPEN_MAX 5
845 #define _SC_JOB_CONTROL 6
846 #define _SC_SAVED_IDS 7
847 #define _SC_VERSION 8
849 asmlinkage s32 sunos_sysconf (int name)
850 {
851 s32 ret;
853 switch (name){
854 case _SC_ARG_MAX:
855 ret = ARG_MAX;
856 break;
857 case _SC_CHILD_MAX:
858 ret = -1; /* no limit */
859 break;
860 case _SC_CLK_TCK:
861 ret = HZ;
862 break;
863 case _SC_NGROUPS_MAX:
864 ret = NGROUPS_MAX;
865 break;
866 case _SC_OPEN_MAX:
867 ret = OPEN_MAX;
868 break;
869 case _SC_JOB_CONTROL:
870 ret = 1; /* yes, we do support job control */
871 break;
872 case _SC_SAVED_IDS:
873 ret = 1; /* yes, we do support saved uids */
874 break;
875 case _SC_VERSION:
876 /* mhm, POSIX_VERSION is in /usr/include/unistd.h
877 * should it go on /usr/include/linux?
878 */
879 ret = 199009;
880 break;
881 default:
882 ret = -1;
883 break;
884 };
885 return ret;
886 }
888 asmlinkage int sunos_semsys(int op, u32 arg1, u32 arg2, u32 arg3, void __user *ptr)
889 {
890 union semun arg4;
891 int ret;
893 switch (op) {
894 case 0:
895 /* Most arguments match on a 1:1 basis but cmd doesn't */
896 switch(arg3) {
897 case 4:
898 arg3=GETPID; break;
899 case 5:
900 arg3=GETVAL; break;
901 case 6:
902 arg3=GETALL; break;
903 case 3:
904 arg3=GETNCNT; break;
905 case 7:
906 arg3=GETZCNT; break;
907 case 8:
908 arg3=SETVAL; break;
909 case 9:
910 arg3=SETALL; break;
911 }
912 /* sys_semctl(): */
913 /* value to modify semaphore to */
914 arg4.__pad = ptr;
915 ret = sys_semctl((int)arg1, (int)arg2, (int)arg3, arg4);
916 break;
917 case 1:
918 /* sys_semget(): */
919 ret = sys_semget((key_t)arg1, (int)arg2, (int)arg3);
920 break;
921 case 2:
922 /* sys_semop(): */
923 ret = sys_semop((int)arg1, (struct sembuf __user *)(unsigned long)arg2,
924 (unsigned int) arg3);
925 break;
926 default:
927 ret = -EINVAL;
928 break;
929 };
930 return ret;
931 }
933 struct msgbuf32 {
934 s32 mtype;
935 char mtext[1];
936 };
938 struct ipc_perm32
939 {
940 key_t key;
941 compat_uid_t uid;
942 compat_gid_t gid;
943 compat_uid_t cuid;
944 compat_gid_t cgid;
945 compat_mode_t mode;
946 unsigned short seq;
947 };
949 struct msqid_ds32
950 {
951 struct ipc_perm32 msg_perm;
952 u32 msg_first;
953 u32 msg_last;
954 compat_time_t msg_stime;
955 compat_time_t msg_rtime;
956 compat_time_t msg_ctime;
957 u32 wwait;
958 u32 rwait;
959 unsigned short msg_cbytes;
960 unsigned short msg_qnum;
961 unsigned short msg_qbytes;
962 compat_ipc_pid_t msg_lspid;
963 compat_ipc_pid_t msg_lrpid;
964 };
966 static inline int sunos_msqid_get(struct msqid_ds32 __user *user,
967 struct msqid_ds *kern)
968 {
969 if (get_user(kern->msg_perm.key, &user->msg_perm.key) ||
970 __get_user(kern->msg_perm.uid, &user->msg_perm.uid) ||
971 __get_user(kern->msg_perm.gid, &user->msg_perm.gid) ||
972 __get_user(kern->msg_perm.cuid, &user->msg_perm.cuid) ||
973 __get_user(kern->msg_perm.cgid, &user->msg_perm.cgid) ||
974 __get_user(kern->msg_stime, &user->msg_stime) ||
975 __get_user(kern->msg_rtime, &user->msg_rtime) ||
976 __get_user(kern->msg_ctime, &user->msg_ctime) ||
977 __get_user(kern->msg_ctime, &user->msg_cbytes) ||
978 __get_user(kern->msg_ctime, &user->msg_qnum) ||
979 __get_user(kern->msg_ctime, &user->msg_qbytes) ||
980 __get_user(kern->msg_ctime, &user->msg_lspid) ||
981 __get_user(kern->msg_ctime, &user->msg_lrpid))
982 return -EFAULT;
983 return 0;
984 }
986 static inline int sunos_msqid_put(struct msqid_ds32 __user *user,
987 struct msqid_ds *kern)
988 {
989 if (put_user(kern->msg_perm.key, &user->msg_perm.key) ||
990 __put_user(kern->msg_perm.uid, &user->msg_perm.uid) ||
991 __put_user(kern->msg_perm.gid, &user->msg_perm.gid) ||
992 __put_user(kern->msg_perm.cuid, &user->msg_perm.cuid) ||
993 __put_user(kern->msg_perm.cgid, &user->msg_perm.cgid) ||
994 __put_user(kern->msg_stime, &user->msg_stime) ||
995 __put_user(kern->msg_rtime, &user->msg_rtime) ||
996 __put_user(kern->msg_ctime, &user->msg_ctime) ||
997 __put_user(kern->msg_ctime, &user->msg_cbytes) ||
998 __put_user(kern->msg_ctime, &user->msg_qnum) ||
999 __put_user(kern->msg_ctime, &user->msg_qbytes) ||
1000 __put_user(kern->msg_ctime, &user->msg_lspid) ||
1001 __put_user(kern->msg_ctime, &user->msg_lrpid))
1002 return -EFAULT;
1003 return 0;
1006 static inline int sunos_msgbuf_get(struct msgbuf32 __user *user, struct msgbuf *kern, int len)
1008 if (get_user(kern->mtype, &user->mtype) ||
1009 __copy_from_user(kern->mtext, &user->mtext, len))
1010 return -EFAULT;
1011 return 0;
1014 static inline int sunos_msgbuf_put(struct msgbuf32 __user *user, struct msgbuf *kern, int len)
1016 if (put_user(kern->mtype, &user->mtype) ||
1017 __copy_to_user(user->mtext, kern->mtext, len))
1018 return -EFAULT;
1019 return 0;
1022 asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
1024 struct sparc_stackf32 __user *sp;
1025 struct msqid_ds kds;
1026 struct msgbuf *kmbuf;
1027 mm_segment_t old_fs = get_fs();
1028 u32 arg5;
1029 int rval;
1031 switch(op) {
1032 case 0:
1033 rval = sys_msgget((key_t)arg1, (int)arg2);
1034 break;
1035 case 1:
1036 if (!sunos_msqid_get((struct msqid_ds32 __user *)(unsigned long)arg3, &kds)) {
1037 set_fs(KERNEL_DS);
1038 rval = sys_msgctl((int)arg1, (int)arg2,
1039 (struct msqid_ds __user *)(unsigned long)arg3);
1040 set_fs(old_fs);
1041 if (!rval)
1042 rval = sunos_msqid_put((struct msqid_ds32 __user *)(unsigned long)arg3,
1043 &kds);
1044 } else
1045 rval = -EFAULT;
1046 break;
1047 case 2:
1048 rval = -EFAULT;
1049 kmbuf = (struct msgbuf *)kmalloc(sizeof(struct msgbuf) + arg3,
1050 GFP_KERNEL);
1051 if (!kmbuf)
1052 break;
1053 sp = (struct sparc_stackf32 __user *)
1054 (current_thread_info()->kregs->u_regs[UREG_FP] & 0xffffffffUL);
1055 if (get_user(arg5, &sp->xxargs[0])) {
1056 rval = -EFAULT;
1057 kfree(kmbuf);
1058 break;
1060 set_fs(KERNEL_DS);
1061 rval = sys_msgrcv((int)arg1, (struct msgbuf __user *) kmbuf,
1062 (size_t)arg3,
1063 (long)arg4, (int)arg5);
1064 set_fs(old_fs);
1065 if (!rval)
1066 rval = sunos_msgbuf_put((struct msgbuf32 __user *)(unsigned long)arg2,
1067 kmbuf, arg3);
1068 kfree(kmbuf);
1069 break;
1070 case 3:
1071 rval = -EFAULT;
1072 kmbuf = (struct msgbuf *)kmalloc(sizeof(struct msgbuf) + arg3,
1073 GFP_KERNEL);
1074 if (!kmbuf || sunos_msgbuf_get((struct msgbuf32 __user *)(unsigned long)arg2,
1075 kmbuf, arg3))
1076 break;
1077 set_fs(KERNEL_DS);
1078 rval = sys_msgsnd((int)arg1, (struct msgbuf __user *) kmbuf,
1079 (size_t)arg3, (int)arg4);
1080 set_fs(old_fs);
1081 kfree(kmbuf);
1082 break;
1083 default:
1084 rval = -EINVAL;
1085 break;
1087 return rval;
1090 struct shmid_ds32 {
1091 struct ipc_perm32 shm_perm;
1092 int shm_segsz;
1093 compat_time_t shm_atime;
1094 compat_time_t shm_dtime;
1095 compat_time_t shm_ctime;
1096 compat_ipc_pid_t shm_cpid;
1097 compat_ipc_pid_t shm_lpid;
1098 unsigned short shm_nattch;
1099 };
1101 static inline int sunos_shmid_get(struct shmid_ds32 __user *user,
1102 struct shmid_ds *kern)
1104 if (get_user(kern->shm_perm.key, &user->shm_perm.key) ||
1105 __get_user(kern->shm_perm.uid, &user->shm_perm.uid) ||
1106 __get_user(kern->shm_perm.gid, &user->shm_perm.gid) ||
1107 __get_user(kern->shm_perm.cuid, &user->shm_perm.cuid) ||
1108 __get_user(kern->shm_perm.cgid, &user->shm_perm.cgid) ||
1109 __get_user(kern->shm_segsz, &user->shm_segsz) ||
1110 __get_user(kern->shm_atime, &user->shm_atime) ||
1111 __get_user(kern->shm_dtime, &user->shm_dtime) ||
1112 __get_user(kern->shm_ctime, &user->shm_ctime) ||
1113 __get_user(kern->shm_cpid, &user->shm_cpid) ||
1114 __get_user(kern->shm_lpid, &user->shm_lpid) ||
1115 __get_user(kern->shm_nattch, &user->shm_nattch))
1116 return -EFAULT;
1117 return 0;
1120 static inline int sunos_shmid_put(struct shmid_ds32 __user *user,
1121 struct shmid_ds *kern)
1123 if (put_user(kern->shm_perm.key, &user->shm_perm.key) ||
1124 __put_user(kern->shm_perm.uid, &user->shm_perm.uid) ||
1125 __put_user(kern->shm_perm.gid, &user->shm_perm.gid) ||
1126 __put_user(kern->shm_perm.cuid, &user->shm_perm.cuid) ||
1127 __put_user(kern->shm_perm.cgid, &user->shm_perm.cgid) ||
1128 __put_user(kern->shm_segsz, &user->shm_segsz) ||
1129 __put_user(kern->shm_atime, &user->shm_atime) ||
1130 __put_user(kern->shm_dtime, &user->shm_dtime) ||
1131 __put_user(kern->shm_ctime, &user->shm_ctime) ||
1132 __put_user(kern->shm_cpid, &user->shm_cpid) ||
1133 __put_user(kern->shm_lpid, &user->shm_lpid) ||
1134 __put_user(kern->shm_nattch, &user->shm_nattch))
1135 return -EFAULT;
1136 return 0;
1139 asmlinkage int sunos_shmsys(int op, u32 arg1, u32 arg2, u32 arg3)
1141 struct shmid_ds ksds;
1142 unsigned long raddr;
1143 mm_segment_t old_fs = get_fs();
1144 int rval;
1146 switch(op) {
1147 case 0:
1148 /* do_shmat(): attach a shared memory area */
1149 rval = do_shmat((int)arg1,(char __user *)(unsigned long)arg2,(int)arg3,&raddr);
1150 if (!rval)
1151 rval = (int) raddr;
1152 break;
1153 case 1:
1154 /* sys_shmctl(): modify shared memory area attr. */
1155 if (!sunos_shmid_get((struct shmid_ds32 __user *)(unsigned long)arg3, &ksds)) {
1156 set_fs(KERNEL_DS);
1157 rval = sys_shmctl((int) arg1,(int) arg2,
1158 (struct shmid_ds __user *) &ksds);
1159 set_fs(old_fs);
1160 if (!rval)
1161 rval = sunos_shmid_put((struct shmid_ds32 __user *)(unsigned long)arg3,
1162 &ksds);
1163 } else
1164 rval = -EFAULT;
1165 break;
1166 case 2:
1167 /* sys_shmdt(): detach a shared memory area */
1168 rval = sys_shmdt((char __user *)(unsigned long)arg1);
1169 break;
1170 case 3:
1171 /* sys_shmget(): get a shared memory area */
1172 rval = sys_shmget((key_t)arg1,(int)arg2,(int)arg3);
1173 break;
1174 default:
1175 rval = -EINVAL;
1176 break;
1177 };
1178 return rval;
1181 extern asmlinkage long sparc32_open(const char __user * filename, int flags, int mode);
1183 asmlinkage int sunos_open(u32 fname, int flags, int mode)
1185 const char __user *filename = compat_ptr(fname);
1187 return sparc32_open(filename, flags, mode);
1190 #define SUNOS_EWOULDBLOCK 35
1192 /* see the sunos man page read(2v) for an explanation
1193 of this garbage. We use O_NDELAY to mark
1194 file descriptors that have been set non-blocking
1195 using 4.2BSD style calls. (tridge) */
1197 static inline int check_nonblock(int ret, int fd)
1199 if (ret == -EAGAIN) {
1200 struct file * file = fget(fd);
1201 if (file) {
1202 if (file->f_flags & O_NDELAY)
1203 ret = -SUNOS_EWOULDBLOCK;
1204 fput(file);
1207 return ret;
1210 asmlinkage int sunos_read(unsigned int fd, char __user *buf, u32 count)
1212 int ret;
1214 ret = check_nonblock(sys_read(fd, buf, count), fd);
1215 return ret;
1218 asmlinkage int sunos_readv(u32 fd, void __user *vector, s32 count)
1220 int ret;
1222 ret = check_nonblock(compat_sys_readv(fd, vector, count), fd);
1223 return ret;
1226 asmlinkage int sunos_write(unsigned int fd, char __user *buf, u32 count)
1228 int ret;
1230 ret = check_nonblock(sys_write(fd, buf, count), fd);
1231 return ret;
1234 asmlinkage int sunos_writev(u32 fd, void __user *vector, s32 count)
1236 int ret;
1238 ret = check_nonblock(compat_sys_writev(fd, vector, count), fd);
1239 return ret;
1242 asmlinkage int sunos_recv(u32 __fd, void __user *ubuf, int size, unsigned flags)
1244 int ret, fd = (int) __fd;
1246 ret = check_nonblock(sys_recv(fd, ubuf, size, flags), fd);
1247 return ret;
1250 asmlinkage int sunos_send(u32 __fd, void __user *buff, int len, unsigned flags)
1252 int ret, fd = (int) __fd;
1254 ret = check_nonblock(sys_send(fd, buff, len, flags), fd);
1255 return ret;
1258 asmlinkage int sunos_accept(u32 __fd, struct sockaddr __user *sa, int __user *addrlen)
1260 int ret, fd = (int) __fd;
1262 while (1) {
1263 ret = check_nonblock(sys_accept(fd, sa, addrlen), fd);
1264 if (ret != -ENETUNREACH && ret != -EHOSTUNREACH)
1265 break;
1267 return ret;
1270 #define SUNOS_SV_INTERRUPT 2
1272 asmlinkage int sunos_sigaction (int sig,
1273 struct old_sigaction32 __user *act,
1274 struct old_sigaction32 __user *oact)
1276 struct k_sigaction new_ka, old_ka;
1277 int ret;
1279 if (act) {
1280 compat_old_sigset_t mask;
1281 u32 u_handler;
1283 if (get_user(u_handler, &act->sa_handler) ||
1284 __get_user(new_ka.sa.sa_flags, &act->sa_flags))
1285 return -EFAULT;
1286 new_ka.sa.sa_handler = compat_ptr(u_handler);
1287 __get_user(mask, &act->sa_mask);
1288 new_ka.sa.sa_restorer = NULL;
1289 new_ka.ka_restorer = NULL;
1290 siginitset(&new_ka.sa.sa_mask, mask);
1291 new_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT;
1294 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
1296 if (!ret && oact) {
1297 old_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT;
1298 if (put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler) ||
1299 __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
1300 return -EFAULT;
1301 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
1304 return ret;
1307 asmlinkage int sunos_setsockopt(u32 __fd, u32 __level, u32 __optname,
1308 char __user *optval, u32 __optlen)
1310 int fd = (int) __fd;
1311 int level = (int) __level;
1312 int optname = (int) __optname;
1313 int optlen = (int) __optlen;
1314 int tr_opt = optname;
1315 int ret;
1317 if (level == SOL_IP) {
1318 /* Multicast socketopts (ttl, membership) */
1319 if (tr_opt >=2 && tr_opt <= 6)
1320 tr_opt += 30;
1322 ret = sys_setsockopt(fd, level, tr_opt,
1323 optval, optlen);
1324 return ret;
1327 asmlinkage int sunos_getsockopt(u32 __fd, u32 __level, u32 __optname,
1328 char __user *optval, int __user *optlen)
1330 int fd = (int) __fd;
1331 int level = (int) __level;
1332 int optname = (int) __optname;
1333 int tr_opt = optname;
1334 int ret;
1336 if (level == SOL_IP) {
1337 /* Multicast socketopts (ttl, membership) */
1338 if (tr_opt >=2 && tr_opt <= 6)
1339 tr_opt += 30;
1341 ret = compat_sys_getsockopt(fd, level, tr_opt,
1342 optval, optlen);
1343 return ret;