The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/compat.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  linux/fs/compat.c
    3  *
    4  *  Kernel compatibililty routines for e.g. 32 bit syscall support
    5  *  on 64 bit kernels.
    6  *
    7  *  Copyright (C) 2002       Stephen Rothwell, IBM Corporation
    8  *  Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
    9  *  Copyright (C) 1998       Eddie C. Dost  (ecd@skynet.be)
   10  *  Copyright (C) 2001,2002  Andi Kleen, SuSE Labs 
   11  *  Copyright (C) 2003       Pavel Machek (pavel@ucw.cz)
   12  *
   13  *  This program is free software; you can redistribute it and/or modify
   14  *  it under the terms of the GNU General Public License version 2 as
   15  *  published by the Free Software Foundation.
   16  */
   17 
   18 #include <linux/stddef.h>
   19 #include <linux/kernel.h>
   20 #include <linux/linkage.h>
   21 #include <linux/compat.h>
   22 #include <linux/errno.h>
   23 #include <linux/time.h>
   24 #include <linux/fs.h>
   25 #include <linux/fcntl.h>
   26 #include <linux/namei.h>
   27 #include <linux/file.h>
   28 #include <linux/fdtable.h>
   29 #include <linux/vfs.h>
   30 #include <linux/ioctl.h>
   31 #include <linux/init.h>
   32 #include <linux/ncp_mount.h>
   33 #include <linux/nfs4_mount.h>
   34 #include <linux/syscalls.h>
   35 #include <linux/ctype.h>
   36 #include <linux/dirent.h>
   37 #include <linux/fsnotify.h>
   38 #include <linux/highuid.h>
   39 #include <linux/personality.h>
   40 #include <linux/rwsem.h>
   41 #include <linux/tsacct_kern.h>
   42 #include <linux/security.h>
   43 #include <linux/highmem.h>
   44 #include <linux/signal.h>
   45 #include <linux/poll.h>
   46 #include <linux/mm.h>
   47 #include <linux/eventpoll.h>
   48 #include <linux/fs_struct.h>
   49 #include <linux/slab.h>
   50 #include <linux/pagemap.h>
   51 
   52 #include <asm/uaccess.h>
   53 #include <asm/mmu_context.h>
   54 #include <asm/ioctls.h>
   55 #include "internal.h"
   56 
   57 int compat_log = 1;
   58 
   59 int compat_printk(const char *fmt, ...)
   60 {
   61         va_list ap;
   62         int ret;
   63         if (!compat_log)
   64                 return 0;
   65         va_start(ap, fmt);
   66         ret = vprintk(fmt, ap);
   67         va_end(ap);
   68         return ret;
   69 }
   70 
   71 #include "read_write.h"
   72 
   73 /*
   74  * Not all architectures have sys_utime, so implement this in terms
   75  * of sys_utimes.
   76  */
   77 asmlinkage long compat_sys_utime(const char __user *filename,
   78                                  struct compat_utimbuf __user *t)
   79 {
   80         struct timespec tv[2];
   81 
   82         if (t) {
   83                 if (get_user(tv[0].tv_sec, &t->actime) ||
   84                     get_user(tv[1].tv_sec, &t->modtime))
   85                         return -EFAULT;
   86                 tv[0].tv_nsec = 0;
   87                 tv[1].tv_nsec = 0;
   88         }
   89         return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0);
   90 }
   91 
   92 asmlinkage long compat_sys_utimensat(unsigned int dfd, const char __user *filename, struct compat_timespec __user *t, int flags)
   93 {
   94         struct timespec tv[2];
   95 
   96         if  (t) {
   97                 if (get_compat_timespec(&tv[0], &t[0]) ||
   98                     get_compat_timespec(&tv[1], &t[1]))
   99                         return -EFAULT;
  100 
  101                 if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT)
  102                         return 0;
  103         }
  104         return do_utimes(dfd, filename, t ? tv : NULL, flags);
  105 }
  106 
  107 asmlinkage long compat_sys_futimesat(unsigned int dfd, const char __user *filename, struct compat_timeval __user *t)
  108 {
  109         struct timespec tv[2];
  110 
  111         if (t) {
  112                 if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
  113                     get_user(tv[0].tv_nsec, &t[0].tv_usec) ||
  114                     get_user(tv[1].tv_sec, &t[1].tv_sec) ||
  115                     get_user(tv[1].tv_nsec, &t[1].tv_usec))
  116                         return -EFAULT;
  117                 if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 ||
  118                     tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0)
  119                         return -EINVAL;
  120                 tv[0].tv_nsec *= 1000;
  121                 tv[1].tv_nsec *= 1000;
  122         }
  123         return do_utimes(dfd, filename, t ? tv : NULL, 0);
  124 }
  125 
  126 asmlinkage long compat_sys_utimes(const char __user *filename, struct compat_timeval __user *t)
  127 {
  128         return compat_sys_futimesat(AT_FDCWD, filename, t);
  129 }
  130 
  131 static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
  132 {
  133         struct compat_stat tmp;
  134 
  135         if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
  136                 return -EOVERFLOW;
  137 
  138         memset(&tmp, 0, sizeof(tmp));
  139         tmp.st_dev = old_encode_dev(stat->dev);
  140         tmp.st_ino = stat->ino;
  141         if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
  142                 return -EOVERFLOW;
  143         tmp.st_mode = stat->mode;
  144         tmp.st_nlink = stat->nlink;
  145         if (tmp.st_nlink != stat->nlink)
  146                 return -EOVERFLOW;
  147         SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
  148         SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
  149         tmp.st_rdev = old_encode_dev(stat->rdev);
  150         if ((u64) stat->size > MAX_NON_LFS)
  151                 return -EOVERFLOW;
  152         tmp.st_size = stat->size;
  153         tmp.st_atime = stat->atime.tv_sec;
  154         tmp.st_atime_nsec = stat->atime.tv_nsec;
  155         tmp.st_mtime = stat->mtime.tv_sec;
  156         tmp.st_mtime_nsec = stat->mtime.tv_nsec;
  157         tmp.st_ctime = stat->ctime.tv_sec;
  158         tmp.st_ctime_nsec = stat->ctime.tv_nsec;
  159         tmp.st_blocks = stat->blocks;
  160         tmp.st_blksize = stat->blksize;
  161         return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
  162 }
  163 
  164 asmlinkage long compat_sys_newstat(const char __user * filename,
  165                 struct compat_stat __user *statbuf)
  166 {
  167         struct kstat stat;
  168         int error;
  169 
  170         error = vfs_stat(filename, &stat);
  171         if (error)
  172                 return error;
  173         return cp_compat_stat(&stat, statbuf);
  174 }
  175 
  176 asmlinkage long compat_sys_newlstat(const char __user * filename,
  177                 struct compat_stat __user *statbuf)
  178 {
  179         struct kstat stat;
  180         int error;
  181 
  182         error = vfs_lstat(filename, &stat);
  183         if (error)
  184                 return error;
  185         return cp_compat_stat(&stat, statbuf);
  186 }
  187 
  188 #ifndef __ARCH_WANT_STAT64
  189 asmlinkage long compat_sys_newfstatat(unsigned int dfd,
  190                 const char __user *filename,
  191                 struct compat_stat __user *statbuf, int flag)
  192 {
  193         struct kstat stat;
  194         int error;
  195 
  196         error = vfs_fstatat(dfd, filename, &stat, flag);
  197         if (error)
  198                 return error;
  199         return cp_compat_stat(&stat, statbuf);
  200 }
  201 #endif
  202 
  203 asmlinkage long compat_sys_newfstat(unsigned int fd,
  204                 struct compat_stat __user * statbuf)
  205 {
  206         struct kstat stat;
  207         int error = vfs_fstat(fd, &stat);
  208 
  209         if (!error)
  210                 error = cp_compat_stat(&stat, statbuf);
  211         return error;
  212 }
  213 
  214 static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
  215 {
  216         
  217         if (sizeof ubuf->f_blocks == 4) {
  218                 if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
  219                      kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
  220                         return -EOVERFLOW;
  221                 /* f_files and f_ffree may be -1; it's okay
  222                  * to stuff that into 32 bits */
  223                 if (kbuf->f_files != 0xffffffffffffffffULL
  224                  && (kbuf->f_files & 0xffffffff00000000ULL))
  225                         return -EOVERFLOW;
  226                 if (kbuf->f_ffree != 0xffffffffffffffffULL
  227                  && (kbuf->f_ffree & 0xffffffff00000000ULL))
  228                         return -EOVERFLOW;
  229         }
  230         if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
  231             __put_user(kbuf->f_type, &ubuf->f_type) ||
  232             __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
  233             __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
  234             __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
  235             __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
  236             __put_user(kbuf->f_files, &ubuf->f_files) ||
  237             __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
  238             __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
  239             __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
  240             __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
  241             __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
  242             __put_user(kbuf->f_flags, &ubuf->f_flags) ||
  243             __clear_user(ubuf->f_spare, sizeof(ubuf->f_spare)))
  244                 return -EFAULT;
  245         return 0;
  246 }
  247 
  248 /*
  249  * The following statfs calls are copies of code from fs/statfs.c and
  250  * should be checked against those from time to time
  251  */
  252 asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
  253 {
  254         struct kstatfs tmp;
  255         int error = user_statfs(pathname, &tmp);
  256         if (!error)
  257                 error = put_compat_statfs(buf, &tmp);
  258         return error;
  259 }
  260 
  261 asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
  262 {
  263         struct kstatfs tmp;
  264         int error = fd_statfs(fd, &tmp);
  265         if (!error)
  266                 error = put_compat_statfs(buf, &tmp);
  267         return error;
  268 }
  269 
  270 static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
  271 {
  272         if (sizeof ubuf->f_blocks == 4) {
  273                 if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
  274                      kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
  275                         return -EOVERFLOW;
  276                 /* f_files and f_ffree may be -1; it's okay
  277                  * to stuff that into 32 bits */
  278                 if (kbuf->f_files != 0xffffffffffffffffULL
  279                  && (kbuf->f_files & 0xffffffff00000000ULL))
  280                         return -EOVERFLOW;
  281                 if (kbuf->f_ffree != 0xffffffffffffffffULL
  282                  && (kbuf->f_ffree & 0xffffffff00000000ULL))
  283                         return -EOVERFLOW;
  284         }
  285         if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
  286             __put_user(kbuf->f_type, &ubuf->f_type) ||
  287             __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
  288             __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
  289             __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
  290             __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
  291             __put_user(kbuf->f_files, &ubuf->f_files) ||
  292             __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
  293             __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
  294             __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
  295             __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
  296             __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
  297             __put_user(kbuf->f_flags, &ubuf->f_flags) ||
  298             __clear_user(ubuf->f_spare, sizeof(ubuf->f_spare)))
  299                 return -EFAULT;
  300         return 0;
  301 }
  302 
  303 asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf)
  304 {
  305         struct kstatfs tmp;
  306         int error;
  307 
  308         if (sz != sizeof(*buf))
  309                 return -EINVAL;
  310 
  311         error = user_statfs(pathname, &tmp);
  312         if (!error)
  313                 error = put_compat_statfs64(buf, &tmp);
  314         return error;
  315 }
  316 
  317 asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf)
  318 {
  319         struct kstatfs tmp;
  320         int error;
  321 
  322         if (sz != sizeof(*buf))
  323                 return -EINVAL;
  324 
  325         error = fd_statfs(fd, &tmp);
  326         if (!error)
  327                 error = put_compat_statfs64(buf, &tmp);
  328         return error;
  329 }
  330 
  331 /*
  332  * This is a copy of sys_ustat, just dealing with a structure layout.
  333  * Given how simple this syscall is that apporach is more maintainable
  334  * than the various conversion hacks.
  335  */
  336 asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u)
  337 {
  338         struct compat_ustat tmp;
  339         struct kstatfs sbuf;
  340         int err = vfs_ustat(new_decode_dev(dev), &sbuf);
  341         if (err)
  342                 return err;
  343 
  344         memset(&tmp, 0, sizeof(struct compat_ustat));
  345         tmp.f_tfree = sbuf.f_bfree;
  346         tmp.f_tinode = sbuf.f_ffree;
  347         if (copy_to_user(u, &tmp, sizeof(struct compat_ustat)))
  348                 return -EFAULT;
  349         return 0;
  350 }
  351 
  352 static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
  353 {
  354         if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
  355             __get_user(kfl->l_type, &ufl->l_type) ||
  356             __get_user(kfl->l_whence, &ufl->l_whence) ||
  357             __get_user(kfl->l_start, &ufl->l_start) ||
  358             __get_user(kfl->l_len, &ufl->l_len) ||
  359             __get_user(kfl->l_pid, &ufl->l_pid))
  360                 return -EFAULT;
  361         return 0;
  362 }
  363 
  364 static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
  365 {
  366         if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
  367             __put_user(kfl->l_type, &ufl->l_type) ||
  368             __put_user(kfl->l_whence, &ufl->l_whence) ||
  369             __put_user(kfl->l_start, &ufl->l_start) ||
  370             __put_user(kfl->l_len, &ufl->l_len) ||
  371             __put_user(kfl->l_pid, &ufl->l_pid))
  372                 return -EFAULT;
  373         return 0;
  374 }
  375 
  376 #ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
  377 static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
  378 {
  379         if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
  380             __get_user(kfl->l_type, &ufl->l_type) ||
  381             __get_user(kfl->l_whence, &ufl->l_whence) ||
  382             __get_user(kfl->l_start, &ufl->l_start) ||
  383             __get_user(kfl->l_len, &ufl->l_len) ||
  384             __get_user(kfl->l_pid, &ufl->l_pid))
  385                 return -EFAULT;
  386         return 0;
  387 }
  388 #endif
  389 
  390 #ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
  391 static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
  392 {
  393         if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
  394             __put_user(kfl->l_type, &ufl->l_type) ||
  395             __put_user(kfl->l_whence, &ufl->l_whence) ||
  396             __put_user(kfl->l_start, &ufl->l_start) ||
  397             __put_user(kfl->l_len, &ufl->l_len) ||
  398             __put_user(kfl->l_pid, &ufl->l_pid))
  399                 return -EFAULT;
  400         return 0;
  401 }
  402 #endif
  403 
  404 asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
  405                 unsigned long arg)
  406 {
  407         mm_segment_t old_fs;
  408         struct flock f;
  409         long ret;
  410 
  411         switch (cmd) {
  412         case F_GETLK:
  413         case F_SETLK:
  414         case F_SETLKW:
  415                 ret = get_compat_flock(&f, compat_ptr(arg));
  416                 if (ret != 0)
  417                         break;
  418                 old_fs = get_fs();
  419                 set_fs(KERNEL_DS);
  420                 ret = sys_fcntl(fd, cmd, (unsigned long)&f);
  421                 set_fs(old_fs);
  422                 if (cmd == F_GETLK && ret == 0) {
  423                         /* GETLK was successful and we need to return the data...
  424                          * but it needs to fit in the compat structure.
  425                          * l_start shouldn't be too big, unless the original
  426                          * start + end is greater than COMPAT_OFF_T_MAX, in which
  427                          * case the app was asking for trouble, so we return
  428                          * -EOVERFLOW in that case.
  429                          * l_len could be too big, in which case we just truncate it,
  430                          * and only allow the app to see that part of the conflicting
  431                          * lock that might make sense to it anyway
  432                          */
  433 
  434                         if (f.l_start > COMPAT_OFF_T_MAX)
  435                                 ret = -EOVERFLOW;
  436                         if (f.l_len > COMPAT_OFF_T_MAX)
  437                                 f.l_len = COMPAT_OFF_T_MAX;
  438                         if (ret == 0)
  439                                 ret = put_compat_flock(&f, compat_ptr(arg));
  440                 }
  441                 break;
  442 
  443         case F_GETLK64:
  444         case F_SETLK64:
  445         case F_SETLKW64:
  446                 ret = get_compat_flock64(&f, compat_ptr(arg));
  447                 if (ret != 0)
  448                         break;
  449                 old_fs = get_fs();
  450                 set_fs(KERNEL_DS);
  451                 ret = sys_fcntl(fd, (cmd == F_GETLK64) ? F_GETLK :
  452                                 ((cmd == F_SETLK64) ? F_SETLK : F_SETLKW),
  453                                 (unsigned long)&f);
  454                 set_fs(old_fs);
  455                 if (cmd == F_GETLK64 && ret == 0) {
  456                         /* need to return lock information - see above for commentary */
  457                         if (f.l_start > COMPAT_LOFF_T_MAX)
  458                                 ret = -EOVERFLOW;
  459                         if (f.l_len > COMPAT_LOFF_T_MAX)
  460                                 f.l_len = COMPAT_LOFF_T_MAX;
  461                         if (ret == 0)
  462                                 ret = put_compat_flock64(&f, compat_ptr(arg));
  463                 }
  464                 break;
  465 
  466         default:
  467                 ret = sys_fcntl(fd, cmd, arg);
  468                 break;
  469         }
  470         return ret;
  471 }
  472 
  473 asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
  474                 unsigned long arg)
  475 {
  476         if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64))
  477                 return -EINVAL;
  478         return compat_sys_fcntl64(fd, cmd, arg);
  479 }
  480 
  481 asmlinkage long
  482 compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p)
  483 {
  484         long ret;
  485         aio_context_t ctx64;
  486 
  487         mm_segment_t oldfs = get_fs();
  488         if (unlikely(get_user(ctx64, ctx32p)))
  489                 return -EFAULT;
  490 
  491         set_fs(KERNEL_DS);
  492         /* The __user pointer cast is valid because of the set_fs() */
  493         ret = sys_io_setup(nr_reqs, (aio_context_t __user *) &ctx64);
  494         set_fs(oldfs);
  495         /* truncating is ok because it's a user address */
  496         if (!ret)
  497                 ret = put_user((u32) ctx64, ctx32p);
  498         return ret;
  499 }
  500 
  501 asmlinkage long
  502 compat_sys_io_getevents(aio_context_t ctx_id,
  503                                  unsigned long min_nr,
  504                                  unsigned long nr,
  505                                  struct io_event __user *events,
  506                                  struct compat_timespec __user *timeout)
  507 {
  508         long ret;
  509         struct timespec t;
  510         struct timespec __user *ut = NULL;
  511 
  512         ret = -EFAULT;
  513         if (unlikely(!access_ok(VERIFY_WRITE, events, 
  514                                 nr * sizeof(struct io_event))))
  515                 goto out;
  516         if (timeout) {
  517                 if (get_compat_timespec(&t, timeout))
  518                         goto out;
  519 
  520                 ut = compat_alloc_user_space(sizeof(*ut));
  521                 if (copy_to_user(ut, &t, sizeof(t)) )
  522                         goto out;
  523         } 
  524         ret = sys_io_getevents(ctx_id, min_nr, nr, events, ut);
  525 out:
  526         return ret;
  527 }
  528 
  529 /* A write operation does a read from user space and vice versa */
  530 #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
  531 
  532 ssize_t compat_rw_copy_check_uvector(int type,
  533                 const struct compat_iovec __user *uvector, unsigned long nr_segs,
  534                 unsigned long fast_segs, struct iovec *fast_pointer,
  535                 struct iovec **ret_pointer)
  536 {
  537         compat_ssize_t tot_len;
  538         struct iovec *iov = *ret_pointer = fast_pointer;
  539         ssize_t ret = 0;
  540         int seg;
  541 
  542         /*
  543          * SuS says "The readv() function *may* fail if the iovcnt argument
  544          * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
  545          * traditionally returned zero for zero segments, so...
  546          */
  547         if (nr_segs == 0)
  548                 goto out;
  549 
  550         ret = -EINVAL;
  551         if (nr_segs > UIO_MAXIOV || nr_segs < 0)
  552                 goto out;
  553         if (nr_segs > fast_segs) {
  554                 ret = -ENOMEM;
  555                 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
  556                 if (iov == NULL)
  557                         goto out;
  558         }
  559         *ret_pointer = iov;
  560 
  561         /*
  562          * Single unix specification:
  563          * We should -EINVAL if an element length is not >= 0 and fitting an
  564          * ssize_t.
  565          *
  566          * In Linux, the total length is limited to MAX_RW_COUNT, there is
  567          * no overflow possibility.
  568          */
  569         tot_len = 0;
  570         ret = -EINVAL;
  571         for (seg = 0; seg < nr_segs; seg++) {
  572                 compat_uptr_t buf;
  573                 compat_ssize_t len;
  574 
  575                 if (__get_user(len, &uvector->iov_len) ||
  576                    __get_user(buf, &uvector->iov_base)) {
  577                         ret = -EFAULT;
  578                         goto out;
  579                 }
  580                 if (len < 0)    /* size_t not fitting in compat_ssize_t .. */
  581                         goto out;
  582                 if (type >= 0 &&
  583                     !access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
  584                         ret = -EFAULT;
  585                         goto out;
  586                 }
  587                 if (len > MAX_RW_COUNT - tot_len)
  588                         len = MAX_RW_COUNT - tot_len;
  589                 tot_len += len;
  590                 iov->iov_base = compat_ptr(buf);
  591                 iov->iov_len = (compat_size_t) len;
  592                 uvector++;
  593                 iov++;
  594         }
  595         ret = tot_len;
  596 
  597 out:
  598         return ret;
  599 }
  600 
  601 static inline long
  602 copy_iocb(long nr, u32 __user *ptr32, struct iocb __user * __user *ptr64)
  603 {
  604         compat_uptr_t uptr;
  605         int i;
  606 
  607         for (i = 0; i < nr; ++i) {
  608                 if (get_user(uptr, ptr32 + i))
  609                         return -EFAULT;
  610                 if (put_user(compat_ptr(uptr), ptr64 + i))
  611                         return -EFAULT;
  612         }
  613         return 0;
  614 }
  615 
  616 #define MAX_AIO_SUBMITS         (PAGE_SIZE/sizeof(struct iocb *))
  617 
  618 asmlinkage long
  619 compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
  620 {
  621         struct iocb __user * __user *iocb64; 
  622         long ret;
  623 
  624         if (unlikely(nr < 0))
  625                 return -EINVAL;
  626 
  627         if (nr > MAX_AIO_SUBMITS)
  628                 nr = MAX_AIO_SUBMITS;
  629         
  630         iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64));
  631         ret = copy_iocb(nr, iocb, iocb64);
  632         if (!ret)
  633                 ret = do_io_submit(ctx_id, nr, iocb64, 1);
  634         return ret;
  635 }
  636 
  637 struct compat_ncp_mount_data {
  638         compat_int_t version;
  639         compat_uint_t ncp_fd;
  640         __compat_uid_t mounted_uid;
  641         compat_pid_t wdog_pid;
  642         unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
  643         compat_uint_t time_out;
  644         compat_uint_t retry_count;
  645         compat_uint_t flags;
  646         __compat_uid_t uid;
  647         __compat_gid_t gid;
  648         compat_mode_t file_mode;
  649         compat_mode_t dir_mode;
  650 };
  651 
  652 struct compat_ncp_mount_data_v4 {
  653         compat_int_t version;
  654         compat_ulong_t flags;
  655         compat_ulong_t mounted_uid;
  656         compat_long_t wdog_pid;
  657         compat_uint_t ncp_fd;
  658         compat_uint_t time_out;
  659         compat_uint_t retry_count;
  660         compat_ulong_t uid;
  661         compat_ulong_t gid;
  662         compat_ulong_t file_mode;
  663         compat_ulong_t dir_mode;
  664 };
  665 
  666 static void *do_ncp_super_data_conv(void *raw_data)
  667 {
  668         int version = *(unsigned int *)raw_data;
  669 
  670         if (version == 3) {
  671                 struct compat_ncp_mount_data *c_n = raw_data;
  672                 struct ncp_mount_data *n = raw_data;
  673 
  674                 n->dir_mode = c_n->dir_mode;
  675                 n->file_mode = c_n->file_mode;
  676                 n->gid = c_n->gid;
  677                 n->uid = c_n->uid;
  678                 memmove (n->mounted_vol, c_n->mounted_vol, (sizeof (c_n->mounted_vol) + 3 * sizeof (unsigned int)));
  679                 n->wdog_pid = c_n->wdog_pid;
  680                 n->mounted_uid = c_n->mounted_uid;
  681         } else if (version == 4) {
  682                 struct compat_ncp_mount_data_v4 *c_n = raw_data;
  683                 struct ncp_mount_data_v4 *n = raw_data;
  684 
  685                 n->dir_mode = c_n->dir_mode;
  686                 n->file_mode = c_n->file_mode;
  687                 n->gid = c_n->gid;
  688                 n->uid = c_n->uid;
  689                 n->retry_count = c_n->retry_count;
  690                 n->time_out = c_n->time_out;
  691                 n->ncp_fd = c_n->ncp_fd;
  692                 n->wdog_pid = c_n->wdog_pid;
  693                 n->mounted_uid = c_n->mounted_uid;
  694                 n->flags = c_n->flags;
  695         } else if (version != 5) {
  696                 return NULL;
  697         }
  698 
  699         return raw_data;
  700 }
  701 
  702 
  703 struct compat_nfs_string {
  704         compat_uint_t len;
  705         compat_uptr_t data;
  706 };
  707 
  708 static inline void compat_nfs_string(struct nfs_string *dst,
  709                                      struct compat_nfs_string *src)
  710 {
  711         dst->data = compat_ptr(src->data);
  712         dst->len = src->len;
  713 }
  714 
  715 struct compat_nfs4_mount_data_v1 {
  716         compat_int_t version;
  717         compat_int_t flags;
  718         compat_int_t rsize;
  719         compat_int_t wsize;
  720         compat_int_t timeo;
  721         compat_int_t retrans;
  722         compat_int_t acregmin;
  723         compat_int_t acregmax;
  724         compat_int_t acdirmin;
  725         compat_int_t acdirmax;
  726         struct compat_nfs_string client_addr;
  727         struct compat_nfs_string mnt_path;
  728         struct compat_nfs_string hostname;
  729         compat_uint_t host_addrlen;
  730         compat_uptr_t host_addr;
  731         compat_int_t proto;
  732         compat_int_t auth_flavourlen;
  733         compat_uptr_t auth_flavours;
  734 };
  735 
  736 static int do_nfs4_super_data_conv(void *raw_data)
  737 {
  738         int version = *(compat_uint_t *) raw_data;
  739 
  740         if (version == 1) {
  741                 struct compat_nfs4_mount_data_v1 *raw = raw_data;
  742                 struct nfs4_mount_data *real = raw_data;
  743 
  744                 /* copy the fields backwards */
  745                 real->auth_flavours = compat_ptr(raw->auth_flavours);
  746                 real->auth_flavourlen = raw->auth_flavourlen;
  747                 real->proto = raw->proto;
  748                 real->host_addr = compat_ptr(raw->host_addr);
  749                 real->host_addrlen = raw->host_addrlen;
  750                 compat_nfs_string(&real->hostname, &raw->hostname);
  751                 compat_nfs_string(&real->mnt_path, &raw->mnt_path);
  752                 compat_nfs_string(&real->client_addr, &raw->client_addr);
  753                 real->acdirmax = raw->acdirmax;
  754                 real->acdirmin = raw->acdirmin;
  755                 real->acregmax = raw->acregmax;
  756                 real->acregmin = raw->acregmin;
  757                 real->retrans = raw->retrans;
  758                 real->timeo = raw->timeo;
  759                 real->wsize = raw->wsize;
  760                 real->rsize = raw->rsize;
  761                 real->flags = raw->flags;
  762                 real->version = raw->version;
  763         }
  764 
  765         return 0;
  766 }
  767 
  768 #define NCPFS_NAME      "ncpfs"
  769 #define NFS4_NAME       "nfs4"
  770 
  771 asmlinkage long compat_sys_mount(const char __user * dev_name,
  772                                  const char __user * dir_name,
  773                                  const char __user * type, unsigned long flags,
  774                                  const void __user * data)
  775 {
  776         char *kernel_type;
  777         unsigned long data_page;
  778         char *kernel_dev;
  779         struct filename *dir;
  780         int retval;
  781 
  782         retval = copy_mount_string(type, &kernel_type);
  783         if (retval < 0)
  784                 goto out;
  785 
  786         dir = getname(dir_name);
  787         retval = PTR_ERR(dir);
  788         if (IS_ERR(dir))
  789                 goto out1;
  790 
  791         retval = copy_mount_string(dev_name, &kernel_dev);
  792         if (retval < 0)
  793                 goto out2;
  794 
  795         retval = copy_mount_options(data, &data_page);
  796         if (retval < 0)
  797                 goto out3;
  798 
  799         retval = -EINVAL;
  800 
  801         if (kernel_type && data_page) {
  802                 if (!strcmp(kernel_type, NCPFS_NAME)) {
  803                         do_ncp_super_data_conv((void *)data_page);
  804                 } else if (!strcmp(kernel_type, NFS4_NAME)) {
  805                         if (do_nfs4_super_data_conv((void *) data_page))
  806                                 goto out4;
  807                 }
  808         }
  809 
  810         retval = do_mount(kernel_dev, dir->name, kernel_type,
  811                         flags, (void*)data_page);
  812 
  813  out4:
  814         free_page(data_page);
  815  out3:
  816         kfree(kernel_dev);
  817  out2:
  818         putname(dir);
  819  out1:
  820         kfree(kernel_type);
  821  out:
  822         return retval;
  823 }
  824 
  825 struct compat_old_linux_dirent {
  826         compat_ulong_t  d_ino;
  827         compat_ulong_t  d_offset;
  828         unsigned short  d_namlen;
  829         char            d_name[1];
  830 };
  831 
  832 struct compat_readdir_callback {
  833         struct compat_old_linux_dirent __user *dirent;
  834         int result;
  835 };
  836 
  837 static int compat_fillonedir(void *__buf, const char *name, int namlen,
  838                         loff_t offset, u64 ino, unsigned int d_type)
  839 {
  840         struct compat_readdir_callback *buf = __buf;
  841         struct compat_old_linux_dirent __user *dirent;
  842         compat_ulong_t d_ino;
  843 
  844         if (buf->result)
  845                 return -EINVAL;
  846         d_ino = ino;
  847         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
  848                 buf->result = -EOVERFLOW;
  849                 return -EOVERFLOW;
  850         }
  851         buf->result++;
  852         dirent = buf->dirent;
  853         if (!access_ok(VERIFY_WRITE, dirent,
  854                         (unsigned long)(dirent->d_name + namlen + 1) -
  855                                 (unsigned long)dirent))
  856                 goto efault;
  857         if (    __put_user(d_ino, &dirent->d_ino) ||
  858                 __put_user(offset, &dirent->d_offset) ||
  859                 __put_user(namlen, &dirent->d_namlen) ||
  860                 __copy_to_user(dirent->d_name, name, namlen) ||
  861                 __put_user(0, dirent->d_name + namlen))
  862                 goto efault;
  863         return 0;
  864 efault:
  865         buf->result = -EFAULT;
  866         return -EFAULT;
  867 }
  868 
  869 asmlinkage long compat_sys_old_readdir(unsigned int fd,
  870         struct compat_old_linux_dirent __user *dirent, unsigned int count)
  871 {
  872         int error;
  873         struct fd f = fdget(fd);
  874         struct compat_readdir_callback buf;
  875 
  876         if (!f.file)
  877                 return -EBADF;
  878 
  879         buf.result = 0;
  880         buf.dirent = dirent;
  881 
  882         error = vfs_readdir(f.file, compat_fillonedir, &buf);
  883         if (buf.result)
  884                 error = buf.result;
  885 
  886         fdput(f);
  887         return error;
  888 }
  889 
  890 struct compat_linux_dirent {
  891         compat_ulong_t  d_ino;
  892         compat_ulong_t  d_off;
  893         unsigned short  d_reclen;
  894         char            d_name[1];
  895 };
  896 
  897 struct compat_getdents_callback {
  898         struct compat_linux_dirent __user *current_dir;
  899         struct compat_linux_dirent __user *previous;
  900         int count;
  901         int error;
  902 };
  903 
  904 static int compat_filldir(void *__buf, const char *name, int namlen,
  905                 loff_t offset, u64 ino, unsigned int d_type)
  906 {
  907         struct compat_linux_dirent __user * dirent;
  908         struct compat_getdents_callback *buf = __buf;
  909         compat_ulong_t d_ino;
  910         int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
  911                 namlen + 2, sizeof(compat_long_t));
  912 
  913         buf->error = -EINVAL;   /* only used if we fail.. */
  914         if (reclen > buf->count)
  915                 return -EINVAL;
  916         d_ino = ino;
  917         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
  918                 buf->error = -EOVERFLOW;
  919                 return -EOVERFLOW;
  920         }
  921         dirent = buf->previous;
  922         if (dirent) {
  923                 if (__put_user(offset, &dirent->d_off))
  924                         goto efault;
  925         }
  926         dirent = buf->current_dir;
  927         if (__put_user(d_ino, &dirent->d_ino))
  928                 goto efault;
  929         if (__put_user(reclen, &dirent->d_reclen))
  930                 goto efault;
  931         if (copy_to_user(dirent->d_name, name, namlen))
  932                 goto efault;
  933         if (__put_user(0, dirent->d_name + namlen))
  934                 goto efault;
  935         if (__put_user(d_type, (char  __user *) dirent + reclen - 1))
  936                 goto efault;
  937         buf->previous = dirent;
  938         dirent = (void __user *)dirent + reclen;
  939         buf->current_dir = dirent;
  940         buf->count -= reclen;
  941         return 0;
  942 efault:
  943         buf->error = -EFAULT;
  944         return -EFAULT;
  945 }
  946 
  947 asmlinkage long compat_sys_getdents(unsigned int fd,
  948                 struct compat_linux_dirent __user *dirent, unsigned int count)
  949 {
  950         struct fd f;
  951         struct compat_linux_dirent __user * lastdirent;
  952         struct compat_getdents_callback buf;
  953         int error;
  954 
  955         if (!access_ok(VERIFY_WRITE, dirent, count))
  956                 return -EFAULT;
  957 
  958         f = fdget(fd);
  959         if (!f.file)
  960                 return -EBADF;
  961 
  962         buf.current_dir = dirent;
  963         buf.previous = NULL;
  964         buf.count = count;
  965         buf.error = 0;
  966 
  967         error = vfs_readdir(f.file, compat_filldir, &buf);
  968         if (error >= 0)
  969                 error = buf.error;
  970         lastdirent = buf.previous;
  971         if (lastdirent) {
  972                 if (put_user(f.file->f_pos, &lastdirent->d_off))
  973                         error = -EFAULT;
  974                 else
  975                         error = count - buf.count;
  976         }
  977         fdput(f);
  978         return error;
  979 }
  980 
  981 #ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
  982 
  983 struct compat_getdents_callback64 {
  984         struct linux_dirent64 __user *current_dir;
  985         struct linux_dirent64 __user *previous;
  986         int count;
  987         int error;
  988 };
  989 
  990 static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
  991                      u64 ino, unsigned int d_type)
  992 {
  993         struct linux_dirent64 __user *dirent;
  994         struct compat_getdents_callback64 *buf = __buf;
  995         int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
  996                 sizeof(u64));
  997         u64 off;
  998 
  999         buf->error = -EINVAL;   /* only used if we fail.. */
 1000         if (reclen > buf->count)
 1001                 return -EINVAL;
 1002         dirent = buf->previous;
 1003 
 1004         if (dirent) {
 1005                 if (__put_user_unaligned(offset, &dirent->d_off))
 1006                         goto efault;
 1007         }
 1008         dirent = buf->current_dir;
 1009         if (__put_user_unaligned(ino, &dirent->d_ino))
 1010                 goto efault;
 1011         off = 0;
 1012         if (__put_user_unaligned(off, &dirent->d_off))
 1013                 goto efault;
 1014         if (__put_user(reclen, &dirent->d_reclen))
 1015                 goto efault;
 1016         if (__put_user(d_type, &dirent->d_type))
 1017                 goto efault;
 1018         if (copy_to_user(dirent->d_name, name, namlen))
 1019                 goto efault;
 1020         if (__put_user(0, dirent->d_name + namlen))
 1021                 goto efault;
 1022         buf->previous = dirent;
 1023         dirent = (void __user *)dirent + reclen;
 1024         buf->current_dir = dirent;
 1025         buf->count -= reclen;
 1026         return 0;
 1027 efault:
 1028         buf->error = -EFAULT;
 1029         return -EFAULT;
 1030 }
 1031 
 1032 asmlinkage long compat_sys_getdents64(unsigned int fd,
 1033                 struct linux_dirent64 __user * dirent, unsigned int count)
 1034 {
 1035         struct fd f;
 1036         struct linux_dirent64 __user * lastdirent;
 1037         struct compat_getdents_callback64 buf;
 1038         int error;
 1039 
 1040         if (!access_ok(VERIFY_WRITE, dirent, count))
 1041                 return -EFAULT;
 1042 
 1043         f = fdget(fd);
 1044         if (!f.file)
 1045                 return -EBADF;
 1046 
 1047         buf.current_dir = dirent;
 1048         buf.previous = NULL;
 1049         buf.count = count;
 1050         buf.error = 0;
 1051 
 1052         error = vfs_readdir(f.file, compat_filldir64, &buf);
 1053         if (error >= 0)
 1054                 error = buf.error;
 1055         lastdirent = buf.previous;
 1056         if (lastdirent) {
 1057                 typeof(lastdirent->d_off) d_off = f.file->f_pos;
 1058                 if (__put_user_unaligned(d_off, &lastdirent->d_off))
 1059                         error = -EFAULT;
 1060                 else
 1061                         error = count - buf.count;
 1062         }
 1063         fdput(f);
 1064         return error;
 1065 }
 1066 #endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */
 1067 
 1068 static ssize_t compat_do_readv_writev(int type, struct file *file,
 1069                                const struct compat_iovec __user *uvector,
 1070                                unsigned long nr_segs, loff_t *pos)
 1071 {
 1072         compat_ssize_t tot_len;
 1073         struct iovec iovstack[UIO_FASTIOV];
 1074         struct iovec *iov = iovstack;
 1075         ssize_t ret;
 1076         io_fn_t fn;
 1077         iov_fn_t fnv;
 1078 
 1079         ret = -EINVAL;
 1080         if (!file->f_op)
 1081                 goto out;
 1082 
 1083         ret = -EFAULT;
 1084         if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
 1085                 goto out;
 1086 
 1087         tot_len = compat_rw_copy_check_uvector(type, uvector, nr_segs,
 1088                                                UIO_FASTIOV, iovstack, &iov);
 1089         if (tot_len == 0) {
 1090                 ret = 0;
 1091                 goto out;
 1092         }
 1093 
 1094         ret = rw_verify_area(type, file, pos, tot_len);
 1095         if (ret < 0)
 1096                 goto out;
 1097 
 1098         fnv = NULL;
 1099         if (type == READ) {
 1100                 fn = file->f_op->read;
 1101                 fnv = file->f_op->aio_read;
 1102         } else {
 1103                 fn = (io_fn_t)file->f_op->write;
 1104                 fnv = file->f_op->aio_write;
 1105         }
 1106 
 1107         if (fnv)
 1108                 ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
 1109                                                 pos, fnv);
 1110         else
 1111                 ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);
 1112 
 1113 out:
 1114         if (iov != iovstack)
 1115                 kfree(iov);
 1116         if ((ret + (type == READ)) > 0) {
 1117                 if (type == READ)
 1118                         fsnotify_access(file);
 1119                 else
 1120                         fsnotify_modify(file);
 1121         }
 1122         return ret;
 1123 }
 1124 
 1125 static size_t compat_readv(struct file *file,
 1126                            const struct compat_iovec __user *vec,
 1127                            unsigned long vlen, loff_t *pos)
 1128 {
 1129         ssize_t ret = -EBADF;
 1130 
 1131         if (!(file->f_mode & FMODE_READ))
 1132                 goto out;
 1133 
 1134         ret = -EINVAL;
 1135         if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
 1136                 goto out;
 1137 
 1138         ret = compat_do_readv_writev(READ, file, vec, vlen, pos);
 1139 
 1140 out:
 1141         if (ret > 0)
 1142                 add_rchar(current, ret);
 1143         inc_syscr(current);
 1144         return ret;
 1145 }
 1146 
 1147 asmlinkage ssize_t
 1148 compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec,
 1149                  unsigned long vlen)
 1150 {
 1151         struct fd f = fdget(fd);
 1152         ssize_t ret;
 1153         loff_t pos;
 1154 
 1155         if (!f.file)
 1156                 return -EBADF;
 1157         pos = f.file->f_pos;
 1158         ret = compat_readv(f.file, vec, vlen, &pos);
 1159         f.file->f_pos = pos;
 1160         fdput(f);
 1161         return ret;
 1162 }
 1163 
 1164 asmlinkage ssize_t
 1165 compat_sys_preadv64(unsigned long fd, const struct compat_iovec __user *vec,
 1166                     unsigned long vlen, loff_t pos)
 1167 {
 1168         struct fd f;
 1169         ssize_t ret;
 1170 
 1171         if (pos < 0)
 1172                 return -EINVAL;
 1173         f = fdget(fd);
 1174         if (!f.file)
 1175                 return -EBADF;
 1176         ret = -ESPIPE;
 1177         if (f.file->f_mode & FMODE_PREAD)
 1178                 ret = compat_readv(f.file, vec, vlen, &pos);
 1179         fdput(f);
 1180         return ret;
 1181 }
 1182 
 1183 asmlinkage ssize_t
 1184 compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec,
 1185                   unsigned long vlen, u32 pos_low, u32 pos_high)
 1186 {
 1187         loff_t pos = ((loff_t)pos_high << 32) | pos_low;
 1188         return compat_sys_preadv64(fd, vec, vlen, pos);
 1189 }
 1190 
 1191 static size_t compat_writev(struct file *file,
 1192                             const struct compat_iovec __user *vec,
 1193                             unsigned long vlen, loff_t *pos)
 1194 {
 1195         ssize_t ret = -EBADF;
 1196 
 1197         if (!(file->f_mode & FMODE_WRITE))
 1198                 goto out;
 1199 
 1200         ret = -EINVAL;
 1201         if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
 1202                 goto out;
 1203 
 1204         ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos);
 1205 
 1206 out:
 1207         if (ret > 0)
 1208                 add_wchar(current, ret);
 1209         inc_syscw(current);
 1210         return ret;
 1211 }
 1212 
 1213 asmlinkage ssize_t
 1214 compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec,
 1215                   unsigned long vlen)
 1216 {
 1217         struct fd f = fdget(fd);
 1218         ssize_t ret;
 1219         loff_t pos;
 1220 
 1221         if (!f.file)
 1222                 return -EBADF;
 1223         pos = f.file->f_pos;
 1224         ret = compat_writev(f.file, vec, vlen, &pos);
 1225         f.file->f_pos = pos;
 1226         fdput(f);
 1227         return ret;
 1228 }
 1229 
 1230 asmlinkage ssize_t
 1231 compat_sys_pwritev64(unsigned long fd, const struct compat_iovec __user *vec,
 1232                      unsigned long vlen, loff_t pos)
 1233 {
 1234         struct fd f;
 1235         ssize_t ret;
 1236 
 1237         if (pos < 0)
 1238                 return -EINVAL;
 1239         f = fdget(fd);
 1240         if (!f.file)
 1241                 return -EBADF;
 1242         ret = -ESPIPE;
 1243         if (f.file->f_mode & FMODE_PWRITE)
 1244                 ret = compat_writev(f.file, vec, vlen, &pos);
 1245         fdput(f);
 1246         return ret;
 1247 }
 1248 
 1249 asmlinkage ssize_t
 1250 compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec,
 1251                    unsigned long vlen, u32 pos_low, u32 pos_high)
 1252 {
 1253         loff_t pos = ((loff_t)pos_high << 32) | pos_low;
 1254         return compat_sys_pwritev64(fd, vec, vlen, pos);
 1255 }
 1256 
 1257 asmlinkage long
 1258 compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32,
 1259                     unsigned int nr_segs, unsigned int flags)
 1260 {
 1261         unsigned i;
 1262         struct iovec __user *iov;
 1263         if (nr_segs > UIO_MAXIOV)
 1264                 return -EINVAL;
 1265         iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec));
 1266         for (i = 0; i < nr_segs; i++) {
 1267                 struct compat_iovec v;
 1268                 if (get_user(v.iov_base, &iov32[i].iov_base) ||
 1269                     get_user(v.iov_len, &iov32[i].iov_len) ||
 1270                     put_user(compat_ptr(v.iov_base), &iov[i].iov_base) ||
 1271                     put_user(v.iov_len, &iov[i].iov_len))
 1272                         return -EFAULT;
 1273         }
 1274         return sys_vmsplice(fd, iov, nr_segs, flags);
 1275 }
 1276 
 1277 /*
 1278  * Exactly like fs/open.c:sys_open(), except that it doesn't set the
 1279  * O_LARGEFILE flag.
 1280  */
 1281 asmlinkage long
 1282 compat_sys_open(const char __user *filename, int flags, umode_t mode)
 1283 {
 1284         return do_sys_open(AT_FDCWD, filename, flags, mode);
 1285 }
 1286 
 1287 /*
 1288  * Exactly like fs/open.c:sys_openat(), except that it doesn't set the
 1289  * O_LARGEFILE flag.
 1290  */
 1291 asmlinkage long
 1292 compat_sys_openat(unsigned int dfd, const char __user *filename, int flags, umode_t mode)
 1293 {
 1294         return do_sys_open(dfd, filename, flags, mode);
 1295 }
 1296 
 1297 #define __COMPAT_NFDBITS       (8 * sizeof(compat_ulong_t))
 1298 
 1299 static int poll_select_copy_remaining(struct timespec *end_time, void __user *p,
 1300                                       int timeval, int ret)
 1301 {
 1302         struct timespec ts;
 1303 
 1304         if (!p)
 1305                 return ret;
 1306 
 1307         if (current->personality & STICKY_TIMEOUTS)
 1308                 goto sticky;
 1309 
 1310         /* No update for zero timeout */
 1311         if (!end_time->tv_sec && !end_time->tv_nsec)
 1312                 return ret;
 1313 
 1314         ktime_get_ts(&ts);
 1315         ts = timespec_sub(*end_time, ts);
 1316         if (ts.tv_sec < 0)
 1317                 ts.tv_sec = ts.tv_nsec = 0;
 1318 
 1319         if (timeval) {
 1320                 struct compat_timeval rtv;
 1321 
 1322                 rtv.tv_sec = ts.tv_sec;
 1323                 rtv.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
 1324 
 1325                 if (!copy_to_user(p, &rtv, sizeof(rtv)))
 1326                         return ret;
 1327         } else {
 1328                 struct compat_timespec rts;
 1329 
 1330                 rts.tv_sec = ts.tv_sec;
 1331                 rts.tv_nsec = ts.tv_nsec;
 1332 
 1333                 if (!copy_to_user(p, &rts, sizeof(rts)))
 1334                         return ret;
 1335         }
 1336         /*
 1337          * If an application puts its timeval in read-only memory, we
 1338          * don't want the Linux-specific update to the timeval to
 1339          * cause a fault after the select has completed
 1340          * successfully. However, because we're not updating the
 1341          * timeval, we can't restart the system call.
 1342          */
 1343 
 1344 sticky:
 1345         if (ret == -ERESTARTNOHAND)
 1346                 ret = -EINTR;
 1347         return ret;
 1348 }
 1349 
 1350 /*
 1351  * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
 1352  * 64-bit unsigned longs.
 1353  */
 1354 static
 1355 int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
 1356                         unsigned long *fdset)
 1357 {
 1358         nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
 1359         if (ufdset) {
 1360                 unsigned long odd;
 1361 
 1362                 if (!access_ok(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
 1363                         return -EFAULT;
 1364 
 1365                 odd = nr & 1UL;
 1366                 nr &= ~1UL;
 1367                 while (nr) {
 1368                         unsigned long h, l;
 1369                         if (__get_user(l, ufdset) || __get_user(h, ufdset+1))
 1370                                 return -EFAULT;
 1371                         ufdset += 2;
 1372                         *fdset++ = h << 32 | l;
 1373                         nr -= 2;
 1374                 }
 1375                 if (odd && __get_user(*fdset, ufdset))
 1376                         return -EFAULT;
 1377         } else {
 1378                 /* Tricky, must clear full unsigned long in the
 1379                  * kernel fdset at the end, this makes sure that
 1380                  * actually happens.
 1381                  */
 1382                 memset(fdset, 0, ((nr + 1) & ~1)*sizeof(compat_ulong_t));
 1383         }
 1384         return 0;
 1385 }
 1386 
 1387 static
 1388 int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
 1389                       unsigned long *fdset)
 1390 {
 1391         unsigned long odd;
 1392         nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
 1393 
 1394         if (!ufdset)
 1395                 return 0;
 1396 
 1397         odd = nr & 1UL;
 1398         nr &= ~1UL;
 1399         while (nr) {
 1400                 unsigned long h, l;
 1401                 l = *fdset++;
 1402                 h = l >> 32;
 1403                 if (__put_user(l, ufdset) || __put_user(h, ufdset+1))
 1404                         return -EFAULT;
 1405                 ufdset += 2;
 1406                 nr -= 2;
 1407         }
 1408         if (odd && __put_user(*fdset, ufdset))
 1409                 return -EFAULT;
 1410         return 0;
 1411 }
 1412 
 1413 
 1414 /*
 1415  * This is a virtual copy of sys_select from fs/select.c and probably
 1416  * should be compared to it from time to time
 1417  */
 1418 
 1419 /*
 1420  * We can actually return ERESTARTSYS instead of EINTR, but I'd
 1421  * like to be certain this leads to no problems. So I return
 1422  * EINTR just for safety.
 1423  *
 1424  * Update: ERESTARTSYS breaks at least the xview clock binary, so
 1425  * I'm trying ERESTARTNOHAND which restart only when you want to.
 1426  */
 1427 int compat_core_sys_select(int n, compat_ulong_t __user *inp,
 1428         compat_ulong_t __user *outp, compat_ulong_t __user *exp,
 1429         struct timespec *end_time)
 1430 {
 1431         fd_set_bits fds;
 1432         void *bits;
 1433         int size, max_fds, ret = -EINVAL;
 1434         struct fdtable *fdt;
 1435         long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
 1436 
 1437         if (n < 0)
 1438                 goto out_nofds;
 1439 
 1440         /* max_fds can increase, so grab it once to avoid race */
 1441         rcu_read_lock();
 1442         fdt = files_fdtable(current->files);
 1443         max_fds = fdt->max_fds;
 1444         rcu_read_unlock();
 1445         if (n > max_fds)
 1446                 n = max_fds;
 1447 
 1448         /*
 1449          * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
 1450          * since we used fdset we need to allocate memory in units of
 1451          * long-words.
 1452          */
 1453         size = FDS_BYTES(n);
 1454         bits = stack_fds;
 1455         if (size > sizeof(stack_fds) / 6) {
 1456                 bits = kmalloc(6 * size, GFP_KERNEL);
 1457                 ret = -ENOMEM;
 1458                 if (!bits)
 1459                         goto out_nofds;
 1460         }
 1461         fds.in      = (unsigned long *)  bits;
 1462         fds.out     = (unsigned long *) (bits +   size);
 1463         fds.ex      = (unsigned long *) (bits + 2*size);
 1464         fds.res_in  = (unsigned long *) (bits + 3*size);
 1465         fds.res_out = (unsigned long *) (bits + 4*size);
 1466         fds.res_ex  = (unsigned long *) (bits + 5*size);
 1467 
 1468         if ((ret = compat_get_fd_set(n, inp, fds.in)) ||
 1469             (ret = compat_get_fd_set(n, outp, fds.out)) ||
 1470             (ret = compat_get_fd_set(n, exp, fds.ex)))
 1471                 goto out;
 1472         zero_fd_set(n, fds.res_in);
 1473         zero_fd_set(n, fds.res_out);
 1474         zero_fd_set(n, fds.res_ex);
 1475 
 1476         ret = do_select(n, &fds, end_time);
 1477 
 1478         if (ret < 0)
 1479                 goto out;
 1480         if (!ret) {
 1481                 ret = -ERESTARTNOHAND;
 1482                 if (signal_pending(current))
 1483                         goto out;
 1484                 ret = 0;
 1485         }
 1486 
 1487         if (compat_set_fd_set(n, inp, fds.res_in) ||
 1488             compat_set_fd_set(n, outp, fds.res_out) ||
 1489             compat_set_fd_set(n, exp, fds.res_ex))
 1490                 ret = -EFAULT;
 1491 out:
 1492         if (bits != stack_fds)
 1493                 kfree(bits);
 1494 out_nofds:
 1495         return ret;
 1496 }
 1497 
 1498 asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
 1499         compat_ulong_t __user *outp, compat_ulong_t __user *exp,
 1500         struct compat_timeval __user *tvp)
 1501 {
 1502         struct timespec end_time, *to = NULL;
 1503         struct compat_timeval tv;
 1504         int ret;
 1505 
 1506         if (tvp) {
 1507                 if (copy_from_user(&tv, tvp, sizeof(tv)))
 1508                         return -EFAULT;
 1509 
 1510                 to = &end_time;
 1511                 if (poll_select_set_timeout(to,
 1512                                 tv.tv_sec + (tv.tv_usec / USEC_PER_SEC),
 1513                                 (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC))
 1514                         return -EINVAL;
 1515         }
 1516 
 1517         ret = compat_core_sys_select(n, inp, outp, exp, to);
 1518         ret = poll_select_copy_remaining(&end_time, tvp, 1, ret);
 1519 
 1520         return ret;
 1521 }
 1522 
 1523 struct compat_sel_arg_struct {
 1524         compat_ulong_t n;
 1525         compat_uptr_t inp;
 1526         compat_uptr_t outp;
 1527         compat_uptr_t exp;
 1528         compat_uptr_t tvp;
 1529 };
 1530 
 1531 asmlinkage long compat_sys_old_select(struct compat_sel_arg_struct __user *arg)
 1532 {
 1533         struct compat_sel_arg_struct a;
 1534 
 1535         if (copy_from_user(&a, arg, sizeof(a)))
 1536                 return -EFAULT;
 1537         return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),
 1538                                  compat_ptr(a.exp), compat_ptr(a.tvp));
 1539 }
 1540 
 1541 static long do_compat_pselect(int n, compat_ulong_t __user *inp,
 1542         compat_ulong_t __user *outp, compat_ulong_t __user *exp,
 1543         struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask,
 1544         compat_size_t sigsetsize)
 1545 {
 1546         compat_sigset_t ss32;
 1547         sigset_t ksigmask, sigsaved;
 1548         struct compat_timespec ts;
 1549         struct timespec end_time, *to = NULL;
 1550         int ret;
 1551 
 1552         if (tsp) {
 1553                 if (copy_from_user(&ts, tsp, sizeof(ts)))
 1554                         return -EFAULT;
 1555 
 1556                 to = &end_time;
 1557                 if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
 1558                         return -EINVAL;
 1559         }
 1560 
 1561         if (sigmask) {
 1562                 if (sigsetsize != sizeof(compat_sigset_t))
 1563                         return -EINVAL;
 1564                 if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
 1565                         return -EFAULT;
 1566                 sigset_from_compat(&ksigmask, &ss32);
 1567 
 1568                 sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
 1569                 sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
 1570         }
 1571 
 1572         ret = compat_core_sys_select(n, inp, outp, exp, to);
 1573         ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
 1574 
 1575         if (ret == -ERESTARTNOHAND) {
 1576                 /*
 1577                  * Don't restore the signal mask yet. Let do_signal() deliver
 1578                  * the signal on the way back to userspace, before the signal
 1579                  * mask is restored.
 1580                  */
 1581                 if (sigmask) {
 1582                         memcpy(&current->saved_sigmask, &sigsaved,
 1583                                         sizeof(sigsaved));
 1584                         set_restore_sigmask();
 1585                 }
 1586         } else if (sigmask)
 1587                 sigprocmask(SIG_SETMASK, &sigsaved, NULL);
 1588 
 1589         return ret;
 1590 }
 1591 
 1592 asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
 1593         compat_ulong_t __user *outp, compat_ulong_t __user *exp,
 1594         struct compat_timespec __user *tsp, void __user *sig)
 1595 {
 1596         compat_size_t sigsetsize = 0;
 1597         compat_uptr_t up = 0;
 1598 
 1599         if (sig) {
 1600                 if (!access_ok(VERIFY_READ, sig,
 1601                                 sizeof(compat_uptr_t)+sizeof(compat_size_t)) ||
 1602                         __get_user(up, (compat_uptr_t __user *)sig) ||
 1603                         __get_user(sigsetsize,
 1604                                 (compat_size_t __user *)(sig+sizeof(up))))
 1605                         return -EFAULT;
 1606         }
 1607         return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up),
 1608                                  sigsetsize);
 1609 }
 1610 
 1611 asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
 1612         unsigned int nfds, struct compat_timespec __user *tsp,
 1613         const compat_sigset_t __user *sigmask, compat_size_t sigsetsize)
 1614 {
 1615         compat_sigset_t ss32;
 1616         sigset_t ksigmask, sigsaved;
 1617         struct compat_timespec ts;
 1618         struct timespec end_time, *to = NULL;
 1619         int ret;
 1620 
 1621         if (tsp) {
 1622                 if (copy_from_user(&ts, tsp, sizeof(ts)))
 1623                         return -EFAULT;
 1624 
 1625                 to = &end_time;
 1626                 if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
 1627                         return -EINVAL;
 1628         }
 1629 
 1630         if (sigmask) {
 1631                 if (sigsetsize != sizeof(compat_sigset_t))
 1632                         return -EINVAL;
 1633                 if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
 1634                         return -EFAULT;
 1635                 sigset_from_compat(&ksigmask, &ss32);
 1636 
 1637                 sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
 1638                 sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
 1639         }
 1640 
 1641         ret = do_sys_poll(ufds, nfds, to);
 1642 
 1643         /* We can restart this syscall, usually */
 1644         if (ret == -EINTR) {
 1645                 /*
 1646                  * Don't restore the signal mask yet. Let do_signal() deliver
 1647                  * the signal on the way back to userspace, before the signal
 1648                  * mask is restored.
 1649                  */
 1650                 if (sigmask) {
 1651                         memcpy(&current->saved_sigmask, &sigsaved,
 1652                                 sizeof(sigsaved));
 1653                         set_restore_sigmask();
 1654                 }
 1655                 ret = -ERESTARTNOHAND;
 1656         } else if (sigmask)
 1657                 sigprocmask(SIG_SETMASK, &sigsaved, NULL);
 1658 
 1659         ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
 1660 
 1661         return ret;
 1662 }
 1663 
 1664 #ifdef CONFIG_EPOLL
 1665 
 1666 asmlinkage long compat_sys_epoll_pwait(int epfd,
 1667                         struct compat_epoll_event __user *events,
 1668                         int maxevents, int timeout,
 1669                         const compat_sigset_t __user *sigmask,
 1670                         compat_size_t sigsetsize)
 1671 {
 1672         long err;
 1673         compat_sigset_t csigmask;
 1674         sigset_t ksigmask, sigsaved;
 1675 
 1676         /*
 1677          * If the caller wants a certain signal mask to be set during the wait,
 1678          * we apply it here.
 1679          */
 1680         if (sigmask) {
 1681                 if (sigsetsize != sizeof(compat_sigset_t))
 1682                         return -EINVAL;
 1683                 if (copy_from_user(&csigmask, sigmask, sizeof(csigmask)))
 1684                         return -EFAULT;
 1685                 sigset_from_compat(&ksigmask, &csigmask);
 1686                 sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
 1687                 sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
 1688         }
 1689 
 1690         err = sys_epoll_wait(epfd, events, maxevents, timeout);
 1691 
 1692         /*
 1693          * If we changed the signal mask, we need to restore the original one.
 1694          * In case we've got a signal while waiting, we do not restore the
 1695          * signal mask yet, and we allow do_signal() to deliver the signal on
 1696          * the way back to userspace, before the signal mask is restored.
 1697          */
 1698         if (sigmask) {
 1699                 if (err == -EINTR) {
 1700                         memcpy(&current->saved_sigmask, &sigsaved,
 1701                                sizeof(sigsaved));
 1702                         set_restore_sigmask();
 1703                 } else
 1704                         sigprocmask(SIG_SETMASK, &sigsaved, NULL);
 1705         }
 1706 
 1707         return err;
 1708 }
 1709 
 1710 #endif /* CONFIG_EPOLL */
 1711 
 1712 #ifdef CONFIG_SIGNALFD
 1713 
 1714 asmlinkage long compat_sys_signalfd4(int ufd,
 1715                                      const compat_sigset_t __user *sigmask,
 1716                                      compat_size_t sigsetsize, int flags)
 1717 {
 1718         compat_sigset_t ss32;
 1719         sigset_t tmp;
 1720         sigset_t __user *ksigmask;
 1721 
 1722         if (sigsetsize != sizeof(compat_sigset_t))
 1723                 return -EINVAL;
 1724         if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
 1725                 return -EFAULT;
 1726         sigset_from_compat(&tmp, &ss32);
 1727         ksigmask = compat_alloc_user_space(sizeof(sigset_t));
 1728         if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t)))
 1729                 return -EFAULT;
 1730 
 1731         return sys_signalfd4(ufd, ksigmask, sizeof(sigset_t), flags);
 1732 }
 1733 
 1734 asmlinkage long compat_sys_signalfd(int ufd,
 1735                                     const compat_sigset_t __user *sigmask,
 1736                                     compat_size_t sigsetsize)
 1737 {
 1738         return compat_sys_signalfd4(ufd, sigmask, sigsetsize, 0);
 1739 }
 1740 #endif /* CONFIG_SIGNALFD */
 1741 
 1742 #ifdef CONFIG_TIMERFD
 1743 
 1744 asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
 1745                                    const struct compat_itimerspec __user *utmr,
 1746                                    struct compat_itimerspec __user *otmr)
 1747 {
 1748         int error;
 1749         struct itimerspec t;
 1750         struct itimerspec __user *ut;
 1751 
 1752         if (get_compat_itimerspec(&t, utmr))
 1753                 return -EFAULT;
 1754         ut = compat_alloc_user_space(2 * sizeof(struct itimerspec));
 1755         if (copy_to_user(&ut[0], &t, sizeof(t)))
 1756                 return -EFAULT;
 1757         error = sys_timerfd_settime(ufd, flags, &ut[0], &ut[1]);
 1758         if (!error && otmr)
 1759                 error = (copy_from_user(&t, &ut[1], sizeof(struct itimerspec)) ||
 1760                          put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0;
 1761 
 1762         return error;
 1763 }
 1764 
 1765 asmlinkage long compat_sys_timerfd_gettime(int ufd,
 1766                                    struct compat_itimerspec __user *otmr)
 1767 {
 1768         int error;
 1769         struct itimerspec t;
 1770         struct itimerspec __user *ut;
 1771 
 1772         ut = compat_alloc_user_space(sizeof(struct itimerspec));
 1773         error = sys_timerfd_gettime(ufd, ut);
 1774         if (!error)
 1775                 error = (copy_from_user(&t, ut, sizeof(struct itimerspec)) ||
 1776                          put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0;
 1777 
 1778         return error;
 1779 }
 1780 
 1781 #endif /* CONFIG_TIMERFD */
 1782 
 1783 #ifdef CONFIG_FHANDLE
 1784 /*
 1785  * Exactly like fs/open.c:sys_open_by_handle_at(), except that it
 1786  * doesn't set the O_LARGEFILE flag.
 1787  */
 1788 asmlinkage long
 1789 compat_sys_open_by_handle_at(int mountdirfd,
 1790                              struct file_handle __user *handle, int flags)
 1791 {
 1792         return do_handle_open(mountdirfd, handle, flags);
 1793 }
 1794 #endif
 1795 
 1796 #ifdef __ARCH_WANT_COMPAT_SYS_SENDFILE
 1797 asmlinkage long compat_sys_sendfile(int out_fd, int in_fd,
 1798                                     compat_off_t __user *offset, compat_size_t count)
 1799 {
 1800         loff_t pos;
 1801         off_t off;
 1802         ssize_t ret;
 1803 
 1804         if (offset) {
 1805                 if (unlikely(get_user(off, offset)))
 1806                         return -EFAULT;
 1807                 pos = off;
 1808                 ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
 1809                 if (unlikely(put_user(pos, offset)))
 1810                         return -EFAULT;
 1811                 return ret;
 1812         }
 1813 
 1814         return do_sendfile(out_fd, in_fd, NULL, count, 0);
 1815 }
 1816 #endif /* __ARCH_WANT_COMPAT_SYS_SENDFILE */

Cache object: 1c4f79601ec462742527f7cb03b95491


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.