Index: head/sys/kern/syscalls.master =================================================================== --- head/sys/kern/syscalls.master (revision 99854) +++ head/sys/kern/syscalls.master (revision 99855) @@ -1,565 +1,568 @@ $FreeBSD$ ; from: @(#)syscalls.master 8.2 (Berkeley) 1/13/94 ; ; System call name/number master file. ; Processed to created init_sysent.c, syscalls.c and syscall.h. ; Columns: number [M]type nargs namespc name alt{name,tag,rtyp}/comments ; number system call number, must be in order ; type one of [M]STD, [M]OBSOL, [M]UNIMPL, [M]COMPAT, [M]CPT_NOA, ; [M]LIBCOMPAT, [M]NODEF, [M]NOARGS, [M]NOPROTO, [M]NOIMPL, -; [M]NOSTD +; [M]NOSTD, [M]COMPAT4 ; namespc one of POSIX, BSD, NOHIDE ; name psuedo-prototype of syscall routine ; If one of the following alts is different, then all appear: ; altname name of system call if different ; alttag name of args struct tag if different from [o]`name'"_args" ; altrtyp return type if not int (bogus - syscalls always return int) ; for UNIMPL/OBSOL, name continues with comments ; types: ; [M] e.g. like MSTD -- means the system call is MP-safe. If no ; M prefix is used, the syscall wrapper will obtain the Giant ; lock for the syscall. ; STD always included ; COMPAT included on COMPAT #ifdef +; COMPAT4 included on COMPAT4 #ifdef (FreeBSD 4 compat) ; LIBCOMPAT included on COMPAT #ifdef, and placed in syscall.h ; OBSOL obsolete, not included in system, only specifies name ; UNIMPL not implemented, placeholder only ; NOSTD implemented but as a lkm that can be statically ; compiled in sysent entry will be filled with lkmsys ; so the SYSCALL_MODULE macro works ; #ifdef's, etc. may be included, and are copied to the output files. #include #include #include ; Reserved/unimplemented system calls in the range 0-150 inclusive ; are reserved for use in future Berkeley releases. ; Additional system calls implemented in vendor and other ; redistributions should be placed in the reserved range at the end ; of the current calls. 0 STD NOHIDE { int nosys(void); } syscall nosys_args int 1 MSTD NOHIDE { void sys_exit(int rval); } exit sys_exit_args void 2 MSTD POSIX { int fork(void); } 3 MSTD POSIX { ssize_t read(int fd, void *buf, size_t nbyte); } 4 MSTD POSIX { ssize_t write(int fd, const void *buf, size_t nbyte); } 5 STD POSIX { int open(char *path, int flags, int mode); } ; XXX should be { int open(const char *path, int flags, ...); } ; but we're not ready for `const' or varargs. ; XXX man page says `mode_t mode'. 6 MSTD POSIX { int close(int fd); } 7 MSTD BSD { int wait4(int pid, int *status, int options, \ struct rusage *rusage); } wait4 wait_args int 8 COMPAT BSD { int creat(char *path, int mode); } 9 STD POSIX { int link(char *path, char *link); } 10 STD POSIX { int unlink(char *path); } 11 OBSOL NOHIDE execv 12 STD POSIX { int chdir(char *path); } 13 STD BSD { int fchdir(int fd); } 14 STD POSIX { int mknod(char *path, int mode, int dev); } 15 STD POSIX { int chmod(char *path, int mode); } 16 STD POSIX { int chown(char *path, int uid, int gid); } 17 MSTD BSD { int obreak(char *nsize); } break obreak_args int 18 STD BSD { int getfsstat(struct statfs *buf, long bufsize, \ int flags); } 19 COMPAT POSIX { long lseek(int fd, long offset, int whence); } 20 MSTD POSIX { pid_t getpid(void); } 21 STD BSD { int mount(char *type, char *path, int flags, \ caddr_t data); } ; XXX `path' should have type `const char *' but we're not ready for that. 22 STD BSD { int unmount(char *path, int flags); } 23 MSTD POSIX { int setuid(uid_t uid); } 24 MSTD POSIX { uid_t getuid(void); } 25 MSTD POSIX { uid_t geteuid(void); } 26 STD BSD { int ptrace(int req, pid_t pid, caddr_t addr, \ int data); } 27 MSTD BSD { int recvmsg(int s, struct msghdr *msg, int flags); } 28 MSTD BSD { int sendmsg(int s, caddr_t msg, int flags); } 29 MSTD BSD { int recvfrom(int s, caddr_t buf, size_t len, \ int flags, caddr_t from, int *fromlenaddr); } 30 MSTD BSD { int accept(int s, caddr_t name, int *anamelen); } 31 MSTD BSD { int getpeername(int fdes, caddr_t asa, int *alen); } 32 MSTD BSD { int getsockname(int fdes, caddr_t asa, int *alen); } 33 STD POSIX { int access(char *path, int flags); } 34 STD BSD { int chflags(char *path, int flags); } 35 STD BSD { int fchflags(int fd, int flags); } 36 STD BSD { int sync(void); } 37 MSTD POSIX { int kill(int pid, int signum); } 38 COMPAT POSIX { int stat(char *path, struct ostat *ub); } 39 MSTD POSIX { pid_t getppid(void); } 40 COMPAT POSIX { int lstat(char *path, struct ostat *ub); } 41 STD POSIX { int dup(u_int fd); } 42 STD POSIX { int pipe(void); } 43 MSTD POSIX { gid_t getegid(void); } 44 MSTD BSD { int profil(caddr_t samples, size_t size, \ size_t offset, u_int scale); } 45 STD BSD { int ktrace(const char *fname, int ops, int facs, \ int pid); } 46 MCOMPAT POSIX { int sigaction(int signum, struct osigaction *nsa, \ struct osigaction *osa); } 47 MSTD POSIX { gid_t getgid(void); } 48 MCOMPAT POSIX { int sigprocmask(int how, osigset_t mask); } ; XXX note nonstandard (bogus) calling convention - the libc stub passes ; us the mask, not a pointer to it, and we return the old mask as the ; (int) return value. 49 MSTD BSD { int getlogin(char *namebuf, u_int namelen); } 50 MSTD BSD { int setlogin(char *namebuf); } 51 MSTD BSD { int acct(char *path); } 52 MCOMPAT POSIX { int sigpending(void); } 53 MSTD BSD { int sigaltstack(stack_t *ss, stack_t *oss); } 54 MSTD POSIX { int ioctl(int fd, u_long com, caddr_t data); } 55 MSTD BSD { int reboot(int opt); } 56 STD POSIX { int revoke(char *path); } 57 STD POSIX { int symlink(char *path, char *link); } 58 STD POSIX { int readlink(char *path, char *buf, int count); } 59 MSTD POSIX { int execve(char *fname, char **argv, char **envv); } 60 MSTD POSIX { int umask(int newmask); } umask umask_args int 61 STD BSD { int chroot(char *path); } 62 MCOMPAT POSIX { int fstat(int fd, struct ostat *sb); } 63 MCOMPAT BSD { int getkerninfo(int op, char *where, size_t *size, \ int arg); } getkerninfo getkerninfo_args int 64 MCOMPAT BSD { int getpagesize(void); } \ getpagesize getpagesize_args int 65 STD BSD { int msync(void *addr, size_t len, int flags); } 66 MSTD BSD { int vfork(void); } 67 OBSOL NOHIDE vread 68 OBSOL NOHIDE vwrite 69 MSTD BSD { int sbrk(int incr); } 70 MSTD BSD { int sstk(int incr); } 71 MCOMPAT BSD { int mmap(void *addr, int len, int prot, \ int flags, int fd, long pos); } 72 MSTD BSD { int ovadvise(int anom); } vadvise ovadvise_args int 73 MSTD BSD { int munmap(void *addr, size_t len); } 74 MSTD BSD { int mprotect(const void *addr, size_t len, int prot); } 75 MSTD BSD { int madvise(void *addr, size_t len, int behav); } 76 OBSOL NOHIDE vhangup 77 OBSOL NOHIDE vlimit 78 MSTD BSD { int mincore(const void *addr, size_t len, \ char *vec); } 79 MSTD POSIX { int getgroups(u_int gidsetsize, gid_t *gidset); } 80 MSTD POSIX { int setgroups(u_int gidsetsize, gid_t *gidset); } 81 MSTD POSIX { int getpgrp(void); } 82 MSTD POSIX { int setpgid(int pid, int pgid); } 83 MSTD BSD { int setitimer(u_int which, struct itimerval *itv, \ struct itimerval *oitv); } 84 MCOMPAT BSD { int wait(void); } 85 MSTD BSD { int swapon(char *name); } 86 MSTD BSD { int getitimer(u_int which, struct itimerval *itv); } 87 MCOMPAT BSD { int gethostname(char *hostname, u_int len); } \ gethostname gethostname_args int 88 MCOMPAT BSD { int sethostname(char *hostname, u_int len); } \ sethostname sethostname_args int 89 MSTD BSD { int getdtablesize(void); } 90 MSTD POSIX { int dup2(u_int from, u_int to); } 91 UNIMPL BSD getdopt 92 MSTD POSIX { int fcntl(int fd, int cmd, long arg); } ; XXX should be { int fcntl(int fd, int cmd, ...); } ; but we're not ready for varargs. ; XXX man page says `int arg' too. 93 MSTD BSD { int select(int nd, fd_set *in, fd_set *ou, \ fd_set *ex, struct timeval *tv); } 94 UNIMPL BSD setdopt 95 STD POSIX { int fsync(int fd); } 96 MSTD BSD { int setpriority(int which, int who, int prio); } 97 MSTD BSD { int socket(int domain, int type, int protocol); } 98 MSTD BSD { int connect(int s, caddr_t name, int namelen); } 99 MCPT_NOA BSD { int accept(int s, caddr_t name, int *anamelen); } \ accept accept_args int 100 MSTD BSD { int getpriority(int which, int who); } 101 MCOMPAT BSD { int send(int s, caddr_t buf, int len, int flags); } 102 MCOMPAT BSD { int recv(int s, caddr_t buf, int len, int flags); } 103 MSTD BSD { int osigreturn(struct osigcontext *sigcntxp); } 104 MSTD BSD { int bind(int s, caddr_t name, int namelen); } 105 MSTD BSD { int setsockopt(int s, int level, int name, \ caddr_t val, int valsize); } 106 MSTD BSD { int listen(int s, int backlog); } 107 OBSOL NOHIDE vtimes 108 MCOMPAT BSD { int sigvec(int signum, struct sigvec *nsv, \ struct sigvec *osv); } 109 MCOMPAT BSD { int sigblock(int mask); } 110 MCOMPAT BSD { int sigsetmask(int mask); } 111 MCOMPAT POSIX { int sigsuspend(osigset_t mask); } ; XXX note nonstandard (bogus) calling convention - the libc stub passes ; us the mask, not a pointer to it. 112 MCOMPAT BSD { int sigstack(struct sigstack *nss, \ struct sigstack *oss); } 113 MCOMPAT BSD { int recvmsg(int s, struct omsghdr *msg, int flags); } 114 MCOMPAT BSD { int sendmsg(int s, caddr_t msg, int flags); } 115 OBSOL NOHIDE vtrace 116 MSTD BSD { int gettimeofday(struct timeval *tp, \ struct timezone *tzp); } 117 MSTD BSD { int getrusage(int who, struct rusage *rusage); } 118 MSTD BSD { int getsockopt(int s, int level, int name, \ caddr_t val, int *avalsize); } 119 UNIMPL NOHIDE resuba (BSD/OS 2.x) 120 MSTD BSD { int readv(int fd, struct iovec *iovp, u_int iovcnt); } 121 MSTD BSD { int writev(int fd, struct iovec *iovp, \ u_int iovcnt); } 122 MSTD BSD { int settimeofday(struct timeval *tv, \ struct timezone *tzp); } 123 STD BSD { int fchown(int fd, int uid, int gid); } 124 STD BSD { int fchmod(int fd, int mode); } 125 MCPT_NOA BSD { int recvfrom(int s, caddr_t buf, size_t len, \ int flags, caddr_t from, int *fromlenaddr); } \ recvfrom recvfrom_args int 126 MSTD BSD { int setreuid(int ruid, int euid); } 127 MSTD BSD { int setregid(int rgid, int egid); } 128 STD POSIX { int rename(char *from, char *to); } 129 COMPAT BSD { int truncate(char *path, long length); } 130 COMPAT BSD { int ftruncate(int fd, long length); } 131 MSTD BSD { int flock(int fd, int how); } 132 STD POSIX { int mkfifo(char *path, int mode); } 133 MSTD BSD { int sendto(int s, caddr_t buf, size_t len, \ int flags, caddr_t to, int tolen); } 134 MSTD BSD { int shutdown(int s, int how); } 135 MSTD BSD { int socketpair(int domain, int type, int protocol, \ int *rsv); } 136 STD POSIX { int mkdir(char *path, int mode); } 137 STD POSIX { int rmdir(char *path); } 138 STD BSD { int utimes(char *path, struct timeval *tptr); } 139 OBSOL NOHIDE 4.2 sigreturn 140 MSTD BSD { int adjtime(struct timeval *delta, \ struct timeval *olddelta); } 141 MCOMPAT BSD { int getpeername(int fdes, caddr_t asa, int *alen); } 142 MCOMPAT BSD { long gethostid(void); } 143 MCOMPAT BSD { int sethostid(long hostid); } 144 MCOMPAT BSD { int getrlimit(u_int which, struct orlimit *rlp); } 145 MCOMPAT BSD { int setrlimit(u_int which, struct orlimit *rlp); } 146 MCOMPAT BSD { int killpg(int pgid, int signum); } 147 MSTD POSIX { int setsid(void); } 148 STD BSD { int quotactl(char *path, int cmd, int uid, \ caddr_t arg); } 149 MCOMPAT BSD { int quota(void); } 150 MCPT_NOA BSD { int getsockname(int fdec, caddr_t asa, int *alen); }\ getsockname getsockname_args int ; Syscalls 151-180 inclusive are reserved for vendor-specific ; system calls. (This includes various calls added for compatibity ; with other Unix variants.) ; Some of these calls are now supported by BSD... 151 UNIMPL NOHIDE sem_lock (BSD/OS 2.x) 152 UNIMPL NOHIDE sem_wakeup (BSD/OS 2.x) 153 UNIMPL NOHIDE asyncdaemon (BSD/OS 2.x) 154 UNIMPL NOHIDE nosys ; 155 is initialized by the NFS code, if present. 155 MNOIMPL BSD { int nfssvc(int flag, caddr_t argp); } 156 COMPAT BSD { int getdirentries(int fd, char *buf, u_int count, \ long *basep); } 157 STD BSD { int statfs(char *path, struct statfs *buf); } 158 STD BSD { int fstatfs(int fd, struct statfs *buf); } 159 UNIMPL NOHIDE nosys 160 UNIMPL NOHIDE nosys 161 STD BSD { int getfh(char *fname, struct fhandle *fhp); } 162 MSTD BSD { int getdomainname(char *domainname, int len); } 163 MSTD BSD { int setdomainname(char *domainname, int len); } 164 MSTD BSD { int uname(struct utsname *name); } 165 STD BSD { int sysarch(int op, char *parms); } 166 MSTD BSD { int rtprio(int function, pid_t pid, \ struct rtprio *rtp); } 167 UNIMPL NOHIDE nosys 168 UNIMPL NOHIDE nosys ; 169 is initialized by the SYSVSEM code if present or loaded 169 MNOSTD BSD { int semsys(int which, int a2, int a3, int a4, \ int a5); } ; 169 is initialized by the SYSVMSG code if present or loaded ; XXX should be { int semsys(int which, ...); } 170 MNOSTD BSD { int msgsys(int which, int a2, int a3, int a4, \ int a5, int a6); } ; 169 is initialized by the SYSVSHM code if present or loaded ; XXX should be { int msgsys(int which, ...); } 171 MNOSTD BSD { int shmsys(int which, int a2, int a3, int a4); } ; XXX should be { int shmsys(int which, ...); } 172 UNIMPL NOHIDE nosys 173 MSTD POSIX { ssize_t pread(int fd, void *buf, size_t nbyte, \ int pad, off_t offset); } 174 MSTD POSIX { ssize_t pwrite(int fd, const void *buf, \ size_t nbyte, int pad, off_t offset); } 175 UNIMPL NOHIDE nosys 176 MSTD BSD { int ntp_adjtime(struct timex *tp); } 177 UNIMPL NOHIDE sfork (BSD/OS 2.x) 178 UNIMPL NOHIDE getdescriptor (BSD/OS 2.x) 179 UNIMPL NOHIDE setdescriptor (BSD/OS 2.x) 180 UNIMPL NOHIDE nosys ; Syscalls 181-199 are used by/reserved for BSD 181 MSTD POSIX { int setgid(gid_t gid); } 182 MSTD BSD { int setegid(gid_t egid); } 183 MSTD BSD { int seteuid(uid_t euid); } 184 UNIMPL BSD lfs_bmapv 185 UNIMPL BSD lfs_markv 186 UNIMPL BSD lfs_segclean 187 UNIMPL BSD lfs_segwait 188 STD POSIX { int stat(char *path, struct stat *ub); } 189 MSTD POSIX { int fstat(int fd, struct stat *sb); } 190 STD POSIX { int lstat(char *path, struct stat *ub); } 191 STD POSIX { int pathconf(char *path, int name); } 192 MSTD POSIX { int fpathconf(int fd, int name); } 193 UNIMPL NOHIDE nosys 194 MSTD BSD { int getrlimit(u_int which, \ struct rlimit *rlp); } \ getrlimit __getrlimit_args int 195 MSTD BSD { int setrlimit(u_int which, \ struct rlimit *rlp); } \ setrlimit __setrlimit_args int 196 STD BSD { int getdirentries(int fd, char *buf, u_int count, \ long *basep); } 197 MSTD BSD { caddr_t mmap(caddr_t addr, size_t len, int prot, \ int flags, int fd, int pad, off_t pos); } 198 STD NOHIDE { int nosys(void); } __syscall __syscall_args int 199 STD POSIX { off_t lseek(int fd, int pad, off_t offset, \ int whence); } 200 STD BSD { int truncate(char *path, int pad, off_t length); } 201 STD BSD { int ftruncate(int fd, int pad, off_t length); } 202 MSTD BSD { int __sysctl(int *name, u_int namelen, void *old, \ size_t *oldlenp, void *new, size_t newlen); } \ __sysctl sysctl_args int ; properly, __sysctl should be a NOHIDE, but making an exception ; here allows to avoid one in libc/sys/Makefile.inc. 203 MSTD BSD { int mlock(const void *addr, size_t len); } 204 MSTD BSD { int munlock(const void *addr, size_t len); } 205 STD BSD { int undelete(char *path); } 206 STD BSD { int futimes(int fd, struct timeval *tptr); } 207 MSTD BSD { int getpgid(pid_t pid); } 208 UNIMPL NOHIDE newreboot (NetBSD) 209 MSTD BSD { int poll(struct pollfd *fds, u_int nfds, \ int timeout); } ; ; The following are reserved for loadable syscalls ; 210 NODEF NOHIDE lkmnosys lkmnosys nosys_args int 211 NODEF NOHIDE lkmnosys lkmnosys nosys_args int 212 NODEF NOHIDE lkmnosys lkmnosys nosys_args int 213 NODEF NOHIDE lkmnosys lkmnosys nosys_args int 214 NODEF NOHIDE lkmnosys lkmnosys nosys_args int 215 NODEF NOHIDE lkmnosys lkmnosys nosys_args int 216 NODEF NOHIDE lkmnosys lkmnosys nosys_args int 217 NODEF NOHIDE lkmnosys lkmnosys nosys_args int 218 NODEF NOHIDE lkmnosys lkmnosys nosys_args int 219 NODEF NOHIDE lkmnosys lkmnosys nosys_args int ; ; The following were introduced with NetBSD/4.4Lite-2 ; They are initialized by thier respective modules/sysinits 220 MNOSTD BSD { int __semctl(int semid, int semnum, int cmd, \ union semun *arg); } 221 MNOSTD BSD { int semget(key_t key, int nsems, int semflg); } 222 MNOSTD BSD { int semop(int semid, struct sembuf *sops, \ u_int nsops); } 223 UNIMPL NOHIDE semconfig 224 MNOSTD BSD { int msgctl(int msqid, int cmd, \ struct msqid_ds *buf); } 225 MNOSTD BSD { int msgget(key_t key, int msgflg); } 226 MNOSTD BSD { int msgsnd(int msqid, void *msgp, size_t msgsz, \ int msgflg); } 227 MNOSTD BSD { int msgrcv(int msqid, void *msgp, size_t msgsz, \ long msgtyp, int msgflg); } 228 MNOSTD BSD { int shmat(int shmid, void *shmaddr, int shmflg); } 229 MNOSTD BSD { int shmctl(int shmid, int cmd, \ struct shmid_ds *buf); } 230 MNOSTD BSD { int shmdt(void *shmaddr); } 231 MNOSTD BSD { int shmget(key_t key, int size, int shmflg); } ; 232 MSTD POSIX { int clock_gettime(clockid_t clock_id, \ struct timespec *tp); } 233 MSTD POSIX { int clock_settime(clockid_t clock_id, \ const struct timespec *tp); } 234 MSTD POSIX { int clock_getres(clockid_t clock_id, \ struct timespec *tp); } 235 UNIMPL NOHIDE timer_create 236 UNIMPL NOHIDE timer_delete 237 UNIMPL NOHIDE timer_settime 238 UNIMPL NOHIDE timer_gettime 239 UNIMPL NOHIDE timer_getoverrun 240 MSTD POSIX { int nanosleep(const struct timespec *rqtp, \ struct timespec *rmtp); } 241 UNIMPL NOHIDE nosys 242 UNIMPL NOHIDE nosys 243 UNIMPL NOHIDE nosys 244 UNIMPL NOHIDE nosys 245 UNIMPL NOHIDE nosys 246 UNIMPL NOHIDE nosys 247 UNIMPL NOHIDE nosys 248 UNIMPL NOHIDE nosys 249 UNIMPL NOHIDE nosys ; syscall numbers initially used in OpenBSD 250 MSTD BSD { int minherit(void *addr, size_t len, int inherit); } 251 MSTD BSD { int rfork(int flags); } 252 MSTD BSD { int openbsd_poll(struct pollfd *fds, u_int nfds, \ int timeout); } 253 STD BSD { int issetugid(void); } 254 STD BSD { int lchown(char *path, int uid, int gid); } 255 UNIMPL NOHIDE nosys 256 UNIMPL NOHIDE nosys 257 UNIMPL NOHIDE nosys 258 UNIMPL NOHIDE nosys 259 UNIMPL NOHIDE nosys 260 UNIMPL NOHIDE nosys 261 UNIMPL NOHIDE nosys 262 UNIMPL NOHIDE nosys 263 UNIMPL NOHIDE nosys 264 UNIMPL NOHIDE nosys 265 UNIMPL NOHIDE nosys 266 UNIMPL NOHIDE nosys 267 UNIMPL NOHIDE nosys 268 UNIMPL NOHIDE nosys 269 UNIMPL NOHIDE nosys 270 UNIMPL NOHIDE nosys 271 UNIMPL NOHIDE nosys 272 STD BSD { int getdents(int fd, char *buf, size_t count); } 273 UNIMPL NOHIDE nosys 274 STD BSD { int lchmod(char *path, mode_t mode); } 275 NOPROTO BSD { int lchown(char *path, uid_t uid, gid_t gid); } netbsd_lchown lchown_args int 276 STD BSD { int lutimes(char *path, struct timeval *tptr); } 277 MNOPROTO BSD { int msync(void *addr, size_t len, int flags); } netbsd_msync msync_args int 278 STD BSD { int nstat(char *path, struct nstat *ub); } 279 MSTD BSD { int nfstat(int fd, struct nstat *sb); } 280 STD BSD { int nlstat(char *path, struct nstat *ub); } 281 UNIMPL NOHIDE nosys 282 UNIMPL NOHIDE nosys 283 UNIMPL NOHIDE nosys 284 UNIMPL NOHIDE nosys 285 UNIMPL NOHIDE nosys 286 UNIMPL NOHIDE nosys 287 UNIMPL NOHIDE nosys 288 UNIMPL NOHIDE nosys 289 UNIMPL NOHIDE nosys 290 UNIMPL NOHIDE nosys 291 UNIMPL NOHIDE nosys 292 UNIMPL NOHIDE nosys 293 UNIMPL NOHIDE nosys 294 UNIMPL NOHIDE nosys 295 UNIMPL NOHIDE nosys 296 UNIMPL NOHIDE nosys ; XXX 297 is 300 in NetBSD 297 STD BSD { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); } 298 STD BSD { int fhopen(const struct fhandle *u_fhp, int flags); } 299 STD BSD { int fhstat(const struct fhandle *u_fhp, struct stat *sb); } ; syscall numbers for FreeBSD 300 MSTD BSD { int modnext(int modid); } 301 MSTD BSD { int modstat(int modid, struct module_stat* stat); } 302 MSTD BSD { int modfnext(int modid); } 303 MSTD BSD { int modfind(const char *name); } 304 MSTD BSD { int kldload(const char *file); } 305 MSTD BSD { int kldunload(int fileid); } 306 MSTD BSD { int kldfind(const char *file); } 307 MSTD BSD { int kldnext(int fileid); } 308 MSTD BSD { int kldstat(int fileid, struct kld_file_stat* stat); } 309 MSTD BSD { int kldfirstmod(int fileid); } 310 MSTD BSD { int getsid(pid_t pid); } 311 MSTD BSD { int setresuid(uid_t ruid, uid_t euid, uid_t suid); } 312 MSTD BSD { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); } 313 OBSOL NOHIDE signanosleep 314 NOSTD BSD { int aio_return(struct aiocb *aiocbp); } 315 NOSTD BSD { int aio_suspend(struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); } 316 NOSTD BSD { int aio_cancel(int fd, struct aiocb *aiocbp); } 317 NOSTD BSD { int aio_error(struct aiocb *aiocbp); } 318 NOSTD BSD { int aio_read(struct aiocb *aiocbp); } 319 NOSTD BSD { int aio_write(struct aiocb *aiocbp); } 320 NOSTD BSD { int lio_listio(int mode, struct aiocb * const *acb_list, int nent, struct sigevent *sig); } 321 MSTD BSD { int yield(void); } 322 OBSOL NOHIDE thr_sleep 323 OBSOL NOHIDE thr_wakeup 324 MSTD BSD { int mlockall(int how); } 325 MSTD BSD { int munlockall(void); } 326 STD BSD { int __getcwd(u_char *buf, u_int buflen); } 327 MSTD POSIX { int sched_setparam (pid_t pid, const struct sched_param *param); } 328 MSTD POSIX { int sched_getparam (pid_t pid, struct sched_param *param); } 329 MSTD POSIX { int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param); } 330 MSTD POSIX { int sched_getscheduler (pid_t pid); } 331 MSTD POSIX { int sched_yield (void); } 332 MSTD POSIX { int sched_get_priority_max (int policy); } 333 MSTD POSIX { int sched_get_priority_min (int policy); } 334 MSTD POSIX { int sched_rr_get_interval (pid_t pid, struct timespec *interval); } 335 STD BSD { int utrace(const void *addr, size_t len); } -336 MSTD BSD { int sendfile(int fd, int s, off_t offset, size_t nbytes, \ +336 MCOMPAT4 BSD { int sendfile(int fd, int s, off_t offset, size_t nbytes, \ struct sf_hdtr *hdtr, off_t *sbytes, int flags); } 337 STD BSD { int kldsym(int fileid, int cmd, void *data); } 338 MSTD BSD { int jail(struct jail *jail); } 339 UNIMPL BSD pioctl 340 MSTD POSIX { int sigprocmask(int how, const sigset_t *set, \ sigset_t *oset); } 341 MSTD POSIX { int sigsuspend(const sigset_t *sigmask); } 342 MSTD POSIX { int sigaction(int sig, const struct sigaction *act, \ struct sigaction *oact); } 343 MSTD POSIX { int sigpending(sigset_t *set); } 344 MSTD BSD { int sigreturn(const struct __ucontext *sigcntxp); } 345 UNIMPL NOHIDE sigtimedwait 346 UNIMPL NOHIDE sigwaitinfo 347 MSTD BSD { int __acl_get_file(const char *path, \ acl_type_t type, struct acl *aclp); } 348 MSTD BSD { int __acl_set_file(const char *path, \ acl_type_t type, struct acl *aclp); } 349 MSTD BSD { int __acl_get_fd(int filedes, acl_type_t type, \ struct acl *aclp); } 350 MSTD BSD { int __acl_set_fd(int filedes, acl_type_t type, \ struct acl *aclp); } 351 MSTD BSD { int __acl_delete_file(const char *path, \ acl_type_t type); } 352 MSTD BSD { int __acl_delete_fd(int filedes, acl_type_t type); } 353 MSTD BSD { int __acl_aclcheck_file(const char *path, \ acl_type_t type, struct acl *aclp); } 354 MSTD BSD { int __acl_aclcheck_fd(int filedes, acl_type_t type, \ struct acl *aclp); } 355 STD BSD { int extattrctl(const char *path, int cmd, \ const char *filename, int attrnamespace, \ const char *attrname); } 356 STD BSD { int extattr_set_file(const char *path, \ int attrnamespace, const char *attrname, \ void *data, size_t nbytes); } 357 STD BSD { ssize_t extattr_get_file(const char *path, \ int attrnamespace, const char *attrname, \ void *data, size_t nbytes); } 358 STD BSD { int extattr_delete_file(const char *path, \ int attrnamespace, const char *attrname); } 359 NOSTD BSD { int aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); } 360 MSTD BSD { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } 361 MSTD BSD { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } 362 MSTD BSD { int kqueue(void); } 363 MSTD BSD { int kevent(int fd, \ const struct kevent *changelist, int nchanges, \ struct kevent *eventlist, int nevents, \ const struct timespec *timeout); } 364 UNIMPL BSD __cap_get_proc 365 UNIMPL BSD __cap_set_proc 366 UNIMPL BSD __cap_get_fd 367 UNIMPL BSD __cap_get_file 368 UNIMPL BSD __cap_set_fd 369 UNIMPL BSD __cap_set_file 370 NODEF NOHIDE lkmressys lkmressys nosys_args int 371 STD BSD { int extattr_set_fd(int fd, int attrnamespace, \ const char *attrname, void *data, \ size_t nbytes); } 372 STD BSD { ssize_t extattr_get_fd(int fd, int attrnamespace, \ const char *attrname, void *data, size_t nbytes); } 373 STD BSD { int extattr_delete_fd(int fd, int attrnamespace, \ const char *attrname); } 374 MSTD BSD { int __setugid(int flag); } 375 NOIMPL BSD { int nfsclnt(int flag, caddr_t argp); } 376 STD BSD { int eaccess(char *path, int flags); } 377 UNIMPL BSD afs_syscall 378 STD BSD { int nmount(struct iovec *iovp, unsigned int iovcnt, \ int flags); } 379 STD BSD { int kse_exit(void); } 380 STD BSD { int kse_wakeup(void); } 381 STD BSD { int kse_new(struct kse_mailbox * mbx, \ int new_grp_flag); } 382 STD BSD { int thread_wakeup(struct thread_mailbox *tmbx); } 383 MSTD BSD { int kse_yield(void); } 384 UNIMPL BSD __mac_get_proc 385 UNIMPL BSD __mac_set_proc 386 UNIMPL BSD __mac_get_fd 387 UNIMPL BSD __mac_get_file 388 UNIMPL BSD __mac_set_fd 389 UNIMPL BSD __mac_set_file 390 STD BSD { int kenv(int what, const char *name, char *value, \ int len); } 391 STD BSD { int lchflags(const char *path, int flags); } 392 STD BSD { int uuidgen(struct uuid *store, int count); } +393 MSTD BSD { int sendfile(int fd, int s, off_t offset, size_t nbytes, \ + struct sf_hdtr *hdtr, off_t *sbytes, int flags); } Index: head/sys/kern/uipc_syscalls.c =================================================================== --- head/sys/kern/uipc_syscalls.c (revision 99854) +++ head/sys/kern/uipc_syscalls.c (revision 99855) @@ -1,1945 +1,1978 @@ /* * Copyright (c) 1982, 1986, 1989, 1990, 1993 * The Regents of the University of California. All rights reserved. * * sendfile(2) and related extensions: * Copyright (c) 1998, David Greenman. 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 the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94 * $FreeBSD$ */ #include "opt_compat.h" #include "opt_ktrace.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KTRACE #include #endif #include #include #include #include #include #include static void sf_buf_init(void *arg); SYSINIT(sock_sf, SI_SUB_MBUF, SI_ORDER_ANY, sf_buf_init, NULL) struct sf_buf *sf_buf_alloc(void); void sf_buf_free(void *addr, void *args); static int sendit(struct thread *td, int s, struct msghdr *mp, int flags); static int recvit(struct thread *td, int s, struct msghdr *mp, void *namelenp); static int accept1(struct thread *td, struct accept_args *uap, int compat); +static int do_sendfile(struct thread *td, struct sendfile_args *uap, int compat); static int getsockname1(struct thread *td, struct getsockname_args *uap, int compat); static int getpeername1(struct thread *td, struct getpeername_args *uap, int compat); /* * Expanded sf_freelist head. Really an SLIST_HEAD() in disguise, with the * sf_freelist head with the sf_lock mutex. */ static struct { SLIST_HEAD(, sf_buf) sf_head; struct mtx sf_lock; } sf_freelist; vm_offset_t sf_base; struct sf_buf *sf_bufs; u_int sf_buf_alloc_want; /* * System call interface to the socket abstraction. */ #if defined(COMPAT_43) || defined(COMPAT_SUNOS) #define COMPAT_OLDSOCK #endif extern struct fileops socketops; /* * MPSAFE */ int socket(td, uap) struct thread *td; register struct socket_args /* { int domain; int type; int protocol; } */ *uap; { struct filedesc *fdp; struct socket *so; struct file *fp; int fd, error; mtx_lock(&Giant); fdp = td->td_proc->p_fd; error = falloc(td, &fp, &fd); if (error) goto done2; fhold(fp); error = socreate(uap->domain, &so, uap->type, uap->protocol, td->td_ucred, td); FILEDESC_LOCK(fdp); if (error) { if (fdp->fd_ofiles[fd] == fp) { fdp->fd_ofiles[fd] = NULL; FILEDESC_UNLOCK(fdp); fdrop(fp, td); } else FILEDESC_UNLOCK(fdp); } else { fp->f_data = so; /* already has ref count */ fp->f_flag = FREAD|FWRITE; fp->f_ops = &socketops; fp->f_type = DTYPE_SOCKET; FILEDESC_UNLOCK(fdp); td->td_retval[0] = fd; } fdrop(fp, td); done2: mtx_unlock(&Giant); return (error); } /* * MPSAFE */ /* ARGSUSED */ int bind(td, uap) struct thread *td; register struct bind_args /* { int s; caddr_t name; int namelen; } */ *uap; { struct socket *so; struct sockaddr *sa; int error; mtx_lock(&Giant); if ((error = fgetsock(td, uap->s, &so, NULL)) != 0) goto done2; if ((error = getsockaddr(&sa, uap->name, uap->namelen)) != 0) goto done1; error = sobind(so, sa, td); FREE(sa, M_SONAME); done1: fputsock(so); done2: mtx_unlock(&Giant); return (error); } /* * MPSAFE */ /* ARGSUSED */ int listen(td, uap) struct thread *td; register struct listen_args /* { int s; int backlog; } */ *uap; { struct socket *so; int error; mtx_lock(&Giant); if ((error = fgetsock(td, uap->s, &so, NULL)) == 0) { error = solisten(so, uap->backlog, td); fputsock(so); } mtx_unlock(&Giant); return(error); } /* * accept1() * MPSAFE */ static int accept1(td, uap, compat) struct thread *td; register struct accept_args /* { int s; caddr_t name; int *anamelen; } */ *uap; int compat; { struct filedesc *fdp; struct file *nfp = NULL; struct sockaddr *sa; int namelen, error, s; struct socket *head, *so; int fd; u_int fflag; mtx_lock(&Giant); fdp = td->td_proc->p_fd; if (uap->name) { error = copyin(uap->anamelen, &namelen, sizeof (namelen)); if(error) goto done2; } error = fgetsock(td, uap->s, &head, &fflag); if (error) goto done2; s = splnet(); if ((head->so_options & SO_ACCEPTCONN) == 0) { splx(s); error = EINVAL; goto done; } if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) { splx(s); error = EWOULDBLOCK; goto done; } while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) { if (head->so_state & SS_CANTRCVMORE) { head->so_error = ECONNABORTED; break; } error = tsleep(&head->so_timeo, PSOCK | PCATCH, "accept", 0); if (error) { splx(s); goto done; } } if (head->so_error) { error = head->so_error; head->so_error = 0; splx(s); goto done; } /* * At this point we know that there is at least one connection * ready to be accepted. Remove it from the queue prior to * allocating the file descriptor for it since falloc() may * block allowing another process to accept the connection * instead. */ so = TAILQ_FIRST(&head->so_comp); TAILQ_REMOVE(&head->so_comp, so, so_list); head->so_qlen--; error = falloc(td, &nfp, &fd); if (error) { /* * Probably ran out of file descriptors. Put the * unaccepted connection back onto the queue and * do another wakeup so some other process might * have a chance at it. */ TAILQ_INSERT_HEAD(&head->so_comp, so, so_list); head->so_qlen++; wakeup_one(&head->so_timeo); splx(s); goto done; } fhold(nfp); td->td_retval[0] = fd; /* connection has been removed from the listen queue */ KNOTE(&head->so_rcv.sb_sel.si_note, 0); so->so_state &= ~SS_COMP; so->so_head = NULL; if (head->so_sigio != NULL) fsetown(fgetown(head->so_sigio), &so->so_sigio); FILE_LOCK(nfp); soref(so); /* file descriptor reference */ nfp->f_data = so; /* nfp has ref count from falloc */ nfp->f_flag = fflag; nfp->f_ops = &socketops; nfp->f_type = DTYPE_SOCKET; FILE_UNLOCK(nfp); sa = 0; error = soaccept(so, &sa); if (error) { /* * return a namelen of zero for older code which might * ignore the return value from accept. */ if (uap->name != NULL) { namelen = 0; (void) copyout(&namelen, uap->anamelen, sizeof(*uap->anamelen)); } goto noconnection; } if (sa == NULL) { namelen = 0; if (uap->name) goto gotnoname; splx(s); error = 0; goto done; } if (uap->name) { /* check sa_len before it is destroyed */ if (namelen > sa->sa_len) namelen = sa->sa_len; #ifdef COMPAT_OLDSOCK if (compat) ((struct osockaddr *)sa)->sa_family = sa->sa_family; #endif error = copyout(sa, uap->name, (u_int)namelen); if (!error) gotnoname: error = copyout(&namelen, uap->anamelen, sizeof (*uap->anamelen)); } noconnection: if (sa) FREE(sa, M_SONAME); /* * close the new descriptor, assuming someone hasn't ripped it * out from under us. */ if (error) { FILEDESC_LOCK(fdp); if (fdp->fd_ofiles[fd] == nfp) { fdp->fd_ofiles[fd] = NULL; FILEDESC_UNLOCK(fdp); fdrop(nfp, td); } else { FILEDESC_UNLOCK(fdp); } } splx(s); /* * Release explicitly held references before returning. */ done: if (nfp != NULL) fdrop(nfp, td); fputsock(head); done2: mtx_unlock(&Giant); return (error); } /* * MPSAFE (accept1() is MPSAFE) */ int accept(td, uap) struct thread *td; struct accept_args *uap; { return (accept1(td, uap, 0)); } #ifdef COMPAT_OLDSOCK /* * MPSAFE (accept1() is MPSAFE) */ int oaccept(td, uap) struct thread *td; struct accept_args *uap; { return (accept1(td, uap, 1)); } #endif /* COMPAT_OLDSOCK */ /* * MPSAFE */ /* ARGSUSED */ int connect(td, uap) struct thread *td; register struct connect_args /* { int s; caddr_t name; int namelen; } */ *uap; { struct socket *so; struct sockaddr *sa; int error, s; mtx_lock(&Giant); if ((error = fgetsock(td, uap->s, &so, NULL)) != 0) goto done2; if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { error = EALREADY; goto done1; } error = getsockaddr(&sa, uap->name, uap->namelen); if (error) goto done1; error = soconnect(so, sa, td); if (error) goto bad; if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { FREE(sa, M_SONAME); error = EINPROGRESS; goto done1; } s = splnet(); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { error = tsleep(&so->so_timeo, PSOCK | PCATCH, "connec", 0); if (error) break; } if (error == 0) { error = so->so_error; so->so_error = 0; } splx(s); bad: so->so_state &= ~SS_ISCONNECTING; FREE(sa, M_SONAME); if (error == ERESTART) error = EINTR; done1: fputsock(so); done2: mtx_unlock(&Giant); return (error); } /* * MPSAFE */ int socketpair(td, uap) struct thread *td; register struct socketpair_args /* { int domain; int type; int protocol; int *rsv; } */ *uap; { register struct filedesc *fdp = td->td_proc->p_fd; struct file *fp1, *fp2; struct socket *so1, *so2; int fd, error, sv[2]; mtx_lock(&Giant); error = socreate(uap->domain, &so1, uap->type, uap->protocol, td->td_ucred, td); if (error) goto done2; error = socreate(uap->domain, &so2, uap->type, uap->protocol, td->td_ucred, td); if (error) goto free1; error = falloc(td, &fp1, &fd); if (error) goto free2; fhold(fp1); sv[0] = fd; fp1->f_data = so1; /* so1 already has ref count */ error = falloc(td, &fp2, &fd); if (error) goto free3; fhold(fp2); fp2->f_data = so2; /* so2 already has ref count */ sv[1] = fd; error = soconnect2(so1, so2); if (error) goto free4; if (uap->type == SOCK_DGRAM) { /* * Datagram socket connection is asymmetric. */ error = soconnect2(so2, so1); if (error) goto free4; } FILE_LOCK(fp1); fp1->f_flag = FREAD|FWRITE; fp1->f_ops = &socketops; fp1->f_type = DTYPE_SOCKET; FILE_UNLOCK(fp1); FILE_LOCK(fp2); fp2->f_flag = FREAD|FWRITE; fp2->f_ops = &socketops; fp2->f_type = DTYPE_SOCKET; FILE_UNLOCK(fp2); error = copyout(sv, uap->rsv, 2 * sizeof (int)); fdrop(fp1, td); fdrop(fp2, td); goto done2; free4: FILEDESC_LOCK(fdp); if (fdp->fd_ofiles[sv[1]] == fp2) { fdp->fd_ofiles[sv[1]] = NULL; FILEDESC_UNLOCK(fdp); fdrop(fp2, td); } else FILEDESC_UNLOCK(fdp); fdrop(fp2, td); free3: FILEDESC_LOCK(fdp); if (fdp->fd_ofiles[sv[0]] == fp1) { fdp->fd_ofiles[sv[0]] = NULL; FILEDESC_UNLOCK(fdp); fdrop(fp1, td); } else FILEDESC_UNLOCK(fdp); fdrop(fp1, td); free2: (void)soclose(so2); free1: (void)soclose(so1); done2: mtx_unlock(&Giant); return (error); } static int sendit(td, s, mp, flags) register struct thread *td; int s; register struct msghdr *mp; int flags; { struct uio auio; register struct iovec *iov; register int i; struct mbuf *control; struct sockaddr *to = NULL; int len, error; struct socket *so; #ifdef KTRACE struct iovec *ktriov = NULL; struct uio ktruio; int iovlen; #endif if ((error = fgetsock(td, s, &so, NULL)) != 0) return (error); auio.uio_iov = mp->msg_iov; auio.uio_iovcnt = mp->msg_iovlen; auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_WRITE; auio.uio_td = td; auio.uio_offset = 0; /* XXX */ auio.uio_resid = 0; iov = mp->msg_iov; for (i = 0; i < mp->msg_iovlen; i++, iov++) { if ((auio.uio_resid += iov->iov_len) < 0) { error = EINVAL; goto bad; } } if (mp->msg_name) { error = getsockaddr(&to, mp->msg_name, mp->msg_namelen); if (error) goto bad; } if (mp->msg_control) { if (mp->msg_controllen < sizeof(struct cmsghdr) #ifdef COMPAT_OLDSOCK && mp->msg_flags != MSG_COMPAT #endif ) { error = EINVAL; goto bad; } error = sockargs(&control, mp->msg_control, mp->msg_controllen, MT_CONTROL); if (error) goto bad; #ifdef COMPAT_OLDSOCK if (mp->msg_flags == MSG_COMPAT) { register struct cmsghdr *cm; M_PREPEND(control, sizeof(*cm), M_TRYWAIT); if (control == 0) { error = ENOBUFS; goto bad; } else { cm = mtod(control, struct cmsghdr *); cm->cmsg_len = control->m_len; cm->cmsg_level = SOL_SOCKET; cm->cmsg_type = SCM_RIGHTS; } } #endif } else { control = 0; } #ifdef KTRACE if (KTRPOINT(td, KTR_GENIO)) { iovlen = auio.uio_iovcnt * sizeof (struct iovec); MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); bcopy(auio.uio_iov, ktriov, iovlen); ktruio = auio; } #endif len = auio.uio_resid; error = so->so_proto->pr_usrreqs->pru_sosend(so, to, &auio, 0, control, flags, td); if (error) { if (auio.uio_resid != len && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; /* Generation of SIGPIPE can be controlled per socket */ if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE)) { PROC_LOCK(td->td_proc); psignal(td->td_proc, SIGPIPE); PROC_UNLOCK(td->td_proc); } } if (error == 0) td->td_retval[0] = len - auio.uio_resid; #ifdef KTRACE if (ktriov != NULL) { if (error == 0) { ktruio.uio_iov = ktriov; ktruio.uio_resid = td->td_retval[0]; ktrgenio(s, UIO_WRITE, &ktruio, error); } FREE(ktriov, M_TEMP); } #endif bad: fputsock(so); if (to) FREE(to, M_SONAME); return (error); } /* * MPSAFE */ int sendto(td, uap) struct thread *td; register struct sendto_args /* { int s; caddr_t buf; size_t len; int flags; caddr_t to; int tolen; } */ *uap; { struct msghdr msg; struct iovec aiov; int error; msg.msg_name = uap->to; msg.msg_namelen = uap->tolen; msg.msg_iov = &aiov; msg.msg_iovlen = 1; msg.msg_control = 0; #ifdef COMPAT_OLDSOCK msg.msg_flags = 0; #endif aiov.iov_base = uap->buf; aiov.iov_len = uap->len; mtx_lock(&Giant); error = sendit(td, uap->s, &msg, uap->flags); mtx_unlock(&Giant); return (error); } #ifdef COMPAT_OLDSOCK /* * MPSAFE */ int osend(td, uap) struct thread *td; register struct osend_args /* { int s; caddr_t buf; int len; int flags; } */ *uap; { struct msghdr msg; struct iovec aiov; int error; msg.msg_name = 0; msg.msg_namelen = 0; msg.msg_iov = &aiov; msg.msg_iovlen = 1; aiov.iov_base = uap->buf; aiov.iov_len = uap->len; msg.msg_control = 0; msg.msg_flags = 0; mtx_lock(&Giant); error = sendit(td, uap->s, &msg, uap->flags); mtx_unlock(&Giant); return (error); } /* * MPSAFE */ int osendmsg(td, uap) struct thread *td; register struct osendmsg_args /* { int s; caddr_t msg; int flags; } */ *uap; { struct msghdr msg; struct iovec aiov[UIO_SMALLIOV], *iov; int error; mtx_lock(&Giant); error = copyin(uap->msg, &msg, sizeof (struct omsghdr)); if (error) goto done2; if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) { if ((u_int)msg.msg_iovlen >= UIO_MAXIOV) { error = EMSGSIZE; goto done2; } MALLOC(iov, struct iovec *, sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, M_WAITOK); } else { iov = aiov; } error = copyin(msg.msg_iov, iov, (unsigned)(msg.msg_iovlen * sizeof (struct iovec))); if (error) goto done; msg.msg_flags = MSG_COMPAT; msg.msg_iov = iov; error = sendit(td, uap->s, &msg, uap->flags); done: if (iov != aiov) FREE(iov, M_IOV); done2: mtx_unlock(&Giant); return (error); } #endif /* * MPSAFE */ int sendmsg(td, uap) struct thread *td; register struct sendmsg_args /* { int s; caddr_t msg; int flags; } */ *uap; { struct msghdr msg; struct iovec aiov[UIO_SMALLIOV], *iov; int error; mtx_lock(&Giant); error = copyin(uap->msg, &msg, sizeof (msg)); if (error) goto done2; if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) { if ((u_int)msg.msg_iovlen >= UIO_MAXIOV) { error = EMSGSIZE; goto done2; } MALLOC(iov, struct iovec *, sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, M_WAITOK); } else { iov = aiov; } if (msg.msg_iovlen && (error = copyin(msg.msg_iov, iov, (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))) goto done; msg.msg_iov = iov; #ifdef COMPAT_OLDSOCK msg.msg_flags = 0; #endif error = sendit(td, uap->s, &msg, uap->flags); done: if (iov != aiov) FREE(iov, M_IOV); done2: mtx_unlock(&Giant); return (error); } static int recvit(td, s, mp, namelenp) register struct thread *td; int s; register struct msghdr *mp; void *namelenp; { struct uio auio; register struct iovec *iov; register int i; int len, error; struct mbuf *m, *control = 0; caddr_t ctlbuf; struct socket *so; struct sockaddr *fromsa = 0; #ifdef KTRACE struct iovec *ktriov = NULL; struct uio ktruio; int iovlen; #endif if ((error = fgetsock(td, s, &so, NULL)) != 0) return (error); auio.uio_iov = mp->msg_iov; auio.uio_iovcnt = mp->msg_iovlen; auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_READ; auio.uio_td = td; auio.uio_offset = 0; /* XXX */ auio.uio_resid = 0; iov = mp->msg_iov; for (i = 0; i < mp->msg_iovlen; i++, iov++) { if ((auio.uio_resid += iov->iov_len) < 0) { fputsock(so); return (EINVAL); } } #ifdef KTRACE if (KTRPOINT(td, KTR_GENIO)) { iovlen = auio.uio_iovcnt * sizeof (struct iovec); MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); bcopy(auio.uio_iov, ktriov, iovlen); ktruio = auio; } #endif len = auio.uio_resid; error = so->so_proto->pr_usrreqs->pru_soreceive(so, &fromsa, &auio, (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0, &mp->msg_flags); if (error) { if (auio.uio_resid != len && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; } #ifdef KTRACE if (ktriov != NULL) { if (error == 0) { ktruio.uio_iov = ktriov; ktruio.uio_resid = len - auio.uio_resid; ktrgenio(s, UIO_READ, &ktruio, error); } FREE(ktriov, M_TEMP); } #endif if (error) goto out; td->td_retval[0] = len - auio.uio_resid; if (mp->msg_name) { len = mp->msg_namelen; if (len <= 0 || fromsa == 0) len = 0; else { #ifndef MIN #define MIN(a,b) ((a)>(b)?(b):(a)) #endif /* save sa_len before it is destroyed by MSG_COMPAT */ len = MIN(len, fromsa->sa_len); #ifdef COMPAT_OLDSOCK if (mp->msg_flags & MSG_COMPAT) ((struct osockaddr *)fromsa)->sa_family = fromsa->sa_family; #endif error = copyout(fromsa, mp->msg_name, (unsigned)len); if (error) goto out; } mp->msg_namelen = len; if (namelenp && (error = copyout(&len, namelenp, sizeof (int)))) { #ifdef COMPAT_OLDSOCK if (mp->msg_flags & MSG_COMPAT) error = 0; /* old recvfrom didn't check */ else #endif goto out; } } if (mp->msg_control) { #ifdef COMPAT_OLDSOCK /* * We assume that old recvmsg calls won't receive access * rights and other control info, esp. as control info * is always optional and those options didn't exist in 4.3. * If we receive rights, trim the cmsghdr; anything else * is tossed. */ if (control && mp->msg_flags & MSG_COMPAT) { if (mtod(control, struct cmsghdr *)->cmsg_level != SOL_SOCKET || mtod(control, struct cmsghdr *)->cmsg_type != SCM_RIGHTS) { mp->msg_controllen = 0; goto out; } control->m_len -= sizeof (struct cmsghdr); control->m_data += sizeof (struct cmsghdr); } #endif len = mp->msg_controllen; m = control; mp->msg_controllen = 0; ctlbuf = mp->msg_control; while (m && len > 0) { unsigned int tocopy; if (len >= m->m_len) tocopy = m->m_len; else { mp->msg_flags |= MSG_CTRUNC; tocopy = len; } if ((error = copyout(mtod(m, caddr_t), ctlbuf, tocopy)) != 0) goto out; ctlbuf += tocopy; len -= tocopy; m = m->m_next; } mp->msg_controllen = ctlbuf - (caddr_t)mp->msg_control; } out: fputsock(so); if (fromsa) FREE(fromsa, M_SONAME); if (control) m_freem(control); return (error); } /* * MPSAFE */ int recvfrom(td, uap) struct thread *td; register struct recvfrom_args /* { int s; caddr_t buf; size_t len; int flags; caddr_t from; int *fromlenaddr; } */ *uap; { struct msghdr msg; struct iovec aiov; int error; mtx_lock(&Giant); if (uap->fromlenaddr) { error = copyin(uap->fromlenaddr, &msg.msg_namelen, sizeof (msg.msg_namelen)); if (error) goto done2; } else { msg.msg_namelen = 0; } msg.msg_name = uap->from; msg.msg_iov = &aiov; msg.msg_iovlen = 1; aiov.iov_base = uap->buf; aiov.iov_len = uap->len; msg.msg_control = 0; msg.msg_flags = uap->flags; error = recvit(td, uap->s, &msg, uap->fromlenaddr); done2: mtx_unlock(&Giant); return(error); } #ifdef COMPAT_OLDSOCK /* * MPSAFE */ int orecvfrom(td, uap) struct thread *td; struct recvfrom_args *uap; { uap->flags |= MSG_COMPAT; return (recvfrom(td, uap)); } #endif #ifdef COMPAT_OLDSOCK /* * MPSAFE */ int orecv(td, uap) struct thread *td; register struct orecv_args /* { int s; caddr_t buf; int len; int flags; } */ *uap; { struct msghdr msg; struct iovec aiov; int error; mtx_lock(&Giant); msg.msg_name = 0; msg.msg_namelen = 0; msg.msg_iov = &aiov; msg.msg_iovlen = 1; aiov.iov_base = uap->buf; aiov.iov_len = uap->len; msg.msg_control = 0; msg.msg_flags = uap->flags; error = recvit(td, uap->s, &msg, NULL); mtx_unlock(&Giant); return (error); } /* * Old recvmsg. This code takes advantage of the fact that the old msghdr * overlays the new one, missing only the flags, and with the (old) access * rights where the control fields are now. * * MPSAFE */ int orecvmsg(td, uap) struct thread *td; register struct orecvmsg_args /* { int s; struct omsghdr *msg; int flags; } */ *uap; { struct msghdr msg; struct iovec aiov[UIO_SMALLIOV], *iov; int error; error = copyin(uap->msg, &msg, sizeof (struct omsghdr)); if (error) return (error); mtx_lock(&Giant); if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) { if ((u_int)msg.msg_iovlen >= UIO_MAXIOV) { error = EMSGSIZE; goto done2; } MALLOC(iov, struct iovec *, sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, M_WAITOK); } else { iov = aiov; } msg.msg_flags = uap->flags | MSG_COMPAT; error = copyin(msg.msg_iov, iov, (unsigned)(msg.msg_iovlen * sizeof (struct iovec))); if (error) goto done; msg.msg_iov = iov; error = recvit(td, uap->s, &msg, &uap->msg->msg_namelen); if (msg.msg_controllen && error == 0) error = copyout(&msg.msg_controllen, &uap->msg->msg_accrightslen, sizeof (int)); done: if (iov != aiov) FREE(iov, M_IOV); done2: mtx_unlock(&Giant); return (error); } #endif /* * MPSAFE */ int recvmsg(td, uap) struct thread *td; register struct recvmsg_args /* { int s; struct msghdr *msg; int flags; } */ *uap; { struct msghdr msg; struct iovec aiov[UIO_SMALLIOV], *uiov, *iov; register int error; mtx_lock(&Giant); error = copyin(uap->msg, &msg, sizeof (msg)); if (error) goto done2; if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) { if ((u_int)msg.msg_iovlen >= UIO_MAXIOV) { error = EMSGSIZE; goto done2; } MALLOC(iov, struct iovec *, sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV, M_WAITOK); } else { iov = aiov; } #ifdef COMPAT_OLDSOCK msg.msg_flags = uap->flags &~ MSG_COMPAT; #else msg.msg_flags = uap->flags; #endif uiov = msg.msg_iov; msg.msg_iov = iov; error = copyin(uiov, iov, (unsigned)(msg.msg_iovlen * sizeof (struct iovec))); if (error) goto done; error = recvit(td, uap->s, &msg, NULL); if (!error) { msg.msg_iov = uiov; error = copyout(&msg, uap->msg, sizeof(msg)); } done: if (iov != aiov) FREE(iov, M_IOV); done2: mtx_unlock(&Giant); return (error); } /* * MPSAFE */ /* ARGSUSED */ int shutdown(td, uap) struct thread *td; register struct shutdown_args /* { int s; int how; } */ *uap; { struct socket *so; int error; mtx_lock(&Giant); if ((error = fgetsock(td, uap->s, &so, NULL)) == 0) { error = soshutdown(so, uap->how); fputsock(so); } mtx_unlock(&Giant); return(error); } /* * MPSAFE */ /* ARGSUSED */ int setsockopt(td, uap) struct thread *td; register struct setsockopt_args /* { int s; int level; int name; caddr_t val; int valsize; } */ *uap; { struct socket *so; struct sockopt sopt; int error; if (uap->val == 0 && uap->valsize != 0) return (EFAULT); if (uap->valsize < 0) return (EINVAL); mtx_lock(&Giant); if ((error = fgetsock(td, uap->s, &so, NULL)) == 0) { sopt.sopt_dir = SOPT_SET; sopt.sopt_level = uap->level; sopt.sopt_name = uap->name; sopt.sopt_val = uap->val; sopt.sopt_valsize = uap->valsize; sopt.sopt_td = td; error = sosetopt(so, &sopt); fputsock(so); } mtx_unlock(&Giant); return(error); } /* * MPSAFE */ /* ARGSUSED */ int getsockopt(td, uap) struct thread *td; register struct getsockopt_args /* { int s; int level; int name; caddr_t val; int *avalsize; } */ *uap; { int valsize, error; struct socket *so; struct sockopt sopt; mtx_lock(&Giant); if ((error = fgetsock(td, uap->s, &so, NULL)) != 0) goto done2; if (uap->val) { error = copyin(uap->avalsize, &valsize, sizeof (valsize)); if (error) goto done1; if (valsize < 0) { error = EINVAL; goto done1; } } else { valsize = 0; } sopt.sopt_dir = SOPT_GET; sopt.sopt_level = uap->level; sopt.sopt_name = uap->name; sopt.sopt_val = uap->val; sopt.sopt_valsize = (size_t)valsize; /* checked non-negative above */ sopt.sopt_td = td; error = sogetopt(so, &sopt); if (error == 0) { valsize = sopt.sopt_valsize; error = copyout(&valsize, uap->avalsize, sizeof (valsize)); } done1: fputsock(so); done2: mtx_unlock(&Giant); return (error); } /* * getsockname1() - Get socket name. * * MPSAFE */ /* ARGSUSED */ static int getsockname1(td, uap, compat) struct thread *td; register struct getsockname_args /* { int fdes; caddr_t asa; int *alen; } */ *uap; int compat; { struct socket *so; struct sockaddr *sa; int len, error; mtx_lock(&Giant); if ((error = fgetsock(td, uap->fdes, &so, NULL)) != 0) goto done2; error = copyin(uap->alen, &len, sizeof (len)); if (error) goto done1; sa = 0; error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &sa); if (error) goto bad; if (sa == 0) { len = 0; goto gotnothing; } len = MIN(len, sa->sa_len); #ifdef COMPAT_OLDSOCK if (compat) ((struct osockaddr *)sa)->sa_family = sa->sa_family; #endif error = copyout(sa, uap->asa, (u_int)len); if (error == 0) gotnothing: error = copyout(&len, uap->alen, sizeof (len)); bad: if (sa) FREE(sa, M_SONAME); done1: fputsock(so); done2: mtx_unlock(&Giant); return (error); } /* * MPSAFE */ int getsockname(td, uap) struct thread *td; struct getsockname_args *uap; { return (getsockname1(td, uap, 0)); } #ifdef COMPAT_OLDSOCK /* * MPSAFE */ int ogetsockname(td, uap) struct thread *td; struct getsockname_args *uap; { return (getsockname1(td, uap, 1)); } #endif /* COMPAT_OLDSOCK */ /* * getpeername1() - Get name of peer for connected socket. * * MPSAFE */ /* ARGSUSED */ static int getpeername1(td, uap, compat) struct thread *td; register struct getpeername_args /* { int fdes; caddr_t asa; int *alen; } */ *uap; int compat; { struct socket *so; struct sockaddr *sa; int len, error; mtx_lock(&Giant); if ((error = fgetsock(td, uap->fdes, &so, NULL)) != 0) goto done2; if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) { error = ENOTCONN; goto done1; } error = copyin(uap->alen, &len, sizeof (len)); if (error) goto done1; sa = 0; error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &sa); if (error) goto bad; if (sa == 0) { len = 0; goto gotnothing; } len = MIN(len, sa->sa_len); #ifdef COMPAT_OLDSOCK if (compat) ((struct osockaddr *)sa)->sa_family = sa->sa_family; #endif error = copyout(sa, uap->asa, (u_int)len); if (error) goto bad; gotnothing: error = copyout(&len, uap->alen, sizeof (len)); bad: if (sa) FREE(sa, M_SONAME); done1: fputsock(so); done2: mtx_unlock(&Giant); return (error); } /* * MPSAFE */ int getpeername(td, uap) struct thread *td; struct getpeername_args *uap; { return (getpeername1(td, uap, 0)); } #ifdef COMPAT_OLDSOCK /* * MPSAFE */ int ogetpeername(td, uap) struct thread *td; struct ogetpeername_args *uap; { /* XXX uap should have type `getpeername_args *' to begin with. */ return (getpeername1(td, (struct getpeername_args *)uap, 1)); } #endif /* COMPAT_OLDSOCK */ int sockargs(mp, buf, buflen, type) struct mbuf **mp; caddr_t buf; int buflen, type; { register struct sockaddr *sa; register struct mbuf *m; int error; if ((u_int)buflen > MLEN) { #ifdef COMPAT_OLDSOCK if (type == MT_SONAME && (u_int)buflen <= 112) buflen = MLEN; /* unix domain compat. hack */ else #endif return (EINVAL); } m = m_get(M_TRYWAIT, type); if (m == NULL) return (ENOBUFS); m->m_len = buflen; error = copyin(buf, mtod(m, caddr_t), (u_int)buflen); if (error) (void) m_free(m); else { *mp = m; if (type == MT_SONAME) { sa = mtod(m, struct sockaddr *); #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN if (sa->sa_family == 0 && sa->sa_len < AF_MAX) sa->sa_family = sa->sa_len; #endif sa->sa_len = buflen; } } return (error); } int getsockaddr(namp, uaddr, len) struct sockaddr **namp; caddr_t uaddr; size_t len; { struct sockaddr *sa; int error; if (len > SOCK_MAXADDRLEN) return ENAMETOOLONG; MALLOC(sa, struct sockaddr *, len, M_SONAME, M_WAITOK); error = copyin(uaddr, sa, len); if (error) { FREE(sa, M_SONAME); } else { #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN if (sa->sa_family == 0 && sa->sa_len < AF_MAX) sa->sa_family = sa->sa_len; #endif sa->sa_len = len; *namp = sa; } return error; } /* * Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-)) * XXX - The sf_buf functions are currently private to sendfile(2), so have * been made static, but may be useful in the future for doing zero-copy in * other parts of the networking code. */ static void sf_buf_init(void *arg) { int i; mtx_init(&sf_freelist.sf_lock, "sf_bufs list lock", NULL, MTX_DEF); mtx_lock(&sf_freelist.sf_lock); SLIST_INIT(&sf_freelist.sf_head); sf_base = kmem_alloc_pageable(kernel_map, nsfbufs * PAGE_SIZE); sf_bufs = malloc(nsfbufs * sizeof(struct sf_buf), M_TEMP, M_NOWAIT | M_ZERO); for (i = 0; i < nsfbufs; i++) { sf_bufs[i].kva = sf_base + i * PAGE_SIZE; SLIST_INSERT_HEAD(&sf_freelist.sf_head, &sf_bufs[i], free_list); } sf_buf_alloc_want = 0; mtx_unlock(&sf_freelist.sf_lock); } /* * Get an sf_buf from the freelist. Will block if none are available. */ struct sf_buf * sf_buf_alloc() { struct sf_buf *sf; int error; mtx_lock(&sf_freelist.sf_lock); while ((sf = SLIST_FIRST(&sf_freelist.sf_head)) == NULL) { sf_buf_alloc_want++; error = msleep(&sf_freelist, &sf_freelist.sf_lock, PVM|PCATCH, "sfbufa", 0); sf_buf_alloc_want--; /* * If we got a signal, don't risk going back to sleep. */ if (error) break; } if (sf != NULL) SLIST_REMOVE_HEAD(&sf_freelist.sf_head, free_list); mtx_unlock(&sf_freelist.sf_lock); return (sf); } #define dtosf(x) (&sf_bufs[((uintptr_t)(x) - (uintptr_t)sf_base) >> PAGE_SHIFT]) /* * Detatch mapped page and release resources back to the system. */ void sf_buf_free(void *addr, void *args) { struct sf_buf *sf; struct vm_page *m; GIANT_REQUIRED; sf = dtosf(addr); pmap_qremove((vm_offset_t)addr, 1); m = sf->m; vm_page_unwire(m, 0); /* * Check for the object going away on us. This can * happen since we don't hold a reference to it. * If so, we're responsible for freeing the page. */ if (m->wire_count == 0 && m->object == NULL) vm_page_free(m); sf->m = NULL; mtx_lock(&sf_freelist.sf_lock); SLIST_INSERT_HEAD(&sf_freelist.sf_head, sf, free_list); if (sf_buf_alloc_want > 0) wakeup_one(&sf_freelist); mtx_unlock(&sf_freelist.sf_lock); } /* * sendfile(2) * * MPSAFE * * int sendfile(int fd, int s, off_t offset, size_t nbytes, * struct sf_hdtr *hdtr, off_t *sbytes, int flags) * * Send a file specified by 'fd' and starting at 'offset' to a socket * specified by 's'. Send only 'nbytes' of the file or until EOF if * nbytes == 0. Optionally add a header and/or trailer to the socket * output. If specified, write the total number of bytes sent into *sbytes. * */ int sendfile(struct thread *td, struct sendfile_args *uap) { + + return (do_sendfile(td, uap, 0)); +} + +#ifdef COMPAT_FREEBSD4 +int +freebsd4_sendfile(struct thread *td, struct freebsd4_sendfile_args *uap) +{ + struct sendfile_args args; + + args.fd = uap->fd; + args.s = uap->s; + args.offset = uap->offset; + args.nbytes = uap->nbytes; + args.hdtr = uap->hdtr; + args.sbytes = uap->sbytes; + args.flags = uap->flags; + + return (do_sendfile(td, &args, 1)); +} +#endif /* COMPAT_FREEBSD4 */ + +static int +do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) +{ struct vnode *vp; struct vm_object *obj; struct socket *so = NULL; struct mbuf *m; struct sf_buf *sf; struct vm_page *pg; struct writev_args nuap; struct sf_hdtr hdtr; off_t off, xfsize, hdtr_size, sbytes = 0; int error, s; mtx_lock(&Giant); hdtr_size = 0; /* * The descriptor must be a regular file and have a backing VM object. */ if ((error = fgetvp_read(td, uap->fd, &vp)) != 0) goto done; if (vp->v_type != VREG || VOP_GETVOBJECT(vp, &obj) != 0) { error = EINVAL; goto done; } if ((error = fgetsock(td, uap->s, &so, NULL)) != 0) goto done; if (so->so_type != SOCK_STREAM) { error = EINVAL; goto done; } if ((so->so_state & SS_ISCONNECTED) == 0) { error = ENOTCONN; goto done; } if (uap->offset < 0) { error = EINVAL; goto done; } /* * If specified, get the pointer to the sf_hdtr struct for * any headers/trailers. */ if (uap->hdtr != NULL) { error = copyin(uap->hdtr, &hdtr, sizeof(hdtr)); if (error) goto done; /* * Send any headers. Wimp out and use writev(2). */ if (hdtr.headers != NULL) { nuap.fd = uap->s; nuap.iovp = hdtr.headers; nuap.iovcnt = hdtr.hdr_cnt; error = writev(td, &nuap); if (error) goto done; - hdtr_size += td->td_retval[0]; + if (compat) + sbytes += td->td_retval[0]; + else + hdtr_size += td->td_retval[0]; } } /* * Protect against multiple writers to the socket. */ (void) sblock(&so->so_snd, M_WAITOK); /* * Loop through the pages in the file, starting with the requested * offset. Get a file page (do I/O if necessary), map the file page * into an sf_buf, attach an mbuf header to the sf_buf, and queue * it on the socket. */ for (off = uap->offset; ; off += xfsize, sbytes += xfsize) { vm_pindex_t pindex; vm_offset_t pgoff; pindex = OFF_TO_IDX(off); retry_lookup: /* * Calculate the amount to transfer. Not to exceed a page, * the EOF, or the passed in nbytes. */ xfsize = obj->un_pager.vnp.vnp_size - off; if (xfsize > PAGE_SIZE) xfsize = PAGE_SIZE; pgoff = (vm_offset_t)(off & PAGE_MASK); if (PAGE_SIZE - pgoff < xfsize) xfsize = PAGE_SIZE - pgoff; if (uap->nbytes && xfsize > (uap->nbytes - sbytes)) xfsize = uap->nbytes - sbytes; if (xfsize <= 0) break; /* * Optimize the non-blocking case by looking at the socket space * before going to the extra work of constituting the sf_buf. */ if ((so->so_state & SS_NBIO) && sbspace(&so->so_snd) <= 0) { if (so->so_state & SS_CANTSENDMORE) error = EPIPE; else error = EAGAIN; sbunlock(&so->so_snd); goto done; } /* * Attempt to look up the page. * * Allocate if not found * * Wait and loop if busy. */ pg = vm_page_lookup(obj, pindex); if (pg == NULL) { pg = vm_page_alloc(obj, pindex, VM_ALLOC_NORMAL); if (pg == NULL) { VM_WAIT; goto retry_lookup; } vm_page_wakeup(pg); } else if (vm_page_sleep_busy(pg, TRUE, "sfpbsy")) { goto retry_lookup; } /* * Wire the page so it does not get ripped out from under * us. */ vm_page_wire(pg); /* * If page is not valid for what we need, initiate I/O */ if (!pg->valid || !vm_page_is_valid(pg, pgoff, xfsize)) { int bsize; /* * Ensure that our page is still around when the I/O * completes. */ vm_page_io_start(pg); /* * Get the page from backing store. */ bsize = vp->v_mount->mnt_stat.f_iosize; vn_lock(vp, LK_SHARED | LK_NOPAUSE | LK_RETRY, td); error = vn_rdwr(UIO_READ, vp, NULL, MAXBSIZE, trunc_page(off), UIO_NOCOPY, IO_NODELOCKED | IO_VMIO | ((MAXBSIZE / bsize) << 16), td->td_ucred, NULL, td); VOP_UNLOCK(vp, 0, td); vm_page_flag_clear(pg, PG_ZERO); vm_page_io_finish(pg); if (error) { vm_page_unwire(pg, 0); /* * See if anyone else might know about this page. * If not and it is not valid, then free it. */ if (pg->wire_count == 0 && pg->valid == 0 && pg->busy == 0 && !(pg->flags & PG_BUSY) && pg->hold_count == 0) { vm_page_busy(pg); vm_page_free(pg); } sbunlock(&so->so_snd); goto done; } } /* * Get a sendfile buf. We usually wait as long as necessary, * but this wait can be interrupted. */ if ((sf = sf_buf_alloc()) == NULL) { vm_page_unwire(pg, 0); if (pg->wire_count == 0 && pg->object == NULL) vm_page_free(pg); sbunlock(&so->so_snd); error = EINTR; goto done; } /* * Allocate a kernel virtual page and insert the physical page * into it. */ sf->m = pg; pmap_qenter(sf->kva, &pg, 1); /* * Get an mbuf header and set it up as having external storage. */ MGETHDR(m, M_TRYWAIT, MT_DATA); if (m == NULL) { error = ENOBUFS; sf_buf_free((void *)sf->kva, NULL); sbunlock(&so->so_snd); goto done; } /* * Setup external storage for mbuf. */ MEXTADD(m, sf->kva, PAGE_SIZE, sf_buf_free, NULL, M_RDONLY, EXT_SFBUF); m->m_data = (char *) sf->kva + pgoff; m->m_pkthdr.len = m->m_len = xfsize; /* * Add the buffer to the socket buffer chain. */ s = splnet(); retry_space: /* * Make sure that the socket is still able to take more data. * CANTSENDMORE being true usually means that the connection * was closed. so_error is true when an error was sensed after * a previous send. * The state is checked after the page mapping and buffer * allocation above since those operations may block and make * any socket checks stale. From this point forward, nothing * blocks before the pru_send (or more accurately, any blocking * results in a loop back to here to re-check). */ if ((so->so_state & SS_CANTSENDMORE) || so->so_error) { if (so->so_state & SS_CANTSENDMORE) { error = EPIPE; } else { error = so->so_error; so->so_error = 0; } m_freem(m); sbunlock(&so->so_snd); splx(s); goto done; } /* * Wait for socket space to become available. We do this just * after checking the connection state above in order to avoid * a race condition with sbwait(). */ if (sbspace(&so->so_snd) < so->so_snd.sb_lowat) { if (so->so_state & SS_NBIO) { m_freem(m); sbunlock(&so->so_snd); splx(s); error = EAGAIN; goto done; } error = sbwait(&so->so_snd); /* * An error from sbwait usually indicates that we've * been interrupted by a signal. If we've sent anything * then return bytes sent, otherwise return the error. */ if (error) { m_freem(m); sbunlock(&so->so_snd); splx(s); goto done; } goto retry_space; } error = (*so->so_proto->pr_usrreqs->pru_send)(so, 0, m, 0, 0, td); splx(s); if (error) { sbunlock(&so->so_snd); goto done; } } sbunlock(&so->so_snd); /* * Send trailers. Wimp out and use writev(2). */ if (uap->hdtr != NULL && hdtr.trailers != NULL) { nuap.fd = uap->s; nuap.iovp = hdtr.trailers; nuap.iovcnt = hdtr.trl_cnt; error = writev(td, &nuap); if (error) goto done; - hdtr_size += td->td_retval[0]; + if (compat) + sbytes += td->td_retval[0]; + else + hdtr_size += td->td_retval[0]; } done: /* * If there was no error we have to clear td->td_retval[0] * because it may have been set by writev. */ if (error == 0) { td->td_retval[0] = 0; } if (uap->sbytes != NULL) { - sbytes += hdtr_size; + if (!compat) + sbytes += hdtr_size; copyout(&sbytes, uap->sbytes, sizeof(off_t)); } if (vp) vrele(vp); if (so) fputsock(so); mtx_unlock(&Giant); return (error); }