kernel - Add vmobj_token, misc vm-related tokenization
[dragonfly.git] / sys / emulation / linux / linux_misc.c
1 /*-
2  * Copyright (c) 1994-1995 Søren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/compat/linux/linux_misc.c,v 1.85.2.9 2002/09/24 08:11:41 mdodd Exp $
29  * $DragonFly: src/sys/emulation/linux/linux_misc.c,v 1.39 2007/06/26 19:31:03 dillon Exp $
30  */
31
32 #include "opt_compat.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/fcntl.h>
37 #include <sys/imgact_aout.h>
38 #include <sys/kernel.h>
39 #include <sys/kern_syscall.h>
40 #include <sys/lock.h>
41 #include <sys/mman.h>
42 #include <sys/mount.h>
43 #include <sys/poll.h>
44 #include <sys/proc.h>
45 #include <sys/priv.h>
46 #include <sys/nlookup.h>
47 #include <sys/blist.h>
48 #include <sys/reboot.h>
49 #include <sys/resourcevar.h>
50 #include <sys/signalvar.h>
51 #include <sys/stat.h>
52 #include <sys/sysctl.h>
53 #include <sys/sysproto.h>
54 #include <sys/time.h>
55 #include <sys/unistd.h>
56 #include <sys/vmmeter.h>
57 #include <sys/vnode.h>
58 #include <sys/wait.h>
59
60 #include <sys/signal2.h>
61 #include <sys/thread2.h>
62 #include <sys/mplock2.h>
63
64 #include <vm/vm.h>
65 #include <vm/pmap.h>
66 #include <vm/vm_kern.h>
67 #include <vm/vm_map.h>
68 #include <vm/vm_extern.h>
69 #include <vm/vm_object.h>
70 #include <vm/vm_zone.h>
71 #include <vm/swap_pager.h>
72
73 #include <machine/frame.h>
74 #include <machine/limits.h>
75 #include <machine/psl.h>
76 #include <machine/sysarch.h>
77 #ifdef __i386__
78 #include <machine/segments.h>
79 #endif
80
81 #include <sys/sched.h>
82
83 #include <emulation/linux/linux_sysproto.h>
84 #include <arch_linux/linux.h>
85 #include <arch_linux/linux_proto.h>
86 #include "linux_mib.h"
87 #include "linux_util.h"
88 #include "linux_emuldata.h"
89 #include "i386/linux.h"
90
91 #define BSD_TO_LINUX_SIGNAL(sig)        \
92         (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
93
94 static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
95         RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
96         RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
97         RLIMIT_MEMLOCK, -1
98 };
99
100 struct l_sysinfo {
101         l_long          uptime;         /* Seconds since boot */
102         l_ulong         loads[3];       /* 1, 5, and 15 minute load averages */
103         l_ulong         totalram;       /* Total usable main memory size */
104         l_ulong         freeram;        /* Available memory size */
105         l_ulong         sharedram;      /* Amount of shared memory */
106         l_ulong         bufferram;      /* Memory used by buffers */
107         l_ulong         totalswap;      /* Total swap space size */
108         l_ulong         freeswap;       /* swap space still available */
109         l_ushort        procs;          /* Number of current processes */
110         l_ushort        pad;            /* explicit padding */
111         l_ulong         totalhigh;      /* Total high memory size */
112         l_ulong         freehigh;       /* Available high memory size */
113         l_uint          mem_unit;       /* Memory unit size in bytes */
114         char            _f[20-2*sizeof(l_long)-sizeof(l_int)]; /* Padding for libc5 */
115 };
116
117 int
118 sys_linux_madvise(struct linux_madvise_args *args)
119 {
120         return 0;
121 }
122
123 /*
124  * MPALMOSTSAFE
125  */
126 int
127 sys_linux_sysinfo(struct linux_sysinfo_args *args)
128 {
129         struct l_sysinfo sysinfo;
130         vm_object_t object;
131         struct timespec ts;
132         int error;
133         int i;
134
135         /* Uptime is copied out of print_uptime() in kern_shutdown.c */
136         getnanouptime(&ts);
137         i = 0;
138         if (ts.tv_sec >= 86400) {
139                 ts.tv_sec %= 86400;
140                 i = 1;
141         }
142         if (i || ts.tv_sec >= 3600) {
143                 ts.tv_sec %= 3600;
144                 i = 1;
145         }
146         if (i || ts.tv_sec >= 60) {
147                 ts.tv_sec %= 60;
148                 i = 1;
149         }
150
151         bzero(&sysinfo, sizeof(sysinfo));
152         sysinfo.uptime=ts.tv_sec;
153
154         /* Use the information from the mib to get our load averages */
155         for (i = 0; i < 3; i++)
156                 sysinfo.loads[i] = averunnable.ldavg[i];
157
158         sysinfo.totalram = Maxmem * PAGE_SIZE;
159         sysinfo.freeram = sysinfo.totalram - vmstats.v_wire_count * PAGE_SIZE;
160         sysinfo.sharedram = 0;
161
162         lwkt_gettoken(&vmobj_token);
163         for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
164              object = TAILQ_NEXT(object, object_list)) {
165                 if (object->type == OBJT_MARKER)
166                         continue;
167                 if (object->shadow_count > 1)
168                         sysinfo.sharedram += object->resident_page_count;
169         }
170         lwkt_reltoken(&vmobj_token);
171
172         sysinfo.sharedram *= PAGE_SIZE;
173         sysinfo.bufferram = 0;
174
175         if (swapblist == NULL) {
176                 sysinfo.totalswap= 0;
177                 sysinfo.freeswap = 0;
178         } else {
179                 sysinfo.totalswap = swapblist->bl_blocks * 1024;
180                 sysinfo.freeswap = swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
181         }
182
183         sysinfo.procs = nprocs;
184         sysinfo.totalhigh = 0;
185         sysinfo.freehigh = 0;
186         sysinfo.mem_unit = 1; /* Set the basic mem unit to 1 */
187
188         error = copyout(&sysinfo, (caddr_t)args->info, sizeof(sysinfo));
189         return (error);
190 }
191
192 /*
193  * MPALMOSTSAFE
194  */
195 int
196 sys_linux_alarm(struct linux_alarm_args *args)
197 {
198         struct thread *td = curthread;
199         struct proc *p = td->td_proc;
200         struct itimerval it, old_it;
201         struct timeval tv;
202
203 #ifdef DEBUG
204         if (ldebug(alarm))
205                 kprintf(ARGS(alarm, "%u"), args->secs);
206 #endif
207
208         if (args->secs > 100000000)
209                 return EINVAL;
210
211         it.it_value.tv_sec = (long)args->secs;
212         it.it_value.tv_usec = 0;
213         it.it_interval.tv_sec = 0;
214         it.it_interval.tv_usec = 0;
215         get_mplock();
216         crit_enter();
217         old_it = p->p_realtimer;
218         getmicrouptime(&tv);
219         if (timevalisset(&old_it.it_value))
220                 callout_stop(&p->p_ithandle);
221         if (it.it_value.tv_sec != 0) {
222                 callout_reset(&p->p_ithandle, tvtohz_high(&it.it_value),
223                              realitexpire, p);
224                 timevaladd(&it.it_value, &tv);
225         }
226         p->p_realtimer = it;
227         crit_exit();
228         rel_mplock();
229         if (timevalcmp(&old_it.it_value, &tv, >)) {
230                 timevalsub(&old_it.it_value, &tv);
231                 if (old_it.it_value.tv_usec != 0)
232                         old_it.it_value.tv_sec++;
233                 args->sysmsg_result = old_it.it_value.tv_sec;
234         }
235         return 0;
236 }
237
238 /*
239  * MPALMOSTSAFE
240  */
241 int
242 sys_linux_brk(struct linux_brk_args *args)
243 {
244         struct thread *td = curthread;
245         struct proc *p = td->td_proc;
246         struct vmspace *vm;
247         vm_offset_t new, old;
248         struct obreak_args bsd_args;
249
250         get_mplock();
251         vm = p->p_vmspace;
252 #ifdef DEBUG
253         if (ldebug(brk))
254                 kprintf(ARGS(brk, "%p"), (void *)args->dsend);
255 #endif
256         old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
257         new = (vm_offset_t)args->dsend;
258         bsd_args.sysmsg_result = 0;
259         bsd_args.nsize = (char *) new;
260         bsd_args.sysmsg_result = 0;
261         if (((caddr_t)new > vm->vm_daddr) && !sys_obreak(&bsd_args))
262                 args->sysmsg_result = (long)new;
263         else
264                 args->sysmsg_result = (long)old;
265         rel_mplock();
266
267         return 0;
268 }
269
270 /*
271  * MPALMOSTSAFE
272  */
273 int
274 sys_linux_uselib(struct linux_uselib_args *args)
275 {
276         struct thread *td = curthread;
277         struct proc *p;
278         struct nlookupdata nd;
279         struct vnode *vp;
280         struct exec *a_out;
281         struct vattr attr;
282         vm_offset_t vmaddr;
283         unsigned long file_offset;
284         vm_offset_t buffer;
285         unsigned long bss_size;
286         int error;
287         int locked;
288         char *path;
289
290         p = td->td_proc;
291
292         error = linux_copyin_path(args->library, &path, LINUX_PATH_EXISTS);
293         if (error)
294                 return (error);
295 #ifdef DEBUG
296         if (ldebug(uselib))
297                 kprintf(ARGS(uselib, "%s"), path);
298 #endif
299
300         a_out = NULL;
301         locked = 0;
302         vp = NULL;
303
304         get_mplock();
305         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
306         nd.nl_flags |= NLC_EXEC;
307         if (error == 0)
308                 error = nlookup(&nd);
309         if (error == 0)
310                 error = cache_vget(&nd.nl_nch, nd.nl_cred, LK_EXCLUSIVE, &vp);
311         if (error)
312                 goto cleanup;
313         /*
314          * From here on down, we have a locked vnode that must be unlocked.
315          */
316         locked = 1;
317
318         /* Writable? */
319         if (vp->v_writecount) {
320                 error = ETXTBSY;
321                 goto cleanup;
322         }
323
324         /* Executable? */
325         error = VOP_GETATTR(vp, &attr);
326         if (error)
327                 goto cleanup;
328
329         if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
330             ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
331                 error = ENOEXEC;
332                 goto cleanup;
333         }
334
335         /* Sensible size? */
336         if (attr.va_size == 0) {
337                 error = ENOEXEC;
338                 goto cleanup;
339         }
340
341         error = VOP_OPEN(vp, FREAD, td->td_ucred, NULL);
342         if (error)
343                 goto cleanup;
344
345         /*
346          * Lock no longer needed
347          */
348         vn_unlock(vp);
349         locked = 0;
350
351         /* Pull in executable header into kernel_map */
352         error = vm_mmap(&kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
353             VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
354         if (error)
355                 goto cleanup;
356
357         /* Is it a Linux binary ? */
358         if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
359                 error = ENOEXEC;
360                 goto cleanup;
361         }
362
363         /*
364          * While we are here, we should REALLY do some more checks
365          */
366
367         /* Set file/virtual offset based on a.out variant. */
368         switch ((int)(a_out->a_magic & 0xffff)) {
369         case 0413:      /* ZMAGIC */
370                 file_offset = 1024;
371                 break;
372         case 0314:      /* QMAGIC */
373                 file_offset = 0;
374                 break;
375         default:
376                 error = ENOEXEC;
377                 goto cleanup;
378         }
379
380         bss_size = round_page(a_out->a_bss);
381
382         /* Check various fields in header for validity/bounds. */
383         if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
384                 error = ENOEXEC;
385                 goto cleanup;
386         }
387
388         /* text + data can't exceed file size */
389         if (a_out->a_data + a_out->a_text > attr.va_size) {
390                 error = EFAULT;
391                 goto cleanup;
392         }
393
394         /*
395          * text/data/bss must not exceed limits
396          * XXX - this is not complete. it should check current usage PLUS
397          * the resources needed by this library.
398          */
399         if (a_out->a_text > maxtsiz ||
400             a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) {
401                 error = ENOMEM;
402                 goto cleanup;
403         }
404
405         /* prevent more writers */
406         vsetflags(vp, VTEXT);
407
408         /*
409          * Check if file_offset page aligned. Currently we cannot handle
410          * misalinged file offsets, and so we read in the entire image
411          * (what a waste).
412          */
413         if (file_offset & PAGE_MASK) {
414 #ifdef DEBUG
415                 kprintf("uselib: Non page aligned binary %lu\n", file_offset);
416 #endif
417                 /* Map text+data read/write/execute */
418
419                 /* a_entry is the load address and is page aligned */
420                 vmaddr = trunc_page(a_out->a_entry);
421
422                 /* get anon user mapping, read+write+execute */
423                 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0,
424                                     &vmaddr, a_out->a_text + a_out->a_data,
425                                     PAGE_SIZE,
426                                     FALSE, VM_MAPTYPE_NORMAL,
427                                     VM_PROT_ALL, VM_PROT_ALL,
428                                     0);
429                 if (error)
430                         goto cleanup;
431
432                 /* map file into kernel_map */
433                 error = vm_mmap(&kernel_map, &buffer,
434                     round_page(a_out->a_text + a_out->a_data + file_offset),
435                     VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp,
436                     trunc_page(file_offset));
437                 if (error)
438                         goto cleanup;
439
440                 /* copy from kernel VM space to user space */
441                 error = copyout((caddr_t)(uintptr_t)(buffer + file_offset),
442                     (caddr_t)vmaddr, a_out->a_text + a_out->a_data);
443
444                 /* release temporary kernel space */
445                 vm_map_remove(&kernel_map, buffer, buffer +
446                     round_page(a_out->a_text + a_out->a_data + file_offset));
447
448                 if (error)
449                         goto cleanup;
450         } else {
451 #ifdef DEBUG
452                 kprintf("uselib: Page aligned binary %lu\n", file_offset);
453 #endif
454                 /*
455                  * for QMAGIC, a_entry is 20 bytes beyond the load address
456                  * to skip the executable header
457                  */
458                 vmaddr = trunc_page(a_out->a_entry);
459
460                 /*
461                  * Map it all into the process's space as a single
462                  * copy-on-write "data" segment.
463                  */
464                 error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
465                     a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
466                     MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, file_offset);
467                 if (error)
468                         goto cleanup;
469         }
470 #ifdef DEBUG
471         kprintf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0],
472             ((long*)vmaddr)[1]);
473 #endif
474         if (bss_size != 0) {
475                 /* Calculate BSS start address */
476                 vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
477                     a_out->a_data;
478
479                 /* allocate some 'anon' space */
480                 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0,
481                                     &vmaddr, bss_size,
482                                     PAGE_SIZE,
483                                     FALSE, VM_MAPTYPE_NORMAL,
484                                     VM_PROT_ALL, VM_PROT_ALL,
485                                     0);
486                 if (error)
487                         goto cleanup;
488         }
489
490 cleanup:
491         /* Unlock/release vnode */
492         if (vp) {
493                 if (locked)
494                         vn_unlock(vp);
495                 vrele(vp);
496         }
497         /* Release the kernel mapping. */
498         if (a_out) {
499                 vm_map_remove(&kernel_map, (vm_offset_t)a_out,
500                     (vm_offset_t)a_out + PAGE_SIZE);
501         }
502         nlookup_done(&nd);
503         rel_mplock();
504         linux_free_path(&path);
505         return (error);
506 }
507
508 /*
509  * MPSAFE
510  */
511 int
512 sys_linux_select(struct linux_select_args *args)
513 {
514         struct select_args bsa;
515         struct timeval tv0, tv1, utv, *tvp;
516         caddr_t sg;
517         int error;
518
519 #ifdef DEBUG
520         if (ldebug(select))
521                 kprintf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
522                     (void *)args->readfds, (void *)args->writefds,
523                     (void *)args->exceptfds, (void *)args->timeout);
524 #endif
525
526         error = 0;
527         bsa.sysmsg_result = 0;
528         bsa.nd = args->nfds;
529         bsa.in = args->readfds;
530         bsa.ou = args->writefds;
531         bsa.ex = args->exceptfds;
532         bsa.tv = (struct timeval *)args->timeout;
533
534         /*
535          * Store current time for computation of the amount of
536          * time left.
537          */
538         if (args->timeout) {
539                 if ((error = copyin((caddr_t)args->timeout, &utv,
540                     sizeof(utv))))
541                         goto select_out;
542 #ifdef DEBUG
543                 if (ldebug(select))
544                         kprintf(LMSG("incoming timeout (%ld/%ld)"),
545                             utv.tv_sec, utv.tv_usec);
546 #endif
547
548                 if (itimerfix(&utv)) {
549                         /*
550                          * The timeval was invalid.  Convert it to something
551                          * valid that will act as it does under Linux.
552                          */
553                         sg = stackgap_init();
554                         tvp = stackgap_alloc(&sg, sizeof(utv));
555                         utv.tv_sec += utv.tv_usec / 1000000;
556                         utv.tv_usec %= 1000000;
557                         if (utv.tv_usec < 0) {
558                                 utv.tv_sec -= 1;
559                                 utv.tv_usec += 1000000;
560                         }
561                         if (utv.tv_sec < 0)
562                                 timevalclear(&utv);
563                         if ((error = copyout(&utv, tvp, sizeof(utv))))
564                                 goto select_out;
565                         bsa.tv = tvp;
566                 }
567                 microtime(&tv0);
568         }
569
570         error = sys_select(&bsa);
571         args->sysmsg_result = bsa.sysmsg_result;
572 #ifdef DEBUG
573         if (ldebug(select))
574                 kprintf(LMSG("real select returns %d"), error);
575 #endif
576         if (error) {
577                 /*
578                  * See fs/select.c in the Linux kernel.  Without this,
579                  * Maelstrom doesn't work.
580                  */
581                 if (error == ERESTART)
582                         error = EINTR;
583                 goto select_out;
584         }
585
586         if (args->timeout) {
587                 if (args->sysmsg_result) {
588                         /*
589                          * Compute how much time was left of the timeout,
590                          * by subtracting the current time and the time
591                          * before we started the call, and subtracting
592                          * that result from the user-supplied value.
593                          */
594                         microtime(&tv1);
595                         timevalsub(&tv1, &tv0);
596                         timevalsub(&utv, &tv1);
597                         if (utv.tv_sec < 0)
598                                 timevalclear(&utv);
599                 } else
600                         timevalclear(&utv);
601 #ifdef DEBUG
602                 if (ldebug(select))
603                         kprintf(LMSG("outgoing timeout (%ld/%ld)"),
604                             utv.tv_sec, utv.tv_usec);
605 #endif
606                 if ((error = copyout(&utv, (caddr_t)args->timeout,
607                     sizeof(utv))))
608                         goto select_out;
609         }
610
611 select_out:
612 #ifdef DEBUG
613         if (ldebug(select))
614                 kprintf(LMSG("select_out -> %d"), error);
615 #endif
616         return error;
617 }
618
619 /*
620  * MPSAFE
621  */
622 int     
623 sys_linux_mremap(struct linux_mremap_args *args)
624 {
625         struct munmap_args bsd_args; 
626         int error = 0;
627
628 #ifdef DEBUG
629         if (ldebug(mremap))
630                 kprintf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
631                     (void *)args->addr, 
632                     (unsigned long)args->old_len, 
633                     (unsigned long)args->new_len,
634                     (unsigned long)args->flags);
635 #endif
636         if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) {
637                 args->sysmsg_resultp = NULL;
638                 return (EINVAL);
639         }
640
641         /*
642          * Check for the page alignment.
643          * Linux defines PAGE_MASK to be FreeBSD ~PAGE_MASK.
644          */
645         if (args->addr & PAGE_MASK) {
646                 args->sysmsg_resultp = NULL;
647                 return (EINVAL);
648         }
649
650         args->new_len = round_page(args->new_len);
651         args->old_len = round_page(args->old_len);
652
653         if (args->new_len > args->old_len) {
654                 args->sysmsg_result = 0;
655                 return ENOMEM;
656         }
657
658         if (args->new_len < args->old_len) {
659                 bsd_args.sysmsg_result = 0;
660                 bsd_args.addr = (caddr_t)(args->addr + args->new_len);
661                 bsd_args.len = args->old_len - args->new_len;
662                 error = sys_munmap(&bsd_args);
663         }
664
665         args->sysmsg_resultp = error ? NULL : (void *)args->addr;
666         return error;
667 }
668
669 #define LINUX_MS_ASYNC          0x0001
670 #define LINUX_MS_INVALIDATE     0x0002
671 #define LINUX_MS_SYNC           0x0004
672
673 /*
674  * MPSAFE
675  */
676 int
677 sys_linux_msync(struct linux_msync_args *args)
678 {
679         struct msync_args bsd_args;
680         int error;
681
682         bsd_args.addr = (caddr_t)args->addr;
683         bsd_args.len = args->len;
684         bsd_args.flags = args->fl & ~LINUX_MS_SYNC;
685         bsd_args.sysmsg_result = 0;
686
687         error = sys_msync(&bsd_args);
688         args->sysmsg_result = bsd_args.sysmsg_result;
689         return(error);
690 }
691
692 /*
693  * MPSAFE
694  */
695 int
696 sys_linux_time(struct linux_time_args *args)
697 {
698         struct timeval tv;
699         l_time_t tm;
700         int error;
701
702 #ifdef DEBUG
703         if (ldebug(time))
704                 kprintf(ARGS(time, "*"));
705 #endif
706
707         microtime(&tv);
708         tm = tv.tv_sec;
709         if (args->tm && (error = copyout(&tm, (caddr_t)args->tm, sizeof(tm))))
710                 return error;
711         args->sysmsg_lresult = tm;
712         return 0;
713 }
714
715 struct l_times_argv {
716         l_long          tms_utime;
717         l_long          tms_stime;
718         l_long          tms_cutime;
719         l_long          tms_cstime;
720 };
721
722 #define CLK_TCK 100     /* Linux uses 100 */
723
724 #define CONVTCK(r)      (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
725
726 /*
727  * MPALMOSTSAFE
728  */
729 int
730 sys_linux_times(struct linux_times_args *args)
731 {
732         struct thread *td = curthread;
733         struct proc *p = td->td_proc;
734         struct timeval tv;
735         struct l_times_argv tms;
736         struct rusage ru;
737         int error;
738
739 #ifdef DEBUG
740         if (ldebug(times))
741                 kprintf(ARGS(times, "*"));
742 #endif
743
744         get_mplock();
745         calcru_proc(p, &ru);
746         rel_mplock();
747
748         tms.tms_utime = CONVTCK(ru.ru_utime);
749         tms.tms_stime = CONVTCK(ru.ru_stime);
750
751         tms.tms_cutime = CONVTCK(p->p_cru.ru_utime);
752         tms.tms_cstime = CONVTCK(p->p_cru.ru_stime);
753
754         if ((error = copyout(&tms, (caddr_t)args->buf, sizeof(tms))))
755                 return error;
756
757         microuptime(&tv);
758         args->sysmsg_result = (int)CONVTCK(tv);
759         return 0;
760 }
761
762 /*
763  * MPALMOSTSAFE
764  */
765 int
766 sys_linux_newuname(struct linux_newuname_args *args)
767 {
768         struct thread *td = curthread;
769         struct l_new_utsname utsname;
770         char *osrelease, *osname;
771
772 #ifdef DEBUG
773         if (ldebug(newuname))
774                 kprintf(ARGS(newuname, "*"));
775 #endif
776
777         get_mplock();
778         osname = linux_get_osname(td);
779         osrelease = linux_get_osrelease(td);
780
781         bzero(&utsname, sizeof(utsname));
782         strncpy(utsname.sysname, osname, LINUX_MAX_UTSNAME-1);
783         strncpy(utsname.nodename, hostname, LINUX_MAX_UTSNAME-1);
784         strncpy(utsname.release, osrelease, LINUX_MAX_UTSNAME-1);
785         strncpy(utsname.version, version, LINUX_MAX_UTSNAME-1);
786         strncpy(utsname.machine, machine, LINUX_MAX_UTSNAME-1);
787         strncpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME-1);
788         rel_mplock();
789
790         return (copyout(&utsname, (caddr_t)args->buf, sizeof(utsname)));
791 }
792
793 /* XXX: why would this be i386-only? most of these are wrong! */
794 #if defined(__i386__)
795 struct l_utimbuf {
796         l_time_t l_actime;
797         l_time_t l_modtime;
798 };
799
800 /*
801  * MPALMOSTSAFE
802  */
803 int
804 sys_linux_utime(struct linux_utime_args *args)
805 {
806         struct timeval tv[2];
807         struct l_utimbuf lut;
808         struct nlookupdata nd;
809         char *path;
810         int error;
811
812         error = linux_copyin_path(args->fname, &path, LINUX_PATH_EXISTS);
813         if (error)
814                 return (error);
815 #ifdef DEBUG
816         if (ldebug(utime))
817                 kprintf(ARGS(utime, "%s, *"), path);
818 #endif
819
820         if (args->times) {
821                 error = copyin(args->times, &lut, sizeof(lut));
822                 if (error)
823                         goto cleanup;
824                 tv[0].tv_sec = lut.l_actime;
825                 tv[0].tv_usec = 0;
826                 tv[1].tv_sec = lut.l_modtime;
827                 tv[1].tv_usec = 0;
828         }
829         get_mplock();
830         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
831         if (error == 0)
832                 error = kern_utimes(&nd, args->times ? tv : NULL);
833         nlookup_done(&nd);
834         rel_mplock();
835 cleanup:
836         linux_free_path(&path);
837         return (error);
838 }
839
840 int
841 sys_linux_utimes(struct linux_utimes_args *args)
842 {
843         l_timeval ltv[2];
844         struct timeval tv[2], *tvp = NULL;
845         struct nlookupdata nd;
846         char *path;
847         int error;
848
849         error = linux_copyin_path(args->fname, &path, LINUX_PATH_EXISTS);
850         if (error)
851                 return (error);
852 #ifdef DEBUG
853         if (ldebug(utimes))
854                 kprintf(ARGS(utimes, "%s, *"), path);
855 #endif
856
857         if (args->tptr) {
858                 error = copyin(args->tptr, ltv, sizeof(ltv));
859                 if (error)
860                         goto cleanup;
861                 tv[0].tv_sec = ltv[0].tv_sec;
862                 tv[0].tv_usec = ltv[0].tv_usec;
863                 tv[1].tv_sec = ltv[1].tv_sec;
864                 tv[1].tv_usec = ltv[1].tv_usec;
865                 tvp = tv;
866         }
867         get_mplock();
868         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
869         if (error == 0)
870                 error = kern_utimes(&nd, tvp);
871         nlookup_done(&nd);
872         rel_mplock();
873 cleanup:
874         linux_free_path(&path);
875         return (error);
876 }
877
878 int
879 sys_linux_futimesat(struct linux_futimesat_args *args)
880 {
881         l_timeval ltv[2];
882         struct timeval tv[2], *tvp = NULL;
883         struct file *fp;
884         struct nlookupdata nd;
885         char *path;
886         int dfd,error;
887
888         error = linux_copyin_path(args->fname, &path, LINUX_PATH_EXISTS);
889         if (error)
890                 return (error);
891 #ifdef DEBUG
892         if (ldebug(futimesat))
893                 kprintf(ARGS(futimesat, "%s, *"), path);
894 #endif
895         if (args->tptr) {
896                 error = copyin(args->tptr, ltv, sizeof(ltv));
897                 if (error)
898                         goto cleanup;
899                 tv[0].tv_sec = ltv[0].tv_sec;
900                 tv[0].tv_usec = ltv[0].tv_usec;
901                 tv[1].tv_sec = ltv[1].tv_sec;
902                 tv[1].tv_usec = ltv[1].tv_usec;
903                 tvp = tv;
904         }
905         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
906         get_mplock();
907         error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, NLC_FOLLOW);
908         if (error == 0)
909                 error = kern_utimes(&nd, tvp);
910         nlookup_done_at(&nd, fp);
911         rel_mplock();
912 cleanup:
913         linux_free_path(&path);
914         return (error);
915 }
916
917
918 int
919 sys_linux_utimensat(struct linux_utimensat_args *args)
920 {
921         struct l_timespec ltv[2];
922         struct timeval tv[2], *tvp = NULL;
923         struct file *fp;
924         struct nlookupdata nd;
925         char *path;
926         int dfd, flags, error = 0;
927
928         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
929                 return (EINVAL);
930
931         if (args->dfd == LINUX_AT_FDCWD && args->fname == NULL)
932                 return (EINVAL);
933
934         if (args->fname) {
935                 error = linux_copyin_path(args->fname, &path, LINUX_PATH_EXISTS);
936                 if (error)
937                         return (error);
938         }
939 #ifdef DEBUG
940         if (ldebug(utimensat))
941                 kprintf(ARGS(utimensat, "%s, *"), path);
942 #endif
943         if (args->tptr) {
944                 error = copyin(args->tptr, ltv, sizeof(ltv));
945                 if (error)
946                         goto cleanup;
947
948                 if (ltv[0].tv_sec == LINUX_UTIME_NOW) {
949                         microtime(&tv[0]);
950                 } else if (ltv[0].tv_sec == LINUX_UTIME_OMIT) {
951                         /* XXX: this is not right, but will do for now */
952                         microtime(&tv[0]);
953                 } else {
954                         tv[0].tv_sec = ltv[0].tv_sec;
955                         /* XXX: we lose precision here, as we don't have ns */
956                         tv[0].tv_usec = ltv[0].tv_nsec/1000;
957                 }
958                 if (ltv[1].tv_sec == LINUX_UTIME_NOW) {
959                         microtime(&tv[1]);
960                 } else if (ltv[1].tv_sec == LINUX_UTIME_OMIT) {
961                         /* XXX: this is not right, but will do for now */
962                         microtime(&tv[1]);
963                 } else {
964                         tv[1].tv_sec = ltv[1].tv_sec;
965                         /* XXX: we lose precision here, as we don't have ns */
966                         tv[1].tv_usec = ltv[1].tv_nsec/1000;
967                 }
968                 tvp = tv;
969         }
970
971         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
972         flags = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? 0 : NLC_FOLLOW;
973
974         get_mplock();
975         if (args->fname) {
976                 error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, flags);
977                 if (error == 0)
978                         error = kern_utimes(&nd, tvp);
979                 nlookup_done_at(&nd, fp);
980         } else {
981                 /* Thank you, Linux, for another non-standard "feature" */
982                 KKASSERT(dfd != AT_FDCWD);
983                 error = kern_futimes(dfd, tvp);
984         }
985         rel_mplock();
986 cleanup:
987         if (args->fname)
988                 linux_free_path(&path);
989
990         return (error);
991 }
992 #endif /* __i386__ */
993
994 #define __WCLONE 0x80000000
995
996 /*
997  * MPALMOSTSAFE
998  */
999 int
1000 sys_linux_waitpid(struct linux_waitpid_args *args)
1001 {
1002         int error, options, status;
1003
1004 #ifdef DEBUG
1005         if (ldebug(waitpid))
1006                 kprintf(ARGS(waitpid, "%d, %p, %d"),
1007                     args->pid, (void *)args->status, args->options);
1008 #endif
1009         options = args->options & (WNOHANG | WUNTRACED);
1010         /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
1011         if (args->options & __WCLONE)
1012                 options |= WLINUXCLONE;
1013
1014         error = kern_wait(args->pid, args->status ? &status : NULL, options,
1015                           NULL, &args->sysmsg_result);
1016
1017         if (error == 0 && args->status) {
1018                 status &= 0xffff;
1019                 if (WIFSIGNALED(status))
1020                         status = (status & 0xffffff80) |
1021                             BSD_TO_LINUX_SIGNAL(WTERMSIG(status));
1022                 else if (WIFSTOPPED(status))
1023                         status = (status & 0xffff00ff) |
1024                             (BSD_TO_LINUX_SIGNAL(WSTOPSIG(status)) << 8);
1025                 error = copyout(&status, args->status, sizeof(status));
1026         }
1027
1028         return (error);
1029 }
1030
1031 /*
1032  * MPALMOSTSAFE
1033  */
1034 int
1035 sys_linux_wait4(struct linux_wait4_args *args)
1036 {
1037         struct thread *td = curthread;
1038         struct lwp *lp = td->td_lwp;
1039         struct rusage rusage;
1040         int error, options, status;
1041
1042 #ifdef DEBUG
1043         if (ldebug(wait4))
1044                 kprintf(ARGS(wait4, "%d, %p, %d, %p"),
1045                     args->pid, (void *)args->status, args->options,
1046                     (void *)args->rusage);
1047 #endif
1048         options = args->options & (WNOHANG | WUNTRACED);
1049         /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
1050         if (args->options & __WCLONE)
1051                 options |= WLINUXCLONE;
1052
1053         error = kern_wait(args->pid, args->status ? &status : NULL, options,
1054                           args->rusage ? &rusage : NULL, &args->sysmsg_result);
1055
1056         if (error == 0)
1057                 lwp_delsig(lp, SIGCHLD);
1058
1059         if (error == 0 && args->status) {
1060                 status &= 0xffff;
1061                 if (WIFSIGNALED(status))
1062                         status = (status & 0xffffff80) |
1063                             BSD_TO_LINUX_SIGNAL(WTERMSIG(status));
1064                 else if (WIFSTOPPED(status))
1065                         status = (status & 0xffff00ff) |
1066                             (BSD_TO_LINUX_SIGNAL(WSTOPSIG(status)) << 8);
1067                 error = copyout(&status, args->status, sizeof(status));
1068         }
1069         if (error == 0 && args->rusage)
1070                 error = copyout(&rusage, args->rusage, sizeof(rusage));
1071
1072         return (error);
1073 }
1074
1075 /*
1076  * MPALMOSTSAFE
1077  */
1078 int
1079 sys_linux_mknod(struct linux_mknod_args *args)
1080 {
1081         struct nlookupdata nd;
1082         char *path;
1083         int error;
1084
1085         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
1086         if (error)
1087                 return (error);
1088 #ifdef DEBUG
1089         if (ldebug(mknod))
1090                 kprintf(ARGS(mknod, "%s, %d, %d"),
1091                     path, args->mode, args->dev);
1092 #endif
1093         get_mplock();
1094         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
1095         if (error == 0) {
1096                 if (args->mode & S_IFIFO) {
1097                         error = kern_mkfifo(&nd, args->mode);
1098                 } else {
1099                         error = kern_mknod(&nd, args->mode,
1100                                            umajor(args->dev),
1101                                            uminor(args->dev));
1102                 }
1103         }
1104         nlookup_done(&nd);
1105         rel_mplock();
1106
1107         linux_free_path(&path);
1108         return(error);
1109 }
1110
1111 int
1112 sys_linux_mknodat(struct linux_mknodat_args *args)
1113 {
1114         struct nlookupdata nd;
1115         struct file *fp;
1116         char *path;
1117         int dfd, error;
1118
1119         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
1120         if (error)
1121                 return (error);
1122 #ifdef DEBUG
1123         if (ldebug(mknod))
1124                 kprintf(ARGS(mknod, "%s, %d, %d"),
1125                     path, args->mode, args->dev);
1126 #endif
1127         get_mplock();
1128         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
1129         error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, 0);
1130         if (error == 0) {
1131                 if (args->mode & S_IFIFO) {
1132                         error = kern_mkfifo(&nd, args->mode);
1133                 } else {
1134                         error = kern_mknod(&nd, args->mode,
1135                                            umajor(args->dev),
1136                                            uminor(args->dev));
1137                 }
1138         }
1139         nlookup_done_at(&nd, fp);
1140         rel_mplock();
1141
1142         linux_free_path(&path);
1143         return(error);
1144 }
1145
1146 /*
1147  * UGH! This is just about the dumbest idea I've ever heard!!
1148  *
1149  * MPSAFE
1150  */
1151 int
1152 sys_linux_personality(struct linux_personality_args *args)
1153 {
1154 #ifdef DEBUG
1155         if (ldebug(personality))
1156                 kprintf(ARGS(personality, "%d"), args->per);
1157 #endif
1158         if (args->per != 0)
1159                 return EINVAL;
1160
1161         /* Yes Jim, it's still a Linux... */
1162         args->sysmsg_result = 0;
1163         return 0;
1164 }
1165
1166 /*
1167  * Wrappers for get/setitimer for debugging..
1168  *
1169  * MPSAFE
1170  */
1171 int
1172 sys_linux_setitimer(struct linux_setitimer_args *args)
1173 {
1174         struct setitimer_args bsa;
1175         struct itimerval foo;
1176         int error;
1177
1178 #ifdef DEBUG
1179         if (ldebug(setitimer))
1180                 kprintf(ARGS(setitimer, "%p, %p"),
1181                     (void *)args->itv, (void *)args->oitv);
1182 #endif
1183         bsa.which = args->which;
1184         bsa.itv = (struct itimerval *)args->itv;
1185         bsa.oitv = (struct itimerval *)args->oitv;
1186         bsa.sysmsg_result = 0;
1187         if (args->itv) {
1188             if ((error = copyin((caddr_t)args->itv, &foo, sizeof(foo))))
1189                 return error;
1190 #ifdef DEBUG
1191             if (ldebug(setitimer)) {
1192                 kprintf("setitimer: value: sec: %ld, usec: %ld\n",
1193                     foo.it_value.tv_sec, foo.it_value.tv_usec);
1194                 kprintf("setitimer: interval: sec: %ld, usec: %ld\n",
1195                     foo.it_interval.tv_sec, foo.it_interval.tv_usec);
1196             }
1197 #endif
1198         }
1199         error = sys_setitimer(&bsa);
1200         args->sysmsg_result = bsa.sysmsg_result;
1201         return(error);
1202 }
1203
1204 /*
1205  * MPSAFE
1206  */
1207 int
1208 sys_linux_getitimer(struct linux_getitimer_args *args)
1209 {
1210         struct getitimer_args bsa;
1211         int error;
1212 #ifdef DEBUG
1213         if (ldebug(getitimer))
1214                 kprintf(ARGS(getitimer, "%p"), (void *)args->itv);
1215 #endif
1216         bsa.which = args->which;
1217         bsa.itv = (struct itimerval *)args->itv;
1218         bsa.sysmsg_result = 0;
1219         error = sys_getitimer(&bsa);
1220         args->sysmsg_result = bsa.sysmsg_result;
1221         return(error);
1222 }
1223
1224 /*
1225  * MPSAFE
1226  */
1227 int
1228 sys_linux_nice(struct linux_nice_args *args)
1229 {
1230         struct setpriority_args bsd_args;
1231         int error;
1232
1233         bsd_args.which = PRIO_PROCESS;
1234         bsd_args.who = 0;       /* current process */
1235         bsd_args.prio = args->inc;
1236         bsd_args.sysmsg_result = 0;
1237         error = sys_setpriority(&bsd_args);
1238         args->sysmsg_result = bsd_args.sysmsg_result;
1239         return(error);
1240 }
1241
1242 /*
1243  * MPALMOSTSAFE
1244  */
1245 int
1246 sys_linux_setgroups(struct linux_setgroups_args *args)
1247 {
1248         struct thread *td = curthread;
1249         struct proc *p = td->td_proc;
1250         struct ucred *newcred, *oldcred;
1251         l_gid_t linux_gidset[NGROUPS];
1252         gid_t *bsd_gidset;
1253         int ngrp, error;
1254
1255         ngrp = args->gidsetsize;
1256         oldcred = td->td_ucred;
1257
1258         /*
1259          * cr_groups[0] holds egid. Setting the whole set from
1260          * the supplied set will cause egid to be changed too.
1261          * Keep cr_groups[0] unchanged to prevent that.
1262          */
1263
1264         if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0)
1265                 return (error);
1266
1267         if ((u_int)ngrp >= NGROUPS)
1268                 return (EINVAL);
1269
1270         get_mplock();
1271         newcred = crdup(oldcred);
1272         if (ngrp > 0) {
1273                 error = copyin((caddr_t)args->grouplist, linux_gidset,
1274                                ngrp * sizeof(l_gid_t));
1275                 if (error) {
1276                         crfree(newcred);
1277                         rel_mplock();
1278                         return (error);
1279                 }
1280
1281                 newcred->cr_ngroups = ngrp + 1;
1282
1283                 bsd_gidset = newcred->cr_groups;
1284                 ngrp--;
1285                 while (ngrp >= 0) {
1286                         bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
1287                         ngrp--;
1288                 }
1289         } else {
1290                 newcred->cr_ngroups = 1;
1291         }
1292
1293         setsugid();
1294         oldcred = p->p_ucred;   /* reload, deal with threads race */
1295         p->p_ucred = newcred;
1296         crfree(oldcred);
1297         rel_mplock();
1298         return (0);
1299 }
1300
1301 /*
1302  * MPSAFE
1303  */
1304 int
1305 sys_linux_getgroups(struct linux_getgroups_args *args)
1306 {
1307         struct thread *td = curthread;
1308         struct ucred *cred;
1309         l_gid_t linux_gidset[NGROUPS];
1310         gid_t *bsd_gidset;
1311         int bsd_gidsetsz, ngrp, error;
1312
1313         cred = td->td_ucred;
1314         bsd_gidset = cred->cr_groups;
1315         bsd_gidsetsz = cred->cr_ngroups - 1;
1316
1317         /*
1318          * cr_groups[0] holds egid. Returning the whole set
1319          * here will cause a duplicate. Exclude cr_groups[0]
1320          * to prevent that.
1321          */
1322
1323         if ((ngrp = args->gidsetsize) == 0) {
1324                 args->sysmsg_result = bsd_gidsetsz;
1325                 return (0);
1326         }
1327
1328         if ((u_int)ngrp < bsd_gidsetsz)
1329                 return (EINVAL);
1330
1331         ngrp = 0;
1332         while (ngrp < bsd_gidsetsz) {
1333                 linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
1334                 ngrp++;
1335         }
1336
1337         if ((error = copyout(linux_gidset, args->grouplist,
1338                              ngrp * sizeof(l_gid_t)))) {
1339                 return (error);
1340         }
1341
1342         args->sysmsg_result = ngrp;
1343         return (0);
1344 }
1345
1346 /*
1347  * MPSAFE
1348  */
1349 int
1350 sys_linux_setrlimit(struct linux_setrlimit_args *args)
1351 {
1352         struct l_rlimit linux_rlim;
1353         struct rlimit rlim;
1354         u_int which;
1355         int error;
1356
1357 #ifdef DEBUG
1358         if (ldebug(setrlimit))
1359                 kprintf(ARGS(setrlimit, "%d, %p"),
1360                     args->resource, (void *)args->rlim);
1361 #endif
1362         if (args->resource >= LINUX_RLIM_NLIMITS)
1363                 return (EINVAL);
1364         which = linux_to_bsd_resource[args->resource];
1365         if (which == -1)
1366                 return (EINVAL);
1367
1368         error = copyin(args->rlim, &linux_rlim, sizeof(linux_rlim));
1369         if (error)
1370                 return (error);
1371         rlim.rlim_cur = (rlim_t)linux_rlim.rlim_cur;
1372         rlim.rlim_max = (rlim_t)linux_rlim.rlim_max;
1373
1374         error = kern_setrlimit(which, &rlim);
1375
1376         return(error);
1377 }
1378
1379 /*
1380  * MPSAFE
1381  */
1382 int
1383 sys_linux_old_getrlimit(struct linux_old_getrlimit_args *args)
1384 {
1385         struct l_rlimit linux_rlim;
1386         struct rlimit rlim;
1387         u_int which;
1388         int error;
1389
1390 #ifdef DEBUG
1391         if (ldebug(old_getrlimit))
1392                 kprintf(ARGS(old_getrlimit, "%d, %p"),
1393                     args->resource, (void *)args->rlim);
1394 #endif
1395         if (args->resource >= LINUX_RLIM_NLIMITS)
1396                 return (EINVAL);
1397         which = linux_to_bsd_resource[args->resource];
1398         if (which == -1)
1399                 return (EINVAL);
1400
1401         error = kern_getrlimit(which, &rlim);
1402
1403         if (error == 0) {
1404                 linux_rlim.rlim_cur = (l_ulong)rlim.rlim_cur;
1405                 if (linux_rlim.rlim_cur == ULONG_MAX)
1406                         linux_rlim.rlim_cur = LONG_MAX;
1407                 linux_rlim.rlim_max = (l_ulong)rlim.rlim_max;
1408                 if (linux_rlim.rlim_max == ULONG_MAX)
1409                         linux_rlim.rlim_max = LONG_MAX;
1410                 error = copyout(&linux_rlim, args->rlim, sizeof(linux_rlim));
1411         }
1412         return (error);
1413 }
1414
1415 /*
1416  * MPSAFE
1417  */
1418 int
1419 sys_linux_getrlimit(struct linux_getrlimit_args *args)
1420 {
1421         struct l_rlimit linux_rlim;
1422         struct rlimit rlim;
1423         u_int which;
1424         int error;
1425
1426 #ifdef DEBUG
1427         if (ldebug(getrlimit))
1428                 kprintf(ARGS(getrlimit, "%d, %p"),
1429                     args->resource, (void *)args->rlim);
1430 #endif
1431         if (args->resource >= LINUX_RLIM_NLIMITS)
1432                 return (EINVAL);
1433         which = linux_to_bsd_resource[args->resource];
1434         if (which == -1)
1435                 return (EINVAL);
1436
1437         error = kern_getrlimit(which, &rlim);
1438
1439         if (error == 0) {
1440                 linux_rlim.rlim_cur = (l_ulong)rlim.rlim_cur;
1441                 linux_rlim.rlim_max = (l_ulong)rlim.rlim_max;
1442                 error = copyout(&linux_rlim, args->rlim, sizeof(linux_rlim));
1443         }
1444         return (error);
1445 }
1446
1447 /*
1448  * MPSAFE
1449  */
1450 int
1451 sys_linux_sched_setscheduler(struct linux_sched_setscheduler_args *args)
1452 {
1453         struct sched_setscheduler_args bsd;
1454         int error;
1455
1456 #ifdef DEBUG
1457         if (ldebug(sched_setscheduler))
1458                 kprintf(ARGS(sched_setscheduler, "%d, %d, %p"),
1459                     args->pid, args->policy, (const void *)args->param);
1460 #endif
1461
1462         switch (args->policy) {
1463         case LINUX_SCHED_OTHER:
1464                 bsd.policy = SCHED_OTHER;
1465                 break;
1466         case LINUX_SCHED_FIFO:
1467                 bsd.policy = SCHED_FIFO;
1468                 break;
1469         case LINUX_SCHED_RR:
1470                 bsd.policy = SCHED_RR;
1471                 break;
1472         default:
1473                 return EINVAL;
1474         }
1475
1476         bsd.pid = args->pid;
1477         bsd.param = (struct sched_param *)args->param;
1478         bsd.sysmsg_result = 0;
1479
1480         error = sys_sched_setscheduler(&bsd);
1481         args->sysmsg_result = bsd.sysmsg_result;
1482         return(error);
1483 }
1484
1485 /*
1486  * MPSAFE
1487  */
1488 int
1489 sys_linux_sched_getscheduler(struct linux_sched_getscheduler_args *args)
1490 {
1491         struct sched_getscheduler_args bsd;
1492         int error;
1493
1494 #ifdef DEBUG
1495         if (ldebug(sched_getscheduler))
1496                 kprintf(ARGS(sched_getscheduler, "%d"), args->pid);
1497 #endif
1498
1499         bsd.sysmsg_result = 0;
1500         bsd.pid = args->pid;
1501         error = sys_sched_getscheduler(&bsd);
1502         args->sysmsg_result = bsd.sysmsg_result;
1503
1504         switch (args->sysmsg_result) {
1505         case SCHED_OTHER:
1506                 args->sysmsg_result = LINUX_SCHED_OTHER;
1507                 break;
1508         case SCHED_FIFO:
1509                 args->sysmsg_result = LINUX_SCHED_FIFO;
1510                 break;
1511         case SCHED_RR:
1512                 args->sysmsg_result = LINUX_SCHED_RR;
1513                 break;
1514         }
1515         return error;
1516 }
1517
1518 /*
1519  * MPSAFE
1520  */
1521 int
1522 sys_linux_sched_get_priority_max(struct linux_sched_get_priority_max_args *args)
1523 {
1524         struct sched_get_priority_max_args bsd;
1525         int error;
1526
1527 #ifdef DEBUG
1528         if (ldebug(sched_get_priority_max))
1529                 kprintf(ARGS(sched_get_priority_max, "%d"), args->policy);
1530 #endif
1531
1532         switch (args->policy) {
1533         case LINUX_SCHED_OTHER:
1534                 bsd.policy = SCHED_OTHER;
1535                 break;
1536         case LINUX_SCHED_FIFO:
1537                 bsd.policy = SCHED_FIFO;
1538                 break;
1539         case LINUX_SCHED_RR:
1540                 bsd.policy = SCHED_RR;
1541                 break;
1542         default:
1543                 return EINVAL;
1544         }
1545         bsd.sysmsg_result = 0;
1546
1547         error = sys_sched_get_priority_max(&bsd);
1548         args->sysmsg_result = bsd.sysmsg_result;
1549         return(error);
1550 }
1551
1552 /*
1553  * MPSAFE
1554  */
1555 int
1556 sys_linux_sched_get_priority_min(struct linux_sched_get_priority_min_args *args)
1557 {
1558         struct sched_get_priority_min_args bsd;
1559         int error;
1560
1561 #ifdef DEBUG
1562         if (ldebug(sched_get_priority_min))
1563                 kprintf(ARGS(sched_get_priority_min, "%d"), args->policy);
1564 #endif
1565
1566         switch (args->policy) {
1567         case LINUX_SCHED_OTHER:
1568                 bsd.policy = SCHED_OTHER;
1569                 break;
1570         case LINUX_SCHED_FIFO:
1571                 bsd.policy = SCHED_FIFO;
1572                 break;
1573         case LINUX_SCHED_RR:
1574                 bsd.policy = SCHED_RR;
1575                 break;
1576         default:
1577                 return EINVAL;
1578         }
1579         bsd.sysmsg_result = 0;
1580
1581         error = sys_sched_get_priority_min(&bsd);
1582         args->sysmsg_result = bsd.sysmsg_result;
1583         return(error);
1584 }
1585
1586 #define REBOOT_CAD_ON   0x89abcdef
1587 #define REBOOT_CAD_OFF  0
1588 #define REBOOT_HALT     0xcdef0123
1589 #define REBOOT_RESTART  0x01234567
1590 #define REBOOT_RESTART2 0xA1B2C3D4
1591 #define REBOOT_POWEROFF 0x4321FEDC
1592 #define REBOOT_MAGIC1   0xfee1dead
1593 #define REBOOT_MAGIC2   0x28121969
1594 #define REBOOT_MAGIC2A  0x05121996
1595 #define REBOOT_MAGIC2B  0x16041998
1596
1597 /*
1598  * MPSAFE
1599  */
1600 int
1601 sys_linux_reboot(struct linux_reboot_args *args)
1602 {
1603         struct reboot_args bsd_args;
1604         int error;
1605
1606 #ifdef DEBUG
1607         if (ldebug(reboot))
1608                 kprintf(ARGS(reboot, "0x%x"), args->cmd);
1609 #endif
1610
1611         if ((args->magic1 != REBOOT_MAGIC1) ||
1612             ((args->magic2 != REBOOT_MAGIC2) &&
1613             (args->magic2 != REBOOT_MAGIC2A) &&
1614             (args->magic2 != REBOOT_MAGIC2B)))
1615                 return EINVAL;
1616
1617         switch (args->cmd) {
1618         case REBOOT_CAD_ON:
1619         case REBOOT_CAD_OFF:
1620                 return (priv_check(curthread, PRIV_REBOOT));
1621                 /* NOTREACHED */
1622         case REBOOT_HALT:
1623                 bsd_args.opt = RB_HALT;
1624                 break;
1625         case REBOOT_RESTART:
1626         case REBOOT_RESTART2:
1627                 bsd_args.opt = 0;
1628                 break;
1629         case REBOOT_POWEROFF:
1630                 bsd_args.opt = RB_POWEROFF;
1631                 break;
1632         default:
1633                 return EINVAL;
1634                 /* NOTREACHED */
1635         }
1636
1637         bsd_args.sysmsg_result = 0;
1638
1639         error = sys_reboot(&bsd_args);
1640         args->sysmsg_result = bsd_args.sysmsg_result;
1641         return(error);
1642 }
1643
1644 /*
1645  * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify
1646  * p->p_retval[1] when COMPAT_43 or COMPAT_SUNOS is defined. This
1647  * globbers registers that are assumed to be preserved. The following
1648  * lightweight syscalls fixes this. See also linux_getgid16() and
1649  * linux_getuid16() in linux_uid16.c.
1650  *
1651  * linux_getpid() - MP SAFE
1652  * linux_getgid() - MP SAFE
1653  * linux_getuid() - MP SAFE
1654  */
1655
1656 /*
1657  * MPALMOSTSAFE
1658  */
1659 int
1660 sys_linux_getpid(struct linux_getpid_args *args)
1661 {
1662         struct linux_emuldata *em;
1663         struct proc *p = curproc;
1664
1665
1666         EMUL_LOCK();
1667         em = emuldata_get(p);
1668         if (em == NULL) /* this should never happen */
1669                 args->sysmsg_result = p->p_pid;
1670         else
1671                 args->sysmsg_result = em->s->group_pid;
1672         EMUL_UNLOCK();
1673
1674         return (0);
1675 }
1676
1677 /*
1678  * MPALMOSTSAFE
1679  */
1680 int
1681 sys_linux_getppid(struct linux_getppid_args *args)
1682 {
1683         struct linux_emuldata *em;
1684         struct proc *parent;
1685         struct proc *p;
1686         pid_t group_pid;
1687
1688         EMUL_LOCK();
1689         em = emuldata_get(curproc);
1690         KKASSERT(em != NULL);
1691         group_pid = em->s->group_pid;
1692         EMUL_UNLOCK();
1693
1694         p = pfind(group_pid);
1695         /* We are not allowed to fail */
1696         if (p == NULL)
1697                 goto out;
1698
1699         parent = p->p_pptr;
1700         if (parent->p_sysent == &elf_linux_sysvec) {
1701                 EMUL_LOCK();
1702                 em = emuldata_get(parent);
1703                 args->sysmsg_result = em->s->group_pid;
1704                 EMUL_UNLOCK();
1705         } else {
1706                 args->sysmsg_result = parent->p_pid;
1707         }
1708
1709 out:
1710         return (0);
1711 }
1712
1713 /*
1714  * MPSAFE
1715  */
1716 int
1717 sys_linux_getgid(struct linux_getgid_args *args)
1718 {
1719         struct thread *td = curthread;
1720
1721         args->sysmsg_result = td->td_ucred->cr_rgid;
1722         return (0);
1723 }
1724
1725 /*
1726  * MPSAFE
1727  */
1728 int
1729 sys_linux_getuid(struct linux_getuid_args *args)
1730 {
1731         struct thread *td = curthread;
1732
1733         args->sysmsg_result = td->td_ucred->cr_ruid;
1734         return (0);
1735 }
1736
1737 /*
1738  * MPSAFE
1739  */
1740 int
1741 sys_linux_getsid(struct linux_getsid_args *args)
1742 {
1743         struct getsid_args bsd;
1744         int error;
1745
1746         bsd.sysmsg_result = 0;
1747         bsd.pid = args->pid;
1748         error = sys_getsid(&bsd);
1749         args->sysmsg_result = bsd.sysmsg_result;
1750         return(error);
1751 }
1752
1753 /*
1754  * MPSAFE
1755  */
1756 int
1757 linux_nosys(struct nosys_args *args)
1758 {
1759         /* XXX */
1760         return (ENOSYS);
1761 }
1762
1763 int
1764 sys_linux_mq_open(struct linux_mq_open_args *args)
1765 {
1766         struct mq_open_args moa;
1767         int error, oflag;
1768
1769         oflag = 0;
1770         if (args->oflag & LINUX_O_RDONLY)
1771                 oflag |= O_RDONLY;
1772         if (args->oflag & LINUX_O_WRONLY)
1773                 oflag |= O_WRONLY;
1774         if (args->oflag & LINUX_O_RDWR)
1775                 oflag |= O_RDWR;
1776
1777         if (args->oflag & LINUX_O_NONBLOCK)
1778                 oflag |= O_NONBLOCK;
1779         if (args->oflag & LINUX_O_CREAT)
1780                 oflag |= O_CREAT;
1781         if (args->oflag & LINUX_O_EXCL)
1782                 oflag |= O_EXCL;
1783
1784         moa.name = args->name;
1785         moa.oflag = oflag;
1786         moa.mode = args->mode;
1787         moa.attr = args->attr;
1788
1789         error = sys_mq_open(&moa);
1790
1791         return (error);
1792 }
1793
1794 int
1795 sys_linux_mq_getsetattr(struct linux_mq_getsetattr_args *args)
1796 {
1797         struct mq_getattr_args gaa;
1798         struct mq_setattr_args saa;
1799         int error;
1800
1801         gaa.mqdes = args->mqd;
1802         gaa.mqstat = args->oattr;
1803
1804         saa.mqdes = args->mqd;
1805         saa.mqstat = args->attr;
1806         saa.mqstat = args->oattr;
1807
1808         if (args->attr != NULL) {
1809                 error = sys_mq_setattr(&saa);
1810         } else {
1811                 error = sys_mq_getattr(&gaa);
1812         }
1813
1814         return error;
1815 }
1816
1817 /*
1818  * Get affinity of a process.
1819  */
1820 int
1821 sys_linux_sched_getaffinity(struct linux_sched_getaffinity_args *args)
1822 {
1823         cpumask_t mask;
1824         struct proc *p;
1825         struct lwp *lp;
1826         int error = 0;
1827
1828 #ifdef DEBUG
1829         if (ldebug(sched_getaffinity))
1830                 kprintf(ARGS(sched_getaffinity, "%d, %d, *"), args->pid,
1831                     args->len);
1832 #endif
1833         if (args->len < sizeof(cpumask_t))
1834                 return (EINVAL);
1835 #if 0
1836         if ((error = priv_check(curthread, PRIV_SCHED_CPUSET)) != 0)
1837                 return (EPERM);
1838 #endif
1839         /* Get the mplock to ensure that the proc is not running */
1840         get_mplock();
1841         if (args->pid == 0) {
1842                 p = curproc;
1843         } else {
1844                 p = pfind(args->pid);
1845                 if (p == NULL) {
1846                         error = ESRCH;
1847                         goto done;
1848                 }
1849         }
1850
1851         lp = FIRST_LWP_IN_PROC(p);
1852         /*
1853          * XXX: if lwp_cpumask is ever changed to support more than
1854          *      32 processors, this needs to be changed to a bcopy.
1855          */
1856         mask = lp->lwp_cpumask;
1857         if ((error = copyout(&mask, args->user_mask_ptr, sizeof(cpumask_t))))
1858                 error = EFAULT;
1859 done:
1860         rel_mplock();
1861 #if 0
1862         if (error == 0)
1863                 args->sysmsg_iresult = sizeof(cpumask_t);
1864 #endif
1865         return (error);
1866 }
1867
1868 /*
1869  *  Set affinity of a process.
1870  */
1871 int
1872 sys_linux_sched_setaffinity(struct linux_sched_setaffinity_args *args)
1873 {
1874 #ifdef DEBUG
1875         if (ldebug(sched_setaffinity))
1876                 kprintf(ARGS(sched_setaffinity, "%d, %d, *"), args->pid,
1877                     args->len);
1878 #endif
1879         /*
1880          * From Linux man page:
1881          * sched_setaffinity() sets the CPU affinity mask of the process
1882          * whose ID is pid to the value specified by mask. If pid is zero, 
1883          * then the calling process is used. The argument cpusetsize is 
1884          * the length (in bytes) of the data pointed to by mask. Normally
1885          * this argument would be specified as sizeof(cpu_set_t).
1886          *
1887          * If the process specified by pid is not currently running on one
1888          * of the CPUs specified in mask, then that process is migrated to
1889          * one of the CPUs specified in mask.
1890          */
1891         /*
1892          * About our implementation: I don't think that it is too important
1893          * to have a working implementation, but if it was ever needed,
1894          * the best approach would be to implement the whole mechanism
1895          * properly in kern_usched.
1896          * The idea has to be to change the affinity mask AND migrate the
1897          * lwp to one of the new valid CPUs for the lwp, in case the current
1898          * CPU isn't anymore in the affinity mask passed in.
1899          * For now, we'll just signal success even if we didn't do anything.
1900          */
1901         return 0;
1902 }
1903
1904 int
1905 sys_linux_gettid(struct linux_gettid_args *args)
1906 {
1907         args->sysmsg_iresult = curproc->p_pid;
1908         return 0;
1909 }
1910
1911 int
1912 sys_linux_getcpu(struct linux_getcpu_args *args)
1913 {
1914         struct globaldata *gd;
1915         l_uint node = 0;
1916         int error;
1917
1918         gd = mycpu;
1919         error = copyout(&gd->gd_cpuid, args->pcpu, sizeof(gd->gd_cpuid));
1920         if (error)
1921                 return (error);
1922         /*
1923          * XXX: this should be the NUMA node, but since we don't implement it,
1924          *      just return 0 for it.
1925          */
1926         error = copyout(&node, args->pnode, sizeof(node));
1927         return (error);
1928 }