Index: stable/9/sys/amd64/linux32/linux.h =================================================================== --- stable/9/sys/amd64/linux32/linux.h (revision 246289) +++ stable/9/sys/amd64/linux32/linux.h (revision 246290) @@ -1,940 +1,941 @@ /*- * Copyright (c) 2004 Tim J. Robbins * Copyright (c) 2001 Doug Rabson * Copyright (c) 1994-1996 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _AMD64_LINUX_H_ #define _AMD64_LINUX_H_ #include /* * debugging support */ extern u_char linux_debug_map[]; #define ldebug(name) isclr(linux_debug_map, LINUX_SYS_linux_ ## name) #define ARGS(nm, fmt) "linux(%ld): "#nm"("fmt")\n", (long)td->td_proc->p_pid #define LMSG(fmt) "linux(%ld): "fmt"\n", (long)td->td_proc->p_pid +#define LINUX_DTRACE linuxulator32 #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_LINUX); #endif #define LINUX32_MAXUSER ((1ul << 32) - PAGE_SIZE) #define LINUX32_SHAREDPAGE (LINUX32_MAXUSER - PAGE_SIZE) #define LINUX32_USRSTACK LINUX32_SHAREDPAGE /* XXX 16 = sizeof(linux32_ps_strings) */ #define LINUX32_PS_STRINGS (LINUX32_USRSTACK - 16) #define LINUX32_MAXDSIZ (512 * 1024 * 1024) /* 512MB */ #define LINUX32_MAXSSIZ (64 * 1024 * 1024) /* 64MB */ #define LINUX32_MAXVMEM 0 /* Unlimited */ #define PTRIN(v) (void *)(uintptr_t)(v) #define PTROUT(v) (l_uintptr_t)(uintptr_t)(v) /* * Provide a separate set of types for the Linux types. */ typedef int l_int; typedef int32_t l_long; typedef int64_t l_longlong; typedef short l_short; typedef unsigned int l_uint; typedef uint32_t l_ulong; typedef uint64_t l_ulonglong; typedef unsigned short l_ushort; typedef l_ulong l_uintptr_t; typedef l_long l_clock_t; typedef l_int l_daddr_t; typedef l_ushort l_dev_t; typedef l_uint l_gid_t; typedef l_ushort l_gid16_t; typedef l_ulong l_ino_t; typedef l_int l_key_t; typedef l_longlong l_loff_t; typedef l_ushort l_mode_t; typedef l_long l_off_t; typedef l_int l_pid_t; typedef l_uint l_size_t; typedef l_long l_suseconds_t; typedef l_long l_time_t; typedef l_uint l_uid_t; typedef l_ushort l_uid16_t; typedef l_int l_timer_t; typedef l_int l_mqd_t; typedef struct { l_int val[2]; } __packed l_fsid_t; typedef struct { l_time_t tv_sec; l_suseconds_t tv_usec; } l_timeval; #define l_fd_set fd_set /* * Miscellaneous */ #define LINUX_NAME_MAX 255 #define LINUX_MAX_UTSNAME 65 #define LINUX_CTL_MAXNAME 10 #define LINUX_AT_COUNT 16 /* Count of used aux entry types. * Keep this synchronized with * elf_linux_fixup() code. */ struct l___sysctl_args { l_uintptr_t name; l_int nlen; l_uintptr_t oldval; l_uintptr_t oldlenp; l_uintptr_t newval; l_size_t newlen; l_ulong __spare[4]; } __packed; /* Scheduling policies */ #define LINUX_SCHED_OTHER 0 #define LINUX_SCHED_FIFO 1 #define LINUX_SCHED_RR 2 /* Resource limits */ #define LINUX_RLIMIT_CPU 0 #define LINUX_RLIMIT_FSIZE 1 #define LINUX_RLIMIT_DATA 2 #define LINUX_RLIMIT_STACK 3 #define LINUX_RLIMIT_CORE 4 #define LINUX_RLIMIT_RSS 5 #define LINUX_RLIMIT_NPROC 6 #define LINUX_RLIMIT_NOFILE 7 #define LINUX_RLIMIT_MEMLOCK 8 #define LINUX_RLIMIT_AS 9 /* Address space limit */ #define LINUX_RLIM_NLIMITS 10 struct l_rlimit { l_ulong rlim_cur; l_ulong rlim_max; } __packed; struct l_rusage { l_timeval ru_utime; l_timeval ru_stime; l_long ru_maxrss; l_long ru_ixrss; l_long ru_idrss; l_long ru_isrss; l_long ru_minflt; l_long ru_majflt; l_long ru_nswap; l_long ru_inblock; l_long ru_oublock; l_long ru_msgsnd; l_long ru_msgrcv; l_long ru_nsignals; l_long ru_nvcsw; l_long ru_nivcsw; } __packed; /* mmap options */ #define LINUX_MAP_SHARED 0x0001 #define LINUX_MAP_PRIVATE 0x0002 #define LINUX_MAP_FIXED 0x0010 #define LINUX_MAP_ANON 0x0020 #define LINUX_MAP_GROWSDOWN 0x0100 struct l_mmap_argv { l_uintptr_t addr; l_size_t len; l_int prot; l_int flags; l_int fd; l_ulong pgoff; }; /* * stat family of syscalls */ struct l_timespec { l_time_t tv_sec; l_long tv_nsec; } __packed; struct l_newstat { l_ushort st_dev; l_ushort __pad1; l_ulong st_ino; l_ushort st_mode; l_ushort st_nlink; l_ushort st_uid; l_ushort st_gid; l_ushort st_rdev; l_ushort __pad2; l_ulong st_size; l_ulong st_blksize; l_ulong st_blocks; struct l_timespec st_atim; struct l_timespec st_mtim; struct l_timespec st_ctim; l_ulong __unused4; l_ulong __unused5; } __packed; struct l_stat { l_ushort st_dev; l_ulong st_ino; l_ushort st_mode; l_ushort st_nlink; l_ushort st_uid; l_ushort st_gid; l_ushort st_rdev; l_long st_size; struct l_timespec st_atim; struct l_timespec st_mtim; struct l_timespec st_ctim; l_long st_blksize; l_long st_blocks; l_ulong st_flags; l_ulong st_gen; }; struct l_stat64 { l_ushort st_dev; u_char __pad0[10]; l_ulong __st_ino; l_uint st_mode; l_uint st_nlink; l_ulong st_uid; l_ulong st_gid; l_ushort st_rdev; u_char __pad3[10]; l_longlong st_size; l_ulong st_blksize; l_ulong st_blocks; l_ulong __pad4; struct l_timespec st_atim; struct l_timespec st_mtim; struct l_timespec st_ctim; l_ulonglong st_ino; } __packed; struct l_statfs64 { l_int f_type; l_int f_bsize; uint64_t f_blocks; uint64_t f_bfree; uint64_t f_bavail; uint64_t f_files; uint64_t f_ffree; l_fsid_t f_fsid; l_int f_namelen; l_int f_spare[6]; } __packed; struct l_new_utsname { char sysname[LINUX_MAX_UTSNAME]; char nodename[LINUX_MAX_UTSNAME]; char release[LINUX_MAX_UTSNAME]; char version[LINUX_MAX_UTSNAME]; char machine[LINUX_MAX_UTSNAME]; char domainname[LINUX_MAX_UTSNAME]; } __packed; /* * Signalling */ #define LINUX_SIGHUP 1 #define LINUX_SIGINT 2 #define LINUX_SIGQUIT 3 #define LINUX_SIGILL 4 #define LINUX_SIGTRAP 5 #define LINUX_SIGABRT 6 #define LINUX_SIGIOT LINUX_SIGABRT #define LINUX_SIGBUS 7 #define LINUX_SIGFPE 8 #define LINUX_SIGKILL 9 #define LINUX_SIGUSR1 10 #define LINUX_SIGSEGV 11 #define LINUX_SIGUSR2 12 #define LINUX_SIGPIPE 13 #define LINUX_SIGALRM 14 #define LINUX_SIGTERM 15 #define LINUX_SIGSTKFLT 16 #define LINUX_SIGCHLD 17 #define LINUX_SIGCONT 18 #define LINUX_SIGSTOP 19 #define LINUX_SIGTSTP 20 #define LINUX_SIGTTIN 21 #define LINUX_SIGTTOU 22 #define LINUX_SIGURG 23 #define LINUX_SIGXCPU 24 #define LINUX_SIGXFSZ 25 #define LINUX_SIGVTALRM 26 #define LINUX_SIGPROF 27 #define LINUX_SIGWINCH 28 #define LINUX_SIGIO 29 #define LINUX_SIGPOLL LINUX_SIGIO #define LINUX_SIGPWR 30 #define LINUX_SIGSYS 31 #define LINUX_SIGRTMIN 32 #define LINUX_SIGTBLSZ 31 #define LINUX_NSIG_WORDS 2 #define LINUX_NBPW 32 #define LINUX_NSIG (LINUX_NBPW * LINUX_NSIG_WORDS) /* sigaction flags */ #define LINUX_SA_NOCLDSTOP 0x00000001 #define LINUX_SA_NOCLDWAIT 0x00000002 #define LINUX_SA_SIGINFO 0x00000004 #define LINUX_SA_RESTORER 0x04000000 #define LINUX_SA_ONSTACK 0x08000000 #define LINUX_SA_RESTART 0x10000000 #define LINUX_SA_INTERRUPT 0x20000000 #define LINUX_SA_NOMASK 0x40000000 #define LINUX_SA_ONESHOT 0x80000000 /* sigprocmask actions */ #define LINUX_SIG_BLOCK 0 #define LINUX_SIG_UNBLOCK 1 #define LINUX_SIG_SETMASK 2 /* sigset_t macros */ #define LINUX_SIGEMPTYSET(set) (set).__bits[0] = (set).__bits[1] = 0 #define LINUX_SIGISMEMBER(set, sig) SIGISMEMBER(set, sig) #define LINUX_SIGADDSET(set, sig) SIGADDSET(set, sig) /* sigaltstack */ #define LINUX_MINSIGSTKSZ 2048 #define LINUX_SS_ONSTACK 1 #define LINUX_SS_DISABLE 2 int linux_to_bsd_sigaltstack(int lsa); int bsd_to_linux_sigaltstack(int bsa); typedef l_uintptr_t l_handler_t; typedef l_ulong l_osigset_t; typedef struct { l_uint __bits[LINUX_NSIG_WORDS]; } __packed l_sigset_t; typedef struct { l_handler_t lsa_handler; l_osigset_t lsa_mask; l_ulong lsa_flags; l_uintptr_t lsa_restorer; } __packed l_osigaction_t; typedef struct { l_handler_t lsa_handler; l_ulong lsa_flags; l_uintptr_t lsa_restorer; l_sigset_t lsa_mask; } __packed l_sigaction_t; typedef struct { l_uintptr_t ss_sp; l_int ss_flags; l_size_t ss_size; } __packed l_stack_t; /* The Linux sigcontext, pretty much a standard 386 trapframe. */ struct l_sigcontext { l_uint sc_gs; l_uint sc_fs; l_uint sc_es; l_uint sc_ds; l_uint sc_edi; l_uint sc_esi; l_uint sc_ebp; l_uint sc_esp; l_uint sc_ebx; l_uint sc_edx; l_uint sc_ecx; l_uint sc_eax; l_uint sc_trapno; l_uint sc_err; l_uint sc_eip; l_uint sc_cs; l_uint sc_eflags; l_uint sc_esp_at_signal; l_uint sc_ss; l_uint sc_387; l_uint sc_mask; l_uint sc_cr2; } __packed; struct l_ucontext { l_ulong uc_flags; l_uintptr_t uc_link; l_stack_t uc_stack; struct l_sigcontext uc_mcontext; l_sigset_t uc_sigmask; } __packed; #define LINUX_SI_MAX_SIZE 128 #define LINUX_SI_PAD_SIZE ((LINUX_SI_MAX_SIZE/sizeof(l_int)) - 3) typedef union l_sigval { l_int sival_int; l_uintptr_t sival_ptr; } l_sigval_t; typedef struct l_siginfo { l_int lsi_signo; l_int lsi_errno; l_int lsi_code; union { l_int _pad[LINUX_SI_PAD_SIZE]; struct { l_pid_t _pid; l_uid_t _uid; } __packed _kill; struct { l_timer_t _tid; l_int _overrun; char _pad[sizeof(l_uid_t) - sizeof(l_int)]; l_sigval_t _sigval; l_int _sys_private; } __packed _timer; struct { l_pid_t _pid; /* sender's pid */ l_uid_t _uid; /* sender's uid */ l_sigval_t _sigval; } __packed _rt; struct { l_pid_t _pid; /* which child */ l_uid_t _uid; /* sender's uid */ l_int _status; /* exit code */ l_clock_t _utime; l_clock_t _stime; } __packed _sigchld; struct { l_uintptr_t _addr; /* Faulting insn/memory ref. */ } __packed _sigfault; struct { l_long _band; /* POLL_IN,POLL_OUT,POLL_MSG */ l_int _fd; } __packed _sigpoll; } _sifields; } __packed l_siginfo_t; #define lsi_pid _sifields._kill._pid #define lsi_uid _sifields._kill._uid #define lsi_tid _sifields._timer._tid #define lsi_overrun _sifields._timer._overrun #define lsi_sys_private _sifields._timer._sys_private #define lsi_status _sifields._sigchld._status #define lsi_utime _sifields._sigchld._utime #define lsi_stime _sifields._sigchld._stime #define lsi_value _sifields._rt._sigval #define lsi_int _sifields._rt._sigval.sival_int #define lsi_ptr _sifields._rt._sigval.sival_ptr #define lsi_addr _sifields._sigfault._addr #define lsi_band _sifields._sigpoll._band #define lsi_fd _sifields._sigpoll._fd struct l_fpreg { u_int16_t significand[4]; u_int16_t exponent; } __packed; struct l_fpxreg { u_int16_t significand[4]; u_int16_t exponent; u_int16_t padding[3]; } __packed; struct l_xmmreg { u_int32_t element[4]; } __packed; struct l_fpstate { /* Regular FPU environment */ u_int32_t cw; u_int32_t sw; u_int32_t tag; u_int32_t ipoff; u_int32_t cssel; u_int32_t dataoff; u_int32_t datasel; struct l_fpreg _st[8]; u_int16_t status; u_int16_t magic; /* 0xffff = regular FPU data */ /* FXSR FPU environment */ u_int32_t _fxsr_env[6]; /* env is ignored. */ u_int32_t mxcsr; u_int32_t reserved; struct l_fpxreg _fxsr_st[8]; /* reg data is ignored. */ struct l_xmmreg _xmm[8]; u_int32_t padding[56]; } __packed; /* * We make the stack look like Linux expects it when calling a signal * handler, but use the BSD way of calling the handler and sigreturn(). * This means that we need to pass the pointer to the handler too. * It is appended to the frame to not interfere with the rest of it. */ struct l_sigframe { l_int sf_sig; struct l_sigcontext sf_sc; struct l_fpstate sf_fpstate; l_uint sf_extramask[LINUX_NSIG_WORDS-1]; l_handler_t sf_handler; } __packed; struct l_rt_sigframe { l_int sf_sig; l_uintptr_t sf_siginfo; l_uintptr_t sf_ucontext; l_siginfo_t sf_si; struct l_ucontext sf_sc; l_handler_t sf_handler; } __packed; extern int bsd_to_linux_signal[]; extern int linux_to_bsd_signal[]; extern struct sysentvec elf_linux_sysvec; /* * Pluggable ioctl handlers */ struct linux_ioctl_args; struct thread; typedef int linux_ioctl_function_t(struct thread *, struct linux_ioctl_args *); struct linux_ioctl_handler { linux_ioctl_function_t *func; int low, high; }; int linux_ioctl_register_handler(struct linux_ioctl_handler *h); int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h); /* * open/fcntl flags */ #define LINUX_O_RDONLY 00000000 #define LINUX_O_WRONLY 00000001 #define LINUX_O_RDWR 00000002 #define LINUX_O_ACCMODE 00000003 #define LINUX_O_CREAT 00000100 #define LINUX_O_EXCL 00000200 #define LINUX_O_NOCTTY 00000400 #define LINUX_O_TRUNC 00001000 #define LINUX_O_APPEND 00002000 #define LINUX_O_NONBLOCK 00004000 #define LINUX_O_NDELAY LINUX_O_NONBLOCK #define LINUX_O_SYNC 00010000 #define LINUX_FASYNC 00020000 #define LINUX_O_DIRECT 00040000 /* Direct disk access hint */ #define LINUX_O_LARGEFILE 00100000 #define LINUX_O_DIRECTORY 00200000 /* Must be a directory */ #define LINUX_O_NOFOLLOW 00400000 /* Do not follow links */ #define LINUX_O_NOATIME 01000000 #define LINUX_O_CLOEXEC 02000000 #define LINUX_F_DUPFD 0 #define LINUX_F_GETFD 1 #define LINUX_F_SETFD 2 #define LINUX_F_GETFL 3 #define LINUX_F_SETFL 4 #define LINUX_F_GETLK 5 #define LINUX_F_SETLK 6 #define LINUX_F_SETLKW 7 #define LINUX_F_SETOWN 8 #define LINUX_F_GETOWN 9 #define LINUX_F_GETLK64 12 #define LINUX_F_SETLK64 13 #define LINUX_F_SETLKW64 14 #define LINUX_F_RDLCK 0 #define LINUX_F_WRLCK 1 #define LINUX_F_UNLCK 2 /* * posix_fadvise advice */ #define LINUX_POSIX_FADV_NORMAL 0 #define LINUX_POSIX_FADV_RANDOM 1 #define LINUX_POSIX_FADV_SEQUENTIAL 2 #define LINUX_POSIX_FADV_WILLNEED 3 #define LINUX_POSIX_FADV_DONTNEED 4 #define LINUX_POSIX_FADV_NOREUSE 5 /* * mount flags */ #define LINUX_MS_RDONLY 0x0001 #define LINUX_MS_NOSUID 0x0002 #define LINUX_MS_NODEV 0x0004 #define LINUX_MS_NOEXEC 0x0008 #define LINUX_MS_REMOUNT 0x0020 /* * SystemV IPC defines */ #define LINUX_SEMOP 1 #define LINUX_SEMGET 2 #define LINUX_SEMCTL 3 #define LINUX_MSGSND 11 #define LINUX_MSGRCV 12 #define LINUX_MSGGET 13 #define LINUX_MSGCTL 14 #define LINUX_SHMAT 21 #define LINUX_SHMDT 22 #define LINUX_SHMGET 23 #define LINUX_SHMCTL 24 #define LINUX_IPC_RMID 0 #define LINUX_IPC_SET 1 #define LINUX_IPC_STAT 2 #define LINUX_IPC_INFO 3 #define LINUX_SHM_LOCK 11 #define LINUX_SHM_UNLOCK 12 #define LINUX_SHM_STAT 13 #define LINUX_SHM_INFO 14 #define LINUX_SHM_RDONLY 0x1000 #define LINUX_SHM_RND 0x2000 #define LINUX_SHM_REMAP 0x4000 /* semctl commands */ #define LINUX_GETPID 11 #define LINUX_GETVAL 12 #define LINUX_GETALL 13 #define LINUX_GETNCNT 14 #define LINUX_GETZCNT 15 #define LINUX_SETVAL 16 #define LINUX_SETALL 17 #define LINUX_SEM_STAT 18 #define LINUX_SEM_INFO 19 union l_semun { l_int val; l_uintptr_t buf; l_uintptr_t array; l_uintptr_t __buf; l_uintptr_t __pad; } __packed; /* * Socket defines */ #define LINUX_SOCKET 1 #define LINUX_BIND 2 #define LINUX_CONNECT 3 #define LINUX_LISTEN 4 #define LINUX_ACCEPT 5 #define LINUX_GETSOCKNAME 6 #define LINUX_GETPEERNAME 7 #define LINUX_SOCKETPAIR 8 #define LINUX_SEND 9 #define LINUX_RECV 10 #define LINUX_SENDTO 11 #define LINUX_RECVFROM 12 #define LINUX_SHUTDOWN 13 #define LINUX_SETSOCKOPT 14 #define LINUX_GETSOCKOPT 15 #define LINUX_SENDMSG 16 #define LINUX_RECVMSG 17 #define LINUX_ACCEPT4 18 #define LINUX_SOL_SOCKET 1 #define LINUX_SOL_IP 0 #define LINUX_SOL_IPX 256 #define LINUX_SOL_AX25 257 #define LINUX_SOL_TCP 6 #define LINUX_SOL_UDP 17 #define LINUX_SO_DEBUG 1 #define LINUX_SO_REUSEADDR 2 #define LINUX_SO_TYPE 3 #define LINUX_SO_ERROR 4 #define LINUX_SO_DONTROUTE 5 #define LINUX_SO_BROADCAST 6 #define LINUX_SO_SNDBUF 7 #define LINUX_SO_RCVBUF 8 #define LINUX_SO_KEEPALIVE 9 #define LINUX_SO_OOBINLINE 10 #define LINUX_SO_NO_CHECK 11 #define LINUX_SO_PRIORITY 12 #define LINUX_SO_LINGER 13 #define LINUX_SO_PEERCRED 17 #define LINUX_SO_RCVLOWAT 18 #define LINUX_SO_SNDLOWAT 19 #define LINUX_SO_RCVTIMEO 20 #define LINUX_SO_SNDTIMEO 21 #define LINUX_SO_TIMESTAMP 29 #define LINUX_SO_ACCEPTCONN 30 #define LINUX_IP_TOS 1 #define LINUX_IP_TTL 2 #define LINUX_IP_HDRINCL 3 #define LINUX_IP_OPTIONS 4 #define LINUX_IP_MULTICAST_IF 32 #define LINUX_IP_MULTICAST_TTL 33 #define LINUX_IP_MULTICAST_LOOP 34 #define LINUX_IP_ADD_MEMBERSHIP 35 #define LINUX_IP_DROP_MEMBERSHIP 36 struct l_sockaddr { l_ushort sa_family; char sa_data[14]; } __packed; struct l_msghdr { l_uintptr_t msg_name; l_int msg_namelen; l_uintptr_t msg_iov; l_size_t msg_iovlen; l_uintptr_t msg_control; l_size_t msg_controllen; l_uint msg_flags; }; struct l_cmsghdr { l_size_t cmsg_len; l_int cmsg_level; l_int cmsg_type; }; struct l_ifmap { l_ulong mem_start; l_ulong mem_end; l_ushort base_addr; u_char irq; u_char dma; u_char port; } __packed; #define LINUX_IFHWADDRLEN 6 #define LINUX_IFNAMSIZ 16 struct l_ifreq { union { char ifrn_name[LINUX_IFNAMSIZ]; } ifr_ifrn; union { struct l_sockaddr ifru_addr; struct l_sockaddr ifru_dstaddr; struct l_sockaddr ifru_broadaddr; struct l_sockaddr ifru_netmask; struct l_sockaddr ifru_hwaddr; l_short ifru_flags[1]; l_int ifru_metric; l_int ifru_mtu; struct l_ifmap ifru_map; char ifru_slave[LINUX_IFNAMSIZ]; l_uintptr_t ifru_data; } ifr_ifru; } __packed; #define ifr_name ifr_ifrn.ifrn_name /* Interface name */ #define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ struct l_ifconf { int ifc_len; union { l_uintptr_t ifcu_buf; l_uintptr_t ifcu_req; } ifc_ifcu; } __packed; #define ifc_buf ifc_ifcu.ifcu_buf #define ifc_req ifc_ifcu.ifcu_req /* * poll() */ #define LINUX_POLLIN 0x0001 #define LINUX_POLLPRI 0x0002 #define LINUX_POLLOUT 0x0004 #define LINUX_POLLERR 0x0008 #define LINUX_POLLHUP 0x0010 #define LINUX_POLLNVAL 0x0020 #define LINUX_POLLRDNORM 0x0040 #define LINUX_POLLRDBAND 0x0080 #define LINUX_POLLWRNORM 0x0100 #define LINUX_POLLWRBAND 0x0200 #define LINUX_POLLMSG 0x0400 struct l_pollfd { l_int fd; l_short events; l_short revents; } __packed; struct l_user_desc { l_uint entry_number; l_uint base_addr; l_uint limit; l_uint seg_32bit:1; l_uint contents:2; l_uint read_exec_only:1; l_uint limit_in_pages:1; l_uint seg_not_present:1; l_uint useable:1; }; #define LINUX_LOWERWORD 0x0000ffff /* * Macros which does the same thing as those in Linux include/asm-um/ldt-i386.h. * These convert Linux user space descriptor to machine one. */ #define LINUX_LDT_entry_a(info) \ ((((info)->base_addr & LINUX_LOWERWORD) << 16) | \ ((info)->limit & LINUX_LOWERWORD)) #define LINUX_ENTRY_B_READ_EXEC_ONLY 9 #define LINUX_ENTRY_B_CONTENTS 10 #define LINUX_ENTRY_B_SEG_NOT_PRESENT 15 #define LINUX_ENTRY_B_BASE_ADDR 16 #define LINUX_ENTRY_B_USEABLE 20 #define LINUX_ENTRY_B_SEG32BIT 22 #define LINUX_ENTRY_B_LIMIT 23 #define LINUX_LDT_entry_b(info) \ (((info)->base_addr & 0xff000000) | \ ((info)->limit & 0xf0000) | \ ((info)->contents << LINUX_ENTRY_B_CONTENTS) | \ (((info)->seg_not_present == 0) << LINUX_ENTRY_B_SEG_NOT_PRESENT) | \ (((info)->base_addr & 0x00ff0000) >> LINUX_ENTRY_B_BASE_ADDR) | \ (((info)->read_exec_only == 0) << LINUX_ENTRY_B_READ_EXEC_ONLY) | \ ((info)->seg_32bit << LINUX_ENTRY_B_SEG32BIT) | \ ((info)->useable << LINUX_ENTRY_B_USEABLE) | \ ((info)->limit_in_pages << LINUX_ENTRY_B_LIMIT) | 0x7000) #define LINUX_LDT_empty(info) \ ((info)->base_addr == 0 && \ (info)->limit == 0 && \ (info)->contents == 0 && \ (info)->seg_not_present == 1 && \ (info)->read_exec_only == 1 && \ (info)->seg_32bit == 0 && \ (info)->limit_in_pages == 0 && \ (info)->useable == 0) /* * Macros for converting segments. * They do the same as those in arch/i386/kernel/process.c in Linux. */ #define LINUX_GET_BASE(desc) \ ((((desc)->a >> 16) & LINUX_LOWERWORD) | \ (((desc)->b << 16) & 0x00ff0000) | \ ((desc)->b & 0xff000000)) #define LINUX_GET_LIMIT(desc) \ (((desc)->a & LINUX_LOWERWORD) | \ ((desc)->b & 0xf0000)) #define LINUX_GET_32BIT(desc) \ (((desc)->b >> LINUX_ENTRY_B_SEG32BIT) & 1) #define LINUX_GET_CONTENTS(desc) \ (((desc)->b >> LINUX_ENTRY_B_CONTENTS) & 3) #define LINUX_GET_WRITABLE(desc) \ (((desc)->b >> LINUX_ENTRY_B_READ_EXEC_ONLY) & 1) #define LINUX_GET_LIMIT_PAGES(desc) \ (((desc)->b >> LINUX_ENTRY_B_LIMIT) & 1) #define LINUX_GET_PRESENT(desc) \ (((desc)->b >> LINUX_ENTRY_B_SEG_NOT_PRESENT) & 1) #define LINUX_GET_USEABLE(desc) \ (((desc)->b >> LINUX_ENTRY_B_USEABLE) & 1) #define LINUX_CLOCK_REALTIME 0 #define LINUX_CLOCK_MONOTONIC 1 #define LINUX_CLOCK_PROCESS_CPUTIME_ID 2 #define LINUX_CLOCK_THREAD_CPUTIME_ID 3 #define LINUX_CLOCK_REALTIME_HR 4 #define LINUX_CLOCK_MONOTONIC_HR 5 #define LINUX_CLONE_VM 0x00000100 #define LINUX_CLONE_FS 0x00000200 #define LINUX_CLONE_FILES 0x00000400 #define LINUX_CLONE_SIGHAND 0x00000800 #define LINUX_CLONE_PID 0x00001000 /* No longer exist in Linux */ #define LINUX_CLONE_VFORK 0x00004000 #define LINUX_CLONE_PARENT 0x00008000 #define LINUX_CLONE_THREAD 0x00010000 #define LINUX_CLONE_SETTLS 0x00080000 #define LINUX_CLONE_PARENT_SETTID 0x00100000 #define LINUX_CLONE_CHILD_CLEARTID 0x00200000 #define LINUX_CLONE_CHILD_SETTID 0x01000000 #define LINUX_THREADING_FLAGS \ (LINUX_CLONE_VM | LINUX_CLONE_FS | LINUX_CLONE_FILES | \ LINUX_CLONE_SIGHAND | LINUX_CLONE_THREAD) struct iovec; struct l_iovec32 { uint32_t iov_base; l_size_t iov_len; }; int linux32_copyiniov(struct l_iovec32 *iovp32, l_ulong iovcnt, struct iovec **iovp, int error); /* robust futexes */ struct linux_robust_list { l_uintptr_t next; }; struct linux_robust_list_head { struct linux_robust_list list; l_long futex_offset; l_uintptr_t pending_list; }; int linux_set_upcall_kse(struct thread *td, register_t stack); int linux_set_cloned_tls(struct thread *td, void *desc); #endif /* !_AMD64_LINUX_H_ */ Index: stable/9/sys/amd64/linux32/linux32_dummy.c =================================================================== --- stable/9/sys/amd64/linux32/linux32_dummy.c (revision 246289) +++ stable/9/sys/amd64/linux32/linux32_dummy.c (revision 246290) @@ -1,168 +1,177 @@ /*- * Copyright (c) 1994-1995 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); +#include "opt_compat.h" +#include "opt_kdtrace.h" + #include +#include +#include #include #include #include #include +#include #include + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); DUMMY(stime); DUMMY(olduname); DUMMY(syslog); DUMMY(uname); DUMMY(vhangup); DUMMY(swapoff); DUMMY(adjtimex); DUMMY(create_module); DUMMY(init_module); DUMMY(delete_module); DUMMY(get_kernel_syms); DUMMY(quotactl); DUMMY(bdflush); DUMMY(sysfs); DUMMY(query_module); DUMMY(nfsservctl); DUMMY(rt_sigqueueinfo); DUMMY(sendfile); DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(pivot_root); DUMMY(mincore); DUMMY(ptrace); DUMMY(lookup_dcookie); DUMMY(epoll_create); DUMMY(epoll_ctl); DUMMY(epoll_wait); DUMMY(remap_file_pages); DUMMY(timer_create); DUMMY(timer_settime); DUMMY(timer_gettime); DUMMY(timer_getoverrun); DUMMY(timer_delete); DUMMY(fstatfs64); DUMMY(mbind); DUMMY(get_mempolicy); DUMMY(set_mempolicy); DUMMY(mq_open); DUMMY(mq_unlink); DUMMY(mq_timedsend); DUMMY(mq_timedreceive); DUMMY(mq_notify); DUMMY(mq_getsetattr); DUMMY(kexec_load); DUMMY(waitid); /* linux 2.6.11: */ DUMMY(add_key); DUMMY(request_key); DUMMY(keyctl); /* linux 2.6.13: */ DUMMY(ioprio_set); DUMMY(ioprio_get); DUMMY(inotify_init); DUMMY(inotify_add_watch); DUMMY(inotify_rm_watch); /* linux 2.6.16: */ DUMMY(migrate_pages); DUMMY(pselect6); DUMMY(ppoll); DUMMY(unshare); /* linux 2.6.17: */ DUMMY(splice); DUMMY(sync_file_range); DUMMY(tee); DUMMY(vmsplice); /* linux 2.6.18: */ DUMMY(move_pages); /* linux 2.6.19: */ DUMMY(getcpu); DUMMY(epoll_pwait); /* linux 2.6.22: */ DUMMY(utimensat); DUMMY(signalfd); DUMMY(timerfd_create); DUMMY(eventfd); /* linux 2.6.23: */ DUMMY(fallocate); /* linux 2.6.25: */ DUMMY(timerfd_settime); DUMMY(timerfd_gettime); /* linux 2.6.27: */ DUMMY(signalfd4); DUMMY(eventfd2); DUMMY(epoll_create1); DUMMY(dup3); DUMMY(pipe2); DUMMY(inotify_init1); /* linux 2.6.30: */ DUMMY(preadv); DUMMY(pwritev); /* linux 2.6.31: */ DUMMY(rt_tsigqueueinfo); DUMMY(perf_event_open); /* linux 2.6.33: */ DUMMY(recvmmsg); DUMMY(fanotify_init); DUMMY(fanotify_mark); /* linux 2.6.36: */ DUMMY(prlimit64); /* later: */ DUMMY(name_to_handle_at); DUMMY(open_by_handle_at); DUMMY(clock_adjtime); DUMMY(syncfs); DUMMY(sendmmsg); DUMMY(setns); DUMMY(process_vm_readv); DUMMY(process_vm_writev); #define DUMMY_XATTR(s) \ int \ linux_ ## s ## xattr( \ struct thread *td, struct linux_ ## s ## xattr_args *arg) \ { \ \ return (ENOATTR); \ } DUMMY_XATTR(set); DUMMY_XATTR(lset); DUMMY_XATTR(fset); DUMMY_XATTR(get); DUMMY_XATTR(lget); DUMMY_XATTR(fget); DUMMY_XATTR(list); DUMMY_XATTR(llist); DUMMY_XATTR(flist); DUMMY_XATTR(remove); DUMMY_XATTR(lremove); DUMMY_XATTR(fremove); Index: stable/9/sys/compat/linux/check_error.d =================================================================== --- stable/9/sys/compat/linux/check_error.d (nonexistent) +++ stable/9/sys/compat/linux/check_error.d (revision 246290) @@ -0,0 +1,144 @@ +#!/usr/sbin/dtrace -qs + +/*- + * Copyright (c) 2008-2012 Alexander Leidinger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Report error conditions: + * - emulation errors (unsupportet stuff, unknown stuff, ...) + * - kernel errors (resource shortage, ...) + * - programming errors (errors which can happen, but should not happen) + */ + +linuxulator*:dummy::not_implemented, +linuxulator*:emul:proc_exit:child_clear_tid_error, +linuxulator*:emul:proc_exit:futex_failed, +linuxulator*:emul:linux_schedtail:copyout_error, +linuxulator*:futex:futex_get:error, +linuxulator*:futex:futex_sleep:requeue_error, +linuxulator*:futex:futex_sleep:sleep_error, +linuxulator*:futex:futex_wait:copyin_error, +linuxulator*:futex:futex_wait:itimerfix_error, +linuxulator*:futex:futex_wait:sleep_error, +linuxulator*:futex:futex_atomic_op:missing_access_check, +linuxulator*:futex:futex_atomic_op:unimplemented_op, +linuxulator*:futex:futex_atomic_op:unimplemented_cmp, +linuxulator*:futex:linux_sys_futex:unimplemented_clockswitch, +linuxulator*:futex:linux_sys_futex:copyin_error, +linuxulator*:futex:linux_sys_futex:unhandled_efault, +linuxulator*:futex:linux_sys_futex:unimplemented_lock_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_unlock_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_trylock_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_wait_requeue_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_cmp_requeue_pi, +linuxulator*:futex:linux_sys_futex:unknown_operation, +linuxulator*:futex:linux_get_robust_list:copyout_error, +linuxulator*:futex:handle_futex_death:copyin_error, +linuxulator*:futex:fetch_robust_entry:copyin_error, +linuxulator*:futex:release_futexes:copyin_error, +linuxulator*:time:linux_clock_gettime:conversion_error, +linuxulator*:time:linux_clock_gettime:gettime_error, +linuxulator*:time:linux_clock_gettime:copyout_error, +linuxulator*:time:linux_clock_settime:conversion_error, +linuxulator*:time:linux_clock_settime:settime_error, +linuxulator*:time:linux_clock_settime:copyin_error, +linuxulator*:time:linux_clock_getres:conversion_error, +linuxulator*:time:linux_clock_getres:getres_error, +linuxulator*:time:linux_clock_getres:copyout_error, +linuxulator*:time:linux_nanosleep:conversion_error, +linuxulator*:time:linux_nanosleep:nanosleep_error, +linuxulator*:time:linux_nanosleep:copyout_error, +linuxulator*:time:linux_nanosleep:copyin_error, +linuxulator*:time:linux_clock_nanosleep:copyin_error, +linuxulator*:time:linux_clock_nanosleep:conversion_error, +linuxulator*:time:linux_clock_nanosleep:copyout_error, +linuxulator*:time:linux_clock_nanosleep:nanosleep_error, +linuxulator*:sysctl:handle_string:copyout_error, +linuxulator*:sysctl:linux_sysctl:copyin_error, +linuxulator*:mib:linux_sysctl_osname:sysctl_string_error, +linuxulator*:mib:linux_sysctl_osrelease:sysctl_string_error, +linuxulator*:mib:linux_sysctl_oss_version:sysctl_string_error, +linuxulator*:mib:linux_prison_create:vfs_copyopt_error, +linuxulator*:mib:linux_prison_check:vfs_copyopt_error, +linuxulator*:mib:linux_prison_check:vfs_getopt_error, +linuxulator*:mib:linux_prison_set:vfs_copyopt_error, +linuxulator*:mib:linux_prison_set:vfs_getopt_error, +linuxulator*:mib:linux_prison_get:vfs_setopt_error, +linuxulator*:mib:linux_prison_get:vfs_setopts_error +{ + printf("ERROR: %s in %s:%s:%s\n", probename, probeprov, probemod, probefunc); + stack(); + ustack(); +} + +linuxulator*:util:linux_driver_get_name_dev:nullcall, +linuxulator*:util:linux_driver_get_major_minor:nullcall, +linuxulator*:futex:linux_sys_futex:invalid_cmp_requeue_use, +linuxulator*:futex:linux_sys_futex:deprecated_requeue, +linuxulator*:futex:linux_set_robust_list:size_error, +linuxulator*:time:linux_clock_getres:nullcall +{ + printf("WARNING: %s:%s:%s:%s in application %s, maybe an application error?\n", probename, probeprov, probemod, probefunc, execname); + stack(); + ustack(); +} + +linuxulator*:util:linux_driver_get_major_minor:notfound +{ + printf("WARNING: Application %s failed to find %s in %s:%s:%s, this may or may not be a problem.\n", execname, stringof(args[0]), probename, probeprov, probemod); + stack(); + ustack(); +} + +linuxulator*:time:linux_to_native_clockid:unknown_clockid +{ + printf("INFO: Application %s tried to use unknown clockid %d. Please report this to freebsd-emulation@FreeBSD.org.\n", execname, arg0); +} + +linuxulator*:time:linux_to_native_clockid:unsupported_clockid, +linuxulator*:time:linux_clock_nanosleep:unsupported_clockid +{ + printf("WARNING: Application %s tried to use unsupported clockid (%d), this may or may not be a problem for the application.\nPatches to support this clockid are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, arg0); +} + +linuxulator*:time:linux_clock_nanosleep:unsupported_flags +{ + printf("WARNING: Application %s tried to use unsupported flags (%d), this may or may not be a problem for the application.\nPatches to support those flags are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, arg0); +} + +linuxulator*:sysctl:linux_sysctl:wrong_length +{ + printf("ERROR: Application %s issued a sysctl which failed the length restrictions.\nThe length passed is %d, the min length supported is 1 and the max length supported is %d.\n", execname, arg0, arg1); + stack(); + ustack(); +} + +linuxulator*:sysctl:linux_sysctl:unsupported_sysctl +{ + printf("ERROR: Application %s issued an unsupported sysctl (%s).\nPatches to support this sysctl are welcome on the freebsd-emulation@FreeBSD.org mailinglist.\n", execname, stringof(args[0])); +} Property changes on: stable/9/sys/compat/linux/check_error.d ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/9/sys/compat/linux/check_internal_locks.d =================================================================== --- stable/9/sys/compat/linux/check_internal_locks.d (nonexistent) +++ stable/9/sys/compat/linux/check_internal_locks.d (revision 246290) @@ -0,0 +1,132 @@ +#!/usr/sbin/dtrace -qs + +/*- + * Copyright (c) 2008-2012 Alexander Leidinger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/** + * Check if the internal locks are correctly acquired/released: + * - no recursive locking (mtx locks, write locks) + * - no unlocking of already unlocked one + * + * Print stacktrace if a lock is longer locked than about 10sec or more. + */ + +#pragma D option dynvarsize=32m +#pragma D option specsize=32m + +BEGIN +{ + check["emul_lock"] = 0; + check["emul_shared_rlock"] = 0; + check["emul_shared_wlock"] = 0; + check["futex_mtx"] = 0; +} + +linuxulator*:locks:emul_lock:locked, +linuxulator*:locks:emul_shared_wlock:locked, +linuxulator*:locks:futex_mtx:locked +/check[probefunc] > 0/ +{ + printf("ERROR: recursive lock of %s (%p),", probefunc, arg0); + printf(" or missing SDT probe in kernel. Stack trace follows:"); + stack(); +} + +linuxulator*:locks:emul_lock:locked, +linuxulator*:locks:emul_shared_rlock:locked, +linuxulator*:locks:emul_shared_wlock:locked, +linuxulator*:locks:futex_mtx:locked +{ + ++check[probefunc]; + @stats[probefunc] = count(); + + ts[probefunc] = timestamp; + spec[probefunc] = speculation(); +} + +linuxulator*:locks:emul_lock:unlock, +linuxulator*:locks:emul_shared_rlock:unlock, +linuxulator*:locks:emul_shared_wlock:unlock, +linuxulator*:locks:futex_mtx:unlock +/check[probefunc] == 0/ +{ + printf("ERROR: unlock attemt of unlocked %s (%p),", probefunc, arg0); + printf(" missing SDT probe in kernel, or dtrace program started"); + printf(" while the %s was already held (race condition).", probefunc); + printf(" Stack trace follows:"); + stack(); +} + +linuxulator*:locks:emul_lock:unlock, +linuxulator*:locks:emul_shared_rlock:unlock, +linuxulator*:locks:emul_shared_wlock:unlock, +linuxulator*:locks:futex_mtx:unlock +{ + discard(spec[probefunc]); + spec[probefunc] = 0; + --check[probefunc]; +} + +/* Timeout handling */ + +tick-10s +/spec["emul_lock"] != 0 && timestamp - ts["emul_lock"] >= 9999999000/ +{ + commit(spec["emul_lock"]); + spec["emul_lock"] = 0; +} + +tick-10s +/spec["emul_shared_wlock"] != 0 && timestamp - ts["emul_shared_wlock"] >= 9999999000/ +{ + commit(spec["emul_shared_wlock"]); + spec["emul_shared_wlock"] = 0; +} + +tick-10s +/spec["emul_shared_rlock"] != 0 && timestamp - ts["emul_shared_rlock"] >= 9999999000/ +{ + commit(spec["emul_shared_rlock"]); + spec["emul_shared_rlock"] = 0; +} + +tick-10s +/spec["futex_mtx"] != 0 && timestamp - ts["futex_mtx"] >= 9999999000/ +{ + commit(spec["futex_mtx"]); + spec["futex_mtx"] = 0; +} + + +/* Statistics */ + +END +{ + printf("Number of locks per type:"); + printa(@stats); +} Property changes on: stable/9/sys/compat/linux/check_internal_locks.d ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/9/sys/compat/linux/linux_dtrace.h =================================================================== --- stable/9/sys/compat/linux/linux_dtrace.h (nonexistent) +++ stable/9/sys/compat/linux/linux_dtrace.h (revision 246290) @@ -0,0 +1,95 @@ +/*- + * Copyright (c) 2008-2012 Alexander Leidinger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _LINUX_DTRACE_H_ +#define _LINUX_DTRACE_H_ + +/** + * DTrace support macros for the linuxulator. + * + * Some wrapper macros to make it more easy to handle the linuxulator + * providers and to allow to make the name depend upon the bitsize. + * + * Basically this is the same as the normal SDT macros in sys/sdt.h. The + * difference is that the provider name is automatically inserted, and + * we do not use a different name for the probe-description. + */ + +#define LIN_SDT_PROVIDER_DEFINE(x) SDT_PROVIDER_DEFINE(x) +#define LIN_SDT_PROVIDER_DECLARE(x) SDT_PROVIDER_DECLARE(x) + +#define _LIN_SDT_PROBE_DECLARE(a, b, c, d) SDT_PROBE_DECLARE(a, b, c, d) +#define LIN_SDT_PROBE_DECLARE(a, b, c) _LIN_SDT_PROBE_DECLARE( \ + LINUX_DTRACE, a, b, c) + +#define _LIN_SDT_PROBE_DEFINE0(a, b, c, d) SDT_PROBE_DEFINE(a, \ + b, c, d, d) +#define LIN_SDT_PROBE_DEFINE0(a, b, c) _LIN_SDT_PROBE_DEFINE0(\ + LINUX_DTRACE, a, b, c) +#define _LIN_SDT_PROBE_DEFINE1(a, b, c, d, e) SDT_PROBE_DEFINE1(a, \ + b, c, d, d, e) +#define LIN_SDT_PROBE_DEFINE1(a, b, c, d) _LIN_SDT_PROBE_DEFINE1(\ + LINUX_DTRACE, a, b, c, d) +#define _LIN_SDT_PROBE_DEFINE2(a, b, c, d, e, f) SDT_PROBE_DEFINE2(a, \ + b, c, d, d, e, f) +#define LIN_SDT_PROBE_DEFINE2(a, b, c, d, e) _LIN_SDT_PROBE_DEFINE2(\ + LINUX_DTRACE, a, b, c, d, e) +#define _LIN_SDT_PROBE_DEFINE3(a, b, c, d, e, f, g) SDT_PROBE_DEFINE3(a, \ + b, c, d, d, e, f, g) +#define LIN_SDT_PROBE_DEFINE3(a, b, c, d, e, f) _LIN_SDT_PROBE_DEFINE3(\ + LINUX_DTRACE, a, b, c, d, e, f) +#define _LIN_SDT_PROBE_DEFINE4(a, b, c, d, e, f, g, h) SDT_PROBE_DEFINE4(a, \ + b, c, d, d, e, f, g, h) +#define LIN_SDT_PROBE_DEFINE4(a, b, c, d, e, f, g) _LIN_SDT_PROBE_DEFINE4(\ + LINUX_DTRACE, a, b, c, d, e, f, g) +#define _LIN_SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h, i) \ + SDT_PROBE_DEFINE5(a, b, c, d, d, e, f, g, h, i) +#define LIN_SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h) _LIN_SDT_PROBE_DEFINE5(\ + LINUX_DTRACE, a, b, c, d, e, f, g, h) + +#define _LIN_SDT_PROBE_ARGTYPE(a, b, c, d, e, f) SDT_PROBE_ARGTYPE(a, b,\ + c, d, e, f) +#define LIN_SDT_PROBE_ARGTYPE(a, b, c, d, e) _LIN_SDT_PROBE_ARGTYPE( \ + LINUX_DTRACE, a, b, c, d, e) + +#define LIN_SDT_PROBE0(a, b, c) SDT_PROBE1(LINUX_DTRACE, a, b, \ + c, 0) +#define LIN_SDT_PROBE1(a, b, c, d) SDT_PROBE1(LINUX_DTRACE, a, b, \ + c, d) +#define LIN_SDT_PROBE2(a, b, c, d, e) SDT_PROBE2(LINUX_DTRACE, a, b, \ + c, d, e) +#define LIN_SDT_PROBE3(a, b, c, d, e, f) SDT_PROBE3(LINUX_DTRACE, a, b, \ + c, d, e, f) +#define LIN_SDT_PROBE4(a, b, c, d, e, f, g) SDT_PROBE4(LINUX_DTRACE, a, b, \ + c, d, e, f, g) +#define _LIN_SDT_PROBE5(a, b, c, d, e, f, g, h, i) SDT_PROBE(a, b, c, d, \ + e, f, g, h, i) +#define LIN_SDT_PROBE5(a, b, c, d, e, f, g, h) _LIN_SDT_PROBE5(LINUX_DTRACE, \ + a, b, c, d, e, f, g, h) + +#endif /* _LINUX_DTRACE_H_ */ Property changes on: stable/9/sys/compat/linux/linux_dtrace.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/9/sys/compat/linux/linux_emul.c =================================================================== --- stable/9/sys/compat/linux/linux_emul.c (revision 246289) +++ stable/9/sys/compat/linux/linux_emul.c (revision 246290) @@ -1,372 +1,473 @@ /*- * Copyright (c) 2006 Roman Divacky * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" +#include "opt_kdtrace.h" #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #ifdef COMPAT_LINUX32 #include #include #else #include #include #endif +#include #include #include +/** + * Special DTrace provider for the linuxulator. + * + * In this file we define the provider for the entire linuxulator. All + * modules (= files of the linuxulator) use it. + * + * We define a different name depending on the emulated bitsize, see + * ../..//linux{,32}/linux.h, e.g.: + * native bitsize = linuxulator + * amd64, 32bit emulation = linuxulator32 + */ +LIN_SDT_PROVIDER_DEFINE(LINUX_DTRACE); + +/** + * Special DTrace module "locks", it covers some linuxulator internal + * locks. + */ +LIN_SDT_PROBE_DEFINE1(locks, emul_lock, locked, "struct mtx *"); +LIN_SDT_PROBE_DEFINE1(locks, emul_lock, unlock, "struct mtx *"); +LIN_SDT_PROBE_DEFINE1(locks, emul_shared_rlock, locked, "struct sx *"); +LIN_SDT_PROBE_DEFINE1(locks, emul_shared_rlock, unlock, "struct sx *"); +LIN_SDT_PROBE_DEFINE1(locks, emul_shared_wlock, locked, "struct sx *"); +LIN_SDT_PROBE_DEFINE1(locks, emul_shared_wlock, unlock, "struct sx *"); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE2(emul, em_find, entry, "struct proc *", "int"); +LIN_SDT_PROBE_DEFINE0(emul, em_find, return); +LIN_SDT_PROBE_DEFINE3(emul, proc_init, entry, "struct thread *", "pid_t", + "int"); +LIN_SDT_PROBE_DEFINE0(emul, proc_init, create_thread); +LIN_SDT_PROBE_DEFINE0(emul, proc_init, fork); +LIN_SDT_PROBE_DEFINE0(emul, proc_init, exec); +LIN_SDT_PROBE_DEFINE0(emul, proc_init, return); +LIN_SDT_PROBE_DEFINE1(emul, proc_exit, entry, "struct proc *"); +LIN_SDT_PROBE_DEFINE0(emul, proc_exit, futex_failed); +LIN_SDT_PROBE_DEFINE3(emul, proc_exit, reparent, "pid_t", "pid_t", + "struct proc *"); +LIN_SDT_PROBE_DEFINE1(emul, proc_exit, child_clear_tid_error, "int"); +LIN_SDT_PROBE_DEFINE0(emul, proc_exit, return); +LIN_SDT_PROBE_DEFINE2(emul, proc_exec, entry, "struct proc *", + "struct image_params *"); +LIN_SDT_PROBE_DEFINE0(emul, proc_exec, return); +LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, entry); +LIN_SDT_PROBE_DEFINE1(emul, linux_schedtail, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, return); +LIN_SDT_PROBE_DEFINE1(emul, linux_set_tid_address, entry, "int *"); +LIN_SDT_PROBE_DEFINE0(emul, linux_set_tid_address, return); +LIN_SDT_PROBE_DEFINE2(emul, linux_kill_threads, entry, "struct thread *", + "int"); +LIN_SDT_PROBE_DEFINE1(emul, linux_kill_threads, kill, "pid_t"); +LIN_SDT_PROBE_DEFINE0(emul, linux_kill_threads, return); + struct sx emul_shared_lock; struct mtx emul_lock; /* this returns locked reference to the emuldata entry (if found) */ struct linux_emuldata * em_find(struct proc *p, int locked) { struct linux_emuldata *em; + LIN_SDT_PROBE2(emul, em_find, entry, p, locked); + if (locked == EMUL_DOLOCK) EMUL_LOCK(&emul_lock); em = p->p_emuldata; if (em == NULL && locked == EMUL_DOLOCK) EMUL_UNLOCK(&emul_lock); + LIN_SDT_PROBE1(emul, em_find, return, em); return (em); } int linux_proc_init(struct thread *td, pid_t child, int flags) { struct linux_emuldata *em, *p_em; struct proc *p; + LIN_SDT_PROBE3(emul, proc_init, entry, td, child, flags); + if (child != 0) { - /* non-exec call */ + /* fork or create a thread */ em = malloc(sizeof *em, M_LINUX, M_WAITOK | M_ZERO); em->pid = child; em->pdeath_signal = 0; em->flags = 0; em->robust_futexes = NULL; if (flags & LINUX_CLONE_THREAD) { /* handled later in the code */ + LIN_SDT_PROBE0(emul, proc_init, create_thread); } else { struct linux_emuldata_shared *s; + LIN_SDT_PROBE0(emul, proc_init, fork); + s = malloc(sizeof *s, M_LINUX, M_WAITOK | M_ZERO); s->refs = 1; s->group_pid = child; LIST_INIT(&s->threads); em->shared = s; } } else { + /* exec */ + LIN_SDT_PROBE0(emul, proc_init, exec); + /* lookup the old one */ em = em_find(td->td_proc, EMUL_DOLOCK); KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n")); } em->child_clear_tid = NULL; em->child_set_tid = NULL; /* * allocate the shared struct only in clone()/fork cases in the case * of clone() td = calling proc and child = pid of the newly created * proc */ if (child != 0) { if (flags & LINUX_CLONE_THREAD) { /* lookup the parent */ /* * we dont have to lock the p_em because * its waiting for us in linux_clone so * there is no chance of it changing the * p_em->shared address */ p_em = em_find(td->td_proc, EMUL_DONTLOCK); KASSERT(p_em != NULL, ("proc_init: parent emuldata not found for CLONE_THREAD\n")); em->shared = p_em->shared; EMUL_SHARED_WLOCK(&emul_shared_lock); em->shared->refs++; EMUL_SHARED_WUNLOCK(&emul_shared_lock); } else { /* * handled earlier to avoid malloc(M_WAITOK) with * rwlock held */ } - } - if (child != 0) { + EMUL_SHARED_WLOCK(&emul_shared_lock); LIST_INSERT_HEAD(&em->shared->threads, em, threads); EMUL_SHARED_WUNLOCK(&emul_shared_lock); p = pfind(child); KASSERT(p != NULL, ("process not found in proc_init\n")); p->p_emuldata = em; PROC_UNLOCK(p); } else EMUL_UNLOCK(&emul_lock); + LIN_SDT_PROBE0(emul, proc_init, return); return (0); } void linux_proc_exit(void *arg __unused, struct proc *p) { struct linux_emuldata *em; int error, shared_flags, shared_xstat; struct thread *td = FIRST_THREAD_IN_PROC(p); int *child_clear_tid; struct proc *q, *nq; if (__predict_true(p->p_sysent != &elf_linux_sysvec)) return; + LIN_SDT_PROBE1(emul, proc_exit, entry, p); + release_futexes(p); /* find the emuldata */ em = em_find(p, EMUL_DOLOCK); KASSERT(em != NULL, ("proc_exit: emuldata not found.\n")); /* reparent all procs that are not a thread leader to initproc */ if (em->shared->group_pid != p->p_pid) { + LIN_SDT_PROBE3(emul, proc_exit, reparent, + em->shared->group_pid, p->p_pid, p); + child_clear_tid = em->child_clear_tid; EMUL_UNLOCK(&emul_lock); sx_xlock(&proctree_lock); wakeup(initproc); PROC_LOCK(p); proc_reparent(p, initproc); p->p_sigparent = SIGCHLD; PROC_UNLOCK(p); sx_xunlock(&proctree_lock); } else { child_clear_tid = em->child_clear_tid; EMUL_UNLOCK(&emul_lock); } EMUL_SHARED_WLOCK(&emul_shared_lock); shared_flags = em->shared->flags; shared_xstat = em->shared->xstat; LIST_REMOVE(em, threads); em->shared->refs--; if (em->shared->refs == 0) { EMUL_SHARED_WUNLOCK(&emul_shared_lock); free(em->shared, M_LINUX); } else EMUL_SHARED_WUNLOCK(&emul_shared_lock); if ((shared_flags & EMUL_SHARED_HASXSTAT) != 0) p->p_xstat = shared_xstat; if (child_clear_tid != NULL) { struct linux_sys_futex_args cup; int null = 0; error = copyout(&null, child_clear_tid, sizeof(null)); if (error) { + LIN_SDT_PROBE1(emul, proc_exit, + child_clear_tid_error, error); + free(em, M_LINUX); + + LIN_SDT_PROBE0(emul, proc_exit, return); return; } /* futexes stuff */ cup.uaddr = child_clear_tid; cup.op = LINUX_FUTEX_WAKE; cup.val = 0x7fffffff; /* Awake everyone */ cup.timeout = NULL; cup.uaddr2 = NULL; cup.val3 = 0; error = linux_sys_futex(FIRST_THREAD_IN_PROC(p), &cup); /* * this cannot happen at the moment and if this happens it * probably means there is a user space bug */ - if (error) + if (error) { + LIN_SDT_PROBE0(emul, proc_exit, futex_failed); printf(LMSG("futex stuff in proc_exit failed.\n")); + } } /* clean the stuff up */ free(em, M_LINUX); /* this is a little weird but rewritten from exit1() */ sx_xlock(&proctree_lock); q = LIST_FIRST(&p->p_children); for (; q != NULL; q = nq) { nq = LIST_NEXT(q, p_sibling); if (q->p_flag & P_WEXIT) continue; if (__predict_false(q->p_sysent != &elf_linux_sysvec)) continue; em = em_find(q, EMUL_DOLOCK); KASSERT(em != NULL, ("linux_reparent: emuldata not found: %i\n", q->p_pid)); PROC_LOCK(q); if ((q->p_flag & P_WEXIT) == 0 && em->pdeath_signal != 0) { kern_psignal(q, em->pdeath_signal); } PROC_UNLOCK(q); EMUL_UNLOCK(&emul_lock); } sx_xunlock(&proctree_lock); + + LIN_SDT_PROBE0(emul, proc_exit, return); } /* * This is used in a case of transition from FreeBSD binary execing to linux binary * in this case we create linux emuldata proc entry with the pid of the currently running * process. */ void linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) { + if (__predict_false(imgp->sysent == &elf_linux_sysvec)) { + LIN_SDT_PROBE2(emul, proc_exec, entry, p, imgp); + } if (__predict_false(imgp->sysent == &elf_linux_sysvec && p->p_sysent != &elf_linux_sysvec)) linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0); if (__predict_false((p->p_sysent->sv_flags & SV_ABI_MASK) == SV_ABI_LINUX)) /* Kill threads regardless of imgp->sysent value */ linux_kill_threads(FIRST_THREAD_IN_PROC(p), SIGKILL); if (__predict_false(imgp->sysent != &elf_linux_sysvec && p->p_sysent == &elf_linux_sysvec)) { struct linux_emuldata *em; /* * XXX:There's a race because here we assign p->p_emuldata NULL * but the process is still counted as linux one for a short * time so some other process might reference it and try to * access its p->p_emuldata and panicing on a NULL reference. */ em = em_find(p, EMUL_DONTLOCK); KASSERT(em != NULL, ("proc_exec: emuldata not found.\n")); EMUL_SHARED_WLOCK(&emul_shared_lock); LIST_REMOVE(em, threads); PROC_LOCK(p); p->p_emuldata = NULL; PROC_UNLOCK(p); em->shared->refs--; if (em->shared->refs == 0) { EMUL_SHARED_WUNLOCK(&emul_shared_lock); free(em->shared, M_LINUX); } else EMUL_SHARED_WUNLOCK(&emul_shared_lock); free(em, M_LINUX); } + + if (__predict_false(imgp->sysent == &elf_linux_sysvec)) { + LIN_SDT_PROBE0(emul, proc_exec, return); + } } void linux_schedtail(struct thread *td) { struct linux_emuldata *em; struct proc *p; int error = 0; int *child_set_tid; p = td->td_proc; + LIN_SDT_PROBE1(emul, linux_schedtail, entry, p); + /* find the emuldata */ em = em_find(p, EMUL_DOLOCK); KASSERT(em != NULL, ("linux_schedtail: emuldata not found.\n")); child_set_tid = em->child_set_tid; EMUL_UNLOCK(&emul_lock); - if (child_set_tid != NULL) + if (child_set_tid != NULL) { error = copyout(&p->p_pid, (int *)child_set_tid, sizeof(p->p_pid)); + if (error != 0) { + LIN_SDT_PROBE1(emul, linux_schedtail, copyout_error, + error); + } + } + + LIN_SDT_PROBE0(emul, linux_schedtail, return); + return; } int linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) { struct linux_emuldata *em; -#ifdef DEBUG - if (ldebug(set_tid_address)) - printf(ARGS(set_tid_address, "%p"), args->tidptr); -#endif + LIN_SDT_PROBE1(emul, linux_set_tid_address, entry, args->tidptr); /* find the emuldata */ em = em_find(td->td_proc, EMUL_DOLOCK); KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); em->child_clear_tid = args->tidptr; td->td_retval[0] = td->td_proc->p_pid; EMUL_UNLOCK(&emul_lock); + + LIN_SDT_PROBE0(emul, linux_set_tid_address, return); return 0; } void linux_kill_threads(struct thread *td, int sig) { struct linux_emuldata *em, *td_em, *tmp_em; struct proc *sp; + LIN_SDT_PROBE2(emul, linux_kill_threads, entry, td, sig); + td_em = em_find(td->td_proc, EMUL_DONTLOCK); KASSERT(td_em != NULL, ("linux_kill_threads: emuldata not found.\n")); EMUL_SHARED_RLOCK(&emul_shared_lock); LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) { if (em->pid == td_em->pid) continue; sp = pfind(em->pid); if ((sp->p_flag & P_WEXIT) == 0) kern_psignal(sp, sig); PROC_UNLOCK(sp); -#ifdef DEBUG - printf(LMSG("linux_kill_threads: kill PID %d\n"), em->pid); -#endif + + LIN_SDT_PROBE1(emul, linux_kill_threads, kill, em->pid); } EMUL_SHARED_RUNLOCK(&emul_shared_lock); + + LIN_SDT_PROBE0(emul, linux_kill_threads, return); } Index: stable/9/sys/compat/linux/linux_emul.h =================================================================== --- stable/9/sys/compat/linux/linux_emul.h (revision 246289) +++ stable/9/sys/compat/linux/linux_emul.h (revision 246290) @@ -1,92 +1,121 @@ /*- * Copyright (c) 2006 Roman Divacky * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _LINUX_EMUL_H_ #define _LINUX_EMUL_H_ #define EMUL_SHARED_HASXSTAT 0x01 struct linux_emuldata_shared { int refs; int flags; int xstat; pid_t group_pid; LIST_HEAD(, linux_emuldata) threads; /* head of list of linux threads */ }; /* * modeled after similar structure in NetBSD * this will be extended as we need more functionality */ struct linux_emuldata { pid_t pid; int *child_set_tid; /* in clone(): Child's TID to set on clone */ int *child_clear_tid;/* in clone(): Child's TID to clear on exit */ struct linux_emuldata_shared *shared; int pdeath_signal; /* parent death signal */ int flags; /* different emuldata flags */ struct linux_robust_list_head *robust_futexes; LIST_ENTRY(linux_emuldata) threads; /* list of linux threads */ }; struct linux_emuldata *em_find(struct proc *, int locked); -#define EMUL_LOCK(l) mtx_lock(l) -#define EMUL_UNLOCK(l) mtx_unlock(l) +/* + * DTrace probes for locks should be fired after locking and before releasing + * to prevent races (to provide data/function stability in dtrace, see the + * output of "dtrace -v ..." and the corresponding dtrace docs). + */ +#define EMUL_LOCK(l) do { \ + mtx_lock(l); \ + LIN_SDT_PROBE1(locks, emul_lock, \ + locked, l); \ + } while (0) +#define EMUL_UNLOCK(l) do { \ + LIN_SDT_PROBE1(locks, emul_lock, \ + unlock, l); \ + mtx_unlock(l); \ + } while (0) -#define EMUL_SHARED_RLOCK(l) sx_slock(l) -#define EMUL_SHARED_RUNLOCK(l) sx_sunlock(l) -#define EMUL_SHARED_WLOCK(l) sx_xlock(l) -#define EMUL_SHARED_WUNLOCK(l) sx_xunlock(l) +#define EMUL_SHARED_RLOCK(l) do { \ + sx_slock(l); \ + LIN_SDT_PROBE1(locks, emul_shared_rlock, \ + locked, l); \ + } while (0) +#define EMUL_SHARED_RUNLOCK(l) do { \ + LIN_SDT_PROBE1(locks, emul_shared_rlock, \ + unlock, l); \ + sx_sunlock(l); \ + } while (0) +#define EMUL_SHARED_WLOCK(l) do { \ + sx_xlock(l); \ + LIN_SDT_PROBE1(locks, emul_shared_wlock, \ + locked, l); \ + } while (0) +#define EMUL_SHARED_WUNLOCK(l) do { \ + LIN_SDT_PROBE1(locks, emul_shared_wlock, \ + unlock, l); \ + sx_xunlock(l); \ + } while (0) /* for em_find use */ #define EMUL_DOLOCK 1 #define EMUL_DONTLOCK 0 /* emuldata flags */ #define LINUX_XDEPR_REQUEUEOP 0x00000001 /* uses deprecated futex REQUEUE op*/ int linux_proc_init(struct thread *, pid_t, int); void linux_proc_exit(void *, struct proc *); void linux_schedtail(struct thread *); void linux_proc_exec(void *, struct proc *, struct image_params *); void linux_kill_threads(struct thread *, int); extern struct sx emul_shared_lock; extern struct mtx emul_lock; #endif /* !_LINUX_EMUL_H_ */ Index: stable/9/sys/compat/linux/linux_fork.c =================================================================== --- stable/9/sys/compat/linux/linux_fork.c (revision 246289) +++ stable/9/sys/compat/linux/linux_fork.c (revision 246290) @@ -1,289 +1,299 @@ /*- * Copyright (c) 2004 Tim J. Robbins * Copyright (c) 2002 Doug Rabson * Copyright (c) 2000 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" +#include "opt_kdtrace.h" #include #include #include #include #include #include #include +#include #include #include #ifdef COMPAT_LINUX32 #include #include #else #include #include #endif +#include #include #include + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/* Linuxulator-global DTrace probes */ +LIN_SDT_PROBE_DECLARE(locks, emul_lock, locked); +LIN_SDT_PROBE_DECLARE(locks, emul_lock, unlock); int linux_fork(struct thread *td, struct linux_fork_args *args) { int error; struct proc *p2; struct thread *td2; #ifdef DEBUG if (ldebug(fork)) printf(ARGS(fork, "")); #endif if ((error = fork1(td, RFFDG | RFPROC | RFSTOPPED, 0, &p2, NULL, 0)) != 0) return (error); td->td_retval[0] = p2->p_pid; td->td_retval[1] = 0; error = linux_proc_init(td, td->td_retval[0], 0); if (error) return (error); td2 = FIRST_THREAD_IN_PROC(p2); /* * Make this runnable after we are finished with it. */ thread_lock(td2); TD_SET_CAN_RUN(td2); sched_add(td2, SRQ_BORING); thread_unlock(td2); return (0); } int linux_vfork(struct thread *td, struct linux_vfork_args *args) { int error; struct proc *p2; struct thread *td2; #ifdef DEBUG if (ldebug(vfork)) printf(ARGS(vfork, "")); #endif /* Exclude RFPPWAIT */ if ((error = fork1(td, RFFDG | RFPROC | RFMEM | RFSTOPPED, 0, &p2, NULL, 0)) != 0) return (error); td->td_retval[0] = p2->p_pid; error = linux_proc_init(td, td->td_retval[0], 0); if (error) return (error); PROC_LOCK(p2); p2->p_flag |= P_PPWAIT; PROC_UNLOCK(p2); td2 = FIRST_THREAD_IN_PROC(p2); /* * Make this runnable after we are finished with it. */ thread_lock(td2); TD_SET_CAN_RUN(td2); sched_add(td2, SRQ_BORING); thread_unlock(td2); /* wait for the children to exit, ie. emulate vfork */ PROC_LOCK(p2); while (p2->p_flag & P_PPWAIT) cv_wait(&p2->p_pwait, &p2->p_mtx); PROC_UNLOCK(p2); return (0); } int linux_clone(struct thread *td, struct linux_clone_args *args) { int error, ff = RFPROC | RFSTOPPED; struct proc *p2; struct thread *td2; int exit_signal; struct linux_emuldata *em; #ifdef DEBUG if (ldebug(clone)) { printf(ARGS(clone, "flags %x, stack %p, parent tid: %p, " "child tid: %p"), (unsigned)args->flags, args->stack, args->parent_tidptr, args->child_tidptr); } #endif exit_signal = args->flags & 0x000000ff; if (LINUX_SIG_VALID(exit_signal)) { if (exit_signal <= LINUX_SIGTBLSZ) exit_signal = linux_to_bsd_signal[_SIG_IDX(exit_signal)]; } else if (exit_signal != 0) return (EINVAL); if (args->flags & LINUX_CLONE_VM) ff |= RFMEM; if (args->flags & LINUX_CLONE_SIGHAND) ff |= RFSIGSHARE; /* * XXX: In Linux, sharing of fs info (chroot/cwd/umask) * and open files is independant. In FreeBSD, its in one * structure but in reality it does not cause any problems * because both of these flags are usually set together. */ if (!(args->flags & (LINUX_CLONE_FILES | LINUX_CLONE_FS))) ff |= RFFDG; /* * Attempt to detect when linux_clone(2) is used for creating * kernel threads. Unfortunately despite the existence of the * CLONE_THREAD flag, version of linuxthreads package used in * most popular distros as of beginning of 2005 doesn't make * any use of it. Therefore, this detection relies on * empirical observation that linuxthreads sets certain * combination of flags, so that we can make more or less * precise detection and notify the FreeBSD kernel that several * processes are in fact part of the same threading group, so * that special treatment is necessary for signal delivery * between those processes and fd locking. */ if ((args->flags & 0xffffff00) == LINUX_THREADING_FLAGS) ff |= RFTHREAD; if (args->flags & LINUX_CLONE_PARENT_SETTID) if (args->parent_tidptr == NULL) return (EINVAL); error = fork1(td, ff, 0, &p2, NULL, 0); if (error) return (error); if (args->flags & (LINUX_CLONE_PARENT | LINUX_CLONE_THREAD)) { sx_xlock(&proctree_lock); PROC_LOCK(p2); proc_reparent(p2, td->td_proc->p_pptr); PROC_UNLOCK(p2); sx_xunlock(&proctree_lock); } /* create the emuldata */ error = linux_proc_init(td, p2->p_pid, args->flags); /* reference it - no need to check this */ em = em_find(p2, EMUL_DOLOCK); KASSERT(em != NULL, ("clone: emuldata not found.")); /* and adjust it */ if (args->flags & LINUX_CLONE_THREAD) { #ifdef notyet PROC_LOCK(p2); p2->p_pgrp = td->td_proc->p_pgrp; PROC_UNLOCK(p2); #endif exit_signal = 0; } if (args->flags & LINUX_CLONE_CHILD_SETTID) em->child_set_tid = args->child_tidptr; else em->child_set_tid = NULL; if (args->flags & LINUX_CLONE_CHILD_CLEARTID) em->child_clear_tid = args->child_tidptr; else em->child_clear_tid = NULL; EMUL_UNLOCK(&emul_lock); if (args->flags & LINUX_CLONE_PARENT_SETTID) { error = copyout(&p2->p_pid, args->parent_tidptr, sizeof(p2->p_pid)); if (error) printf(LMSG("copyout failed!")); } PROC_LOCK(p2); p2->p_sigparent = exit_signal; PROC_UNLOCK(p2); td2 = FIRST_THREAD_IN_PROC(p2); /* * In a case of stack = NULL, we are supposed to COW calling process * stack. This is what normal fork() does, so we just keep tf_rsp arg * intact. */ if (args->stack) linux_set_upcall_kse(td2, PTROUT(args->stack)); if (args->flags & LINUX_CLONE_SETTLS) linux_set_cloned_tls(td2, args->tls); #ifdef DEBUG if (ldebug(clone)) printf(LMSG("clone: successful rfork to %d, " "stack %p sig = %d"), (int)p2->p_pid, args->stack, exit_signal); #endif if (args->flags & LINUX_CLONE_VFORK) { PROC_LOCK(p2); p2->p_flag |= P_PPWAIT; PROC_UNLOCK(p2); } /* * Make this runnable after we are finished with it. */ thread_lock(td2); TD_SET_CAN_RUN(td2); sched_add(td2, SRQ_BORING); thread_unlock(td2); td->td_retval[0] = p2->p_pid; td->td_retval[1] = 0; if (args->flags & LINUX_CLONE_VFORK) { /* wait for the children to exit, ie. emulate vfork */ PROC_LOCK(p2); while (p2->p_flag & P_PPWAIT) cv_wait(&p2->p_pwait, &p2->p_mtx); PROC_UNLOCK(p2); } return (0); } Index: stable/9/sys/compat/linux/linux_futex.c =================================================================== --- stable/9/sys/compat/linux/linux_futex.c (revision 246289) +++ stable/9/sys/compat/linux/linux_futex.c (revision 246290) @@ -1,887 +1,1228 @@ /* $NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $ */ /*- * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Emmanuel Dreyfus * 4. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #if 0 __KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $"); #endif #include "opt_compat.h" +#include "opt_kdtrace.h" #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #ifdef COMPAT_LINUX32 #include #include #else #include #include #endif +#include #include #include #include -MALLOC_DEFINE(M_FUTEX, "futex", "Linux futexes"); -MALLOC_DEFINE(M_FUTEX_WP, "futex wp", "Linux futexes wp"); +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); +/* Linuxulator-global DTrace probes */ +LIN_SDT_PROBE_DECLARE(locks, emul_lock, locked); +LIN_SDT_PROBE_DECLARE(locks, emul_lock, unlock); + +/** + * Futex part for the special DTrace module "locks". + */ +LIN_SDT_PROBE_DEFINE1(locks, futex_mtx, locked, "struct mtx *"); +LIN_SDT_PROBE_DEFINE1(locks, futex_mtx, unlock, "struct mtx *"); + +/** + * Per futex probes. + */ +LIN_SDT_PROBE_DEFINE1(futex, futex, create, "struct sx *"); +LIN_SDT_PROBE_DEFINE1(futex, futex, destroy, "struct sx *"); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE2(futex, futex_put, entry, "struct futex *", + "struct waiting_proc *"); +LIN_SDT_PROBE_DEFINE3(futex, futex_put, destroy, "uint32_t *", "uint32_t", + "int"); +LIN_SDT_PROBE_DEFINE3(futex, futex_put, unlock, "uint32_t *", "uint32_t", + "int"); +LIN_SDT_PROBE_DEFINE0(futex, futex_put, return); +LIN_SDT_PROBE_DEFINE3(futex, futex_get0, entry, "uint32_t *", "struct futex **", + "uint32_t"); +LIN_SDT_PROBE_DEFINE1(futex, futex_get0, umtx_key_get_error, "int"); +LIN_SDT_PROBE_DEFINE3(futex, futex_get0, shared, "uint32_t *", "uint32_t", + "int"); +LIN_SDT_PROBE_DEFINE1(futex, futex_get0, null, "uint32_t *"); +LIN_SDT_PROBE_DEFINE3(futex, futex_get0, new, "uint32_t *", "uint32_t", "int"); +LIN_SDT_PROBE_DEFINE1(futex, futex_get0, return, "int"); +LIN_SDT_PROBE_DEFINE3(futex, futex_get, entry, "uint32_t *", + "struct waiting_proc **", "struct futex **"); +LIN_SDT_PROBE_DEFINE0(futex, futex_get, error); +LIN_SDT_PROBE_DEFINE1(futex, futex_get, return, "int"); +LIN_SDT_PROBE_DEFINE3(futex, futex_sleep, entry, "struct futex *", + "struct waiting_proc **", "int"); +LIN_SDT_PROBE_DEFINE5(futex, futex_sleep, requeue_error, "int", "uint32_t *", + "struct waiting_proc *", "uint32_t *", "uint32_t"); +LIN_SDT_PROBE_DEFINE3(futex, futex_sleep, sleep_error, "int", "uint32_t *", + "struct waiting_proc *"); +LIN_SDT_PROBE_DEFINE1(futex, futex_sleep, return, "int"); +LIN_SDT_PROBE_DEFINE3(futex, futex_wake, entry, "struct futex *", "int", + "uint32_t"); +LIN_SDT_PROBE_DEFINE3(futex, futex_wake, iterate, "uint32_t", + "struct waiting_proc *", "uin32_t"); +LIN_SDT_PROBE_DEFINE1(futex, futex_wake, wakeup, "struct waiting_proc *"); +LIN_SDT_PROBE_DEFINE1(futex, futex_wake, return, "int"); +LIN_SDT_PROBE_DEFINE4(futex, futex_requeue, entry, "struct futex *", "int", + "struct futex *", "int"); +LIN_SDT_PROBE_DEFINE1(futex, futex_requeue, wakeup, "struct waiting_proc *"); +LIN_SDT_PROBE_DEFINE3(futex, futex_requeue, requeue, "uint32_t *", + "struct waiting_proc *", "uint32_t"); +LIN_SDT_PROBE_DEFINE1(futex, futex_requeue, return, "int"); +LIN_SDT_PROBE_DEFINE4(futex, futex_wait, entry, "struct futex *", + "struct waiting_proc **", "struct l_timespec *", "uint32_t"); +LIN_SDT_PROBE_DEFINE1(futex, futex_wait, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE1(futex, futex_wait, itimerfix_error, "int"); +LIN_SDT_PROBE_DEFINE1(futex, futex_wait, sleep_error, "int"); +LIN_SDT_PROBE_DEFINE1(futex, futex_wait, return, "int"); +LIN_SDT_PROBE_DEFINE3(futex, futex_atomic_op, entry, "struct thread *", + "int", "uint32_t"); +LIN_SDT_PROBE_DEFINE4(futex, futex_atomic_op, decoded_op, "int", "int", "int", + "int"); +LIN_SDT_PROBE_DEFINE0(futex, futex_atomic_op, missing_access_check); +LIN_SDT_PROBE_DEFINE1(futex, futex_atomic_op, unimplemented_op, "int"); +LIN_SDT_PROBE_DEFINE1(futex, futex_atomic_op, unimplemented_cmp, "int"); +LIN_SDT_PROBE_DEFINE1(futex, futex_atomic_op, return, "int"); +LIN_SDT_PROBE_DEFINE2(futex, linux_sys_futex, entry, "struct thread *", + "struct linux_sys_futex_args *"); +LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_clockswitch); +LIN_SDT_PROBE_DEFINE1(futex, linux_sys_futex, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, invalid_cmp_requeue_use); +LIN_SDT_PROBE_DEFINE3(futex, linux_sys_futex, debug_wait, "uint32_t *", + "uint32_t", "uint32_t"); +LIN_SDT_PROBE_DEFINE4(futex, linux_sys_futex, debug_wait_value_neq, + "uint32_t *", "uint32_t", "int", "uint32_t"); +LIN_SDT_PROBE_DEFINE3(futex, linux_sys_futex, debug_wake, "uint32_t *", + "uint32_t", "uint32_t"); +LIN_SDT_PROBE_DEFINE5(futex, linux_sys_futex, debug_cmp_requeue, "uint32_t *", + "uint32_t", "uint32_t", "uint32_t *", "struct l_timespec *"); +LIN_SDT_PROBE_DEFINE2(futex, linux_sys_futex, debug_cmp_requeue_value_neq, + "uint32_t", "int"); +LIN_SDT_PROBE_DEFINE5(futex, linux_sys_futex, debug_wake_op, "uint32_t *", + "int", "uint32_t", "uint32_t *", "uint32_t"); +LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unhandled_efault); +LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_lock_pi); +LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_unlock_pi); +LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_trylock_pi); +LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, deprecated_requeue); +LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_wait_requeue_pi); +LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_cmp_requeue_pi); +LIN_SDT_PROBE_DEFINE1(futex, linux_sys_futex, unknown_operation, "int"); +LIN_SDT_PROBE_DEFINE1(futex, linux_sys_futex, return, "int"); +LIN_SDT_PROBE_DEFINE2(futex, linux_set_robust_list, entry, "struct thread *", + "struct linux_set_robust_list_args *"); +LIN_SDT_PROBE_DEFINE0(futex, linux_set_robust_list, size_error); +LIN_SDT_PROBE_DEFINE1(futex, linux_set_robust_list, return, "int"); +LIN_SDT_PROBE_DEFINE2(futex, linux_get_robust_list, entry, "struct thread *", + "struct linux_get_robust_list_args *"); +LIN_SDT_PROBE_DEFINE1(futex, linux_get_robust_list, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE1(futex, linux_get_robust_list, return, "int"); +LIN_SDT_PROBE_DEFINE3(futex, handle_futex_death, entry, "struct proc *", + "uint32_t *", "int"); +LIN_SDT_PROBE_DEFINE1(futex, handle_futex_death, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE1(futex, handle_futex_death, return, "int"); +LIN_SDT_PROBE_DEFINE3(futex, fetch_robust_entry, entry, + "struct linux_robust_list **", "struct linux_robust_list **", "int *"); +LIN_SDT_PROBE_DEFINE1(futex, fetch_robust_entry, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE1(futex, fetch_robust_entry, return, "int"); +LIN_SDT_PROBE_DEFINE1(futex, release_futexes, entry, "struct proc *"); +LIN_SDT_PROBE_DEFINE1(futex, release_futexes, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE0(futex, release_futexes, return); + +static MALLOC_DEFINE(M_FUTEX, "futex", "Linux futexes"); +static MALLOC_DEFINE(M_FUTEX_WP, "futex wp", "Linux futexes wp"); + struct futex; struct waiting_proc { uint32_t wp_flags; struct futex *wp_futex; TAILQ_ENTRY(waiting_proc) wp_list; }; struct futex { struct sx f_lck; uint32_t *f_uaddr; /* user-supplied value, for debug */ struct umtx_key f_key; uint32_t f_refcount; uint32_t f_bitset; LIST_ENTRY(futex) f_list; TAILQ_HEAD(lf_waiting_proc, waiting_proc) f_waiting_proc; }; struct futex_list futex_list; #define FUTEX_LOCK(f) sx_xlock(&(f)->f_lck) #define FUTEX_UNLOCK(f) sx_xunlock(&(f)->f_lck) -#define FUTEX_INIT(f) sx_init_flags(&(f)->f_lck, "ftlk", SX_DUPOK) -#define FUTEX_DESTROY(f) sx_destroy(&(f)->f_lck) +#define FUTEX_INIT(f) do { \ + sx_init_flags(&(f)->f_lck, "ftlk", \ + SX_DUPOK); \ + LIN_SDT_PROBE1(futex, futex, create, \ + &(f)->f_lck); \ + } while (0) +#define FUTEX_DESTROY(f) do { \ + LIN_SDT_PROBE1(futex, futex, destroy, \ + &(f)->f_lck); \ + sx_destroy(&(f)->f_lck); \ + } while (0) #define FUTEX_ASSERT_LOCKED(f) sx_assert(&(f)->f_lck, SA_XLOCKED) struct mtx futex_mtx; /* protects the futex list */ -#define FUTEXES_LOCK mtx_lock(&futex_mtx) -#define FUTEXES_UNLOCK mtx_unlock(&futex_mtx) +#define FUTEXES_LOCK do { \ + mtx_lock(&futex_mtx); \ + LIN_SDT_PROBE1(locks, futex_mtx, \ + locked, &futex_mtx); \ + } while (0) +#define FUTEXES_UNLOCK do { \ + LIN_SDT_PROBE1(locks, futex_mtx, \ + unlock, &futex_mtx); \ + mtx_unlock(&futex_mtx); \ + } while (0) /* flags for futex_get() */ #define FUTEX_CREATE_WP 0x1 /* create waiting_proc */ #define FUTEX_DONTCREATE 0x2 /* don't create futex if not exists */ #define FUTEX_DONTEXISTS 0x4 /* return EINVAL if futex exists */ #define FUTEX_SHARED 0x8 /* shared futex */ /* wp_flags */ #define FUTEX_WP_REQUEUED 0x1 /* wp requeued - wp moved from wp_list * of futex where thread sleep to wp_list * of another futex. */ #define FUTEX_WP_REMOVED 0x2 /* wp is woken up and removed from futex * wp_list to prevent double wakeup. */ /* support.s */ int futex_xchgl(int oparg, uint32_t *uaddr, int *oldval); int futex_addl(int oparg, uint32_t *uaddr, int *oldval); int futex_orl(int oparg, uint32_t *uaddr, int *oldval); int futex_andl(int oparg, uint32_t *uaddr, int *oldval); int futex_xorl(int oparg, uint32_t *uaddr, int *oldval); static void futex_put(struct futex *f, struct waiting_proc *wp) { + LIN_SDT_PROBE2(futex, futex_put, entry, f, wp); FUTEX_ASSERT_LOCKED(f); if (wp != NULL) { if ((wp->wp_flags & FUTEX_WP_REMOVED) == 0) TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list); free(wp, M_FUTEX_WP); } FUTEXES_LOCK; if (--f->f_refcount == 0) { LIST_REMOVE(f, f_list); FUTEXES_UNLOCK; FUTEX_UNLOCK(f); + LIN_SDT_PROBE3(futex, futex_put, destroy, f->f_uaddr, + f->f_refcount, f->f_key.shared); LINUX_CTR3(sys_futex, "futex_put destroy uaddr %p ref %d " "shared %d", f->f_uaddr, f->f_refcount, f->f_key.shared); umtx_key_release(&f->f_key); FUTEX_DESTROY(f); free(f, M_FUTEX); + + LIN_SDT_PROBE0(futex, futex_put, return); return; } + LIN_SDT_PROBE3(futex, futex_put, unlock, f->f_uaddr, f->f_refcount, + f->f_key.shared); LINUX_CTR3(sys_futex, "futex_put uaddr %p ref %d shared %d", f->f_uaddr, f->f_refcount, f->f_key.shared); FUTEXES_UNLOCK; FUTEX_UNLOCK(f); + + LIN_SDT_PROBE0(futex, futex_put, return); } static int futex_get0(uint32_t *uaddr, struct futex **newf, uint32_t flags) { struct futex *f, *tmpf; struct umtx_key key; int error; + LIN_SDT_PROBE3(futex, futex_get0, entry, uaddr, newf, flags); + *newf = tmpf = NULL; error = umtx_key_get(uaddr, TYPE_FUTEX, (flags & FUTEX_SHARED) ? AUTO_SHARE : THREAD_SHARE, &key); - if (error) + if (error) { + LIN_SDT_PROBE1(futex, futex_get0, umtx_key_get_error, error); + LIN_SDT_PROBE1(futex, futex_get0, return, error); return (error); + } retry: FUTEXES_LOCK; LIST_FOREACH(f, &futex_list, f_list) { if (umtx_key_match(&f->f_key, &key)) { if (tmpf != NULL) { FUTEX_UNLOCK(tmpf); FUTEX_DESTROY(tmpf); free(tmpf, M_FUTEX); } if (flags & FUTEX_DONTEXISTS) { FUTEXES_UNLOCK; umtx_key_release(&key); + + LIN_SDT_PROBE1(futex, futex_get0, return, + EINVAL); return (EINVAL); } /* * Increment refcount of the found futex to * prevent it from deallocation before FUTEX_LOCK() */ ++f->f_refcount; FUTEXES_UNLOCK; umtx_key_release(&key); FUTEX_LOCK(f); *newf = f; + LIN_SDT_PROBE3(futex, futex_get0, shared, uaddr, + f->f_refcount, f->f_key.shared); LINUX_CTR3(sys_futex, "futex_get uaddr %p ref %d shared %d", uaddr, f->f_refcount, f->f_key.shared); + + LIN_SDT_PROBE1(futex, futex_get0, return, 0); return (0); } } if (flags & FUTEX_DONTCREATE) { FUTEXES_UNLOCK; umtx_key_release(&key); + LIN_SDT_PROBE1(futex, futex_get0, null, uaddr); LINUX_CTR1(sys_futex, "futex_get uaddr %p null", uaddr); + + LIN_SDT_PROBE1(futex, futex_get0, return, 0); return (0); } if (tmpf == NULL) { FUTEXES_UNLOCK; tmpf = malloc(sizeof(*tmpf), M_FUTEX, M_WAITOK | M_ZERO); tmpf->f_uaddr = uaddr; tmpf->f_key = key; tmpf->f_refcount = 1; tmpf->f_bitset = FUTEX_BITSET_MATCH_ANY; FUTEX_INIT(tmpf); TAILQ_INIT(&tmpf->f_waiting_proc); /* * Lock the new futex before an insert into the futex_list * to prevent futex usage by other. */ FUTEX_LOCK(tmpf); goto retry; } LIST_INSERT_HEAD(&futex_list, tmpf, f_list); FUTEXES_UNLOCK; + LIN_SDT_PROBE3(futex, futex_get0, new, uaddr, tmpf->f_refcount, + tmpf->f_key.shared); LINUX_CTR3(sys_futex, "futex_get uaddr %p ref %d shared %d new", uaddr, tmpf->f_refcount, tmpf->f_key.shared); *newf = tmpf; + + LIN_SDT_PROBE1(futex, futex_get0, return, 0); return (0); } static int futex_get(uint32_t *uaddr, struct waiting_proc **wp, struct futex **f, uint32_t flags) { int error; + LIN_SDT_PROBE3(futex, futex_get, entry, uaddr, wp, f); + if (flags & FUTEX_CREATE_WP) { *wp = malloc(sizeof(struct waiting_proc), M_FUTEX_WP, M_WAITOK); (*wp)->wp_flags = 0; } error = futex_get0(uaddr, f, flags); if (error) { + LIN_SDT_PROBE0(futex, futex_get, error); + if (flags & FUTEX_CREATE_WP) free(*wp, M_FUTEX_WP); + + LIN_SDT_PROBE1(futex, futex_get, return, error); return (error); } if (flags & FUTEX_CREATE_WP) { TAILQ_INSERT_HEAD(&(*f)->f_waiting_proc, *wp, wp_list); (*wp)->wp_futex = *f; } + LIN_SDT_PROBE1(futex, futex_get, return, error); return (error); } static int futex_sleep(struct futex *f, struct waiting_proc *wp, int timeout) { int error; FUTEX_ASSERT_LOCKED(f); + LIN_SDT_PROBE3(futex, futex_sleep, entry, f, wp, timeout); LINUX_CTR4(sys_futex, "futex_sleep enter uaddr %p wp %p timo %d ref %d", f->f_uaddr, wp, timeout, f->f_refcount); error = sx_sleep(wp, &f->f_lck, PCATCH, "futex", timeout); if (wp->wp_flags & FUTEX_WP_REQUEUED) { KASSERT(f != wp->wp_futex, ("futex != wp_futex")); - LINUX_CTR5(sys_futex, "futex_sleep out error %d uaddr %p w" + + if (error) { + LIN_SDT_PROBE5(futex, futex_sleep, requeue_error, error, + f->f_uaddr, wp, wp->wp_futex->f_uaddr, + wp->wp_futex->f_refcount); + } + + LINUX_CTR5(sys_futex, "futex_sleep out error %d uaddr %p wp" " %p requeued uaddr %p ref %d", error, f->f_uaddr, wp, wp->wp_futex->f_uaddr, wp->wp_futex->f_refcount); futex_put(f, NULL); f = wp->wp_futex; FUTEX_LOCK(f); - } else + } else { + if (error) { + LIN_SDT_PROBE3(futex, futex_sleep, sleep_error, error, + f->f_uaddr, wp); + } LINUX_CTR3(sys_futex, "futex_sleep out error %d uaddr %p wp %p", error, f->f_uaddr, wp); + } futex_put(f, wp); + + LIN_SDT_PROBE1(futex, futex_sleep, return, error); return (error); } static int futex_wake(struct futex *f, int n, uint32_t bitset) { struct waiting_proc *wp, *wpt; int count = 0; - if (bitset == 0) + LIN_SDT_PROBE3(futex, futex_wake, entry, f, n, bitset); + + if (bitset == 0) { + LIN_SDT_PROBE1(futex, futex_wake, return, EINVAL); return (EINVAL); + } FUTEX_ASSERT_LOCKED(f); TAILQ_FOREACH_SAFE(wp, &f->f_waiting_proc, wp_list, wpt) { + LIN_SDT_PROBE3(futex, futex_wake, iterate, f->f_uaddr, wp, + f->f_refcount); LINUX_CTR3(sys_futex, "futex_wake uaddr %p wp %p ref %d", f->f_uaddr, wp, f->f_refcount); /* * Unless we find a matching bit in * the bitset, continue searching. */ if (!(wp->wp_futex->f_bitset & bitset)) continue; wp->wp_flags |= FUTEX_WP_REMOVED; TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list); + LIN_SDT_PROBE1(futex, futex_wake, wakeup, wp); wakeup_one(wp); if (++count == n) break; } + LIN_SDT_PROBE1(futex, futex_wake, return, count); return (count); } static int futex_requeue(struct futex *f, int n, struct futex *f2, int n2) { struct waiting_proc *wp, *wpt; int count = 0; + LIN_SDT_PROBE4(futex, futex_requeue, entry, f, n, f2, n2); + FUTEX_ASSERT_LOCKED(f); FUTEX_ASSERT_LOCKED(f2); TAILQ_FOREACH_SAFE(wp, &f->f_waiting_proc, wp_list, wpt) { if (++count <= n) { LINUX_CTR2(sys_futex, "futex_req_wake uaddr %p wp %p", f->f_uaddr, wp); wp->wp_flags |= FUTEX_WP_REMOVED; TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list); + LIN_SDT_PROBE1(futex, futex_requeue, wakeup, wp); wakeup_one(wp); } else { + LIN_SDT_PROBE3(futex, futex_requeue, requeue, + f->f_uaddr, wp, f2->f_uaddr); LINUX_CTR3(sys_futex, "futex_requeue uaddr %p wp %p to %p", f->f_uaddr, wp, f2->f_uaddr); wp->wp_flags |= FUTEX_WP_REQUEUED; /* Move wp to wp_list of f2 futex */ TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list); TAILQ_INSERT_HEAD(&f2->f_waiting_proc, wp, wp_list); /* * Thread which sleeps on wp after waking should * acquire f2 lock, so increment refcount of f2 to * prevent it from premature deallocation. */ wp->wp_futex = f2; FUTEXES_LOCK; ++f2->f_refcount; FUTEXES_UNLOCK; if (count - n >= n2) break; } } + LIN_SDT_PROBE1(futex, futex_requeue, return, count); return (count); } static int futex_wait(struct futex *f, struct waiting_proc *wp, struct l_timespec *ts, uint32_t bitset) { struct l_timespec timeout; struct timeval tv; int timeout_hz; int error; - if (bitset == 0) + LIN_SDT_PROBE4(futex, futex_wait, entry, f, wp, ts, bitset); + + if (bitset == 0) { + LIN_SDT_PROBE1(futex, futex_wait, return, EINVAL); return (EINVAL); + } + f->f_bitset = bitset; if (ts != NULL) { error = copyin(ts, &timeout, sizeof(timeout)); - if (error) + if (error) { + LIN_SDT_PROBE1(futex, futex_wait, copyin_error, error); + LIN_SDT_PROBE1(futex, futex_wait, return, error); return (error); + } TIMESPEC_TO_TIMEVAL(&tv, &timeout); error = itimerfix(&tv); - if (error) + if (error) { + LIN_SDT_PROBE1(futex, futex_wait, itimerfix_error, + error); + LIN_SDT_PROBE1(futex, futex_wait, return, error); return (error); + } timeout_hz = tvtohz(&tv); } else timeout_hz = 0; error = futex_sleep(f, wp, timeout_hz); + if (error) { + LIN_SDT_PROBE1(futex, futex_wait, sleep_error, error); + } if (error == EWOULDBLOCK) error = ETIMEDOUT; + LIN_SDT_PROBE1(futex, futex_wait, return, error); return (error); } static int futex_atomic_op(struct thread *td, int encoded_op, uint32_t *uaddr) { int op = (encoded_op >> 28) & 7; int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; int oldval = 0, ret; + LIN_SDT_PROBE3(futex, futex_atomic_op, entry, td, encoded_op, uaddr); + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; -#ifdef DEBUG - if (ldebug(sys_futex)) - printf("futex_atomic_op: op = %d, cmp = %d, oparg = %x, " - "cmparg = %x, uaddr = %p\n", - op, cmp, oparg, cmparg, uaddr); -#endif + LIN_SDT_PROBE4(futex, futex_atomic_op, decoded_op, op, cmp, oparg, + cmparg); + /* XXX: Linux verifies access here and returns EFAULT */ + LIN_SDT_PROBE0(futex, futex_atomic_op, missing_access_check); switch (op) { case FUTEX_OP_SET: ret = futex_xchgl(oparg, uaddr, &oldval); break; case FUTEX_OP_ADD: ret = futex_addl(oparg, uaddr, &oldval); break; case FUTEX_OP_OR: ret = futex_orl(oparg, uaddr, &oldval); break; case FUTEX_OP_ANDN: ret = futex_andl(~oparg, uaddr, &oldval); break; case FUTEX_OP_XOR: ret = futex_xorl(oparg, uaddr, &oldval); break; default: + LIN_SDT_PROBE1(futex, futex_atomic_op, unimplemented_op, op); ret = -ENOSYS; break; } - if (ret) + if (ret) { + LIN_SDT_PROBE1(futex, futex_atomic_op, return, ret); return (ret); + } switch (cmp) { case FUTEX_OP_CMP_EQ: - return (oldval == cmparg); + ret = (oldval == cmparg); + break; case FUTEX_OP_CMP_NE: - return (oldval != cmparg); + ret = (oldval != cmparg); + break; case FUTEX_OP_CMP_LT: - return (oldval < cmparg); + ret = (oldval < cmparg); + break; case FUTEX_OP_CMP_GE: - return (oldval >= cmparg); + ret = (oldval >= cmparg); + break; case FUTEX_OP_CMP_LE: - return (oldval <= cmparg); + ret = (oldval <= cmparg); + break; case FUTEX_OP_CMP_GT: - return (oldval > cmparg); + ret = (oldval > cmparg); + break; default: - return (-ENOSYS); + LIN_SDT_PROBE1(futex, futex_atomic_op, unimplemented_cmp, cmp); + ret = -ENOSYS; } + + LIN_SDT_PROBE1(futex, futex_atomic_op, return, ret); + return (ret); } int linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) { int clockrt, nrwake, op_ret, ret, val; struct linux_emuldata *em; struct waiting_proc *wp; struct futex *f, *f2; int error; uint32_t flags; + LIN_SDT_PROBE2(futex, linux_sys_futex, entry, td, args); + if (args->op & LINUX_FUTEX_PRIVATE_FLAG) { flags = 0; args->op &= ~LINUX_FUTEX_PRIVATE_FLAG; } else flags = FUTEX_SHARED; /* * Currently support for switching between CLOCK_MONOTONIC and * CLOCK_REALTIME is not present. However Linux forbids the use of * FUTEX_CLOCK_REALTIME with any op except FUTEX_WAIT_BITSET and * FUTEX_WAIT_REQUEUE_PI. */ clockrt = args->op & LINUX_FUTEX_CLOCK_REALTIME; args->op = args->op & ~LINUX_FUTEX_CLOCK_REALTIME; if (clockrt && args->op != LINUX_FUTEX_WAIT_BITSET && - args->op != LINUX_FUTEX_WAIT_REQUEUE_PI) + args->op != LINUX_FUTEX_WAIT_REQUEUE_PI) { + LIN_SDT_PROBE0(futex, linux_sys_futex, + unimplemented_clockswitch); + LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS); return (ENOSYS); + } error = 0; f = f2 = NULL; switch (args->op) { case LINUX_FUTEX_WAIT: args->val3 = FUTEX_BITSET_MATCH_ANY; /* FALLTHROUGH */ case LINUX_FUTEX_WAIT_BITSET: - + LIN_SDT_PROBE3(futex, linux_sys_futex, debug_wait, args->uaddr, + args->val, args->val3); LINUX_CTR3(sys_futex, "WAIT uaddr %p val %d val3 %d", args->uaddr, args->val, args->val3); -#ifdef DEBUG - if (ldebug(sys_futex)) - printf(ARGS(sys_futex, - "futex_wait uaddr %p val %d val3 %d"), - args->uaddr, args->val, args->val3); -#endif + error = futex_get(args->uaddr, &wp, &f, flags | FUTEX_CREATE_WP); - if (error) + if (error) { + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); return (error); + } + error = copyin(args->uaddr, &val, sizeof(val)); if (error) { + LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error, + error); LINUX_CTR1(sys_futex, "WAIT copyin failed %d", error); futex_put(f, wp); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); return (error); } if (val != args->val) { + LIN_SDT_PROBE4(futex, linux_sys_futex, + debug_wait_value_neq, args->uaddr, args->val, val, + args->val3); LINUX_CTR4(sys_futex, "WAIT uaddr %p val %d != uval %d val3 %d", args->uaddr, args->val, val, args->val3); futex_put(f, wp); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, + EWOULDBLOCK); return (EWOULDBLOCK); } error = futex_wait(f, wp, args->timeout, args->val3); break; case LINUX_FUTEX_WAKE: args->val3 = FUTEX_BITSET_MATCH_ANY; /* FALLTHROUGH */ case LINUX_FUTEX_WAKE_BITSET: - + LIN_SDT_PROBE3(futex, linux_sys_futex, debug_wake, args->uaddr, + args->val, args->val3); LINUX_CTR3(sys_futex, "WAKE uaddr %p val % d val3 %d", args->uaddr, args->val, args->val3); -#ifdef DEBUG - if (ldebug(sys_futex)) - printf(ARGS(sys_futex, "futex_wake uaddr %p val %d val3 %d"), - args->uaddr, args->val, args->val3); -#endif error = futex_get(args->uaddr, NULL, &f, flags | FUTEX_DONTCREATE); - if (error) + if (error) { + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); return (error); + } + if (f == NULL) { td->td_retval[0] = 0; + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); return (error); } td->td_retval[0] = futex_wake(f, args->val, args->val3); futex_put(f, NULL); break; case LINUX_FUTEX_CMP_REQUEUE: - + LIN_SDT_PROBE5(futex, linux_sys_futex, debug_cmp_requeue, + args->uaddr, args->val, args->val3, args->uaddr2, + args->timeout); LINUX_CTR5(sys_futex, "CMP_REQUEUE uaddr %p " "val %d val3 %d uaddr2 %p val2 %d", args->uaddr, args->val, args->val3, args->uaddr2, (int)(unsigned long)args->timeout); -#ifdef DEBUG - if (ldebug(sys_futex)) - printf(ARGS(sys_futex, "futex_cmp_requeue uaddr %p " - "val %d val3 %d uaddr2 %p val2 %d"), - args->uaddr, args->val, args->val3, args->uaddr2, - (int)(unsigned long)args->timeout); -#endif - /* * Linux allows this, we would not, it is an incorrect * usage of declared ABI, so return EINVAL. */ - if (args->uaddr == args->uaddr2) + if (args->uaddr == args->uaddr2) { + LIN_SDT_PROBE0(futex, linux_sys_futex, + invalid_cmp_requeue_use); + LIN_SDT_PROBE1(futex, linux_sys_futex, return, EINVAL); return (EINVAL); + } + error = futex_get(args->uaddr, NULL, &f, flags); - if (error) + if (error) { + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); return (error); + } /* * To avoid deadlocks return EINVAL if second futex * exists at this time. * * Glibc fall back to FUTEX_WAKE in case of any error * returned by FUTEX_CMP_REQUEUE. */ error = futex_get(args->uaddr2, NULL, &f2, flags | FUTEX_DONTEXISTS); if (error) { futex_put(f, NULL); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); return (error); } error = copyin(args->uaddr, &val, sizeof(val)); if (error) { + LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error, + error); LINUX_CTR1(sys_futex, "CMP_REQUEUE copyin failed %d", error); futex_put(f2, NULL); futex_put(f, NULL); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); return (error); } if (val != args->val3) { + LIN_SDT_PROBE2(futex, linux_sys_futex, + debug_cmp_requeue_value_neq, args->val, val); LINUX_CTR2(sys_futex, "CMP_REQUEUE val %d != uval %d", args->val, val); futex_put(f2, NULL); futex_put(f, NULL); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, EAGAIN); return (EAGAIN); } nrwake = (int)(unsigned long)args->timeout; td->td_retval[0] = futex_requeue(f, args->val, f2, nrwake); futex_put(f2, NULL); futex_put(f, NULL); break; case LINUX_FUTEX_WAKE_OP: - + LIN_SDT_PROBE5(futex, linux_sys_futex, debug_wake_op, + args->uaddr, args->op, args->val, args->uaddr2, args->val3); LINUX_CTR5(sys_futex, "WAKE_OP " "uaddr %p op %d val %x uaddr2 %p val3 %x", args->uaddr, args->op, args->val, args->uaddr2, args->val3); -#ifdef DEBUG - if (ldebug(sys_futex)) - printf(ARGS(sys_futex, "futex_wake_op " - "uaddr %p op %d val %x uaddr2 %p val3 %x"), - args->uaddr, args->op, args->val, - args->uaddr2, args->val3); -#endif error = futex_get(args->uaddr, NULL, &f, flags); - if (error) + if (error) { + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); return (error); + } + if (args->uaddr != args->uaddr2) error = futex_get(args->uaddr2, NULL, &f2, flags); if (error) { futex_put(f, NULL); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); return (error); } /* * This function returns positive number as results and * negative as errors */ op_ret = futex_atomic_op(td, args->val3, args->uaddr2); if (op_ret < 0) { /* XXX: We don't handle the EFAULT yet. */ if (op_ret != -EFAULT) { if (f2 != NULL) futex_put(f2, NULL); futex_put(f, NULL); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, + -op_ret); return (-op_ret); + } else { + LIN_SDT_PROBE0(futex, linux_sys_futex, + unhandled_efault); } if (f2 != NULL) futex_put(f2, NULL); futex_put(f, NULL); + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, EFAULT); return (EFAULT); } ret = futex_wake(f, args->val, args->val3); if (op_ret > 0) { op_ret = 0; nrwake = (int)(unsigned long)args->timeout; if (f2 != NULL) op_ret += futex_wake(f2, nrwake, args->val3); else op_ret += futex_wake(f, nrwake, args->val3); ret += op_ret; } if (f2 != NULL) futex_put(f2, NULL); futex_put(f, NULL); td->td_retval[0] = ret; break; case LINUX_FUTEX_LOCK_PI: /* not yet implemented */ linux_msg(td, "linux_sys_futex: " "op LINUX_FUTEX_LOCK_PI not implemented\n"); + LIN_SDT_PROBE0(futex, linux_sys_futex, unimplemented_lock_pi); + LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS); return (ENOSYS); case LINUX_FUTEX_UNLOCK_PI: /* not yet implemented */ linux_msg(td, "linux_sys_futex: " "op LINUX_FUTEX_UNLOCK_PI not implemented\n"); + LIN_SDT_PROBE0(futex, linux_sys_futex, unimplemented_unlock_pi); + LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS); return (ENOSYS); case LINUX_FUTEX_TRYLOCK_PI: /* not yet implemented */ linux_msg(td, "linux_sys_futex: " "op LINUX_FUTEX_TRYLOCK_PI not implemented\n"); + LIN_SDT_PROBE0(futex, linux_sys_futex, + unimplemented_trylock_pi); + LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS); return (ENOSYS); case LINUX_FUTEX_REQUEUE: /* * Glibc does not use this operation since version 2.3.3, * as it is racy and replaced by FUTEX_CMP_REQUEUE operation. * Glibc versions prior to 2.3.3 fall back to FUTEX_WAKE when * FUTEX_REQUEUE returned EINVAL. */ em = em_find(td->td_proc, EMUL_DONTLOCK); if ((em->flags & LINUX_XDEPR_REQUEUEOP) == 0) { linux_msg(td, "linux_sys_futex: " "unsupported futex_requeue op\n"); em->flags |= LINUX_XDEPR_REQUEUEOP; + LIN_SDT_PROBE0(futex, linux_sys_futex, + deprecated_requeue); } + + LIN_SDT_PROBE1(futex, linux_sys_futex, return, EINVAL); return (EINVAL); case LINUX_FUTEX_WAIT_REQUEUE_PI: /* not yet implemented */ linux_msg(td, "linux_sys_futex: " "op FUTEX_WAIT_REQUEUE_PI not implemented\n"); + LIN_SDT_PROBE0(futex, linux_sys_futex, + unimplemented_wait_requeue_pi); + LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS); return (ENOSYS); case LINUX_FUTEX_CMP_REQUEUE_PI: /* not yet implemented */ linux_msg(td, "linux_sys_futex: " "op LINUX_FUTEX_CMP_REQUEUE_PI not implemented\n"); + LIN_SDT_PROBE0(futex, linux_sys_futex, + unimplemented_cmp_requeue_pi); + LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS); return (ENOSYS); default: linux_msg(td, "linux_sys_futex: unknown op %d\n", args->op); + LIN_SDT_PROBE1(futex, linux_sys_futex, unknown_operation, + args->op); + LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS); return (ENOSYS); } + LIN_SDT_PROBE1(futex, linux_sys_futex, return, error); return (error); } int linux_set_robust_list(struct thread *td, struct linux_set_robust_list_args *args) { struct linux_emuldata *em; -#ifdef DEBUG - if (ldebug(set_robust_list)) - printf(ARGS(set_robust_list, "head %p len %d"), - args->head, args->len); -#endif + LIN_SDT_PROBE2(futex, linux_set_robust_list, entry, td, args); - if (args->len != sizeof(struct linux_robust_list_head)) + if (args->len != sizeof(struct linux_robust_list_head)) { + LIN_SDT_PROBE0(futex, linux_set_robust_list, size_error); + LIN_SDT_PROBE1(futex, linux_set_robust_list, return, EINVAL); return (EINVAL); + } em = em_find(td->td_proc, EMUL_DOLOCK); em->robust_futexes = args->head; EMUL_UNLOCK(&emul_lock); + LIN_SDT_PROBE1(futex, linux_set_robust_list, return, 0); return (0); } int linux_get_robust_list(struct thread *td, struct linux_get_robust_list_args *args) { struct linux_emuldata *em; struct linux_robust_list_head *head; l_size_t len = sizeof(struct linux_robust_list_head); int error = 0; -#ifdef DEBUG - if (ldebug(get_robust_list)) - printf(ARGS(get_robust_list, "")); -#endif + LIN_SDT_PROBE2(futex, linux_get_robust_list, entry, td, args); if (!args->pid) { em = em_find(td->td_proc, EMUL_DONTLOCK); head = em->robust_futexes; } else { struct proc *p; p = pfind(args->pid); - if (p == NULL) + if (p == NULL) { + LIN_SDT_PROBE1(futex, linux_get_robust_list, return, + ESRCH); return (ESRCH); + } em = em_find(p, EMUL_DONTLOCK); /* XXX: ptrace? */ if (priv_check(td, PRIV_CRED_SETUID) || priv_check(td, PRIV_CRED_SETEUID) || p_candebug(td, p)) { PROC_UNLOCK(p); + + LIN_SDT_PROBE1(futex, linux_get_robust_list, return, + EPERM); return (EPERM); } head = em->robust_futexes; PROC_UNLOCK(p); } error = copyout(&len, args->len, sizeof(l_size_t)); - if (error) + if (error) { + LIN_SDT_PROBE1(futex, linux_get_robust_list, copyout_error, + error); + LIN_SDT_PROBE1(futex, linux_get_robust_list, return, EFAULT); return (EFAULT); + } error = copyout(head, args->head, sizeof(struct linux_robust_list_head)); + if (error) { + LIN_SDT_PROBE1(futex, linux_get_robust_list, copyout_error, + error); + } + LIN_SDT_PROBE1(futex, linux_get_robust_list, return, error); return (error); } static int handle_futex_death(struct proc *p, uint32_t *uaddr, int pi) { uint32_t uval, nval, mval; struct futex *f; int error; + LIN_SDT_PROBE3(futex, handle_futex_death, entry, p, uaddr, pi); + retry: - if (copyin(uaddr, &uval, 4)) + error = copyin(uaddr, &uval, 4); + if (error) { + LIN_SDT_PROBE1(futex, handle_futex_death, copyin_error, error); + LIN_SDT_PROBE1(futex, handle_futex_death, return, EFAULT); return (EFAULT); + } if ((uval & FUTEX_TID_MASK) == p->p_pid) { mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED; nval = casuword32(uaddr, uval, mval); - if (nval == -1) + if (nval == -1) { + LIN_SDT_PROBE1(futex, handle_futex_death, return, + EFAULT); return (EFAULT); + } if (nval != uval) goto retry; if (!pi && (uval & FUTEX_WAITERS)) { error = futex_get(uaddr, NULL, &f, FUTEX_DONTCREATE | FUTEX_SHARED); - if (error) + if (error) { + LIN_SDT_PROBE1(futex, handle_futex_death, + return, error); return (error); + } if (f != NULL) { futex_wake(f, 1, FUTEX_BITSET_MATCH_ANY); futex_put(f, NULL); } } } + LIN_SDT_PROBE1(futex, handle_futex_death, return, 0); return (0); } static int fetch_robust_entry(struct linux_robust_list **entry, struct linux_robust_list **head, int *pi) { l_ulong uentry; + int error; - if (copyin((const void *)head, &uentry, sizeof(l_ulong))) + LIN_SDT_PROBE3(futex, fetch_robust_entry, entry, entry, head, pi); + + error = copyin((const void *)head, &uentry, sizeof(l_ulong)); + if (error) { + LIN_SDT_PROBE1(futex, fetch_robust_entry, copyin_error, error); + LIN_SDT_PROBE1(futex, fetch_robust_entry, return, EFAULT); return (EFAULT); + } *entry = (void *)(uentry & ~1UL); *pi = uentry & 1; + LIN_SDT_PROBE1(futex, fetch_robust_entry, return, 0); return (0); } /* This walks the list of robust futexes releasing them. */ void release_futexes(struct proc *p) { struct linux_robust_list_head *head = NULL; struct linux_robust_list *entry, *next_entry, *pending; unsigned int limit = 2048, pi, next_pi, pip; struct linux_emuldata *em; l_long futex_offset; - int rc; + int rc, error; + LIN_SDT_PROBE1(futex, release_futexes, entry, p); + em = em_find(p, EMUL_DONTLOCK); head = em->robust_futexes; - if (head == NULL) + if (head == NULL) { + LIN_SDT_PROBE0(futex, release_futexes, return); return; + } - if (fetch_robust_entry(&entry, PTRIN(&head->list.next), &pi)) + if (fetch_robust_entry(&entry, PTRIN(&head->list.next), &pi)) { + LIN_SDT_PROBE0(futex, release_futexes, return); return; + } - if (copyin(&head->futex_offset, &futex_offset, sizeof(futex_offset))) + error = copyin(&head->futex_offset, &futex_offset, + sizeof(futex_offset)); + if (error) { + LIN_SDT_PROBE1(futex, release_futexes, copyin_error, error); + LIN_SDT_PROBE0(futex, release_futexes, return); return; + } - if (fetch_robust_entry(&pending, PTRIN(&head->pending_list), &pip)) + if (fetch_robust_entry(&pending, PTRIN(&head->pending_list), &pip)) { + LIN_SDT_PROBE0(futex, release_futexes, return); return; + } while (entry != &head->list) { rc = fetch_robust_entry(&next_entry, PTRIN(&entry->next), &next_pi); if (entry != pending) - if (handle_futex_death(p, (uint32_t *)entry + futex_offset, pi)) + if (handle_futex_death(p, + (uint32_t *)entry + futex_offset, pi)) { + LIN_SDT_PROBE0(futex, release_futexes, return); return; - if (rc) + } + if (rc) { + LIN_SDT_PROBE0(futex, release_futexes, return); return; + } entry = next_entry; pi = next_pi; if (!--limit) break; sched_relinquish(curthread); } if (pending) handle_futex_death(p, (uint32_t *)pending + futex_offset, pip); + + LIN_SDT_PROBE0(futex, release_futexes, return); } Index: stable/9/sys/compat/linux/linux_mib.c =================================================================== --- stable/9/sys/compat/linux/linux_mib.c (revision 246289) +++ stable/9/sys/compat/linux/linux_mib.c (revision 246290) @@ -1,611 +1,857 @@ /*- * Copyright (c) 1999 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); +#include "opt_compat.h" +#include "opt_kdtrace.h" + #include #include +#include #include #include #include #include #include #include #include #include #include -#include "opt_compat.h" - #ifdef COMPAT_LINUX32 #include #else #include #endif +#include #include +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osname, entry); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, sysctl_string_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, return, "int"); + +LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osrelease, entry); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, sysctl_string_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, return, "int"); +LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_oss_version, entry); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, sysctl_string_error, + "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_map_osrel, entry, "char *", "int *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_map_osrel, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_get_prison, entry, "struct prison *", + "struct prison **"); +LIN_SDT_PROBE_DEFINE1(mib, linux_get_prison, return, "struct linux_prison *"); +LIN_SDT_PROBE_DEFINE2(mib, linux_alloc_prison, entry, "struct prison *", + "struct linux_prison **"); +LIN_SDT_PROBE_DEFINE1(mib, linux_alloc_prison, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_prison_create, entry, "void *", "void *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, vfs_copyopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_prison_check, entry, "void *", "void *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_copyopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_getopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_prison_set, entry, "void *", "void *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_copyopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_getopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_prison_get, entry, "void *", "void *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopt_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopts_error, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, return, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_prison_destructor, entry, "void *"); +LIN_SDT_PROBE_DEFINE0(mib, linux_prison_destructor, return); +LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, entry); +LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, return); +LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, entry); +LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, return); +LIN_SDT_PROBE_DEFINE2(mib, linux_get_osname, entry, "struct thread *", + "char *"); +LIN_SDT_PROBE_DEFINE0(mib, linux_get_osname, return); +LIN_SDT_PROBE_DEFINE2(mib, linux_set_osname, entry, "struct thread *", + "char *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_set_osname, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_get_osrelease, entry, "struct thread *", + "char *"); +LIN_SDT_PROBE_DEFINE0(mib, linux_get_osrelease, return); +LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, entry, "struct thread *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, return, "int"); +LIN_SDT_PROBE_DEFINE2(mib, linux_set_osrelease, entry, "struct thread *", + "char *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_set_osrelease, return, "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, entry, "struct thread *"); +LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, return, "int"); + +LIN_SDT_PROBE_DEFINE2(mib, linux_set_oss_version, entry, "struct thread *", + "int"); +LIN_SDT_PROBE_DEFINE1(mib, linux_set_oss_version, return, "int"); + struct linux_prison { char pr_osname[LINUX_MAX_UTSNAME]; char pr_osrelease[LINUX_MAX_UTSNAME]; int pr_oss_version; int pr_osrel; }; static struct linux_prison lprison0 = { .pr_osname = "Linux", .pr_osrelease = "2.6.16", .pr_oss_version = 0x030600, .pr_osrel = 2006016 }; static unsigned linux_osd_jail_slot; SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0, "Linux mode"); static int linux_set_osname(struct thread *td, char *osname); static int linux_set_osrelease(struct thread *td, char *osrelease); static int linux_set_oss_version(struct thread *td, int oss_version); static int linux_sysctl_osname(SYSCTL_HANDLER_ARGS) { char osname[LINUX_MAX_UTSNAME]; int error; + LIN_SDT_PROBE0(mib, linux_sysctl_osname, entry); + linux_get_osname(req->td, osname); error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req); - if (error || req->newptr == NULL) + if (error != 0 || req->newptr == NULL) { + LIN_SDT_PROBE1(mib, linux_sysctl_osname, sysctl_string_error, + error); + LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error); return (error); + } error = linux_set_osname(req->td, osname); + + LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error); return (error); } SYSCTL_PROC(_compat_linux, OID_AUTO, osname, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 0, 0, linux_sysctl_osname, "A", "Linux kernel OS name"); static int linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS) { char osrelease[LINUX_MAX_UTSNAME]; int error; + LIN_SDT_PROBE0(mib, linux_sysctl_osrelease, entry); + linux_get_osrelease(req->td, osrelease); error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req); - if (error || req->newptr == NULL) + if (error != 0 || req->newptr == NULL) { + LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, sysctl_string_error, + error); + LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error); return (error); + } error = linux_set_osrelease(req->td, osrelease); + + LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error); return (error); } SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 0, 0, linux_sysctl_osrelease, "A", "Linux kernel OS release"); static int linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS) { int oss_version; int error; + LIN_SDT_PROBE0(mib, linux_sysctl_oss_version, entry); + oss_version = linux_get_oss_version(req->td); error = sysctl_handle_int(oidp, &oss_version, 0, req); - if (error || req->newptr == NULL) + if (error != 0 || req->newptr == NULL) { + LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, + sysctl_string_error, error); + LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error); return (error); + } error = linux_set_oss_version(req->td, oss_version); + + LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error); return (error); } SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 0, 0, linux_sysctl_oss_version, "I", "Linux OSS version"); /* * Map the osrelease into integer */ static int linux_map_osrel(char *osrelease, int *osrel) { char *sep, *eosrelease; int len, v0, v1, v2, v; + LIN_SDT_PROBE2(mib, linux_map_osrel, entry, osrelease, osrel); + len = strlen(osrelease); eosrelease = osrelease + len; v0 = strtol(osrelease, &sep, 10); - if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') + if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') { + LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); return (EINVAL); + } osrelease = sep + 1; v1 = strtol(osrelease, &sep, 10); - if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') + if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') { + LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); return (EINVAL); + } osrelease = sep + 1; v2 = strtol(osrelease, &sep, 10); - if (osrelease == sep || sep != eosrelease) + if (osrelease == sep || sep != eosrelease) { + LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); return (EINVAL); + } v = v0 * 1000000 + v1 * 1000 + v2; - if (v < 1000000) + if (v < 1000000) { + LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL); return (EINVAL); + } *osrel = v; + + LIN_SDT_PROBE1(mib, linux_map_osrel, return, 0); return (0); } /* * Find a prison with Linux info. * Return the Linux info and the (locked) prison. */ static struct linux_prison * linux_find_prison(struct prison *spr, struct prison **prp) { struct prison *pr; struct linux_prison *lpr; + LIN_SDT_PROBE2(mib, linux_get_prison, entry, spr, prp); + if (!linux_osd_jail_slot) /* In case osd_register failed. */ spr = &prison0; for (pr = spr;; pr = pr->pr_parent) { mtx_lock(&pr->pr_mtx); lpr = (pr == &prison0) ? &lprison0 : osd_jail_get(pr, linux_osd_jail_slot); if (lpr != NULL) break; mtx_unlock(&pr->pr_mtx); } *prp = pr; + + LIN_SDT_PROBE1(mib, linux_get_prison, return, lpr); return (lpr); } /* * Ensure a prison has its own Linux info. If lprp is non-null, point it to * the Linux info and lock the prison. */ static int linux_alloc_prison(struct prison *pr, struct linux_prison **lprp) { struct prison *ppr; struct linux_prison *lpr, *nlpr; int error; + LIN_SDT_PROBE2(mib, linux_alloc_prison, entry, pr, lprp); + /* If this prison already has Linux info, return that. */ error = 0; lpr = linux_find_prison(pr, &ppr); if (ppr == pr) goto done; /* * Allocate a new info record. Then check again, in case something * changed during the allocation. */ mtx_unlock(&ppr->pr_mtx); nlpr = malloc(sizeof(struct linux_prison), M_PRISON, M_WAITOK); lpr = linux_find_prison(pr, &ppr); if (ppr == pr) { free(nlpr, M_PRISON); goto done; } /* Inherit the initial values from the ancestor. */ mtx_lock(&pr->pr_mtx); error = osd_jail_set(pr, linux_osd_jail_slot, nlpr); if (error == 0) { bcopy(lpr, nlpr, sizeof(*lpr)); lpr = nlpr; } else { free(nlpr, M_PRISON); lpr = NULL; } mtx_unlock(&ppr->pr_mtx); done: if (lprp != NULL) *lprp = lpr; else mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_alloc_prison, return, error); return (error); } /* * Jail OSD methods for Linux prison data. */ static int linux_prison_create(void *obj, void *data) { struct prison *pr = obj; struct vfsoptlist *opts = data; - int jsys; + int jsys, error; - if (vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)) == 0 && - jsys == JAIL_SYS_INHERIT) + LIN_SDT_PROBE2(mib, linux_prison_create, entry, obj, data); + + error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_create, vfs_copyopt_error, + error); + } else if (jsys == JAIL_SYS_INHERIT) { + LIN_SDT_PROBE1(mib, linux_prison_create, return, 0); return (0); + } /* * Inherit a prison's initial values from its parent * (different from JAIL_SYS_INHERIT which also inherits changes). */ - return linux_alloc_prison(pr, NULL); + error = linux_alloc_prison(pr, NULL); + + LIN_SDT_PROBE1(mib, linux_prison_create, return, error); + return (error); } static int linux_prison_check(void *obj __unused, void *data) { struct vfsoptlist *opts = data; char *osname, *osrelease; int error, jsys, len, osrel, oss_version; + LIN_SDT_PROBE2(mib, linux_prison_check, entry, obj, data); + /* Check that the parameters are correct. */ error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error, + error); + } if (error != ENOENT) { - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, return, error); return (error); - if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) + } + if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) { + LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL); return (EINVAL); + } } error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error, + error); + } if (error != ENOENT) { - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, return, error); return (error); - if (len == 0 || osname[len - 1] != '\0') + } + if (len == 0 || osname[len - 1] != '\0') { + LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL); return (EINVAL); + } if (len > LINUX_MAX_UTSNAME) { vfs_opterror(opts, "linux.osname too long"); + LIN_SDT_PROBE1(mib, linux_prison_check, return, + ENAMETOOLONG); return (ENAMETOOLONG); } } error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error, + error); + } if (error != ENOENT) { - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_check, return, error); return (error); - if (len == 0 || osrelease[len - 1] != '\0') + } + if (len == 0 || osrelease[len - 1] != '\0') { + LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL); return (EINVAL); + } if (len > LINUX_MAX_UTSNAME) { vfs_opterror(opts, "linux.osrelease too long"); + LIN_SDT_PROBE1(mib, linux_prison_check, return, + ENAMETOOLONG); return (ENAMETOOLONG); } error = linux_map_osrel(osrelease, &osrel); if (error != 0) { vfs_opterror(opts, "linux.osrelease format error"); + LIN_SDT_PROBE1(mib, linux_prison_check, return, error); return (error); } } error = vfs_copyopt(opts, "linux.oss_version", &oss_version, sizeof(oss_version)); - return (error == ENOENT ? 0 : error); + if (error != 0) + LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error, error); + + if (error == ENOENT) + error = 0; + LIN_SDT_PROBE1(mib, linux_prison_check, return, error); + return (error); } static int linux_prison_set(void *obj, void *data) { struct linux_prison *lpr; struct prison *pr = obj; struct vfsoptlist *opts = data; char *osname, *osrelease; int error, gotversion, jsys, len, oss_version; + LIN_SDT_PROBE2(mib, linux_prison_set, entry, obj, data); + /* Set the parameters, which should be correct. */ error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)); + if (error != 0) + LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error); if (error == ENOENT) jsys = -1; error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len); + if (error != 0) + LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error); if (error == ENOENT) osname = NULL; else jsys = JAIL_SYS_NEW; error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len); + if (error != 0) + LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error); if (error == ENOENT) osrelease = NULL; else jsys = JAIL_SYS_NEW; error = vfs_copyopt(opts, "linux.oss_version", &oss_version, sizeof(oss_version)); + if (error != 0) + LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error); if (error == ENOENT) gotversion = 0; else { gotversion = 1; jsys = JAIL_SYS_NEW; } switch (jsys) { case JAIL_SYS_INHERIT: /* "linux=inherit": inherit the parent's Linux info. */ mtx_lock(&pr->pr_mtx); osd_jail_del(pr, linux_osd_jail_slot); mtx_unlock(&pr->pr_mtx); break; case JAIL_SYS_NEW: /* * "linux=new" or "linux.*": * the prison gets its own Linux info. */ error = linux_alloc_prison(pr, &lpr); if (error) { mtx_unlock(&pr->pr_mtx); + LIN_SDT_PROBE1(mib, linux_prison_set, return, error); return (error); } if (osrelease) { error = linux_map_osrel(osrelease, &lpr->pr_osrel); if (error) { mtx_unlock(&pr->pr_mtx); + LIN_SDT_PROBE1(mib, linux_prison_set, return, + error); return (error); } strlcpy(lpr->pr_osrelease, osrelease, LINUX_MAX_UTSNAME); } if (osname) strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME); if (gotversion) lpr->pr_oss_version = oss_version; mtx_unlock(&pr->pr_mtx); } + + LIN_SDT_PROBE1(mib, linux_prison_set, return, 0); return (0); } SYSCTL_JAIL_PARAM_SYS_NODE(linux, CTLFLAG_RW, "Jail Linux parameters"); SYSCTL_JAIL_PARAM_STRING(_linux, osname, CTLFLAG_RW, LINUX_MAX_UTSNAME, "Jail Linux kernel OS name"); SYSCTL_JAIL_PARAM_STRING(_linux, osrelease, CTLFLAG_RW, LINUX_MAX_UTSNAME, "Jail Linux kernel OS release"); SYSCTL_JAIL_PARAM(_linux, oss_version, CTLTYPE_INT | CTLFLAG_RW, "I", "Jail Linux OSS version"); static int linux_prison_get(void *obj, void *data) { struct linux_prison *lpr; struct prison *ppr; struct prison *pr = obj; struct vfsoptlist *opts = data; int error, i; static int version0; + LIN_SDT_PROBE2(mib, linux_prison_get, entry, obj, data); + /* See if this prison is the one with the Linux info. */ lpr = linux_find_prison(pr, &ppr); i = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; error = vfs_setopt(opts, "linux", &i, sizeof(i)); - if (error != 0 && error != ENOENT) - goto done; + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, error); + if (error != ENOENT) + goto done; + } if (i) { error = vfs_setopts(opts, "linux.osname", lpr->pr_osname); - if (error != 0 && error != ENOENT) - goto done; + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, + error); + if (error != ENOENT) + goto done; + } error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease); - if (error != 0 && error != ENOENT) - goto done; + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, + error); + if (error != ENOENT) + goto done; + } error = vfs_setopt(opts, "linux.oss_version", &lpr->pr_oss_version, sizeof(lpr->pr_oss_version)); - if (error != 0 && error != ENOENT) - goto done; + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, + error); + if(error != ENOENT) + goto done; + } } else { /* * If this prison is inheriting its Linux info, report * empty/zero parameters. */ error = vfs_setopts(opts, "linux.osname", ""); - if (error != 0 && error != ENOENT) - goto done; + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, + error); + if(error != ENOENT) + goto done; + } error = vfs_setopts(opts, "linux.osrelease", ""); - if (error != 0 && error != ENOENT) - goto done; + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error, + error); + if(error != ENOENT) + goto done; + } error = vfs_setopt(opts, "linux.oss_version", &version0, sizeof(lpr->pr_oss_version)); - if (error != 0 && error != ENOENT) - goto done; + if (error != 0) { + LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, + error); + if(error != ENOENT) + goto done; + } } error = 0; done: mtx_unlock(&ppr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_prison_get, return, error); return (error); } static void linux_prison_destructor(void *data) { + LIN_SDT_PROBE1(mib, linux_prison_destructor, entry, data); free(data, M_PRISON); + LIN_SDT_PROBE0(mib, linux_prison_destructor, return); } void linux_osd_jail_register(void) { struct prison *pr; osd_method_t methods[PR_MAXMETHOD] = { [PR_METHOD_CREATE] = linux_prison_create, [PR_METHOD_GET] = linux_prison_get, [PR_METHOD_SET] = linux_prison_set, [PR_METHOD_CHECK] = linux_prison_check }; + LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry); + linux_osd_jail_slot = osd_jail_register(linux_prison_destructor, methods); if (linux_osd_jail_slot > 0) { /* Copy the system linux info to any current prisons. */ sx_xlock(&allprison_lock); TAILQ_FOREACH(pr, &allprison, pr_list) (void)linux_alloc_prison(pr, NULL); sx_xunlock(&allprison_lock); } + + LIN_SDT_PROBE0(mib, linux_osd_jail_register, return); } void linux_osd_jail_deregister(void) { + LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry); + if (linux_osd_jail_slot) osd_jail_deregister(linux_osd_jail_slot); + + LIN_SDT_PROBE0(mib, linux_osd_jail_register, return); } void linux_get_osname(struct thread *td, char *dst) { struct prison *pr; struct linux_prison *lpr; + LIN_SDT_PROBE2(mib, linux_get_osname, entry, td, dst); + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME); mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE0(mib, linux_get_osname, return); } static int linux_set_osname(struct thread *td, char *osname) { struct prison *pr; struct linux_prison *lpr; + LIN_SDT_PROBE2(mib, linux_set_osname, entry, td, osname); + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME); mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_set_osname, return, 0); return (0); } void linux_get_osrelease(struct thread *td, char *dst) { struct prison *pr; struct linux_prison *lpr; + LIN_SDT_PROBE2(mib, linux_get_osrelease, entry, td, dst); + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME); mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE0(mib, linux_get_osrelease, return); } int linux_kernver(struct thread *td) { struct prison *pr; struct linux_prison *lpr; int osrel; + LIN_SDT_PROBE1(mib, linux_kernver, entry, td); + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); osrel = lpr->pr_osrel; mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_kernver, return, osrel); return (osrel); } static int linux_set_osrelease(struct thread *td, char *osrelease) { struct prison *pr; struct linux_prison *lpr; int error; + LIN_SDT_PROBE2(mib, linux_set_osrelease, entry, td, osrelease); + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); error = linux_map_osrel(osrelease, &lpr->pr_osrel); if (error == 0) strlcpy(lpr->pr_osrelease, osrelease, LINUX_MAX_UTSNAME); mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_set_osrelease, return, error); return (error); } int linux_get_oss_version(struct thread *td) { struct prison *pr; struct linux_prison *lpr; int version; + LIN_SDT_PROBE1(mib, linux_get_oss_version, entry, td); + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); version = lpr->pr_oss_version; mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_get_oss_version, return, version); return (version); } static int linux_set_oss_version(struct thread *td, int oss_version) { struct prison *pr; struct linux_prison *lpr; + LIN_SDT_PROBE2(mib, linux_set_oss_version, entry, td, oss_version); + lpr = linux_find_prison(td->td_ucred->cr_prison, &pr); lpr->pr_oss_version = oss_version; mtx_unlock(&pr->pr_mtx); + + LIN_SDT_PROBE1(mib, linux_set_oss_version, return, 0); return (0); } #if defined(DEBUG) || defined(KTR) +/* XXX: can be removed when every ldebug(...) and KTR stuff are removed. */ u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))]; static int linux_debug(int syscall, int toggle, int global) { if (global) { char c = toggle ? 0 : 0xff; memset(linux_debug_map, c, sizeof(linux_debug_map)); return (0); } if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL) return (EINVAL); if (toggle) clrbit(linux_debug_map, syscall); else setbit(linux_debug_map, syscall); return (0); } /* * Usage: sysctl linux.debug=.<0/1> * * E.g.: sysctl linux.debug=21.0 * * As a special case, syscall "all" will apply to all syscalls globally. */ #define LINUX_MAX_DEBUGSTR 16 static int linux_sysctl_debug(SYSCTL_HANDLER_ARGS) { char value[LINUX_MAX_DEBUGSTR], *p; int error, sysc, toggle; int global = 0; value[0] = '\0'; error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req); if (error || req->newptr == NULL) return (error); for (p = value; *p != '\0' && *p != '.'; p++); if (*p == '\0') return (EINVAL); *p++ = '\0'; sysc = strtol(value, NULL, 0); toggle = strtol(p, NULL, 0); if (strcmp(value, "all") == 0) global = 1; error = linux_debug(sysc, toggle, global); return (error); } SYSCTL_PROC(_compat_linux, OID_AUTO, debug, CTLTYPE_STRING | CTLFLAG_RW, 0, 0, linux_sysctl_debug, "A", "Linux debugging control"); #endif /* DEBUG || KTR */ Index: stable/9/sys/compat/linux/linux_misc.c =================================================================== --- stable/9/sys/compat/linux/linux_misc.c (revision 246289) +++ stable/9/sys/compat/linux/linux_misc.c (revision 246290) @@ -1,1918 +1,1932 @@ /*- * Copyright (c) 2002 Doug Rabson * Copyright (c) 1994-1995 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" +#include "opt_kdtrace.h" #include #include #include #if defined(__i386__) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef COMPAT_LINUX32 #include #include #else #include #include #endif +#include #include #include #include #include #include #include #include + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/* Linuxulator-global DTrace probes */ +LIN_SDT_PROBE_DECLARE(locks, emul_lock, locked); +LIN_SDT_PROBE_DECLARE(locks, emul_lock, unlock); +LIN_SDT_PROBE_DECLARE(locks, emul_shared_rlock, locked); +LIN_SDT_PROBE_DECLARE(locks, emul_shared_rlock, unlock); +LIN_SDT_PROBE_DECLARE(locks, emul_shared_wlock, locked); +LIN_SDT_PROBE_DECLARE(locks, emul_shared_wlock, unlock); int stclohz; /* Statistics clock frequency */ static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = { RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK, RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE, RLIMIT_MEMLOCK, RLIMIT_AS }; struct l_sysinfo { l_long uptime; /* Seconds since boot */ l_ulong loads[3]; /* 1, 5, and 15 minute load averages */ #define LINUX_SYSINFO_LOADS_SCALE 65536 l_ulong totalram; /* Total usable main memory size */ l_ulong freeram; /* Available memory size */ l_ulong sharedram; /* Amount of shared memory */ l_ulong bufferram; /* Memory used by buffers */ l_ulong totalswap; /* Total swap space size */ l_ulong freeswap; /* swap space still available */ l_ushort procs; /* Number of current processes */ l_ushort pads; l_ulong totalbig; l_ulong freebig; l_uint mem_unit; char _f[20-2*sizeof(l_long)-sizeof(l_int)]; /* padding */ }; int linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args) { struct l_sysinfo sysinfo; vm_object_t object; int i, j; struct timespec ts; getnanouptime(&ts); if (ts.tv_nsec != 0) ts.tv_sec++; sysinfo.uptime = ts.tv_sec; /* Use the information from the mib to get our load averages */ for (i = 0; i < 3; i++) sysinfo.loads[i] = averunnable.ldavg[i] * LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale; sysinfo.totalram = physmem * PAGE_SIZE; sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE; sysinfo.sharedram = 0; mtx_lock(&vm_object_list_mtx); TAILQ_FOREACH(object, &vm_object_list, object_list) if (object->shadow_count > 1) sysinfo.sharedram += object->resident_page_count; mtx_unlock(&vm_object_list_mtx); sysinfo.sharedram *= PAGE_SIZE; sysinfo.bufferram = 0; swap_pager_status(&i, &j); sysinfo.totalswap = i * PAGE_SIZE; sysinfo.freeswap = (i - j) * PAGE_SIZE; sysinfo.procs = nprocs; /* The following are only present in newer Linux kernels. */ sysinfo.totalbig = 0; sysinfo.freebig = 0; sysinfo.mem_unit = 1; return (copyout(&sysinfo, args->info, sizeof(sysinfo))); } int linux_alarm(struct thread *td, struct linux_alarm_args *args) { struct itimerval it, old_it; u_int secs; int error; #ifdef DEBUG if (ldebug(alarm)) printf(ARGS(alarm, "%u"), args->secs); #endif secs = args->secs; if (secs > INT_MAX) secs = INT_MAX; it.it_value.tv_sec = (long) secs; it.it_value.tv_usec = 0; it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 0; error = kern_setitimer(td, ITIMER_REAL, &it, &old_it); if (error) return (error); if (timevalisset(&old_it.it_value)) { if (old_it.it_value.tv_usec != 0) old_it.it_value.tv_sec++; td->td_retval[0] = old_it.it_value.tv_sec; } return (0); } int linux_brk(struct thread *td, struct linux_brk_args *args) { struct vmspace *vm = td->td_proc->p_vmspace; vm_offset_t new, old; struct obreak_args /* { char * nsize; } */ tmp; #ifdef DEBUG if (ldebug(brk)) printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend); #endif old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); new = (vm_offset_t)args->dsend; tmp.nsize = (char *)new; if (((caddr_t)new > vm->vm_daddr) && !sys_obreak(td, &tmp)) td->td_retval[0] = (long)new; else td->td_retval[0] = (long)old; return (0); } #if defined(__i386__) /* XXX: what about amd64/linux32? */ int linux_uselib(struct thread *td, struct linux_uselib_args *args) { struct nameidata ni; struct vnode *vp; struct exec *a_out; struct vattr attr; vm_offset_t vmaddr; unsigned long file_offset; unsigned long bss_size; char *library; ssize_t aresid; int error, locked, vfslocked, writecount; LCONVPATHEXIST(td, args->library, &library); #ifdef DEBUG if (ldebug(uselib)) printf(ARGS(uselib, "%s"), library); #endif a_out = NULL; vfslocked = 0; locked = 0; vp = NULL; NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, UIO_SYSSPACE, library, td); error = namei(&ni); LFREEPATH(library); if (error) goto cleanup; vp = ni.ni_vp; vfslocked = NDHASGIANT(&ni); NDFREE(&ni, NDF_ONLY_PNBUF); /* * From here on down, we have a locked vnode that must be unlocked. * XXX: The code below largely duplicates exec_check_permissions(). */ locked = 1; /* Writable? */ error = VOP_GET_WRITECOUNT(vp, &writecount); if (error != 0) goto cleanup; if (writecount != 0) { error = ETXTBSY; goto cleanup; } /* Executable? */ error = VOP_GETATTR(vp, &attr, td->td_ucred); if (error) goto cleanup; if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) { /* EACCESS is what exec(2) returns. */ error = ENOEXEC; goto cleanup; } /* Sensible size? */ if (attr.va_size == 0) { error = ENOEXEC; goto cleanup; } /* Can we access it? */ error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td); if (error) goto cleanup; /* * XXX: This should use vn_open() so that it is properly authorized, * and to reduce code redundancy all over the place here. * XXX: Not really, it duplicates far more of exec_check_permissions() * than vn_open(). */ #ifdef MAC error = mac_vnode_check_open(td->td_ucred, vp, VREAD); if (error) goto cleanup; #endif error = VOP_OPEN(vp, FREAD, td->td_ucred, td, NULL); if (error) goto cleanup; /* Pull in executable header into exec_map */ error = vm_mmap(exec_map, (vm_offset_t *)&a_out, PAGE_SIZE, VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 0); if (error) goto cleanup; /* Is it a Linux binary ? */ if (((a_out->a_magic >> 16) & 0xff) != 0x64) { error = ENOEXEC; goto cleanup; } /* * While we are here, we should REALLY do some more checks */ /* Set file/virtual offset based on a.out variant. */ switch ((int)(a_out->a_magic & 0xffff)) { case 0413: /* ZMAGIC */ file_offset = 1024; break; case 0314: /* QMAGIC */ file_offset = 0; break; default: error = ENOEXEC; goto cleanup; } bss_size = round_page(a_out->a_bss); /* Check various fields in header for validity/bounds. */ if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) { error = ENOEXEC; goto cleanup; } /* text + data can't exceed file size */ if (a_out->a_data + a_out->a_text > attr.va_size) { error = EFAULT; goto cleanup; } /* * text/data/bss must not exceed limits * XXX - this is not complete. it should check current usage PLUS * the resources needed by this library. */ PROC_LOCK(td->td_proc); if (a_out->a_text > maxtsiz || a_out->a_data + bss_size > lim_cur(td->td_proc, RLIMIT_DATA) || racct_set(td->td_proc, RACCT_DATA, a_out->a_data + bss_size) != 0) { PROC_UNLOCK(td->td_proc); error = ENOMEM; goto cleanup; } PROC_UNLOCK(td->td_proc); /* * Prevent more writers. * XXX: Note that if any of the VM operations fail below we don't * clear this flag. */ VOP_SET_TEXT(vp); /* * Lock no longer needed */ locked = 0; VOP_UNLOCK(vp, 0); VFS_UNLOCK_GIANT(vfslocked); /* * Check if file_offset page aligned. Currently we cannot handle * misalinged file offsets, and so we read in the entire image * (what a waste). */ if (file_offset & PAGE_MASK) { #ifdef DEBUG printf("uselib: Non page aligned binary %lu\n", file_offset); #endif /* Map text+data read/write/execute */ /* a_entry is the load address and is page aligned */ vmaddr = trunc_page(a_out->a_entry); /* get anon user mapping, read+write+execute */ error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0); if (error) goto cleanup; error = vn_rdwr(UIO_READ, vp, (void *)vmaddr, file_offset, a_out->a_text + a_out->a_data, UIO_USERSPACE, 0, td->td_ucred, NOCRED, &aresid, td); if (error != 0) goto cleanup; if (aresid != 0) { error = ENOEXEC; goto cleanup; } } else { #ifdef DEBUG printf("uselib: Page aligned binary %lu\n", file_offset); #endif /* * for QMAGIC, a_entry is 20 bytes beyond the load address * to skip the executable header */ vmaddr = trunc_page(a_out->a_entry); /* * Map it all into the process's space as a single * copy-on-write "data" segment. */ error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr, a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, file_offset); if (error) goto cleanup; } #ifdef DEBUG printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long *)vmaddr)[0], ((long *)vmaddr)[1]); #endif if (bss_size != 0) { /* Calculate BSS start address */ vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data; /* allocate some 'anon' space */ error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0, &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0); if (error) goto cleanup; } cleanup: /* Unlock vnode if needed */ if (locked) { VOP_UNLOCK(vp, 0); VFS_UNLOCK_GIANT(vfslocked); } /* Release the temporary mapping. */ if (a_out) kmem_free_wakeup(exec_map, (vm_offset_t)a_out, PAGE_SIZE); return (error); } #endif /* __i386__ */ int linux_select(struct thread *td, struct linux_select_args *args) { l_timeval ltv; struct timeval tv0, tv1, utv, *tvp; int error; #ifdef DEBUG if (ldebug(select)) printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds, (void *)args->readfds, (void *)args->writefds, (void *)args->exceptfds, (void *)args->timeout); #endif /* * Store current time for computation of the amount of * time left. */ if (args->timeout) { if ((error = copyin(args->timeout, <v, sizeof(ltv)))) goto select_out; utv.tv_sec = ltv.tv_sec; utv.tv_usec = ltv.tv_usec; #ifdef DEBUG if (ldebug(select)) printf(LMSG("incoming timeout (%jd/%ld)"), (intmax_t)utv.tv_sec, utv.tv_usec); #endif if (itimerfix(&utv)) { /* * The timeval was invalid. Convert it to something * valid that will act as it does under Linux. */ utv.tv_sec += utv.tv_usec / 1000000; utv.tv_usec %= 1000000; if (utv.tv_usec < 0) { utv.tv_sec -= 1; utv.tv_usec += 1000000; } if (utv.tv_sec < 0) timevalclear(&utv); } microtime(&tv0); tvp = &utv; } else tvp = NULL; error = kern_select(td, args->nfds, args->readfds, args->writefds, args->exceptfds, tvp, sizeof(l_int) * 8); #ifdef DEBUG if (ldebug(select)) printf(LMSG("real select returns %d"), error); #endif if (error) goto select_out; if (args->timeout) { if (td->td_retval[0]) { /* * Compute how much time was left of the timeout, * by subtracting the current time and the time * before we started the call, and subtracting * that result from the user-supplied value. */ microtime(&tv1); timevalsub(&tv1, &tv0); timevalsub(&utv, &tv1); if (utv.tv_sec < 0) timevalclear(&utv); } else timevalclear(&utv); #ifdef DEBUG if (ldebug(select)) printf(LMSG("outgoing timeout (%jd/%ld)"), (intmax_t)utv.tv_sec, utv.tv_usec); #endif ltv.tv_sec = utv.tv_sec; ltv.tv_usec = utv.tv_usec; if ((error = copyout(<v, args->timeout, sizeof(ltv)))) goto select_out; } select_out: #ifdef DEBUG if (ldebug(select)) printf(LMSG("select_out -> %d"), error); #endif return (error); } int linux_mremap(struct thread *td, struct linux_mremap_args *args) { struct munmap_args /* { void *addr; size_t len; } */ bsd_args; int error = 0; #ifdef DEBUG if (ldebug(mremap)) printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"), (void *)(uintptr_t)args->addr, (unsigned long)args->old_len, (unsigned long)args->new_len, (unsigned long)args->flags); #endif if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) { td->td_retval[0] = 0; return (EINVAL); } /* * Check for the page alignment. * Linux defines PAGE_MASK to be FreeBSD ~PAGE_MASK. */ if (args->addr & PAGE_MASK) { td->td_retval[0] = 0; return (EINVAL); } args->new_len = round_page(args->new_len); args->old_len = round_page(args->old_len); if (args->new_len > args->old_len) { td->td_retval[0] = 0; return (ENOMEM); } if (args->new_len < args->old_len) { bsd_args.addr = (caddr_t)((uintptr_t)args->addr + args->new_len); bsd_args.len = args->old_len - args->new_len; error = sys_munmap(td, &bsd_args); } td->td_retval[0] = error ? 0 : (uintptr_t)args->addr; return (error); } #define LINUX_MS_ASYNC 0x0001 #define LINUX_MS_INVALIDATE 0x0002 #define LINUX_MS_SYNC 0x0004 int linux_msync(struct thread *td, struct linux_msync_args *args) { struct msync_args bsd_args; bsd_args.addr = (caddr_t)(uintptr_t)args->addr; bsd_args.len = (uintptr_t)args->len; bsd_args.flags = args->fl & ~LINUX_MS_SYNC; return (sys_msync(td, &bsd_args)); } int linux_time(struct thread *td, struct linux_time_args *args) { struct timeval tv; l_time_t tm; int error; #ifdef DEBUG if (ldebug(time)) printf(ARGS(time, "*")); #endif microtime(&tv); tm = tv.tv_sec; if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm)))) return (error); td->td_retval[0] = tm; return (0); } struct l_times_argv { l_clock_t tms_utime; l_clock_t tms_stime; l_clock_t tms_cutime; l_clock_t tms_cstime; }; /* * Glibc versions prior to 2.2.1 always use hard-coded CLK_TCK value. * Since 2.2.1 Glibc uses value exported from kernel via AT_CLKTCK * auxiliary vector entry. */ #define CLK_TCK 100 #define CONVOTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) #define CONVNTCK(r) (r.tv_sec * stclohz + r.tv_usec / (1000000 / stclohz)) #define CONVTCK(r) (linux_kernver(td) >= LINUX_KERNVER_2004000 ? \ CONVNTCK(r) : CONVOTCK(r)) int linux_times(struct thread *td, struct linux_times_args *args) { struct timeval tv, utime, stime, cutime, cstime; struct l_times_argv tms; struct proc *p; int error; #ifdef DEBUG if (ldebug(times)) printf(ARGS(times, "*")); #endif if (args->buf != NULL) { p = td->td_proc; PROC_LOCK(p); PROC_SLOCK(p); calcru(p, &utime, &stime); PROC_SUNLOCK(p); calccru(p, &cutime, &cstime); PROC_UNLOCK(p); tms.tms_utime = CONVTCK(utime); tms.tms_stime = CONVTCK(stime); tms.tms_cutime = CONVTCK(cutime); tms.tms_cstime = CONVTCK(cstime); if ((error = copyout(&tms, args->buf, sizeof(tms)))) return (error); } microuptime(&tv); td->td_retval[0] = (int)CONVTCK(tv); return (0); } int linux_newuname(struct thread *td, struct linux_newuname_args *args) { struct l_new_utsname utsname; char osname[LINUX_MAX_UTSNAME]; char osrelease[LINUX_MAX_UTSNAME]; char *p; #ifdef DEBUG if (ldebug(newuname)) printf(ARGS(newuname, "*")); #endif linux_get_osname(td, osname); linux_get_osrelease(td, osrelease); bzero(&utsname, sizeof(utsname)); strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME); getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME); getcreddomainname(td->td_ucred, utsname.domainname, LINUX_MAX_UTSNAME); strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME); strlcpy(utsname.version, version, LINUX_MAX_UTSNAME); for (p = utsname.version; *p != '\0'; ++p) if (*p == '\n') { *p = '\0'; break; } strlcpy(utsname.machine, linux_platform, LINUX_MAX_UTSNAME); return (copyout(&utsname, args->buf, sizeof(utsname))); } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) struct l_utimbuf { l_time_t l_actime; l_time_t l_modtime; }; int linux_utime(struct thread *td, struct linux_utime_args *args) { struct timeval tv[2], *tvp; struct l_utimbuf lut; char *fname; int error; LCONVPATHEXIST(td, args->fname, &fname); #ifdef DEBUG if (ldebug(utime)) printf(ARGS(utime, "%s, *"), fname); #endif if (args->times) { if ((error = copyin(args->times, &lut, sizeof lut))) { LFREEPATH(fname); return (error); } tv[0].tv_sec = lut.l_actime; tv[0].tv_usec = 0; tv[1].tv_sec = lut.l_modtime; tv[1].tv_usec = 0; tvp = tv; } else tvp = NULL; error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); LFREEPATH(fname); return (error); } int linux_utimes(struct thread *td, struct linux_utimes_args *args) { l_timeval ltv[2]; struct timeval tv[2], *tvp = NULL; char *fname; int error; LCONVPATHEXIST(td, args->fname, &fname); #ifdef DEBUG if (ldebug(utimes)) printf(ARGS(utimes, "%s, *"), fname); #endif if (args->tptr != NULL) { if ((error = copyin(args->tptr, ltv, sizeof ltv))) { LFREEPATH(fname); return (error); } tv[0].tv_sec = ltv[0].tv_sec; tv[0].tv_usec = ltv[0].tv_usec; tv[1].tv_sec = ltv[1].tv_sec; tv[1].tv_usec = ltv[1].tv_usec; tvp = tv; } error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); LFREEPATH(fname); return (error); } int linux_futimesat(struct thread *td, struct linux_futimesat_args *args) { l_timeval ltv[2]; struct timeval tv[2], *tvp = NULL; char *fname; int error, dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHEXIST_AT(td, args->filename, &fname, dfd); #ifdef DEBUG if (ldebug(futimesat)) printf(ARGS(futimesat, "%s, *"), fname); #endif if (args->utimes != NULL) { if ((error = copyin(args->utimes, ltv, sizeof ltv))) { LFREEPATH(fname); return (error); } tv[0].tv_sec = ltv[0].tv_sec; tv[0].tv_usec = ltv[0].tv_usec; tv[1].tv_sec = ltv[1].tv_sec; tv[1].tv_usec = ltv[1].tv_usec; tvp = tv; } error = kern_utimesat(td, dfd, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE); LFREEPATH(fname); return (error); } #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ int linux_common_wait(struct thread *td, int pid, int *status, int options, struct rusage *ru) { int error, tmpstat; error = kern_wait(td, pid, &tmpstat, options, ru); if (error) return (error); if (status) { tmpstat &= 0xffff; if (WIFSIGNALED(tmpstat)) tmpstat = (tmpstat & 0xffffff80) | BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat)); else if (WIFSTOPPED(tmpstat)) tmpstat = (tmpstat & 0xffff00ff) | (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8); error = copyout(&tmpstat, status, sizeof(int)); } return (error); } int linux_waitpid(struct thread *td, struct linux_waitpid_args *args) { int options; #ifdef DEBUG if (ldebug(waitpid)) printf(ARGS(waitpid, "%d, %p, %d"), args->pid, (void *)args->status, args->options); #endif /* * this is necessary because the test in kern_wait doesn't work * because we mess with the options here */ if (args->options & ~(WUNTRACED | WNOHANG | WCONTINUED | __WCLONE)) return (EINVAL); options = (args->options & (WNOHANG | WUNTRACED)); /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ if (args->options & __WCLONE) options |= WLINUXCLONE; return (linux_common_wait(td, args->pid, args->status, options, NULL)); } int linux_mknod(struct thread *td, struct linux_mknod_args *args) { char *path; int error; LCONVPATHCREAT(td, args->path, &path); #ifdef DEBUG if (ldebug(mknod)) printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev); #endif switch (args->mode & S_IFMT) { case S_IFIFO: case S_IFSOCK: error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode); break; case S_IFCHR: case S_IFBLK: error = kern_mknod(td, path, UIO_SYSSPACE, args->mode, args->dev); break; case S_IFDIR: error = EPERM; break; case 0: args->mode |= S_IFREG; /* FALLTHROUGH */ case S_IFREG: error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, args->mode); if (error == 0) kern_close(td, td->td_retval[0]); break; default: error = EINVAL; break; } LFREEPATH(path); return (error); } int linux_mknodat(struct thread *td, struct linux_mknodat_args *args) { char *path; int error, dfd; dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; LCONVPATHCREAT_AT(td, args->filename, &path, dfd); #ifdef DEBUG if (ldebug(mknodat)) printf(ARGS(mknodat, "%s, %d, %d"), path, args->mode, args->dev); #endif switch (args->mode & S_IFMT) { case S_IFIFO: case S_IFSOCK: error = kern_mkfifoat(td, dfd, path, UIO_SYSSPACE, args->mode); break; case S_IFCHR: case S_IFBLK: error = kern_mknodat(td, dfd, path, UIO_SYSSPACE, args->mode, args->dev); break; case S_IFDIR: error = EPERM; break; case 0: args->mode |= S_IFREG; /* FALLTHROUGH */ case S_IFREG: error = kern_openat(td, dfd, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, args->mode); if (error == 0) kern_close(td, td->td_retval[0]); break; default: error = EINVAL; break; } LFREEPATH(path); return (error); } /* * UGH! This is just about the dumbest idea I've ever heard!! */ int linux_personality(struct thread *td, struct linux_personality_args *args) { #ifdef DEBUG if (ldebug(personality)) printf(ARGS(personality, "%lu"), (unsigned long)args->per); #endif if (args->per != 0) return (EINVAL); /* Yes Jim, it's still a Linux... */ td->td_retval[0] = 0; return (0); } struct l_itimerval { l_timeval it_interval; l_timeval it_value; }; #define B2L_ITIMERVAL(bip, lip) \ (bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec; \ (bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec; \ (bip)->it_value.tv_sec = (lip)->it_value.tv_sec; \ (bip)->it_value.tv_usec = (lip)->it_value.tv_usec; int linux_setitimer(struct thread *td, struct linux_setitimer_args *uap) { int error; struct l_itimerval ls; struct itimerval aitv, oitv; #ifdef DEBUG if (ldebug(setitimer)) printf(ARGS(setitimer, "%p, %p"), (void *)uap->itv, (void *)uap->oitv); #endif if (uap->itv == NULL) { uap->itv = uap->oitv; return (linux_getitimer(td, (struct linux_getitimer_args *)uap)); } error = copyin(uap->itv, &ls, sizeof(ls)); if (error != 0) return (error); B2L_ITIMERVAL(&aitv, &ls); #ifdef DEBUG if (ldebug(setitimer)) { printf("setitimer: value: sec: %jd, usec: %ld\n", (intmax_t)aitv.it_value.tv_sec, aitv.it_value.tv_usec); printf("setitimer: interval: sec: %jd, usec: %ld\n", (intmax_t)aitv.it_interval.tv_sec, aitv.it_interval.tv_usec); } #endif error = kern_setitimer(td, uap->which, &aitv, &oitv); if (error != 0 || uap->oitv == NULL) return (error); B2L_ITIMERVAL(&ls, &oitv); return (copyout(&ls, uap->oitv, sizeof(ls))); } int linux_getitimer(struct thread *td, struct linux_getitimer_args *uap) { int error; struct l_itimerval ls; struct itimerval aitv; #ifdef DEBUG if (ldebug(getitimer)) printf(ARGS(getitimer, "%p"), (void *)uap->itv); #endif error = kern_getitimer(td, uap->which, &aitv); if (error != 0) return (error); B2L_ITIMERVAL(&ls, &aitv); return (copyout(&ls, uap->itv, sizeof(ls))); } int linux_nice(struct thread *td, struct linux_nice_args *args) { struct setpriority_args bsd_args; bsd_args.which = PRIO_PROCESS; bsd_args.who = 0; /* current process */ bsd_args.prio = args->inc; return (sys_setpriority(td, &bsd_args)); } int linux_setgroups(struct thread *td, struct linux_setgroups_args *args) { struct ucred *newcred, *oldcred; l_gid_t *linux_gidset; gid_t *bsd_gidset; int ngrp, error; struct proc *p; ngrp = args->gidsetsize; if (ngrp < 0 || ngrp >= ngroups_max + 1) return (EINVAL); linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK); error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t)); if (error) goto out; newcred = crget(); p = td->td_proc; PROC_LOCK(p); oldcred = crcopysafe(p, newcred); /* * cr_groups[0] holds egid. Setting the whole set from * the supplied set will cause egid to be changed too. * Keep cr_groups[0] unchanged to prevent that. */ if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0) { PROC_UNLOCK(p); crfree(newcred); goto out; } if (ngrp > 0) { newcred->cr_ngroups = ngrp + 1; bsd_gidset = newcred->cr_groups; ngrp--; while (ngrp >= 0) { bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; ngrp--; } } else newcred->cr_ngroups = 1; setsugid(p); p->p_ucred = newcred; PROC_UNLOCK(p); crfree(oldcred); error = 0; out: free(linux_gidset, M_TEMP); return (error); } int linux_getgroups(struct thread *td, struct linux_getgroups_args *args) { struct ucred *cred; l_gid_t *linux_gidset; gid_t *bsd_gidset; int bsd_gidsetsz, ngrp, error; cred = td->td_ucred; bsd_gidset = cred->cr_groups; bsd_gidsetsz = cred->cr_ngroups - 1; /* * cr_groups[0] holds egid. Returning the whole set * here will cause a duplicate. Exclude cr_groups[0] * to prevent that. */ if ((ngrp = args->gidsetsize) == 0) { td->td_retval[0] = bsd_gidsetsz; return (0); } if (ngrp < bsd_gidsetsz) return (EINVAL); ngrp = 0; linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), M_TEMP, M_WAITOK); while (ngrp < bsd_gidsetsz) { linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; ngrp++; } error = copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t)); free(linux_gidset, M_TEMP); if (error) return (error); td->td_retval[0] = ngrp; return (0); } int linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args) { struct rlimit bsd_rlim; struct l_rlimit rlim; u_int which; int error; #ifdef DEBUG if (ldebug(setrlimit)) printf(ARGS(setrlimit, "%d, %p"), args->resource, (void *)args->rlim); #endif if (args->resource >= LINUX_RLIM_NLIMITS) return (EINVAL); which = linux_to_bsd_resource[args->resource]; if (which == -1) return (EINVAL); error = copyin(args->rlim, &rlim, sizeof(rlim)); if (error) return (error); bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur; bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max; return (kern_setrlimit(td, which, &bsd_rlim)); } int linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args) { struct l_rlimit rlim; struct proc *p = td->td_proc; struct rlimit bsd_rlim; u_int which; #ifdef DEBUG if (ldebug(old_getrlimit)) printf(ARGS(old_getrlimit, "%d, %p"), args->resource, (void *)args->rlim); #endif if (args->resource >= LINUX_RLIM_NLIMITS) return (EINVAL); which = linux_to_bsd_resource[args->resource]; if (which == -1) return (EINVAL); PROC_LOCK(p); lim_rlimit(p, which, &bsd_rlim); PROC_UNLOCK(p); #ifdef COMPAT_LINUX32 rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur; if (rlim.rlim_cur == UINT_MAX) rlim.rlim_cur = INT_MAX; rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max; if (rlim.rlim_max == UINT_MAX) rlim.rlim_max = INT_MAX; #else rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur; if (rlim.rlim_cur == ULONG_MAX) rlim.rlim_cur = LONG_MAX; rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max; if (rlim.rlim_max == ULONG_MAX) rlim.rlim_max = LONG_MAX; #endif return (copyout(&rlim, args->rlim, sizeof(rlim))); } int linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args) { struct l_rlimit rlim; struct proc *p = td->td_proc; struct rlimit bsd_rlim; u_int which; #ifdef DEBUG if (ldebug(getrlimit)) printf(ARGS(getrlimit, "%d, %p"), args->resource, (void *)args->rlim); #endif if (args->resource >= LINUX_RLIM_NLIMITS) return (EINVAL); which = linux_to_bsd_resource[args->resource]; if (which == -1) return (EINVAL); PROC_LOCK(p); lim_rlimit(p, which, &bsd_rlim); PROC_UNLOCK(p); rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur; rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max; return (copyout(&rlim, args->rlim, sizeof(rlim))); } int linux_sched_setscheduler(struct thread *td, struct linux_sched_setscheduler_args *args) { struct sched_setscheduler_args bsd; #ifdef DEBUG if (ldebug(sched_setscheduler)) printf(ARGS(sched_setscheduler, "%d, %d, %p"), args->pid, args->policy, (const void *)args->param); #endif switch (args->policy) { case LINUX_SCHED_OTHER: bsd.policy = SCHED_OTHER; break; case LINUX_SCHED_FIFO: bsd.policy = SCHED_FIFO; break; case LINUX_SCHED_RR: bsd.policy = SCHED_RR; break; default: return (EINVAL); } bsd.pid = args->pid; bsd.param = (struct sched_param *)args->param; return (sys_sched_setscheduler(td, &bsd)); } int linux_sched_getscheduler(struct thread *td, struct linux_sched_getscheduler_args *args) { struct sched_getscheduler_args bsd; int error; #ifdef DEBUG if (ldebug(sched_getscheduler)) printf(ARGS(sched_getscheduler, "%d"), args->pid); #endif bsd.pid = args->pid; error = sys_sched_getscheduler(td, &bsd); switch (td->td_retval[0]) { case SCHED_OTHER: td->td_retval[0] = LINUX_SCHED_OTHER; break; case SCHED_FIFO: td->td_retval[0] = LINUX_SCHED_FIFO; break; case SCHED_RR: td->td_retval[0] = LINUX_SCHED_RR; break; } return (error); } int linux_sched_get_priority_max(struct thread *td, struct linux_sched_get_priority_max_args *args) { struct sched_get_priority_max_args bsd; #ifdef DEBUG if (ldebug(sched_get_priority_max)) printf(ARGS(sched_get_priority_max, "%d"), args->policy); #endif switch (args->policy) { case LINUX_SCHED_OTHER: bsd.policy = SCHED_OTHER; break; case LINUX_SCHED_FIFO: bsd.policy = SCHED_FIFO; break; case LINUX_SCHED_RR: bsd.policy = SCHED_RR; break; default: return (EINVAL); } return (sys_sched_get_priority_max(td, &bsd)); } int linux_sched_get_priority_min(struct thread *td, struct linux_sched_get_priority_min_args *args) { struct sched_get_priority_min_args bsd; #ifdef DEBUG if (ldebug(sched_get_priority_min)) printf(ARGS(sched_get_priority_min, "%d"), args->policy); #endif switch (args->policy) { case LINUX_SCHED_OTHER: bsd.policy = SCHED_OTHER; break; case LINUX_SCHED_FIFO: bsd.policy = SCHED_FIFO; break; case LINUX_SCHED_RR: bsd.policy = SCHED_RR; break; default: return (EINVAL); } return (sys_sched_get_priority_min(td, &bsd)); } #define REBOOT_CAD_ON 0x89abcdef #define REBOOT_CAD_OFF 0 #define REBOOT_HALT 0xcdef0123 #define REBOOT_RESTART 0x01234567 #define REBOOT_RESTART2 0xA1B2C3D4 #define REBOOT_POWEROFF 0x4321FEDC #define REBOOT_MAGIC1 0xfee1dead #define REBOOT_MAGIC2 0x28121969 #define REBOOT_MAGIC2A 0x05121996 #define REBOOT_MAGIC2B 0x16041998 int linux_reboot(struct thread *td, struct linux_reboot_args *args) { struct reboot_args bsd_args; #ifdef DEBUG if (ldebug(reboot)) printf(ARGS(reboot, "0x%x"), args->cmd); #endif if (args->magic1 != REBOOT_MAGIC1) return (EINVAL); switch (args->magic2) { case REBOOT_MAGIC2: case REBOOT_MAGIC2A: case REBOOT_MAGIC2B: break; default: return (EINVAL); } switch (args->cmd) { case REBOOT_CAD_ON: case REBOOT_CAD_OFF: return (priv_check(td, PRIV_REBOOT)); case REBOOT_HALT: bsd_args.opt = RB_HALT; break; case REBOOT_RESTART: case REBOOT_RESTART2: bsd_args.opt = 0; break; case REBOOT_POWEROFF: bsd_args.opt = RB_POWEROFF; break; default: return (EINVAL); } return (sys_reboot(td, &bsd_args)); } /* * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify * td->td_retval[1] when COMPAT_43 is defined. This clobbers registers that * are assumed to be preserved. The following lightweight syscalls fixes * this. See also linux_getgid16() and linux_getuid16() in linux_uid16.c * * linux_getpid() - MP SAFE * linux_getgid() - MP SAFE * linux_getuid() - MP SAFE */ int linux_getpid(struct thread *td, struct linux_getpid_args *args) { struct linux_emuldata *em; #ifdef DEBUG if (ldebug(getpid)) printf(ARGS(getpid, "")); #endif if (linux_use26(td)) { em = em_find(td->td_proc, EMUL_DONTLOCK); KASSERT(em != NULL, ("getpid: emuldata not found.\n")); td->td_retval[0] = em->shared->group_pid; } else { td->td_retval[0] = td->td_proc->p_pid; } return (0); } int linux_gettid(struct thread *td, struct linux_gettid_args *args) { #ifdef DEBUG if (ldebug(gettid)) printf(ARGS(gettid, "")); #endif td->td_retval[0] = td->td_proc->p_pid; return (0); } int linux_getppid(struct thread *td, struct linux_getppid_args *args) { struct linux_emuldata *em; struct proc *p, *pp; #ifdef DEBUG if (ldebug(getppid)) printf(ARGS(getppid, "")); #endif if (!linux_use26(td)) { PROC_LOCK(td->td_proc); td->td_retval[0] = td->td_proc->p_pptr->p_pid; PROC_UNLOCK(td->td_proc); return (0); } em = em_find(td->td_proc, EMUL_DONTLOCK); KASSERT(em != NULL, ("getppid: process emuldata not found.\n")); /* find the group leader */ p = pfind(em->shared->group_pid); if (p == NULL) { #ifdef DEBUG printf(LMSG("parent process not found.\n")); #endif return (0); } pp = p->p_pptr; /* switch to parent */ PROC_LOCK(pp); PROC_UNLOCK(p); /* if its also linux process */ if (pp->p_sysent == &elf_linux_sysvec) { em = em_find(pp, EMUL_DONTLOCK); KASSERT(em != NULL, ("getppid: parent emuldata not found.\n")); td->td_retval[0] = em->shared->group_pid; } else td->td_retval[0] = pp->p_pid; PROC_UNLOCK(pp); return (0); } int linux_getgid(struct thread *td, struct linux_getgid_args *args) { #ifdef DEBUG if (ldebug(getgid)) printf(ARGS(getgid, "")); #endif td->td_retval[0] = td->td_ucred->cr_rgid; return (0); } int linux_getuid(struct thread *td, struct linux_getuid_args *args) { #ifdef DEBUG if (ldebug(getuid)) printf(ARGS(getuid, "")); #endif td->td_retval[0] = td->td_ucred->cr_ruid; return (0); } int linux_getsid(struct thread *td, struct linux_getsid_args *args) { struct getsid_args bsd; #ifdef DEBUG if (ldebug(getsid)) printf(ARGS(getsid, "%i"), args->pid); #endif bsd.pid = args->pid; return (sys_getsid(td, &bsd)); } int linux_nosys(struct thread *td, struct nosys_args *ignore) { return (ENOSYS); } int linux_getpriority(struct thread *td, struct linux_getpriority_args *args) { struct getpriority_args bsd_args; int error; #ifdef DEBUG if (ldebug(getpriority)) printf(ARGS(getpriority, "%i, %i"), args->which, args->who); #endif bsd_args.which = args->which; bsd_args.who = args->who; error = sys_getpriority(td, &bsd_args); td->td_retval[0] = 20 - td->td_retval[0]; return (error); } int linux_sethostname(struct thread *td, struct linux_sethostname_args *args) { int name[2]; #ifdef DEBUG if (ldebug(sethostname)) printf(ARGS(sethostname, "*, %i"), args->len); #endif name[0] = CTL_KERN; name[1] = KERN_HOSTNAME; return (userland_sysctl(td, name, 2, 0, 0, 0, args->hostname, args->len, 0, 0)); } int linux_setdomainname(struct thread *td, struct linux_setdomainname_args *args) { int name[2]; #ifdef DEBUG if (ldebug(setdomainname)) printf(ARGS(setdomainname, "*, %i"), args->len); #endif name[0] = CTL_KERN; name[1] = KERN_NISDOMAINNAME; return (userland_sysctl(td, name, 2, 0, 0, 0, args->name, args->len, 0, 0)); } int linux_exit_group(struct thread *td, struct linux_exit_group_args *args) { struct linux_emuldata *em; #ifdef DEBUG if (ldebug(exit_group)) printf(ARGS(exit_group, "%i"), args->error_code); #endif em = em_find(td->td_proc, EMUL_DONTLOCK); if (em->shared->refs > 1) { EMUL_SHARED_WLOCK(&emul_shared_lock); em->shared->flags |= EMUL_SHARED_HASXSTAT; em->shared->xstat = W_EXITCODE(args->error_code, 0); EMUL_SHARED_WUNLOCK(&emul_shared_lock); if (linux_use26(td)) linux_kill_threads(td, SIGKILL); } /* * XXX: we should send a signal to the parent if * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?) * as it doesnt occur often. */ exit1(td, W_EXITCODE(args->error_code, 0)); return (0); } #define _LINUX_CAPABILITY_VERSION 0x19980330 struct l_user_cap_header { l_int version; l_int pid; }; struct l_user_cap_data { l_int effective; l_int permitted; l_int inheritable; }; int linux_capget(struct thread *td, struct linux_capget_args *args) { struct l_user_cap_header luch; struct l_user_cap_data lucd; int error; if (args->hdrp == NULL) return (EFAULT); error = copyin(args->hdrp, &luch, sizeof(luch)); if (error != 0) return (error); if (luch.version != _LINUX_CAPABILITY_VERSION) { luch.version = _LINUX_CAPABILITY_VERSION; error = copyout(&luch, args->hdrp, sizeof(luch)); if (error) return (error); return (EINVAL); } if (luch.pid) return (EPERM); if (args->datap) { /* * The current implementation doesn't support setting * a capability (it's essentially a stub) so indicate * that no capabilities are currently set or available * to request. */ bzero (&lucd, sizeof(lucd)); error = copyout(&lucd, args->datap, sizeof(lucd)); } return (error); } int linux_capset(struct thread *td, struct linux_capset_args *args) { struct l_user_cap_header luch; struct l_user_cap_data lucd; int error; if (args->hdrp == NULL || args->datap == NULL) return (EFAULT); error = copyin(args->hdrp, &luch, sizeof(luch)); if (error != 0) return (error); if (luch.version != _LINUX_CAPABILITY_VERSION) { luch.version = _LINUX_CAPABILITY_VERSION; error = copyout(&luch, args->hdrp, sizeof(luch)); if (error) return (error); return (EINVAL); } if (luch.pid) return (EPERM); error = copyin(args->datap, &lucd, sizeof(lucd)); if (error != 0) return (error); /* We currently don't support setting any capabilities. */ if (lucd.effective || lucd.permitted || lucd.inheritable) { linux_msg(td, "capset effective=0x%x, permitted=0x%x, " "inheritable=0x%x is not implemented", (int)lucd.effective, (int)lucd.permitted, (int)lucd.inheritable); return (EPERM); } return (0); } int linux_prctl(struct thread *td, struct linux_prctl_args *args) { int error = 0, max_size; struct proc *p = td->td_proc; char comm[LINUX_MAX_COMM_LEN]; struct linux_emuldata *em; int pdeath_signal; #ifdef DEBUG if (ldebug(prctl)) printf(ARGS(prctl, "%d, %d, %d, %d, %d"), args->option, args->arg2, args->arg3, args->arg4, args->arg5); #endif switch (args->option) { case LINUX_PR_SET_PDEATHSIG: if (!LINUX_SIG_VALID(args->arg2)) return (EINVAL); em = em_find(p, EMUL_DOLOCK); KASSERT(em != NULL, ("prctl: emuldata not found.\n")); em->pdeath_signal = args->arg2; EMUL_UNLOCK(&emul_lock); break; case LINUX_PR_GET_PDEATHSIG: em = em_find(p, EMUL_DOLOCK); KASSERT(em != NULL, ("prctl: emuldata not found.\n")); pdeath_signal = em->pdeath_signal; EMUL_UNLOCK(&emul_lock); error = copyout(&pdeath_signal, (void *)(register_t)args->arg2, sizeof(pdeath_signal)); break; case LINUX_PR_GET_KEEPCAPS: /* * Indicate that we always clear the effective and * permitted capability sets when the user id becomes * non-zero (actually the capability sets are simply * always zero in the current implementation). */ td->td_retval[0] = 0; break; case LINUX_PR_SET_KEEPCAPS: /* * Ignore requests to keep the effective and permitted * capability sets when the user id becomes non-zero. */ break; case LINUX_PR_SET_NAME: /* * To be on the safe side we need to make sure to not * overflow the size a linux program expects. We already * do this here in the copyin, so that we don't need to * check on copyout. */ max_size = MIN(sizeof(comm), sizeof(p->p_comm)); error = copyinstr((void *)(register_t)args->arg2, comm, max_size, NULL); /* Linux silently truncates the name if it is too long. */ if (error == ENAMETOOLONG) { /* * XXX: copyinstr() isn't documented to populate the * array completely, so do a copyin() to be on the * safe side. This should be changed in case * copyinstr() is changed to guarantee this. */ error = copyin((void *)(register_t)args->arg2, comm, max_size - 1); comm[max_size - 1] = '\0'; } if (error) return (error); PROC_LOCK(p); strlcpy(p->p_comm, comm, sizeof(p->p_comm)); PROC_UNLOCK(p); break; case LINUX_PR_GET_NAME: PROC_LOCK(p); strlcpy(comm, p->p_comm, sizeof(comm)); PROC_UNLOCK(p); error = copyout(comm, (void *)(register_t)args->arg2, strlen(comm) + 1); break; default: error = EINVAL; break; } return (error); } /* * Get affinity of a process. */ int linux_sched_getaffinity(struct thread *td, struct linux_sched_getaffinity_args *args) { int error; struct cpuset_getaffinity_args cga; #ifdef DEBUG if (ldebug(sched_getaffinity)) printf(ARGS(sched_getaffinity, "%d, %d, *"), args->pid, args->len); #endif if (args->len < sizeof(cpuset_t)) return (EINVAL); cga.level = CPU_LEVEL_WHICH; cga.which = CPU_WHICH_PID; cga.id = args->pid; cga.cpusetsize = sizeof(cpuset_t); cga.mask = (cpuset_t *) args->user_mask_ptr; if ((error = sys_cpuset_getaffinity(td, &cga)) == 0) td->td_retval[0] = sizeof(cpuset_t); return (error); } /* * Set affinity of a process. */ int linux_sched_setaffinity(struct thread *td, struct linux_sched_setaffinity_args *args) { struct cpuset_setaffinity_args csa; #ifdef DEBUG if (ldebug(sched_setaffinity)) printf(ARGS(sched_setaffinity, "%d, %d, *"), args->pid, args->len); #endif if (args->len < sizeof(cpuset_t)) return (EINVAL); csa.level = CPU_LEVEL_WHICH; csa.which = CPU_WHICH_PID; csa.id = args->pid; csa.cpusetsize = sizeof(cpuset_t); csa.mask = (cpuset_t *) args->user_mask_ptr; return (sys_cpuset_setaffinity(td, &csa)); } Index: stable/9/sys/compat/linux/linux_sysctl.c =================================================================== --- stable/9/sys/compat/linux/linux_sysctl.c (revision 246289) +++ stable/9/sys/compat/linux/linux_sysctl.c (revision 246290) @@ -1,143 +1,193 @@ /*- * Copyright (c) 2001 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" +#include "opt_kdtrace.h" #include +#include #include #include #include #include +#include #include #include #include #ifdef COMPAT_LINUX32 #include #include #else #include #include #endif +#include #include #define LINUX_CTL_KERN 1 #define LINUX_CTL_VM 2 #define LINUX_CTL_NET 3 #define LINUX_CTL_PROC 4 #define LINUX_CTL_FS 5 #define LINUX_CTL_DEBUG 6 #define LINUX_CTL_DEV 7 #define LINUX_CTL_BUS 8 /* CTL_KERN names */ #define LINUX_KERN_OSTYPE 1 #define LINUX_KERN_OSRELEASE 2 #define LINUX_KERN_OSREV 3 #define LINUX_KERN_VERSION 4 +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE2(sysctl, handle_string, entry, "struct l___sysctl_args *", + "char *"); +LIN_SDT_PROBE_DEFINE1(sysctl, handle_string, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE1(sysctl, handle_string, return, "int"); +LIN_SDT_PROBE_DEFINE2(sysctl, linux_sysctl, entry, "struct l___sysctl_args *", + "struct thread *"); +LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE2(sysctl, linux_sysctl, wrong_length, "int", "int"); +LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, unsupported_sysctl, "char *"); +LIN_SDT_PROBE_DEFINE1(sysctl, linux_sysctl, return, "int"); + static int handle_string(struct l___sysctl_args *la, char *value) { int error; + LIN_SDT_PROBE2(sysctl, handle_string, entry, la, value); + if (la->oldval != 0) { l_int len = strlen(value); error = copyout(value, PTRIN(la->oldval), len + 1); if (!error && la->oldlenp != 0) error = copyout(&len, PTRIN(la->oldlenp), sizeof(len)); - if (error) + if (error) { + LIN_SDT_PROBE1(sysctl, handle_string, copyout_error, + error); + LIN_SDT_PROBE1(sysctl, handle_string, return, error); return (error); + } } - if (la->newval != 0) + if (la->newval != 0) { + LIN_SDT_PROBE1(sysctl, handle_string, return, ENOTDIR); return (ENOTDIR); + } + LIN_SDT_PROBE1(sysctl, handle_string, return, 0); return (0); } int linux_sysctl(struct thread *td, struct linux_sysctl_args *args) { struct l___sysctl_args la; struct sbuf *sb; l_int *mib; + char *sysctl_string; int error, i; + LIN_SDT_PROBE2(sysctl, linux_sysctl, entry, td, args->args); + error = copyin(args->args, &la, sizeof(la)); - if (error) + if (error) { + LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error); + LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error); return (error); + } - if (la.nlen <= 0 || la.nlen > LINUX_CTL_MAXNAME) + if (la.nlen <= 0 || la.nlen > LINUX_CTL_MAXNAME) { + LIN_SDT_PROBE2(sysctl, linux_sysctl, wrong_length, la.nlen, + LINUX_CTL_MAXNAME); + LIN_SDT_PROBE1(sysctl, linux_sysctl, return, ENOTDIR); return (ENOTDIR); + } mib = malloc(la.nlen * sizeof(l_int), M_TEMP, M_WAITOK); error = copyin(PTRIN(la.name), mib, la.nlen * sizeof(l_int)); if (error) { + LIN_SDT_PROBE1(sysctl, linux_sysctl, copyin_error, error); + LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error); free(mib, M_TEMP); return (error); } switch (mib[0]) { case LINUX_CTL_KERN: if (la.nlen < 2) break; switch (mib[1]) { case LINUX_KERN_VERSION: error = handle_string(&la, version); free(mib, M_TEMP); + LIN_SDT_PROBE1(sysctl, linux_sysctl, return, error); return (error); default: break; } break; default: break; } sb = sbuf_new(NULL, NULL, 20 + la.nlen * 5, SBUF_AUTOEXTEND); if (sb == NULL) { linux_msg(td, "sysctl is not implemented"); + LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl, + "unknown sysctl, ENOMEM during lookup"); } else { sbuf_printf(sb, "sysctl "); for (i = 0; i < la.nlen; i++) sbuf_printf(sb, "%c%d", (i) ? ',' : '{', mib[i]); sbuf_printf(sb, "} is not implemented"); sbuf_finish(sb); + sysctl_string = sbuf_data(sb); linux_msg(td, "%s", sbuf_data(sb)); + LIN_SDT_PROBE1(sysctl, linux_sysctl, unsupported_sysctl, + sysctl_string); sbuf_delete(sb); } free(mib, M_TEMP); + + LIN_SDT_PROBE1(sysctl, linux_sysctl, return, ENOTDIR); return (ENOTDIR); } Index: stable/9/sys/compat/linux/linux_time.c =================================================================== --- stable/9/sys/compat/linux/linux_time.c (revision 246289) +++ stable/9/sys/compat/linux/linux_time.c (revision 246290) @@ -1,239 +1,416 @@ /* $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Emmanuel Dreyfus. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #if 0 __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $"); #endif #include "opt_compat.h" +#include "opt_kdtrace.h" #include +#include #include #include +#include #include #include #include #include #include #include #include #ifdef COMPAT_LINUX32 #include #include #else #include #include #endif +#include + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE2(time, native_to_linux_timespec, entry, + "struct l_timespec *", "struct timespec *"); +LIN_SDT_PROBE_DEFINE0(time, native_to_linux_timespec, return); +LIN_SDT_PROBE_DEFINE2(time, linux_to_native_timespec, entry, + "struct timespec *", "struct l_timespec *"); +LIN_SDT_PROBE_DEFINE1(time, linux_to_native_timespec, return, "int"); +LIN_SDT_PROBE_DEFINE2(time, linux_to_native_clockid, entry, "clockid_t *", + "clockid_t"); +LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid, + "clockid_t"); +LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid, + "clockid_t"); +LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, return, "int"); +LIN_SDT_PROBE_DEFINE2(time, linux_clock_gettime, entry, "clockid_t", + "struct l_timespec *"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, conversion_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, return, "int"); +LIN_SDT_PROBE_DEFINE2(time, linux_clock_settime, entry, "clockid_t", + "struct l_timespec *"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, settime_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, return, "int"); +LIN_SDT_PROBE_DEFINE2(time, linux_clock_getres, entry, "clockid_t", + "struct l_timespec *"); +LIN_SDT_PROBE_DEFINE0(time, linux_clock_getres, nullcall); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, conversion_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, getres_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, return, "int"); +LIN_SDT_PROBE_DEFINE2(time, linux_nanosleep, entry, "const struct l_timespec *", + "struct l_timespec *"); +LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, conversion_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, nanosleep_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, return, "int"); +LIN_SDT_PROBE_DEFINE4(time, linux_clock_nanosleep, entry, "clockid_t", "int", + "struct l_timespec *", "struct l_timespec *"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, conversion_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, nanosleep_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_flags, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_clockid, "int"); +LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, return, "int"); + static void native_to_linux_timespec(struct l_timespec *, struct timespec *); static int linux_to_native_timespec(struct timespec *, struct l_timespec *); static int linux_to_native_clockid(clockid_t *, clockid_t); static void native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp) { + + LIN_SDT_PROBE2(time, native_to_linux_timespec, entry, ltp, ntp); + ltp->tv_sec = ntp->tv_sec; ltp->tv_nsec = ntp->tv_nsec; + + LIN_SDT_PROBE0(time, native_to_linux_timespec, return); } static int linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp) { - if (ltp->tv_sec < 0 || ltp->tv_nsec > (l_long)999999999L) + + LIN_SDT_PROBE2(time, linux_to_native_timespec, entry, ntp, ltp); + + if (ltp->tv_sec < 0 || ltp->tv_nsec > (l_long)999999999L) { + LIN_SDT_PROBE1(time, linux_to_native_timespec, return, EINVAL); return (EINVAL); + } ntp->tv_sec = ltp->tv_sec; ntp->tv_nsec = ltp->tv_nsec; + LIN_SDT_PROBE1(time, linux_to_native_timespec, return, 0); return (0); } static int linux_to_native_clockid(clockid_t *n, clockid_t l) { + + LIN_SDT_PROBE2(time, linux_to_native_clockid, entry, n, l); + switch (l) { case LINUX_CLOCK_REALTIME: *n = CLOCK_REALTIME; break; case LINUX_CLOCK_MONOTONIC: *n = CLOCK_MONOTONIC; break; case LINUX_CLOCK_PROCESS_CPUTIME_ID: case LINUX_CLOCK_THREAD_CPUTIME_ID: case LINUX_CLOCK_REALTIME_HR: case LINUX_CLOCK_MONOTONIC_HR: + LIN_SDT_PROBE1(time, linux_to_native_clockid, + unsupported_clockid, l); + LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL); + return (EINVAL); + break; default: + LIN_SDT_PROBE1(time, linux_to_native_clockid, + unknown_clockid, l); + LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL); return (EINVAL); break; } + LIN_SDT_PROBE1(time, linux_to_native_clockid, return, 0); return (0); } int linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args) { struct l_timespec lts; int error; clockid_t nwhich = 0; /* XXX: GCC */ struct timespec tp; + LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp); + error = linux_to_native_clockid(&nwhich, args->which); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_gettime, conversion_error, + error); + LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); return (error); + } error = kern_clock_gettime(td, nwhich, &tp); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error); + LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); return (error); + } native_to_linux_timespec(<s, &tp); - return (copyout(<s, args->tp, sizeof lts)); + error = copyout(<s, args->tp, sizeof lts); + if (error != 0) + LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error); + + LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); + return (error); } int linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args) { struct timespec ts; struct l_timespec lts; int error; clockid_t nwhich = 0; /* XXX: GCC */ + LIN_SDT_PROBE2(time, linux_clock_settime, entry, args->which, args->tp); + error = linux_to_native_clockid(&nwhich, args->which); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error, + error); + LIN_SDT_PROBE1(time, linux_clock_settime, return, error); return (error); + } error = copyin(args->tp, <s, sizeof lts); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error); + LIN_SDT_PROBE1(time, linux_clock_settime, return, error); return (error); + } error = linux_to_native_timespec(&ts, <s); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error, + error); + LIN_SDT_PROBE1(time, linux_clock_settime, return, error); return (error); + } - return (kern_clock_settime(td, nwhich, &ts)); + error = kern_clock_settime(td, nwhich, &ts); + if (error != 0) + LIN_SDT_PROBE1(time, linux_clock_settime, settime_error, error); + + LIN_SDT_PROBE1(time, linux_clock_settime, return, error); + return (error); } int linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args) { struct timespec ts; struct l_timespec lts; int error; clockid_t nwhich = 0; /* XXX: GCC */ - if (args->tp == NULL) + LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp); + + if (args->tp == NULL) { + LIN_SDT_PROBE0(time, linux_clock_getres, nullcall); + LIN_SDT_PROBE1(time, linux_clock_getres, return, 0); return (0); + } error = linux_to_native_clockid(&nwhich, args->which); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error, + error); + LIN_SDT_PROBE1(time, linux_clock_getres, return, error); return (error); + } error = kern_clock_getres(td, nwhich, &ts); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error); + LIN_SDT_PROBE1(time, linux_clock_getres, return, error); return (error); + } native_to_linux_timespec(<s, &ts); - return (copyout(<s, args->tp, sizeof lts)); + error = copyout(<s, args->tp, sizeof lts); + if (error != 0) + LIN_SDT_PROBE1(time, linux_clock_getres, copyout_error, error); + + LIN_SDT_PROBE1(time, linux_clock_getres, return, error); + return (error); } int linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args) { struct timespec *rmtp; struct l_timespec lrqts, lrmts; struct timespec rqts, rmts; int error; + LIN_SDT_PROBE2(time, linux_nanosleep, entry, args->rqtp, args->rmtp); + error = copyin(args->rqtp, &lrqts, sizeof lrqts); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error); + LIN_SDT_PROBE1(time, linux_nanosleep, return, error); return (error); + } if (args->rmtp != NULL) rmtp = &rmts; else rmtp = NULL; error = linux_to_native_timespec(&rqts, &lrqts); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error); + LIN_SDT_PROBE1(time, linux_nanosleep, return, error); return (error); + } error = kern_nanosleep(td, &rqts, rmtp); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_nanosleep, nanosleep_error, error); + LIN_SDT_PROBE1(time, linux_nanosleep, return, error); return (error); + } if (args->rmtp != NULL) { native_to_linux_timespec(&lrmts, rmtp); error = copyout(&lrmts, args->rmtp, sizeof(lrmts)); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error, + error); + LIN_SDT_PROBE1(time, linux_nanosleep, return, error); return (error); + } } + LIN_SDT_PROBE1(time, linux_nanosleep, return, 0); return (0); } int linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args) { struct timespec *rmtp; struct l_timespec lrqts, lrmts; struct timespec rqts, rmts; int error; - if (args->flags != 0) + LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which, + args->flags, args->rqtp, args->rmtp); + + if (args->flags != 0) { + /* XXX deal with TIMER_ABSTIME */ + LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags, + args->flags); + LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL); return (EINVAL); /* XXX deal with TIMER_ABSTIME */ + } - if (args->which != LINUX_CLOCK_REALTIME) + if (args->which != LINUX_CLOCK_REALTIME) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid, + args->which); + LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL); return (EINVAL); + } error = copyin(args->rqtp, &lrqts, sizeof lrqts); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error, + error); + LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); return (error); + } if (args->rmtp != NULL) rmtp = &rmts; else rmtp = NULL; error = linux_to_native_timespec(&rqts, &lrqts); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error, + error); + LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); return (error); + } error = kern_nanosleep(td, &rqts, rmtp); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep, nanosleep_error, + error); + LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); return (error); + } if (args->rmtp != NULL) { native_to_linux_timespec(&lrmts, rmtp); error = copyout(&lrmts, args->rmtp, sizeof lrmts ); - if (error != 0) + if (error != 0) { + LIN_SDT_PROBE1(time, linux_clock_nanosleep, + copyout_error, error); + LIN_SDT_PROBE1(time, linux_nanosleep, return, error); return (error); + } } + LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, 0); return (0); } Index: stable/9/sys/compat/linux/linux_uid16.c =================================================================== --- stable/9/sys/compat/linux/linux_uid16.c (revision 246289) +++ stable/9/sys/compat/linux/linux_uid16.c (revision 246290) @@ -1,308 +1,441 @@ /*- * Copyright (c) 2001 The FreeBSD Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" +#include "opt_kdtrace.h" #include #include +#include #include #include #include #include #include +#include #include #include #include #ifdef COMPAT_LINUX32 #include #include #else #include #include #endif +#include #include +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE3(uid16, linux_chown16, entry, "char *", "l_uid16_t", + "l_gid16_t"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_chown16, conv_path, "char *"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_chown16, return, "int"); +LIN_SDT_PROBE_DEFINE3(uid16, linux_lchown16, entry, "char *", "l_uid16_t", + "l_gid16_t"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_lchown16, conv_path, "char *"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_lchown16, return, "int"); +LIN_SDT_PROBE_DEFINE2(uid16, linux_setgroups16, entry, "l_uint", "l_gid16_t *"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, priv_check_cred_error, "int"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setgroups16, return, "int"); +LIN_SDT_PROBE_DEFINE2(uid16, linux_getgroups16, entry, "l_uint", "l_gid16_t *"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_getgroups16, copyout_error, "int"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_getgroups16, return, "int"); +LIN_SDT_PROBE_DEFINE0(uid16, linux_getgid16, entry); +LIN_SDT_PROBE_DEFINE1(uid16, linux_getgid16, return, "int"); +LIN_SDT_PROBE_DEFINE0(uid16, linux_getuid16, entry); +LIN_SDT_PROBE_DEFINE1(uid16, linux_getuid16, return, "int"); +LIN_SDT_PROBE_DEFINE0(uid16, linux_getegid16, entry); +LIN_SDT_PROBE_DEFINE1(uid16, linux_getegid16, return, "int"); +LIN_SDT_PROBE_DEFINE0(uid16, linux_geteuid16, entry); +LIN_SDT_PROBE_DEFINE1(uid16, linux_geteuid16, return, "int"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setgid16, entry, "l_gid16_t"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setgid16, return, "int"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setuid16, entry, "l_uid16_t"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setuid16, return, "int"); +LIN_SDT_PROBE_DEFINE2(uid16, linux_setregid16, entry, "l_git16_t", "l_git16_t"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setregid16, return, "int"); +LIN_SDT_PROBE_DEFINE2(uid16, linux_setreuid16, entry, "l_uid16_t", "l_uid16_t"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setreuid16, return, "int"); +LIN_SDT_PROBE_DEFINE3(uid16, linux_setresgid16, entry, "l_gid16_t", "l_gid16_t", + "l_gid16_t"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setresgid16, return, "int"); +LIN_SDT_PROBE_DEFINE3(uid16, linux_setresuid16, entry, "l_uid16_t", "l_uid16_t", + "l_uid16_t"); +LIN_SDT_PROBE_DEFINE1(uid16, linux_setresuid16, return, "int"); + DUMMY(setfsuid16); DUMMY(setfsgid16); DUMMY(getresuid16); DUMMY(getresgid16); #define CAST_NOCHG(x) ((x == 0xFFFF) ? -1 : x) int linux_chown16(struct thread *td, struct linux_chown16_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); -#ifdef DEBUG - if (ldebug(chown16)) - printf(ARGS(chown16, "%s, %d, %d"), path, args->uid, args->gid); -#endif + /* + * The DTrace probes have to be after the LCONVPATHEXIST, as + * LCONVPATHEXIST may return on its own and we do not want to + * have a stray entry without the corresponding return. + */ + LIN_SDT_PROBE3(uid16, linux_chown16, entry, args->path, args->uid, + args->gid); + LIN_SDT_PROBE1(uid16, linux_chown16, conv_path, path); + error = kern_chown(td, path, UIO_SYSSPACE, CAST_NOCHG(args->uid), CAST_NOCHG(args->gid)); LFREEPATH(path); + + LIN_SDT_PROBE1(uid16, linux_chown16, return, error); return (error); } int linux_lchown16(struct thread *td, struct linux_lchown16_args *args) { char *path; int error; LCONVPATHEXIST(td, args->path, &path); -#ifdef DEBUG - if (ldebug(lchown16)) - printf(ARGS(lchown16, "%s, %d, %d"), path, args->uid, - args->gid); -#endif + /* + * The DTrace probes have to be after the LCONVPATHEXIST, as + * LCONVPATHEXIST may return on its own and we do not want to + * have a stray entry without the corresponding return. + */ + LIN_SDT_PROBE3(uid16, linux_lchown16, entry, args->path, args->uid, + args->gid); + LIN_SDT_PROBE1(uid16, linux_lchown16, conv_path, path); + error = kern_lchown(td, path, UIO_SYSSPACE, CAST_NOCHG(args->uid), CAST_NOCHG(args->gid)); LFREEPATH(path); + + LIN_SDT_PROBE1(uid16, linux_lchown16, return, error); return (error); } int linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args) { struct ucred *newcred, *oldcred; l_gid16_t *linux_gidset; gid_t *bsd_gidset; int ngrp, error; struct proc *p; -#ifdef DEBUG - if (ldebug(setgroups16)) - printf(ARGS(setgroups16, "%d, *"), args->gidsetsize); -#endif + LIN_SDT_PROBE2(uid16, linux_setgroups16, entry, args->gidsetsize, + args->gidset); ngrp = args->gidsetsize; - if (ngrp < 0 || ngrp >= ngroups_max + 1) + if (ngrp < 0 || ngrp >= ngroups_max + 1) { + LIN_SDT_PROBE1(uid16, linux_setgroups16, return, EINVAL); return (EINVAL); + } linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK); error = copyin(args->gidset, linux_gidset, ngrp * sizeof(l_gid16_t)); if (error) { + LIN_SDT_PROBE1(uid16, linux_setgroups16, copyin_error, error); + LIN_SDT_PROBE1(uid16, linux_setgroups16, return, error); free(linux_gidset, M_TEMP); return (error); } newcred = crget(); p = td->td_proc; PROC_LOCK(p); oldcred = crcopysafe(p, newcred); /* * cr_groups[0] holds egid. Setting the whole set from * the supplied set will cause egid to be changed too. * Keep cr_groups[0] unchanged to prevent that. */ if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0) { PROC_UNLOCK(p); crfree(newcred); + + LIN_SDT_PROBE1(uid16, linux_setgroups16, priv_check_cred_error, + error); goto out; } if (ngrp > 0) { newcred->cr_ngroups = ngrp + 1; bsd_gidset = newcred->cr_groups; ngrp--; while (ngrp >= 0) { bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; ngrp--; } } else newcred->cr_ngroups = 1; setsugid(td->td_proc); p->p_ucred = newcred; PROC_UNLOCK(p); crfree(oldcred); error = 0; out: free(linux_gidset, M_TEMP); + + LIN_SDT_PROBE1(uid16, linux_setgroups16, return, error); return (error); } int linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args) { struct ucred *cred; l_gid16_t *linux_gidset; gid_t *bsd_gidset; int bsd_gidsetsz, ngrp, error; -#ifdef DEBUG - if (ldebug(getgroups16)) - printf(ARGS(getgroups16, "%d, *"), args->gidsetsize); -#endif + LIN_SDT_PROBE2(uid16, linux_getgroups16, entry, args->gidsetsize, + args->gidset); cred = td->td_ucred; bsd_gidset = cred->cr_groups; bsd_gidsetsz = cred->cr_ngroups - 1; /* * cr_groups[0] holds egid. Returning the whole set * here will cause a duplicate. Exclude cr_groups[0] * to prevent that. */ if ((ngrp = args->gidsetsize) == 0) { td->td_retval[0] = bsd_gidsetsz; + + LIN_SDT_PROBE1(uid16, linux_getgroups16, return, 0); return (0); } - if (ngrp < bsd_gidsetsz) + if (ngrp < bsd_gidsetsz) { + LIN_SDT_PROBE1(uid16, linux_getgroups16, return, EINVAL); return (EINVAL); + } ngrp = 0; linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), M_TEMP, M_WAITOK); while (ngrp < bsd_gidsetsz) { linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; ngrp++; } error = copyout(linux_gidset, args->gidset, ngrp * sizeof(l_gid16_t)); free(linux_gidset, M_TEMP); - if (error) + if (error) { + LIN_SDT_PROBE1(uid16, linux_getgroups16, copyout_error, error); + LIN_SDT_PROBE1(uid16, linux_getgroups16, return, error); return (error); + } td->td_retval[0] = ngrp; + + LIN_SDT_PROBE1(uid16, linux_getgroups16, return, 0); return (0); } /* * The FreeBSD native getgid(2) and getuid(2) also modify td->td_retval[1] * when COMPAT_43 is defined. This clobbers registers that are assumed to * be preserved. The following lightweight syscalls fixes this. See also * linux_getpid(2), linux_getgid(2) and linux_getuid(2) in linux_misc.c * * linux_getgid16() - MP SAFE * linux_getuid16() - MP SAFE */ int linux_getgid16(struct thread *td, struct linux_getgid16_args *args) { + LIN_SDT_PROBE0(uid16, linux_getgid16, entry); + td->td_retval[0] = td->td_ucred->cr_rgid; + + LIN_SDT_PROBE1(uid16, linux_getgid16, return, 0); return (0); } int linux_getuid16(struct thread *td, struct linux_getuid16_args *args) { + LIN_SDT_PROBE0(uid16, linux_getuid16, entry); + td->td_retval[0] = td->td_ucred->cr_ruid; + + LIN_SDT_PROBE1(uid16, linux_getuid16, return, 0); return (0); } int linux_getegid16(struct thread *td, struct linux_getegid16_args *args) { struct getegid_args bsd; + int error; - return (sys_getegid(td, &bsd)); + LIN_SDT_PROBE0(uid16, linux_getegid16, entry); + + error = sys_getegid(td, &bsd); + + LIN_SDT_PROBE1(uid16, linux_getegid16, return, error); + return (error); } int linux_geteuid16(struct thread *td, struct linux_geteuid16_args *args) { struct geteuid_args bsd; + int error; - return (sys_geteuid(td, &bsd)); + LIN_SDT_PROBE0(uid16, linux_geteuid16, entry); + + error = sys_geteuid(td, &bsd); + + LIN_SDT_PROBE1(uid16, linux_geteuid16, return, error); + return (error); } int linux_setgid16(struct thread *td, struct linux_setgid16_args *args) { struct setgid_args bsd; + int error; + LIN_SDT_PROBE1(uid16, linux_setgid16, entry, args->gid); + bsd.gid = args->gid; - return (sys_setgid(td, &bsd)); + error = sys_setgid(td, &bsd); + + LIN_SDT_PROBE1(uid16, linux_setgid16, return, error); + return (error); } int linux_setuid16(struct thread *td, struct linux_setuid16_args *args) { struct setuid_args bsd; + int error; + LIN_SDT_PROBE1(uid16, linux_setuid16, entry, args->uid); + bsd.uid = args->uid; - return (sys_setuid(td, &bsd)); + error = sys_setuid(td, &bsd); + + LIN_SDT_PROBE1(uid16, linux_setuid16, return, error); + return (error); } int linux_setregid16(struct thread *td, struct linux_setregid16_args *args) { struct setregid_args bsd; + int error; + LIN_SDT_PROBE2(uid16, linux_setregid16, entry, args->rgid, args->egid); + bsd.rgid = CAST_NOCHG(args->rgid); bsd.egid = CAST_NOCHG(args->egid); - return (sys_setregid(td, &bsd)); + error = sys_setregid(td, &bsd); + + LIN_SDT_PROBE1(uid16, linux_setregid16, return, error); + return (error); } int linux_setreuid16(struct thread *td, struct linux_setreuid16_args *args) { struct setreuid_args bsd; + int error; + LIN_SDT_PROBE2(uid16, linux_setreuid16, entry, args->ruid, args->euid); + bsd.ruid = CAST_NOCHG(args->ruid); bsd.euid = CAST_NOCHG(args->euid); - return (sys_setreuid(td, &bsd)); + error = sys_setreuid(td, &bsd); + + LIN_SDT_PROBE1(uid16, linux_setreuid16, return, error); + return (error); } int linux_setresgid16(struct thread *td, struct linux_setresgid16_args *args) { struct setresgid_args bsd; + int error; + LIN_SDT_PROBE3(uid16, linux_setresgid16, entry, args->rgid, args->egid, + args->sgid); + bsd.rgid = CAST_NOCHG(args->rgid); bsd.egid = CAST_NOCHG(args->egid); bsd.sgid = CAST_NOCHG(args->sgid); - return (sys_setresgid(td, &bsd)); + error = sys_setresgid(td, &bsd); + + LIN_SDT_PROBE1(uid16, linux_setresgid16, return, error); + return (error); } int linux_setresuid16(struct thread *td, struct linux_setresuid16_args *args) { struct setresuid_args bsd; + int error; + LIN_SDT_PROBE3(uid16, linux_setresuid16, entry, args->ruid, args->euid, + args->suid); + bsd.ruid = CAST_NOCHG(args->ruid); bsd.euid = CAST_NOCHG(args->euid); bsd.suid = CAST_NOCHG(args->suid); - return (sys_setresuid(td, &bsd)); + error = sys_setresuid(td, &bsd); + + LIN_SDT_PROBE1(uid16, linux_setresuid16, return, error); + return (error); } Index: stable/9/sys/compat/linux/linux_util.c =================================================================== --- stable/9/sys/compat/linux/linux_util.c (revision 246289) +++ stable/9/sys/compat/linux/linux_util.c (revision 246290) @@ -1,243 +1,333 @@ /*- * Copyright (c) 1994 Christos Zoulas * Copyright (c) 1995 Frank van der Linden * Copyright (c) 1995 Scott Bartram * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" +#include "opt_kdtrace.h" #include #include #include #include #include +#include #include #include #include #include +#include #include #include #include #include #include #ifdef COMPAT_LINUX32 #include #else #include #endif +#include + const char linux_emul_path[] = "/compat/linux"; +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/** + * DTrace probes in this module. + */ +LIN_SDT_PROBE_DEFINE5(util, linux_emul_convpath, entry, "const char *", + "enum uio_seg", "char **", "int", "int"); +LIN_SDT_PROBE_DEFINE1(util, linux_emul_convpath, return, "int"); +LIN_SDT_PROBE_DEFINE1(util, linux_msg, entry, "const char *"); +LIN_SDT_PROBE_DEFINE0(util, linux_msg, return); +LIN_SDT_PROBE_DEFINE2(util, linux_driver_get_name_dev, entry, "device_t", + "const char *"); +LIN_SDT_PROBE_DEFINE0(util, linux_driver_get_name_dev, nullcall); +LIN_SDT_PROBE_DEFINE1(util, linux_driver_get_name_dev, return, "char *"); +LIN_SDT_PROBE_DEFINE3(util, linux_driver_get_major_minor, entry, "char *", + "int *", "int *"); +LIN_SDT_PROBE_DEFINE0(util, linux_driver_get_major_minor, nullcall); +LIN_SDT_PROBE_DEFINE1(util, linux_driver_get_major_minor, notfound, "char *"); +LIN_SDT_PROBE_DEFINE3(util, linux_driver_get_major_minor, return, "int", + "int", "int"); +LIN_SDT_PROBE_DEFINE0(util, linux_get_char_devices, entry); +LIN_SDT_PROBE_DEFINE1(util, linux_get_char_devices, return, "char *"); +LIN_SDT_PROBE_DEFINE1(util, linux_free_get_char_devices, entry, "char *"); +LIN_SDT_PROBE_DEFINE0(util, linux_free_get_char_devices, return); +LIN_SDT_PROBE_DEFINE1(util, linux_device_register_handler, entry, + "struct linux_device_handler *"); +LIN_SDT_PROBE_DEFINE1(util, linux_device_register_handler, return, "int"); +LIN_SDT_PROBE_DEFINE1(util, linux_device_unregister_handler, entry, + "struct linux_device_handler *"); +LIN_SDT_PROBE_DEFINE1(util, linux_device_unregister_handler, return, "int"); + /* * Search an alternate path before passing pathname arguments on to * system calls. Useful for keeping a separate 'emulation tree'. * * If cflag is set, we check if an attempt can be made to create the * named file, i.e. we check if the directory it should be in exists. */ int -linux_emul_convpath(td, path, pathseg, pbuf, cflag, dfd) - struct thread *td; - const char *path; - enum uio_seg pathseg; - char **pbuf; - int cflag; - int dfd; +linux_emul_convpath(struct thread *td, const char *path, enum uio_seg pathseg, + char **pbuf, int cflag, int dfd) { + int retval; - return (kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf, - cflag, dfd)); + LIN_SDT_PROBE5(util, linux_emul_convpath, entry, path, pathseg, pbuf, + cflag, dfd); + + retval = kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf, + cflag, dfd); + + LIN_SDT_PROBE1(util, linux_emul_convpath, return, retval); + return (retval); } void linux_msg(const struct thread *td, const char *fmt, ...) { va_list ap; struct proc *p; + LIN_SDT_PROBE1(util, linux_msg, entry, fmt); + p = td->td_proc; printf("linux: pid %d (%s): ", (int)p->p_pid, p->p_comm); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); + + LIN_SDT_PROBE0(util, linux_msg, return); } struct device_element { TAILQ_ENTRY(device_element) list; struct linux_device_handler entry; }; static TAILQ_HEAD(, device_element) devices = TAILQ_HEAD_INITIALIZER(devices); static struct linux_device_handler null_handler = { "mem", "mem", "null", "null", 1, 3, 1}; DATA_SET(linux_device_handler_set, null_handler); char * linux_driver_get_name_dev(device_t dev) { struct device_element *de; const char *device_name = device_get_name(dev); - if (device_name == NULL) + LIN_SDT_PROBE2(util, linux_driver_get_name_dev, entry, dev, + device_name); + + if (device_name == NULL) { + LIN_SDT_PROBE0(util, linux_driver_get_name_dev, nullcall); + LIN_SDT_PROBE1(util, linux_driver_get_name_dev, return, NULL); return NULL; + } TAILQ_FOREACH(de, &devices, list) { - if (strcmp(device_name, de->entry.bsd_driver_name) == 0) + if (strcmp(device_name, de->entry.bsd_driver_name) == 0) { + LIN_SDT_PROBE1(util, linux_driver_get_name_dev, return, + de->entry.linux_driver_name); return (de->entry.linux_driver_name); + } } + LIN_SDT_PROBE1(util, linux_driver_get_name_dev, return, NULL); return NULL; } int linux_driver_get_major_minor(const char *node, int *major, int *minor) { struct device_element *de; - if (node == NULL || major == NULL || minor == NULL) + LIN_SDT_PROBE3(util, linux_driver_get_major_minor, entry, node, major, + minor); + + if (node == NULL || major == NULL || minor == NULL) { + LIN_SDT_PROBE0(util, linux_driver_get_major_minor, nullcall); + LIN_SDT_PROBE3(util, linux_driver_get_major_minor, return, 1, + 0, 0); return 1; + } if (strlen(node) > strlen("pts/") && strncmp(node, "pts/", strlen("pts/")) == 0) { unsigned long devno; /* * Linux checks major and minors of the slave device * to make sure it's a pty device, so let's make him * believe it is. */ devno = strtoul(node + strlen("pts/"), NULL, 10); *major = 136 + (devno / 256); *minor = devno % 256; + + LIN_SDT_PROBE3(util, linux_driver_get_major_minor, return, 0, + *major, *minor); return 0; } TAILQ_FOREACH(de, &devices, list) { if (strcmp(node, de->entry.bsd_device_name) == 0) { *major = de->entry.linux_major; *minor = de->entry.linux_minor; + + LIN_SDT_PROBE3(util, linux_driver_get_major_minor, + return, 0, *major, *minor); return 0; } } + LIN_SDT_PROBE1(util, linux_driver_get_major_minor, notfound, node); + LIN_SDT_PROBE3(util, linux_driver_get_major_minor, return, 1, 0, 0); return 1; } char * linux_get_char_devices() { struct device_element *de; char *temp, *string, *last; char formated[256]; int current_size = 0, string_size = 1024; + LIN_SDT_PROBE0(util, linux_get_char_devices, entry); + string = malloc(string_size, M_LINUX, M_WAITOK); string[0] = '\000'; last = ""; TAILQ_FOREACH(de, &devices, list) { if (!de->entry.linux_char_device) continue; temp = string; if (strcmp(last, de->entry.bsd_driver_name) != 0) { last = de->entry.bsd_driver_name; snprintf(formated, sizeof(formated), "%3d %s\n", de->entry.linux_major, de->entry.linux_device_name); if (strlen(formated) + current_size >= string_size) { string_size *= 2; string = malloc(string_size, M_LINUX, M_WAITOK); bcopy(temp, string, current_size); free(temp, M_LINUX); } strcat(string, formated); current_size = strlen(string); } } + LIN_SDT_PROBE1(util, linux_get_char_devices, return, string); return string; } void linux_free_get_char_devices(char *string) { + + LIN_SDT_PROBE1(util, linux_get_char_devices, entry, string); + free(string, M_LINUX); + + LIN_SDT_PROBE0(util, linux_get_char_devices, return); } static int linux_major_starting = 200; int linux_device_register_handler(struct linux_device_handler *d) { struct device_element *de; - if (d == NULL) + LIN_SDT_PROBE1(util, linux_device_register_handler, entry, d); + + if (d == NULL) { + LIN_SDT_PROBE1(util, linux_device_register_handler, return, + EINVAL); return (EINVAL); + } - de = malloc(sizeof(*de), - M_LINUX, M_WAITOK); + de = malloc(sizeof(*de), M_LINUX, M_WAITOK); if (d->linux_major < 0) { d->linux_major = linux_major_starting++; } bcopy(d, &de->entry, sizeof(*d)); /* Add the element to the list, sorted on span. */ TAILQ_INSERT_TAIL(&devices, de, list); + LIN_SDT_PROBE1(util, linux_device_register_handler, return, 0); return (0); } int linux_device_unregister_handler(struct linux_device_handler *d) { struct device_element *de; - if (d == NULL) + LIN_SDT_PROBE1(util, linux_device_unregister_handler, entry, d); + + if (d == NULL) { + LIN_SDT_PROBE1(util, linux_device_unregister_handler, return, + EINVAL); return (EINVAL); + } TAILQ_FOREACH(de, &devices, list) { if (bcmp(d, &de->entry, sizeof(*d)) == 0) { TAILQ_REMOVE(&devices, de, list); free(de, M_LINUX); + + LIN_SDT_PROBE1(util, linux_device_unregister_handler, + return, 0); return (0); } } + LIN_SDT_PROBE1(util, linux_device_unregister_handler, return, EINVAL); return (EINVAL); } Index: stable/9/sys/compat/linux/linux_util.h =================================================================== --- stable/9/sys/compat/linux/linux_util.h (revision 246289) +++ stable/9/sys/compat/linux/linux_util.h (revision 246290) @@ -1,133 +1,141 @@ /*- * Copyright (c) 1994 Christos Zoulas * Copyright (c) 1995 Frank van der Linden * Copyright (c) 1995 Scott Bartram * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * from: svr4_util.h,v 1.5 1994/11/18 02:54:31 christos Exp * from: linux_util.h,v 1.2 1995/03/05 23:23:50 fvdl Exp * $FreeBSD$ */ #ifndef _LINUX_UTIL_H_ #define _LINUX_UTIL_H_ #include #include #include #include #include #include #include #include #include extern const char linux_emul_path[]; int linux_emul_convpath(struct thread *, const char *, enum uio_seg, char **, int, int); #define LCONVPATH_AT(td, upath, pathp, i, dfd) \ do { \ int _error; \ \ _error = linux_emul_convpath(td, upath, UIO_USERSPACE, \ pathp, i, dfd); \ if (*(pathp) == NULL) \ return (_error); \ } while (0) #define LCONVPATH(td, upath, pathp, i) \ LCONVPATH_AT(td, upath, pathp, i, AT_FDCWD) #define LCONVPATHEXIST(td, upath, pathp) LCONVPATH(td, upath, pathp, 0) #define LCONVPATHEXIST_AT(td, upath, pathp, dfd) LCONVPATH_AT(td, upath, pathp, 0, dfd) #define LCONVPATHCREAT(td, upath, pathp) LCONVPATH(td, upath, pathp, 1) #define LCONVPATHCREAT_AT(td, upath, pathp, dfd) LCONVPATH_AT(td, upath, pathp, 1, dfd) #define LFREEPATH(path) free(path, M_TEMP) #define DUMMY(s) \ +LIN_SDT_PROBE_DEFINE0(dummy, s, entry); \ +LIN_SDT_PROBE_DEFINE0(dummy, s, not_implemented); \ +LIN_SDT_PROBE_DEFINE1(dummy, s, return, "int"); \ int \ linux_ ## s(struct thread *td, struct linux_ ## s ## _args *args) \ { \ static pid_t pid; \ \ + LIN_SDT_PROBE0(dummy, s, entry); \ + \ if (pid != td->td_proc->p_pid) { \ linux_msg(td, "syscall %s not implemented", #s); \ + LIN_SDT_PROBE0(dummy, s, not_implemented); \ pid = td->td_proc->p_pid; \ }; \ + \ + LIN_SDT_PROBE1(dummy, s, return, ENOSYS); \ return (ENOSYS); \ } \ struct __hack void linux_msg(const struct thread *td, const char *fmt, ...) __printflike(2, 3); struct linux_device_handler { char *bsd_driver_name; char *linux_driver_name; char *bsd_device_name; char *linux_device_name; int linux_major; int linux_minor; int linux_char_device; }; int linux_device_register_handler(struct linux_device_handler *h); int linux_device_unregister_handler(struct linux_device_handler *h); char *linux_driver_get_name_dev(device_t dev); int linux_driver_get_major_minor(const char *node, int *major, int *minor); char *linux_get_char_devices(void); void linux_free_get_char_devices(char *string); #if defined(KTR) #define KTR_LINUX KTR_SUBSYS #define LINUX_CTRFMT(nm, fmt) #nm"("fmt")" #define LINUX_CTR6(f, m, p1, p2, p3, p4, p5, p6) do { \ if (ldebug(f)) \ CTR6(KTR_LINUX, LINUX_CTRFMT(f, m), \ p1, p2, p3, p4, p5, p6); \ } while (0) #define LINUX_CTR(f) LINUX_CTR6(f, "", 0, 0, 0, 0, 0, 0) #define LINUX_CTR0(f, m) LINUX_CTR6(f, m, 0, 0, 0, 0, 0, 0) #define LINUX_CTR1(f, m, p1) LINUX_CTR6(f, m, p1, 0, 0, 0, 0, 0) #define LINUX_CTR2(f, m, p1, p2) LINUX_CTR6(f, m, p1, p2, 0, 0, 0, 0) #define LINUX_CTR3(f, m, p1, p2, p3) LINUX_CTR6(f, m, p1, p2, p3, 0, 0, 0) #define LINUX_CTR4(f, m, p1, p2, p3, p4) LINUX_CTR6(f, m, p1, p2, p3, p4, 0, 0) #define LINUX_CTR5(f, m, p1, p2, p3, p4, p5) LINUX_CTR6(f, m, p1, p2, p3, p4, p5, 0) #else #define LINUX_CTR(f) #define LINUX_CTR0(f, m) #define LINUX_CTR1(f, m, p1) #define LINUX_CTR2(f, m, p1, p2) #define LINUX_CTR3(f, m, p1, p2, p3) #define LINUX_CTR4(f, m, p1, p2, p3, p4) #define LINUX_CTR5(f, m, p1, p2, p3, p4, p5) #define LINUX_CTR6(f, m, p1, p2, p3, p4, p5, p6) #endif #endif /* !_LINUX_UTIL_H_ */ Index: stable/9/sys/compat/linux/stats_timing.d =================================================================== --- stable/9/sys/compat/linux/stats_timing.d (nonexistent) +++ stable/9/sys/compat/linux/stats_timing.d (revision 246290) @@ -0,0 +1,94 @@ +#!/usr/sbin/dtrace -qs + +/*- + * Copyright (c) 2008-2012 Alexander Leidinger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/** + * Some statistics (all per provider): + * - number of calls to a function per executable binary (not per PID!) + * - allows to see where an optimization would be beneficial for a given + * application + * - graph of CPU time spend in functions per executable binary + * - together with the number of calls to this function this allows + * to determine if a kernel optimization would be beneficial / is + * possible for a given application + * - graph of longest running (CPU-time!) function in total + * - may help finding problem cases in the kernel code + * - timing statistics for the emul_lock + * - graph of longest held (CPU-time!) locks + */ + +#pragma D option dynvarsize=32m + +linuxulator*:::entry +{ + self->time[probefunc] = vtimestamp; + @calls[probeprov, execname, probefunc] = count(); +} + +linuxulator*:::return +/self->time[probefunc] != 0/ +{ + this->timediff = self->time[probefunc] - vtimestamp; + + @stats[probeprov, execname, probefunc] = quantize(this->timediff); + @longest[probeprov, probefunc] = max(this->timediff); + + self->time[probefunc] = 0; +} + +linuxulator*:::locked +{ + self->lock[arg0] = vtimestamp; +} + +linuxulator*:::unlock +/self->lock[arg0] != 0/ +{ + this->timediff = self->lock[arg0] - vtimestamp; + + @lockstats[probefunc] = quantize(this->timediff); + @longlock[probefunc] = max(this->timediff); + + self->lock[arg0] = 0; +} + +END +{ + printf("Number of calls per provider/application/kernel function:"); + printa(@calls); + printf("CPU-timing statistics per provider/application/kernel function (in ns):"); + printa(@stats); + printf("Longest running (CPU-time!) functions per provider (in ns):"); + printa(@longest); + printf("Lock CPU-timing statistics:"); + printa(@lockstats); + printf("Longest running (CPU-time!) locks:"); + printa(@longlock); +} + Property changes on: stable/9/sys/compat/linux/stats_timing.d ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/9/sys/compat/linux/trace_futexes.d =================================================================== --- stable/9/sys/compat/linux/trace_futexes.d (nonexistent) +++ stable/9/sys/compat/linux/trace_futexes.d (revision 246290) @@ -0,0 +1,182 @@ +#!/usr/sbin/dtrace -qs + +/*- + * Copyright (c) 2011-2012 Alexander Leidinger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/** + * Trace futex operations: + * - internal locks + * - size of the futex list + * - report error conditions (emulation errors, kernel errors, + * programming errors) + * - execution time (wallclock) of futex related functions + */ + +#pragma D option specsize=32m + +/* Error conditions */ +linuxulator*:futex:futex_get:error, +linuxulator*:futex:futex_sleep:requeue_error, +linuxulator*:futex:futex_sleep:sleep_error, +linuxulator*:futex:futex_wait:copyin_error, +linuxulator*:futex:futex_wait:itimerfix_error, +linuxulator*:futex:futex_wait:sleep_error, +linuxulator*:futex:futex_atomic_op:missing_access_check, +linuxulator*:futex:futex_atomic_op:unimplemented_op, +linuxulator*:futex:futex_atomic_op:unimplemented_cmp, +linuxulator*:futex:linux_sys_futex:unimplemented_clockswitch, +linuxulator*:futex:linux_sys_futex:copyin_error, +linuxulator*:futex:linux_sys_futex:unhandled_efault, +linuxulator*:futex:linux_sys_futex:unimplemented_lock_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_unlock_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_trylock_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_wait_requeue_pi, +linuxulator*:futex:linux_sys_futex:unimplemented_cmp_requeue_pi, +linuxulator*:futex:linux_sys_futex:unknown_operation, +linuxulator*:futex:linux_get_robust_list:copyout_error, +linuxulator*:futex:handle_futex_death:copyin_error, +linuxulator*:futex:fetch_robust_entry:copyin_error, +linuxulator*:futex:release_futexes:copyin_error +{ + printf("ERROR: %s in %s:%s:%s\n", probename, probeprov, probemod, + probefunc); + stack(); + ustack(); +} + +linuxulator*:futex:linux_sys_futex:invalid_cmp_requeue_use, +linuxulator*:futex:linux_sys_futex:deprecated_requeue, +linuxulator*:futex:linux_set_robust_list:size_error +{ + printf("WARNING: %s:%s:%s:%s in application %s, maybe an application error?\n", + probename, probeprov, probemod, probefunc, execname); + stack(); + ustack(); +} + + +/* Per futex checks/statistics */ + +linuxulator*:futex:futex:create +{ + ++futex_count; + @max_futexes = max(futex_count); +} + +linuxulator*:futex:futex:destroy +/futex_count == 0/ +{ + printf("ERROR: Request to destroy a futex which was not created,\n"); + printf(" or this script was started after some futexes where\n"); + printf(" created. Stack trace:\n"); + stack(); + ustack(); +} + +linuxulator*:futex:futex:destroy +{ + --futex_count; +} + + +/* Internal locks */ + +linuxulator*:locks:futex_mtx:locked +{ + ++check[probefunc, arg0]; + @stats[probefunc] = count(); + + ts[probefunc] = timestamp; + spec[probefunc] = speculation(); + printf("Stacktrace of last lock operation of the %s:\n", probefunc); + stack(); +} + +linuxulator*:locks:futex_mtx:unlock +/check[probefunc, arg0] == 0/ +{ + printf("ERROR: unlock attemt of unlocked %s (%p),", probefunc, arg0); + printf(" missing SDT probe in kernel, or dtrace program started"); + printf(" while the %s was already held (race condition).", probefunc); + printf(" Stack trace follows:"); + stack(); +} + +linuxulator*:locks:futex_mtx:unlock +{ + discard(spec[probefunc]); + spec[probefunc] = 0; + --check[probefunc, arg0]; +} + +/* Timeout handling for internal locks */ + +tick-10s +/spec["futex_mtx"] != 0 && timestamp - ts["futex_mtx"] >= 9999999000/ +{ + commit(spec["futex_mtx"]); + spec["futex_mtx"] = 0; +} + + +/* Timing statistings */ + +linuxulator*:futex::entry +{ + self->time[probefunc] = timestamp; + @calls[probeprov, execname, probefunc] = count(); +} + +linuxulator*:futex::return +/self->time[probefunc] != 0/ +{ + this->timediff = self->time[probefunc] - timestamp; + + @timestats[probeprov, execname, probefunc] = quantize(this->timediff); + @longest[probeprov, probefunc] = max(this->timediff); + + self->time[probefunc] = 0; +} + + +/* Statistics */ + +END +{ + printf("Number of locks per type:"); + printa(@stats); + printf("Number of maximum number of futexes in the futex list:"); + printa(@max_futexes); + printf("Number of futexes still existing: %d", futex_count); + printf("Number of calls per provider/application/kernel function:"); + printa(@calls); + printf("Wallclock-timing statistics per provider/application/kernel function (in ns):"); + printa(@timestats); + printf("Longest running (wallclock!) functions per provider (in ns):"); + printa(@longest); +} Property changes on: stable/9/sys/compat/linux/trace_futexes.d ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/9/sys/i386/linux/linux.h =================================================================== --- stable/9/sys/i386/linux/linux.h (revision 246289) +++ stable/9/sys/i386/linux/linux.h (revision 246290) @@ -1,900 +1,901 @@ /*- * Copyright (c) 1994-1996 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _I386_LINUX_H_ #define _I386_LINUX_H_ #include /* for sigval union */ #include /* * debugging support */ extern u_char linux_debug_map[]; #define ldebug(name) isclr(linux_debug_map, LINUX_SYS_linux_ ## name) #define ARGS(nm, fmt) "linux(%ld): "#nm"("fmt")\n", (long)td->td_proc->p_pid #define LMSG(fmt) "linux(%ld): "fmt"\n", (long)td->td_proc->p_pid +#define LINUX_DTRACE linuxulator #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_LINUX); #endif #define LINUX_SHAREDPAGE (VM_MAXUSER_ADDRESS - PAGE_SIZE) #define LINUX_USRSTACK LINUX_SHAREDPAGE #define PTRIN(v) (void *)(v) #define PTROUT(v) (l_uintptr_t)(v) /* * Provide a separate set of types for the Linux types. */ typedef int l_int; typedef int32_t l_long; typedef int64_t l_longlong; typedef short l_short; typedef unsigned int l_uint; typedef uint32_t l_ulong; typedef uint64_t l_ulonglong; typedef unsigned short l_ushort; typedef char *l_caddr_t; typedef l_ulong l_uintptr_t; typedef l_long l_clock_t; typedef l_int l_daddr_t; typedef l_ushort l_dev_t; typedef l_uint l_gid_t; typedef l_ushort l_gid16_t; typedef l_ulong l_ino_t; typedef l_int l_key_t; typedef l_longlong l_loff_t; typedef l_ushort l_mode_t; typedef l_long l_off_t; typedef l_int l_pid_t; typedef l_uint l_size_t; typedef l_long l_suseconds_t; typedef l_long l_time_t; typedef l_uint l_uid_t; typedef l_ushort l_uid16_t; typedef l_int l_timer_t; typedef l_int l_mqd_t; typedef struct { l_int val[2]; } l_fsid_t; typedef struct { l_time_t tv_sec; l_suseconds_t tv_usec; } l_timeval; #define l_fd_set fd_set /* * Miscellaneous */ #define LINUX_NAME_MAX 255 #define LINUX_MAX_UTSNAME 65 #define LINUX_CTL_MAXNAME 10 #define LINUX_AT_COUNT 16 /* Count of used aux entry types. * Keep this synchronized with * elf_linux_fixup() code. */ struct l___sysctl_args { l_int *name; l_int nlen; void *oldval; l_size_t *oldlenp; void *newval; l_size_t newlen; l_ulong __spare[4]; }; /* Scheduling policies */ #define LINUX_SCHED_OTHER 0 #define LINUX_SCHED_FIFO 1 #define LINUX_SCHED_RR 2 /* Resource limits */ #define LINUX_RLIMIT_CPU 0 #define LINUX_RLIMIT_FSIZE 1 #define LINUX_RLIMIT_DATA 2 #define LINUX_RLIMIT_STACK 3 #define LINUX_RLIMIT_CORE 4 #define LINUX_RLIMIT_RSS 5 #define LINUX_RLIMIT_NPROC 6 #define LINUX_RLIMIT_NOFILE 7 #define LINUX_RLIMIT_MEMLOCK 8 #define LINUX_RLIMIT_AS 9 /* Address space limit */ #define LINUX_RLIM_NLIMITS 10 struct l_rlimit { l_ulong rlim_cur; l_ulong rlim_max; }; /* mmap options */ #define LINUX_MAP_SHARED 0x0001 #define LINUX_MAP_PRIVATE 0x0002 #define LINUX_MAP_FIXED 0x0010 #define LINUX_MAP_ANON 0x0020 #define LINUX_MAP_GROWSDOWN 0x0100 struct l_mmap_argv { l_uintptr_t addr; l_size_t len; l_int prot; l_int flags; l_int fd; l_off_t pgoff; } __packed; /* * stat family of syscalls */ struct l_timespec { l_time_t tv_sec; l_long tv_nsec; }; struct l_newstat { l_ushort st_dev; l_ushort __pad1; l_ulong st_ino; l_ushort st_mode; l_ushort st_nlink; l_ushort st_uid; l_ushort st_gid; l_ushort st_rdev; l_ushort __pad2; l_ulong st_size; l_ulong st_blksize; l_ulong st_blocks; struct l_timespec st_atim; struct l_timespec st_mtim; struct l_timespec st_ctim; l_ulong __unused4; l_ulong __unused5; }; struct l_stat { l_ushort st_dev; l_ulong st_ino; l_ushort st_mode; l_ushort st_nlink; l_ushort st_uid; l_ushort st_gid; l_ushort st_rdev; l_long st_size; struct l_timespec st_atim; struct l_timespec st_mtim; struct l_timespec st_ctim; l_long st_blksize; l_long st_blocks; l_ulong st_flags; l_ulong st_gen; }; struct l_stat64 { l_ushort st_dev; u_char __pad0[10]; l_ulong __st_ino; l_uint st_mode; l_uint st_nlink; l_ulong st_uid; l_ulong st_gid; l_ushort st_rdev; u_char __pad3[10]; l_longlong st_size; l_ulong st_blksize; l_ulong st_blocks; l_ulong __pad4; struct l_timespec st_atim; struct l_timespec st_mtim; struct l_timespec st_ctim; l_ulonglong st_ino; }; struct l_statfs64 { l_int f_type; l_int f_bsize; uint64_t f_blocks; uint64_t f_bfree; uint64_t f_bavail; uint64_t f_files; uint64_t f_ffree; l_fsid_t f_fsid; l_int f_namelen; l_int f_spare[6]; }; struct l_new_utsname { char sysname[LINUX_MAX_UTSNAME]; char nodename[LINUX_MAX_UTSNAME]; char release[LINUX_MAX_UTSNAME]; char version[LINUX_MAX_UTSNAME]; char machine[LINUX_MAX_UTSNAME]; char domainname[LINUX_MAX_UTSNAME]; }; /* * Signalling */ #define LINUX_SIGHUP 1 #define LINUX_SIGINT 2 #define LINUX_SIGQUIT 3 #define LINUX_SIGILL 4 #define LINUX_SIGTRAP 5 #define LINUX_SIGABRT 6 #define LINUX_SIGIOT LINUX_SIGABRT #define LINUX_SIGBUS 7 #define LINUX_SIGFPE 8 #define LINUX_SIGKILL 9 #define LINUX_SIGUSR1 10 #define LINUX_SIGSEGV 11 #define LINUX_SIGUSR2 12 #define LINUX_SIGPIPE 13 #define LINUX_SIGALRM 14 #define LINUX_SIGTERM 15 #define LINUX_SIGSTKFLT 16 #define LINUX_SIGCHLD 17 #define LINUX_SIGCONT 18 #define LINUX_SIGSTOP 19 #define LINUX_SIGTSTP 20 #define LINUX_SIGTTIN 21 #define LINUX_SIGTTOU 22 #define LINUX_SIGURG 23 #define LINUX_SIGXCPU 24 #define LINUX_SIGXFSZ 25 #define LINUX_SIGVTALRM 26 #define LINUX_SIGPROF 27 #define LINUX_SIGWINCH 28 #define LINUX_SIGIO 29 #define LINUX_SIGPOLL LINUX_SIGIO #define LINUX_SIGPWR 30 #define LINUX_SIGSYS 31 #define LINUX_SIGRTMIN 32 #define LINUX_SIGTBLSZ 31 #define LINUX_NSIG_WORDS 2 #define LINUX_NBPW 32 #define LINUX_NSIG (LINUX_NBPW * LINUX_NSIG_WORDS) /* sigaction flags */ #define LINUX_SA_NOCLDSTOP 0x00000001 #define LINUX_SA_NOCLDWAIT 0x00000002 #define LINUX_SA_SIGINFO 0x00000004 #define LINUX_SA_RESTORER 0x04000000 #define LINUX_SA_ONSTACK 0x08000000 #define LINUX_SA_RESTART 0x10000000 #define LINUX_SA_INTERRUPT 0x20000000 #define LINUX_SA_NOMASK 0x40000000 #define LINUX_SA_ONESHOT 0x80000000 /* sigprocmask actions */ #define LINUX_SIG_BLOCK 0 #define LINUX_SIG_UNBLOCK 1 #define LINUX_SIG_SETMASK 2 /* sigset_t macros */ #define LINUX_SIGEMPTYSET(set) (set).__bits[0] = (set).__bits[1] = 0 #define LINUX_SIGISMEMBER(set, sig) SIGISMEMBER(set, sig) #define LINUX_SIGADDSET(set, sig) SIGADDSET(set, sig) /* sigaltstack */ #define LINUX_MINSIGSTKSZ 2048 #define LINUX_SS_ONSTACK 1 #define LINUX_SS_DISABLE 2 int linux_to_bsd_sigaltstack(int lsa); int bsd_to_linux_sigaltstack(int bsa); typedef void (*l_handler_t)(l_int); typedef l_ulong l_osigset_t; typedef struct { l_uint __bits[LINUX_NSIG_WORDS]; } l_sigset_t; typedef struct { l_handler_t lsa_handler; l_osigset_t lsa_mask; l_ulong lsa_flags; void (*lsa_restorer)(void); } l_osigaction_t; typedef struct { l_handler_t lsa_handler; l_ulong lsa_flags; void (*lsa_restorer)(void); l_sigset_t lsa_mask; } l_sigaction_t; typedef struct { void *ss_sp; l_int ss_flags; l_size_t ss_size; } l_stack_t; /* The Linux sigcontext, pretty much a standard 386 trapframe. */ struct l_sigcontext { l_int sc_gs; l_int sc_fs; l_int sc_es; l_int sc_ds; l_int sc_edi; l_int sc_esi; l_int sc_ebp; l_int sc_esp; l_int sc_ebx; l_int sc_edx; l_int sc_ecx; l_int sc_eax; l_int sc_trapno; l_int sc_err; l_int sc_eip; l_int sc_cs; l_int sc_eflags; l_int sc_esp_at_signal; l_int sc_ss; l_int sc_387; l_int sc_mask; l_int sc_cr2; }; struct l_ucontext { l_ulong uc_flags; void *uc_link; l_stack_t uc_stack; struct l_sigcontext uc_mcontext; l_sigset_t uc_sigmask; }; #define LINUX_SI_MAX_SIZE 128 #define LINUX_SI_PAD_SIZE ((LINUX_SI_MAX_SIZE/sizeof(l_int)) - 3) typedef union l_sigval { l_int sival_int; l_uintptr_t sival_ptr; } l_sigval_t; typedef struct l_siginfo { l_int lsi_signo; l_int lsi_errno; l_int lsi_code; union { l_int _pad[LINUX_SI_PAD_SIZE]; struct { l_pid_t _pid; l_uid_t _uid; } _kill; struct { l_timer_t _tid; l_int _overrun; char _pad[sizeof(l_uid_t) - sizeof(l_int)]; l_sigval_t _sigval; l_int _sys_private; } _timer; struct { l_pid_t _pid; /* sender's pid */ l_uid_t _uid; /* sender's uid */ l_sigval_t _sigval; } _rt; struct { l_pid_t _pid; /* which child */ l_uid_t _uid; /* sender's uid */ l_int _status; /* exit code */ l_clock_t _utime; l_clock_t _stime; } _sigchld; struct { l_uintptr_t _addr; /* Faulting insn/memory ref. */ } _sigfault; struct { l_long _band; /* POLL_IN,POLL_OUT,POLL_MSG */ l_int _fd; } _sigpoll; } _sifields; } l_siginfo_t; #define lsi_pid _sifields._kill._pid #define lsi_uid _sifields._kill._uid #define lsi_tid _sifields._timer._tid #define lsi_overrun _sifields._timer._overrun #define lsi_sys_private _sifields._timer._sys_private #define lsi_status _sifields._sigchld._status #define lsi_utime _sifields._sigchld._utime #define lsi_stime _sifields._sigchld._stime #define lsi_value _sifields._rt._sigval #define lsi_int _sifields._rt._sigval.sival_int #define lsi_ptr _sifields._rt._sigval.sival_ptr #define lsi_addr _sifields._sigfault._addr #define lsi_band _sifields._sigpoll._band #define lsi_fd _sifields._sigpoll._fd struct l_fpreg { u_int16_t significand[4]; u_int16_t exponent; }; struct l_fpxreg { u_int16_t significand[4]; u_int16_t exponent; u_int16_t padding[3]; }; struct l_xmmreg { u_int32_t element[4]; }; struct l_fpstate { /* Regular FPU environment */ u_int32_t cw; u_int32_t sw; u_int32_t tag; u_int32_t ipoff; u_int32_t cssel; u_int32_t dataoff; u_int32_t datasel; struct l_fpreg _st[8]; u_int16_t status; u_int16_t magic; /* 0xffff = regular FPU data */ /* FXSR FPU environment */ u_int32_t _fxsr_env[6]; /* env is ignored. */ u_int32_t mxcsr; u_int32_t reserved; struct l_fpxreg _fxsr_st[8]; /* reg data is ignored. */ struct l_xmmreg _xmm[8]; u_int32_t padding[56]; }; /* * We make the stack look like Linux expects it when calling a signal * handler, but use the BSD way of calling the handler and sigreturn(). * This means that we need to pass the pointer to the handler too. * It is appended to the frame to not interfere with the rest of it. */ struct l_sigframe { l_int sf_sig; struct l_sigcontext sf_sc; struct l_fpstate sf_fpstate; l_uint sf_extramask[LINUX_NSIG_WORDS-1]; l_handler_t sf_handler; }; struct l_rt_sigframe { l_int sf_sig; l_siginfo_t *sf_siginfo; struct l_ucontext *sf_ucontext; l_siginfo_t sf_si; struct l_ucontext sf_sc; l_handler_t sf_handler; }; extern int bsd_to_linux_signal[]; extern int linux_to_bsd_signal[]; extern struct sysentvec linux_sysvec; extern struct sysentvec elf_linux_sysvec; /* * Pluggable ioctl handlers */ struct linux_ioctl_args; struct thread; typedef int linux_ioctl_function_t(struct thread *, struct linux_ioctl_args *); struct linux_ioctl_handler { linux_ioctl_function_t *func; int low, high; }; int linux_ioctl_register_handler(struct linux_ioctl_handler *h); int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h); /* * open/fcntl flags */ #define LINUX_O_RDONLY 00000000 #define LINUX_O_WRONLY 00000001 #define LINUX_O_RDWR 00000002 #define LINUX_O_ACCMODE 00000003 #define LINUX_O_CREAT 00000100 #define LINUX_O_EXCL 00000200 #define LINUX_O_NOCTTY 00000400 #define LINUX_O_TRUNC 00001000 #define LINUX_O_APPEND 00002000 #define LINUX_O_NONBLOCK 00004000 #define LINUX_O_NDELAY LINUX_O_NONBLOCK #define LINUX_O_SYNC 00010000 #define LINUX_FASYNC 00020000 #define LINUX_O_DIRECT 00040000 /* Direct disk access hint */ #define LINUX_O_LARGEFILE 00100000 #define LINUX_O_DIRECTORY 00200000 /* Must be a directory */ #define LINUX_O_NOFOLLOW 00400000 /* Do not follow links */ #define LINUX_O_NOATIME 01000000 #define LINUX_O_CLOEXEC 02000000 #define LINUX_F_DUPFD 0 #define LINUX_F_GETFD 1 #define LINUX_F_SETFD 2 #define LINUX_F_GETFL 3 #define LINUX_F_SETFL 4 #define LINUX_F_GETLK 5 #define LINUX_F_SETLK 6 #define LINUX_F_SETLKW 7 #define LINUX_F_SETOWN 8 #define LINUX_F_GETOWN 9 #define LINUX_F_GETLK64 12 #define LINUX_F_SETLK64 13 #define LINUX_F_SETLKW64 14 #define LINUX_F_RDLCK 0 #define LINUX_F_WRLCK 1 #define LINUX_F_UNLCK 2 /* * posix_fadvise advice */ #define LINUX_POSIX_FADV_NORMAL 0 #define LINUX_POSIX_FADV_RANDOM 1 #define LINUX_POSIX_FADV_SEQUENTIAL 2 #define LINUX_POSIX_FADV_WILLNEED 3 #define LINUX_POSIX_FADV_DONTNEED 4 #define LINUX_POSIX_FADV_NOREUSE 5 /* * mount flags */ #define LINUX_MS_RDONLY 0x0001 #define LINUX_MS_NOSUID 0x0002 #define LINUX_MS_NODEV 0x0004 #define LINUX_MS_NOEXEC 0x0008 #define LINUX_MS_REMOUNT 0x0020 /* * SystemV IPC defines */ #define LINUX_SEMOP 1 #define LINUX_SEMGET 2 #define LINUX_SEMCTL 3 #define LINUX_MSGSND 11 #define LINUX_MSGRCV 12 #define LINUX_MSGGET 13 #define LINUX_MSGCTL 14 #define LINUX_SHMAT 21 #define LINUX_SHMDT 22 #define LINUX_SHMGET 23 #define LINUX_SHMCTL 24 #define LINUX_IPC_RMID 0 #define LINUX_IPC_SET 1 #define LINUX_IPC_STAT 2 #define LINUX_IPC_INFO 3 #define LINUX_SHM_LOCK 11 #define LINUX_SHM_UNLOCK 12 #define LINUX_SHM_STAT 13 #define LINUX_SHM_INFO 14 #define LINUX_SHM_RDONLY 0x1000 #define LINUX_SHM_RND 0x2000 #define LINUX_SHM_REMAP 0x4000 /* semctl commands */ #define LINUX_GETPID 11 #define LINUX_GETVAL 12 #define LINUX_GETALL 13 #define LINUX_GETNCNT 14 #define LINUX_GETZCNT 15 #define LINUX_SETVAL 16 #define LINUX_SETALL 17 #define LINUX_SEM_STAT 18 #define LINUX_SEM_INFO 19 union l_semun { l_int val; struct l_semid_ds *buf; l_ushort *array; struct l_seminfo *__buf; void *__pad; }; /* * Socket defines */ #define LINUX_SOCKET 1 #define LINUX_BIND 2 #define LINUX_CONNECT 3 #define LINUX_LISTEN 4 #define LINUX_ACCEPT 5 #define LINUX_GETSOCKNAME 6 #define LINUX_GETPEERNAME 7 #define LINUX_SOCKETPAIR 8 #define LINUX_SEND 9 #define LINUX_RECV 10 #define LINUX_SENDTO 11 #define LINUX_RECVFROM 12 #define LINUX_SHUTDOWN 13 #define LINUX_SETSOCKOPT 14 #define LINUX_GETSOCKOPT 15 #define LINUX_SENDMSG 16 #define LINUX_RECVMSG 17 #define LINUX_ACCEPT4 18 #define LINUX_SOL_SOCKET 1 #define LINUX_SOL_IP 0 #define LINUX_SOL_IPX 256 #define LINUX_SOL_AX25 257 #define LINUX_SOL_TCP 6 #define LINUX_SOL_UDP 17 #define LINUX_SO_DEBUG 1 #define LINUX_SO_REUSEADDR 2 #define LINUX_SO_TYPE 3 #define LINUX_SO_ERROR 4 #define LINUX_SO_DONTROUTE 5 #define LINUX_SO_BROADCAST 6 #define LINUX_SO_SNDBUF 7 #define LINUX_SO_RCVBUF 8 #define LINUX_SO_KEEPALIVE 9 #define LINUX_SO_OOBINLINE 10 #define LINUX_SO_NO_CHECK 11 #define LINUX_SO_PRIORITY 12 #define LINUX_SO_LINGER 13 #define LINUX_SO_PEERCRED 17 #define LINUX_SO_RCVLOWAT 18 #define LINUX_SO_SNDLOWAT 19 #define LINUX_SO_RCVTIMEO 20 #define LINUX_SO_SNDTIMEO 21 #define LINUX_SO_TIMESTAMP 29 #define LINUX_SO_ACCEPTCONN 30 #define LINUX_IP_TOS 1 #define LINUX_IP_TTL 2 #define LINUX_IP_HDRINCL 3 #define LINUX_IP_OPTIONS 4 #define LINUX_IP_MULTICAST_IF 32 #define LINUX_IP_MULTICAST_TTL 33 #define LINUX_IP_MULTICAST_LOOP 34 #define LINUX_IP_ADD_MEMBERSHIP 35 #define LINUX_IP_DROP_MEMBERSHIP 36 struct l_sockaddr { l_ushort sa_family; char sa_data[14]; }; struct l_msghdr { l_uintptr_t msg_name; l_int msg_namelen; l_uintptr_t msg_iov; l_size_t msg_iovlen; l_uintptr_t msg_control; l_size_t msg_controllen; l_uint msg_flags; }; struct l_cmsghdr { l_size_t cmsg_len; l_int cmsg_level; l_int cmsg_type; }; struct l_ifmap { l_ulong mem_start; l_ulong mem_end; l_ushort base_addr; u_char irq; u_char dma; u_char port; }; #define LINUX_IFHWADDRLEN 6 #define LINUX_IFNAMSIZ 16 struct l_ifreq { union { char ifrn_name[LINUX_IFNAMSIZ]; } ifr_ifrn; union { struct l_sockaddr ifru_addr; struct l_sockaddr ifru_dstaddr; struct l_sockaddr ifru_broadaddr; struct l_sockaddr ifru_netmask; struct l_sockaddr ifru_hwaddr; l_short ifru_flags[1]; l_int ifru_metric; l_int ifru_mtu; struct l_ifmap ifru_map; char ifru_slave[LINUX_IFNAMSIZ]; l_caddr_t ifru_data; } ifr_ifru; }; #define ifr_name ifr_ifrn.ifrn_name /* Interface name */ #define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ /* * poll() */ #define LINUX_POLLIN 0x0001 #define LINUX_POLLPRI 0x0002 #define LINUX_POLLOUT 0x0004 #define LINUX_POLLERR 0x0008 #define LINUX_POLLHUP 0x0010 #define LINUX_POLLNVAL 0x0020 #define LINUX_POLLRDNORM 0x0040 #define LINUX_POLLRDBAND 0x0080 #define LINUX_POLLWRNORM 0x0100 #define LINUX_POLLWRBAND 0x0200 #define LINUX_POLLMSG 0x0400 struct l_pollfd { l_int fd; l_short events; l_short revents; }; struct l_user_desc { l_uint entry_number; l_uint base_addr; l_uint limit; l_uint seg_32bit:1; l_uint contents:2; l_uint read_exec_only:1; l_uint limit_in_pages:1; l_uint seg_not_present:1; l_uint useable:1; }; struct l_desc_struct { unsigned long a, b; }; #define LINUX_LOWERWORD 0x0000ffff /* * Macros which does the same thing as those in Linux include/asm-um/ldt-i386.h. * These convert Linux user space descriptor to machine one. */ #define LINUX_LDT_entry_a(info) \ ((((info)->base_addr & LINUX_LOWERWORD) << 16) | \ ((info)->limit & LINUX_LOWERWORD)) #define LINUX_ENTRY_B_READ_EXEC_ONLY 9 #define LINUX_ENTRY_B_CONTENTS 10 #define LINUX_ENTRY_B_SEG_NOT_PRESENT 15 #define LINUX_ENTRY_B_BASE_ADDR 16 #define LINUX_ENTRY_B_USEABLE 20 #define LINUX_ENTRY_B_SEG32BIT 22 #define LINUX_ENTRY_B_LIMIT 23 #define LINUX_LDT_entry_b(info) \ (((info)->base_addr & 0xff000000) | \ ((info)->limit & 0xf0000) | \ ((info)->contents << LINUX_ENTRY_B_CONTENTS) | \ (((info)->seg_not_present == 0) << LINUX_ENTRY_B_SEG_NOT_PRESENT) | \ (((info)->base_addr & 0x00ff0000) >> LINUX_ENTRY_B_BASE_ADDR) | \ (((info)->read_exec_only == 0) << LINUX_ENTRY_B_READ_EXEC_ONLY) | \ ((info)->seg_32bit << LINUX_ENTRY_B_SEG32BIT) | \ ((info)->useable << LINUX_ENTRY_B_USEABLE) | \ ((info)->limit_in_pages << LINUX_ENTRY_B_LIMIT) | 0x7000) #define LINUX_LDT_empty(info) \ ((info)->base_addr == 0 && \ (info)->limit == 0 && \ (info)->contents == 0 && \ (info)->seg_not_present == 1 && \ (info)->read_exec_only == 1 && \ (info)->seg_32bit == 0 && \ (info)->limit_in_pages == 0 && \ (info)->useable == 0) /* * Macros for converting segments. * They do the same as those in arch/i386/kernel/process.c in Linux. */ #define LINUX_GET_BASE(desc) \ ((((desc)->a >> 16) & LINUX_LOWERWORD) | \ (((desc)->b << 16) & 0x00ff0000) | \ ((desc)->b & 0xff000000)) #define LINUX_GET_LIMIT(desc) \ (((desc)->a & LINUX_LOWERWORD) | \ ((desc)->b & 0xf0000)) #define LINUX_GET_32BIT(desc) \ (((desc)->b >> LINUX_ENTRY_B_SEG32BIT) & 1) #define LINUX_GET_CONTENTS(desc) \ (((desc)->b >> LINUX_ENTRY_B_CONTENTS) & 3) #define LINUX_GET_WRITABLE(desc) \ (((desc)->b >> LINUX_ENTRY_B_READ_EXEC_ONLY) & 1) #define LINUX_GET_LIMIT_PAGES(desc) \ (((desc)->b >> LINUX_ENTRY_B_LIMIT) & 1) #define LINUX_GET_PRESENT(desc) \ (((desc)->b >> LINUX_ENTRY_B_SEG_NOT_PRESENT) & 1) #define LINUX_GET_USEABLE(desc) \ (((desc)->b >> LINUX_ENTRY_B_USEABLE) & 1) #define LINUX_CLOCK_REALTIME 0 #define LINUX_CLOCK_MONOTONIC 1 #define LINUX_CLOCK_PROCESS_CPUTIME_ID 2 #define LINUX_CLOCK_THREAD_CPUTIME_ID 3 #define LINUX_CLOCK_REALTIME_HR 4 #define LINUX_CLOCK_MONOTONIC_HR 5 #define LINUX_CLONE_VM 0x00000100 #define LINUX_CLONE_FS 0x00000200 #define LINUX_CLONE_FILES 0x00000400 #define LINUX_CLONE_SIGHAND 0x00000800 #define LINUX_CLONE_PID 0x00001000 /* No longer exist in Linux */ #define LINUX_CLONE_VFORK 0x00004000 #define LINUX_CLONE_PARENT 0x00008000 #define LINUX_CLONE_THREAD 0x00010000 #define LINUX_CLONE_SETTLS 0x00080000 #define LINUX_CLONE_PARENT_SETTID 0x00100000 #define LINUX_CLONE_CHILD_CLEARTID 0x00200000 #define LINUX_CLONE_CHILD_SETTID 0x01000000 #define LINUX_THREADING_FLAGS \ (LINUX_CLONE_VM | LINUX_CLONE_FS | LINUX_CLONE_FILES | \ LINUX_CLONE_SIGHAND | LINUX_CLONE_THREAD) /* robust futexes */ struct linux_robust_list { struct linux_robust_list *next; }; struct linux_robust_list_head { struct linux_robust_list list; l_long futex_offset; struct linux_robust_list *pending_list; }; int linux_set_upcall_kse(struct thread *td, register_t stack); int linux_set_cloned_tls(struct thread *td, void *desc); #endif /* !_I386_LINUX_H_ */ Index: stable/9/sys/i386/linux/linux_dummy.c =================================================================== --- stable/9/sys/i386/linux/linux_dummy.c (revision 246289) +++ stable/9/sys/i386/linux/linux_dummy.c (revision 246290) @@ -1,159 +1,168 @@ /*- * Copyright (c) 1994-1995 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); +#include "opt_compat.h" +#include "opt_kdtrace.h" + #include +#include +#include #include #include #include #include +#include #include + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); DUMMY(stime); DUMMY(fstat); DUMMY(olduname); DUMMY(syslog); DUMMY(uname); DUMMY(vhangup); DUMMY(vm86old); DUMMY(swapoff); DUMMY(adjtimex); DUMMY(create_module); DUMMY(init_module); DUMMY(delete_module); DUMMY(get_kernel_syms); DUMMY(quotactl); DUMMY(bdflush); DUMMY(sysfs); DUMMY(vm86); DUMMY(query_module); DUMMY(nfsservctl); DUMMY(rt_sigqueueinfo); DUMMY(sendfile); /* different semantics */ DUMMY(setfsuid); DUMMY(setfsgid); DUMMY(pivot_root); DUMMY(mincore); DUMMY(lookup_dcookie); DUMMY(epoll_create); DUMMY(epoll_ctl); DUMMY(epoll_wait); DUMMY(remap_file_pages); DUMMY(fstatfs64); DUMMY(mbind); DUMMY(get_mempolicy); DUMMY(set_mempolicy); DUMMY(kexec_load); DUMMY(waitid); /* linux 2.6.11: */ DUMMY(add_key); DUMMY(request_key); DUMMY(keyctl); /* linux 2.6.13: */ DUMMY(ioprio_set); DUMMY(ioprio_get); DUMMY(inotify_init); DUMMY(inotify_add_watch); DUMMY(inotify_rm_watch); /* linux 2.6.16: */ DUMMY(migrate_pages); DUMMY(pselect6); DUMMY(ppoll); DUMMY(unshare); /* linux 2.6.17: */ DUMMY(splice); DUMMY(sync_file_range); DUMMY(tee); DUMMY(vmsplice); /* linux 2.6.18: */ DUMMY(move_pages); /* linux 2.6.19: */ DUMMY(getcpu); DUMMY(epoll_pwait); /* linux 2.6.22: */ DUMMY(utimensat); DUMMY(signalfd); DUMMY(timerfd_create); DUMMY(eventfd); /* linux 2.6.23: */ DUMMY(fallocate); /* linux 2.6.25: */ DUMMY(timerfd_settime); DUMMY(timerfd_gettime); /* linux 2.6.27: */ DUMMY(signalfd4); DUMMY(eventfd2); DUMMY(epoll_create1); DUMMY(dup3); DUMMY(pipe2); DUMMY(inotify_init1); /* linux 2.6.30: */ DUMMY(preadv); DUMMY(pwritev); /* linux 2.6.31 */ DUMMY(rt_tsigqueueinfo); DUMMY(perf_event_open); /* linux 2.6.33: */ DUMMY(recvmmsg); DUMMY(fanotify_init); DUMMY(fanotify_mark); /* linux 2.6.36: */ DUMMY(prlimit64); /* later: */ DUMMY(name_to_handle_at); DUMMY(open_by_handle_at); DUMMY(clock_adjtime); DUMMY(syncfs); DUMMY(sendmmsg); DUMMY(setns); DUMMY(process_vm_readv); DUMMY(process_vm_writev); #define DUMMY_XATTR(s) \ int \ linux_ ## s ## xattr( \ struct thread *td, struct linux_ ## s ## xattr_args *arg) \ { \ \ return (ENOATTR); \ } DUMMY_XATTR(set); DUMMY_XATTR(lset); DUMMY_XATTR(fset); DUMMY_XATTR(get); DUMMY_XATTR(lget); DUMMY_XATTR(fget); DUMMY_XATTR(list); DUMMY_XATTR(llist); DUMMY_XATTR(flist); DUMMY_XATTR(remove); DUMMY_XATTR(lremove); DUMMY_XATTR(fremove); Index: stable/9/sys/modules/linux/Makefile =================================================================== --- stable/9/sys/modules/linux/Makefile (revision 246289) +++ stable/9/sys/modules/linux/Makefile (revision 246290) @@ -1,70 +1,70 @@ # $FreeBSD$ .if ${MACHINE_CPUARCH} == "amd64" SFX= 32 CFLAGS+=-DCOMPAT_FREEBSD32 -DCOMPAT_LINUX32 .endif .PATH: ${.CURDIR}/../../compat/linux ${.CURDIR}/../../${MACHINE_CPUARCH}/linux${SFX} KMOD= linux SRCS= linux_fork.c linux${SFX}_dummy.c linux_emul.c linux_file.c \ linux_futex.c linux_getcwd.c linux_ioctl.c linux_ipc.c \ linux${SFX}_machdep.c linux_mib.c linux_misc.c linux_signal.c \ linux_socket.c linux_stats.c linux_sysctl.c linux${SFX}_sysent.c \ linux${SFX}_sysvec.c linux_uid16.c linux_util.c linux_time.c \ - opt_inet6.h opt_compat.h opt_posix.h opt_usb.h vnode_if.h \ - device_if.h bus_if.h assym.s + opt_inet6.h opt_compat.h opt_kdtrace.h opt_posix.h opt_usb.h \ + vnode_if.h device_if.h bus_if.h assym.s # XXX: for assym.s SRCS+= opt_kstack_pages.h opt_nfs.h opt_compat.h opt_hwpmc_hooks.h .if ${MACHINE_CPUARCH} == "i386" SRCS+= opt_apic.h .endif OBJS= linux${SFX}_locore.o linux${SFX}_support.o .if ${MACHINE_CPUARCH} == "i386" SRCS+= linux_ptrace.c imgact_linux.c opt_cpu.h .endif EXPORT_SYMS= EXPORT_SYMS+= linux_emul_path EXPORT_SYMS+= linux_get_osname EXPORT_SYMS+= linux_get_osrelease EXPORT_SYMS+= linux_ifname EXPORT_SYMS+= linux_ioctl_register_handler EXPORT_SYMS+= linux_ioctl_unregister_handler CLEANFILES= linux${SFX}_assym.h linux${SFX}_genassym.o linux${SFX}_assym.h: linux${SFX}_genassym.o .if exists(@) linux${SFX}_assym.h: @/kern/genassym.sh .endif sh @/kern/genassym.sh linux${SFX}_genassym.o > ${.TARGET} linux${SFX}_locore.o: linux${SFX}_locore.s linux${SFX}_assym.h ${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \ ${.IMPSRC} -o ${.TARGET} linux${SFX}_support.o: linux${SFX}_support.s assym.s linux${SFX}_assym.h ${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \ ${.IMPSRC} -o ${.TARGET} linux${SFX}_genassym.o: linux${SFX}_genassym.c linux.h @ machine ${CC} -c ${CFLAGS:N-fno-common} ${.IMPSRC} .if !defined(KERNBUILDDIR) opt_inet6.h: echo "#define INET6 1" > ${.TARGET} .if defined(KTR) CFLAGS+= -DKTR .endif .endif .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.linux32_locore.s= ${CLANG_NO_IAS} CFLAGS+= ${CFLAGS.${.IMPSRC:T}} Index: stable/9/sys/modules =================================================================== --- stable/9/sys/modules (revision 246289) +++ stable/9/sys/modules (revision 246290) Property changes on: stable/9/sys/modules ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/modules:r235078 Index: stable/9/sys =================================================================== --- stable/9/sys (revision 246289) +++ stable/9/sys (revision 246290) Property changes on: stable/9/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys:r235063,235078