linux/fs/read_write.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/read_write.c
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 */
   6
   7#include <linux/slab.h> 
   8#include <linux/stat.h>
   9#include <linux/fcntl.h>
  10#include <linux/file.h>
  11#include <linux/uio.h>
  12#include <linux/smp_lock.h>
  13#include <linux/fsnotify.h>
  14#include <linux/security.h>
  15#include <linux/module.h>
  16#include <linux/syscalls.h>
  17#include <linux/pagemap.h>
  18#include <linux/splice.h>
  19#include "read_write.h"
  20
  21#include <asm/uaccess.h>
  22#include <asm/unistd.h>
  23
  24const struct file_operations generic_ro_fops = {
  25        .llseek         = generic_file_llseek,
  26        .read           = do_sync_read,
  27        .aio_read       = generic_file_aio_read,
  28        .mmap           = generic_file_readonly_mmap,
  29        .splice_read    = generic_file_splice_read,
  30};
  31
  32EXPORT_SYMBOL(generic_ro_fops);
  33
  34loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
  35{
  36        loff_t retval;
  37        struct inode *inode = file->f_mapping->host;
  38
  39        mutex_lock(&inode->i_mutex);
  40        switch (origin) {
  41                case SEEK_END:
  42                        offset += inode->i_size;
  43                        break;
  44                case SEEK_CUR:
  45                        offset += file->f_pos;
  46        }
  47        retval = -EINVAL;
  48        if (offset>=0 && offset<=inode->i_sb->s_maxbytes) {
  49                if (offset != file->f_pos) {
  50                        file->f_pos = offset;
  51                        file->f_version = 0;
  52                }
  53                retval = offset;
  54        }
  55        mutex_unlock(&inode->i_mutex);
  56        return retval;
  57}
  58
  59EXPORT_SYMBOL(generic_file_llseek);
  60
  61loff_t remote_llseek(struct file *file, loff_t offset, int origin)
  62{
  63        loff_t retval;
  64
  65        lock_kernel();
  66        switch (origin) {
  67                case SEEK_END:
  68                        offset += i_size_read(file->f_path.dentry->d_inode);
  69                        break;
  70                case SEEK_CUR:
  71                        offset += file->f_pos;
  72        }
  73        retval = -EINVAL;
  74        if (offset>=0 && offset<=file->f_path.dentry->d_inode->i_sb->s_maxbytes) {
  75                if (offset != file->f_pos) {
  76                        file->f_pos = offset;
  77                        file->f_version = 0;
  78                }
  79                retval = offset;
  80        }
  81        unlock_kernel();
  82        return retval;
  83}
  84EXPORT_SYMBOL(remote_llseek);
  85
  86loff_t no_llseek(struct file *file, loff_t offset, int origin)
  87{
  88        return -ESPIPE;
  89}
  90EXPORT_SYMBOL(no_llseek);
  91
  92loff_t default_llseek(struct file *file, loff_t offset, int origin)
  93{
  94        loff_t retval;
  95
  96        lock_kernel();
  97        switch (origin) {
  98                case SEEK_END:
  99                        offset += i_size_read(file->f_path.dentry->d_inode);
 100                        break;
 101                case SEEK_CUR:
 102                        offset += file->f_pos;
 103        }
 104        retval = -EINVAL;
 105        if (offset >= 0) {
 106                if (offset != file->f_pos) {
 107                        file->f_pos = offset;
 108                        file->f_version = 0;
 109                }
 110                retval = offset;
 111        }
 112        unlock_kernel();
 113        return retval;
 114}
 115EXPORT_SYMBOL(default_llseek);
 116
 117loff_t vfs_llseek(struct file *file, loff_t offset, int origin)
 118{
 119        loff_t (*fn)(struct file *, loff_t, int);
 120
 121        fn = no_llseek;
 122        if (file->f_mode & FMODE_LSEEK) {
 123                fn = default_llseek;
 124                if (file->f_op && file->f_op->llseek)
 125                        fn = file->f_op->llseek;
 126        }
 127        return fn(file, offset, origin);
 128}
 129EXPORT_SYMBOL(vfs_llseek);
 130
 131asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
 132{
 133        off_t retval;
 134        struct file * file;
 135        int fput_needed;
 136
 137        retval = -EBADF;
 138        file = fget_light(fd, &fput_needed);
 139        if (!file)
 140                goto bad;
 141
 142        retval = -EINVAL;
 143        if (origin <= SEEK_MAX) {
 144                loff_t res = vfs_llseek(file, offset, origin);
 145                retval = res;
 146                if (res != (loff_t)retval)
 147                        retval = -EOVERFLOW;    /* LFS: should only happen on 32 bit platforms */
 148        }
 149        fput_light(file, fput_needed);
 150bad:
 151        return retval;
 152}
 153
 154#ifdef __ARCH_WANT_SYS_LLSEEK
 155asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
 156                           unsigned long offset_low, loff_t __user * result,
 157                           unsigned int origin)
 158{
 159        int retval;
 160        struct file * file;
 161        loff_t offset;
 162        int fput_needed;
 163
 164        retval = -EBADF;
 165        file = fget_light(fd, &fput_needed);
 166        if (!file)
 167                goto bad;
 168
 169        retval = -EINVAL;
 170        if (origin > SEEK_MAX)
 171                goto out_putf;
 172
 173        offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low,
 174                        origin);
 175
 176        retval = (int)offset;
 177        if (offset >= 0) {
 178                retval = -EFAULT;
 179                if (!copy_to_user(result, &offset, sizeof(offset)))
 180                        retval = 0;
 181        }
 182out_putf:
 183        fput_light(file, fput_needed);
 184bad:
 185        return retval;
 186}
 187#endif
 188
 189/*
 190 * rw_verify_area doesn't like huge counts. We limit
 191 * them to something that fits in "int" so that others
 192 * won't have to do range checks all the time.
 193 */
 194#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
 195
 196int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
 197{
 198        struct inode *inode;
 199        loff_t pos;
 200        int retval = -EINVAL;
 201
 202        inode = file->f_path.dentry->d_inode;
 203        if (unlikely((ssize_t) count < 0))
 204                return retval;
 205        pos = *ppos;
 206        if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
 207                return retval;
 208
 209        if (unlikely(inode->i_flock && mandatory_lock(inode))) {
 210                retval = locks_mandatory_area(
 211                        read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
 212                        inode, file, pos, count);
 213                if (retval < 0)
 214                        return retval;
 215        }
 216        retval = security_file_permission(file,
 217                                read_write == READ ? MAY_READ : MAY_WRITE);
 218        if (retval)
 219                return retval;
 220        return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;
 221}
 222
 223static void wait_on_retry_sync_kiocb(struct kiocb *iocb)
 224{
 225        set_current_state(TASK_UNINTERRUPTIBLE);
 226        if (!kiocbIsKicked(iocb))
 227                schedule();
 228        else
 229                kiocbClearKicked(iocb);
 230        __set_current_state(TASK_RUNNING);
 231}
 232
 233ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
 234{
 235        struct iovec iov = { .iov_base = buf, .iov_len = len };
 236        struct kiocb kiocb;
 237        ssize_t ret;
 238
 239        init_sync_kiocb(&kiocb, filp);
 240        kiocb.ki_pos = *ppos;
 241        kiocb.ki_left = len;
 242
 243        for (;;) {
 244                ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
 245                if (ret != -EIOCBRETRY)
 246                        break;
 247                wait_on_retry_sync_kiocb(&kiocb);
 248        }
 249
 250        if (-EIOCBQUEUED == ret)
 251                ret = wait_on_sync_kiocb(&kiocb);
 252        *ppos = kiocb.ki_pos;
 253        return ret;
 254}
 255
 256EXPORT_SYMBOL(do_sync_read);
 257
 258ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
 259{
 260        ssize_t ret;
 261
 262        if (!(file->f_mode & FMODE_READ))
 263                return -EBADF;
 264        if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
 265                return -EINVAL;
 266        if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
 267                return -EFAULT;
 268
 269        ret = rw_verify_area(READ, file, pos, count);
 270        if (ret >= 0) {
 271                count = ret;
 272                if (file->f_op->read)
 273                        ret = file->f_op->read(file, buf, count, pos);
 274                else
 275                        ret = do_sync_read(file, buf, count, pos);
 276                if (ret > 0) {
 277                        fsnotify_access(file->f_path.dentry);
 278                        add_rchar(current, ret);
 279                }
 280                inc_syscr(current);
 281        }
 282
 283        return ret;
 284}
 285
 286EXPORT_SYMBOL(vfs_read);
 287
 288ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
 289{
 290        struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
 291        struct kiocb kiocb;
 292        ssize_t ret;
 293
 294        init_sync_kiocb(&kiocb, filp);
 295        kiocb.ki_pos = *ppos;
 296        kiocb.ki_left = len;
 297
 298        for (;;) {
 299                ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);
 300                if (ret != -EIOCBRETRY)
 301                        break;
 302                wait_on_retry_sync_kiocb(&kiocb);
 303        }
 304
 305        if (-EIOCBQUEUED == ret)
 306                ret = wait_on_sync_kiocb(&kiocb);
 307        *ppos = kiocb.ki_pos;
 308        return ret;
 309}
 310
 311EXPORT_SYMBOL(do_sync_write);
 312
 313ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
 314{
 315        ssize_t ret;
 316
 317        if (!(file->f_mode & FMODE_WRITE))
 318                return -EBADF;
 319        if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
 320                return -EINVAL;
 321        if (unlikely(!access_ok(VERIFY_READ, buf, count)))
 322                return -EFAULT;
 323
 324        ret = rw_verify_area(WRITE, file, pos, count);
 325        if (ret >= 0) {
 326                count = ret;
 327                if (file->f_op->write)
 328                        ret = file->f_op->write(file, buf, count, pos);
 329                else
 330                        ret = do_sync_write(file, buf, count, pos);
 331                if (ret > 0) {
 332                        fsnotify_modify(file->f_path.dentry);
 333                        add_wchar(current, ret);
 334                }
 335                inc_syscw(current);
 336        }
 337
 338        return ret;
 339}
 340
 341EXPORT_SYMBOL(vfs_write);
 342
 343static inline loff_t file_pos_read(struct file *file)
 344{
 345        return file->f_pos;
 346}
 347
 348static inline void file_pos_write(struct file *file, loff_t pos)
 349{
 350        file->f_pos = pos;
 351}
 352
 353asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
 354{
 355        struct file *file;
 356        ssize_t ret = -EBADF;
 357        int fput_needed;
 358
 359        file = fget_light(fd, &fput_needed);
 360        if (file) {
 361                loff_t pos = file_pos_read(file);
 362                ret = vfs_read(file, buf, count, &pos);
 363                file_pos_write(file, pos);
 364                fput_light(file, fput_needed);
 365        }
 366
 367        return ret;
 368}
 369
 370asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
 371{
 372        struct file *file;
 373        ssize_t ret = -EBADF;
 374        int fput_needed;
 375
 376        file = fget_light(fd, &fput_needed);
 377        if (file) {
 378                loff_t pos = file_pos_read(file);
 379                ret = vfs_write(file, buf, count, &pos);
 380                file_pos_write(file, pos);
 381                fput_light(file, fput_needed);
 382        }
 383
 384        return ret;
 385}
 386
 387asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
 388                             size_t count, loff_t pos)
 389{
 390        struct file *file;
 391        ssize_t ret = -EBADF;
 392        int fput_needed;
 393
 394        if (pos < 0)
 395                return -EINVAL;
 396
 397        file = fget_light(fd, &fput_needed);
 398        if (file) {
 399                ret = -ESPIPE;
 400                if (file->f_mode & FMODE_PREAD)
 401                        ret = vfs_read(file, buf, count, &pos);
 402                fput_light(file, fput_needed);
 403        }
 404
 405        return ret;
 406}
 407
 408asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
 409                              size_t count, loff_t pos)
 410{
 411        struct file *file;
 412        ssize_t ret = -EBADF;
 413        int fput_needed;
 414
 415        if (pos < 0)
 416                return -EINVAL;
 417
 418        file = fget_light(fd, &fput_needed);
 419        if (file) {
 420                ret = -ESPIPE;
 421                if (file->f_mode & FMODE_PWRITE)  
 422                        ret = vfs_write(file, buf, count, &pos);
 423                fput_light(file, fput_needed);
 424        }
 425
 426        return ret;
 427}
 428
 429/*
 430 * Reduce an iovec's length in-place.  Return the resulting number of segments
 431 */
 432unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
 433{
 434        unsigned long seg = 0;
 435        size_t len = 0;
 436
 437        while (seg < nr_segs) {
 438                seg++;
 439                if (len + iov->iov_len >= to) {
 440                        iov->iov_len = to - len;
 441                        break;
 442                }
 443                len += iov->iov_len;
 444                iov++;
 445        }
 446        return seg;
 447}
 448EXPORT_SYMBOL(iov_shorten);
 449
 450ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
 451                unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn)
 452{
 453        struct kiocb kiocb;
 454        ssize_t ret;
 455
 456        init_sync_kiocb(&kiocb, filp);
 457        kiocb.ki_pos = *ppos;
 458        kiocb.ki_left = len;
 459        kiocb.ki_nbytes = len;
 460
 461        for (;;) {
 462                ret = fn(&kiocb, iov, nr_segs, kiocb.ki_pos);
 463                if (ret != -EIOCBRETRY)
 464                        break;
 465                wait_on_retry_sync_kiocb(&kiocb);
 466        }
 467
 468        if (ret == -EIOCBQUEUED)
 469                ret = wait_on_sync_kiocb(&kiocb);
 470        *ppos = kiocb.ki_pos;
 471        return ret;
 472}
 473
 474/* Do it by hand, with file-ops */
 475ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
 476                unsigned long nr_segs, loff_t *ppos, io_fn_t fn)
 477{
 478        struct iovec *vector = iov;
 479        ssize_t ret = 0;
 480
 481        while (nr_segs > 0) {
 482                void __user *base;
 483                size_t len;
 484                ssize_t nr;
 485
 486                base = vector->iov_base;
 487                len = vector->iov_len;
 488                vector++;
 489                nr_segs--;
 490
 491                nr = fn(filp, base, len, ppos);
 492
 493                if (nr < 0) {
 494                        if (!ret)
 495                                ret = nr;
 496                        break;
 497                }
 498                ret += nr;
 499                if (nr != len)
 500                        break;
 501        }
 502
 503        return ret;
 504}
 505
 506/* A write operation does a read from user space and vice versa */
 507#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
 508
 509ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
 510                              unsigned long nr_segs, unsigned long fast_segs,
 511                              struct iovec *fast_pointer,
 512                              struct iovec **ret_pointer)
 513  {
 514        unsigned long seg;
 515        ssize_t ret;
 516        struct iovec *iov = fast_pointer;
 517
 518        /*
 519         * SuS says "The readv() function *may* fail if the iovcnt argument
 520         * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
 521         * traditionally returned zero for zero segments, so...
 522         */
 523        if (nr_segs == 0) {
 524                ret = 0;
 525                goto out;
 526        }
 527
 528        /*
 529         * First get the "struct iovec" from user memory and
 530         * verify all the pointers
 531         */
 532        if (nr_segs > UIO_MAXIOV) {
 533                ret = -EINVAL;
 534                goto out;
 535        }
 536        if (nr_segs > fast_segs) {
 537                iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
 538                if (iov == NULL) {
 539                        ret = -ENOMEM;
 540                        goto out;
 541                }
 542        }
 543        if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
 544                ret = -EFAULT;
 545                goto out;
 546        }
 547
 548        /*
 549         * According to the Single Unix Specification we should return EINVAL
 550         * if an element length is < 0 when cast to ssize_t or if the
 551         * total length would overflow the ssize_t return value of the
 552         * system call.
 553         */
 554        ret = 0;
 555        for (seg = 0; seg < nr_segs; seg++) {
 556                void __user *buf = iov[seg].iov_base;
 557                ssize_t len = (ssize_t)iov[seg].iov_len;
 558
 559                /* see if we we're about to use an invalid len or if
 560                 * it's about to overflow ssize_t */
 561                if (len < 0 || (ret + len < ret)) {
 562                        ret = -EINVAL;
 563                        goto out;
 564                }
 565                if (unlikely(!access_ok(vrfy_dir(type), buf, len))) {
 566                        ret = -EFAULT;
 567                        goto out;
 568                }
 569
 570                ret += len;
 571        }
 572out:
 573        *ret_pointer = iov;
 574        return ret;
 575}
 576
 577static ssize_t do_readv_writev(int type, struct file *file,
 578                               const struct iovec __user * uvector,
 579                               unsigned long nr_segs, loff_t *pos)
 580{
 581        size_t tot_len;
 582        struct iovec iovstack[UIO_FASTIOV];
 583        struct iovec *iov = iovstack;
 584        ssize_t ret;
 585        io_fn_t fn;
 586        iov_fn_t fnv;
 587
 588        if (!file->f_op) {
 589                ret = -EINVAL;
 590                goto out;
 591        }
 592
 593        ret = rw_copy_check_uvector(type, uvector, nr_segs,
 594                        ARRAY_SIZE(iovstack), iovstack, &iov);
 595        if (ret <= 0)
 596                goto out;
 597
 598        tot_len = ret;
 599        ret = rw_verify_area(type, file, pos, tot_len);
 600        if (ret < 0)
 601                goto out;
 602
 603        fnv = NULL;
 604        if (type == READ) {
 605                fn = file->f_op->read;
 606                fnv = file->f_op->aio_read;
 607        } else {
 608                fn = (io_fn_t)file->f_op->write;
 609                fnv = file->f_op->aio_write;
 610        }
 611
 612        if (fnv)
 613                ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
 614                                                pos, fnv);
 615        else
 616                ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);
 617
 618out:
 619        if (iov != iovstack)
 620                kfree(iov);
 621        if ((ret + (type == READ)) > 0) {
 622                if (type == READ)
 623                        fsnotify_access(file->f_path.dentry);
 624                else
 625                        fsnotify_modify(file->f_path.dentry);
 626        }
 627        return ret;
 628}
 629
 630ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
 631                  unsigned long vlen, loff_t *pos)
 632{
 633        if (!(file->f_mode & FMODE_READ))
 634                return -EBADF;
 635        if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
 636                return -EINVAL;
 637
 638        return do_readv_writev(READ, file, vec, vlen, pos);
 639}
 640
 641EXPORT_SYMBOL(vfs_readv);
 642
 643ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
 644                   unsigned long vlen, loff_t *pos)
 645{
 646        if (!(file->f_mode & FMODE_WRITE))
 647                return -EBADF;
 648        if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
 649                return -EINVAL;
 650
 651        return do_readv_writev(WRITE, file, vec, vlen, pos);
 652}
 653
 654EXPORT_SYMBOL(vfs_writev);
 655
 656asmlinkage ssize_t
 657sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
 658{
 659        struct file *file;
 660        ssize_t ret = -EBADF;
 661        int fput_needed;
 662
 663        file = fget_light(fd, &fput_needed);
 664        if (file) {
 665                loff_t pos = file_pos_read(file);
 666                ret = vfs_readv(file, vec, vlen, &pos);
 667                file_pos_write(file, pos);
 668                fput_light(file, fput_needed);
 669        }
 670
 671        if (ret > 0)
 672                add_rchar(current, ret);
 673        inc_syscr(current);
 674        return ret;
 675}
 676
 677asmlinkage ssize_t
 678sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
 679{
 680        struct file *file;
 681        ssize_t ret = -EBADF;
 682        int fput_needed;
 683
 684        file = fget_light(fd, &fput_needed);
 685        if (file) {
 686                loff_t pos = file_pos_read(file);
 687                ret = vfs_writev(file, vec, vlen, &pos);
 688                file_pos_write(file, pos);
 689                fput_light(file, fput_needed);
 690        }
 691
 692        if (ret > 0)
 693                add_wchar(current, ret);
 694        inc_syscw(current);
 695        return ret;
 696}
 697
 698static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
 699                           size_t count, loff_t max)
 700{
 701        struct file * in_file, * out_file;
 702        struct inode * in_inode, * out_inode;
 703        loff_t pos;
 704        ssize_t retval;
 705        int fput_needed_in, fput_needed_out, fl;
 706
 707        /*
 708         * Get input file, and verify that it is ok..
 709         */
 710        retval = -EBADF;
 711        in_file = fget_light(in_fd, &fput_needed_in);
 712        if (!in_file)
 713                goto out;
 714        if (!(in_file->f_mode & FMODE_READ))
 715                goto fput_in;
 716        retval = -EINVAL;
 717        in_inode = in_file->f_path.dentry->d_inode;
 718        if (!in_inode)
 719                goto fput_in;
 720        if (!in_file->f_op || !in_file->f_op->splice_read)
 721                goto fput_in;
 722        retval = -ESPIPE;
 723        if (!ppos)
 724                ppos = &in_file->f_pos;
 725        else
 726                if (!(in_file->f_mode & FMODE_PREAD))
 727                        goto fput_in;
 728        retval = rw_verify_area(READ, in_file, ppos, count);
 729        if (retval < 0)
 730                goto fput_in;
 731        count = retval;
 732
 733        /*
 734         * Get output file, and verify that it is ok..
 735         */
 736        retval = -EBADF;
 737        out_file = fget_light(out_fd, &fput_needed_out);
 738        if (!out_file)
 739                goto fput_in;
 740        if (!(out_file->f_mode & FMODE_WRITE))
 741                goto fput_out;
 742        retval = -EINVAL;
 743        if (!out_file->f_op || !out_file->f_op->sendpage)
 744                goto fput_out;
 745        out_inode = out_file->f_path.dentry->d_inode;
 746        retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
 747        if (retval < 0)
 748                goto fput_out;
 749        count = retval;
 750
 751        if (!max)
 752                max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
 753
 754        pos = *ppos;
 755        retval = -EINVAL;
 756        if (unlikely(pos < 0))
 757                goto fput_out;
 758        if (unlikely(pos + count > max)) {
 759                retval = -EOVERFLOW;
 760                if (pos >= max)
 761                        goto fput_out;
 762                count = max - pos;
 763        }
 764
 765        fl = 0;
 766#if 0
 767        /*
 768         * We need to debate whether we can enable this or not. The
 769         * man page documents EAGAIN return for the output at least,
 770         * and the application is arguably buggy if it doesn't expect
 771         * EAGAIN on a non-blocking file descriptor.
 772         */
 773        if (in_file->f_flags & O_NONBLOCK)
 774                fl = SPLICE_F_NONBLOCK;
 775#endif
 776        retval = do_splice_direct(in_file, ppos, out_file, count, fl);
 777
 778        if (retval > 0) {
 779                add_rchar(current, retval);
 780                add_wchar(current, retval);
 781        }
 782
 783        inc_syscr(current);
 784        inc_syscw(current);
 785        if (*ppos > max)
 786                retval = -EOVERFLOW;
 787
 788fput_out:
 789        fput_light(out_file, fput_needed_out);
 790fput_in:
 791        fput_light(in_file, fput_needed_in);
 792out:
 793        return retval;
 794}
 795
 796asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count)
 797{
 798        loff_t pos;
 799        off_t off;
 800        ssize_t ret;
 801
 802        if (offset) {
 803                if (unlikely(get_user(off, offset)))
 804                        return -EFAULT;
 805                pos = off;
 806                ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
 807                if (unlikely(put_user(pos, offset)))
 808                        return -EFAULT;
 809                return ret;
 810        }
 811
 812        return do_sendfile(out_fd, in_fd, NULL, count, 0);
 813}
 814
 815asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count)
 816{
 817        loff_t pos;
 818        ssize_t ret;
 819
 820        if (offset) {
 821                if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
 822                        return -EFAULT;
 823                ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
 824                if (unlikely(put_user(pos, offset)))
 825                        return -EFAULT;
 826                return ret;
 827        }
 828
 829        return do_sendfile(out_fd, in_fd, NULL, count, 0);
 830}
 831
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.