Merge branch 'splice' of git://brick.kernel.dk/data/git/linux-2.6-block
authorLinus Torvalds <torvalds@g5.osdl.org>
Sat, 21 Oct 2006 17:01:52 +0000 (10:01 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Sat, 21 Oct 2006 17:01:52 +0000 (10:01 -0700)
* 'splice' of git://brick.kernel.dk/data/git/linux-2.6-block:
  [PATCH] Remove SUID when splicing into an inode
  [PATCH] Add lockless helpers for remove_suid()
  [PATCH] Introduce generic_file_splice_write_nolock()
  [PATCH] Take i_mutex in splice_from_pipe()

1  2 
mm/filemap.c

diff --combined mm/filemap.c
@@@ -75,8 -75,8 +75,8 @@@ generic_file_direct_IO(int rw, struct k
   *  ->mmap_sem
   *    ->lock_page             (access_process_vm)
   *
 - *  ->mmap_sem
 - *    ->i_mutex                       (msync)
 + *  ->i_mutex                 (generic_file_buffered_write)
 + *    ->mmap_sem              (fault_in_pages_readable->do_page_fault)
   *
   *  ->i_mutex
   *    ->i_alloc_sem             (various)
@@@ -1884,11 -1884,10 +1884,10 @@@ repeat
   *    if suid or (sgid and xgrp)
   *            remove privs
   */
- int remove_suid(struct dentry *dentry)
+ int should_remove_suid(struct dentry *dentry)
  {
        mode_t mode = dentry->d_inode->i_mode;
        int kill = 0;
-       int result = 0;
  
        /* suid always must be killed */
        if (unlikely(mode & S_ISUID))
        if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
                kill |= ATTR_KILL_SGID;
  
-       if (unlikely(kill && !capable(CAP_FSETID))) {
-               struct iattr newattrs;
+       if (unlikely(kill && !capable(CAP_FSETID)))
+               return kill;
  
-               newattrs.ia_valid = ATTR_FORCE | kill;
-               result = notify_change(dentry, &newattrs);
-       }
-       return result;
+       return 0;
+ }
+ int __remove_suid(struct dentry *dentry, int kill)
+ {
+       struct iattr newattrs;
+       newattrs.ia_valid = ATTR_FORCE | kill;
+       return notify_change(dentry, &newattrs);
+ }
+ int remove_suid(struct dentry *dentry)
+ {
+       int kill = should_remove_suid(dentry);
+       if (unlikely(kill))
+               return __remove_suid(dentry, kill);
+       return 0;
  }
  EXPORT_SYMBOL(remove_suid);
  
@@@ -2222,7 -2236,7 +2236,7 @@@ __generic_file_aio_write_nolock(struct 
                                unsigned long nr_segs, loff_t *ppos)
  {
        struct file *file = iocb->ki_filp;
 -      const struct address_space * mapping = file->f_mapping;
 +      struct address_space * mapping = file->f_mapping;
        size_t ocount;          /* original count */
        size_t count;           /* after file limit checks */
        struct inode    *inode = mapping->host;
  
        /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
        if (unlikely(file->f_flags & O_DIRECT)) {
 -              written = generic_file_direct_write(iocb, iov,
 -                              &nr_segs, pos, ppos, count, ocount);
 +              loff_t endbyte;
 +              ssize_t written_buffered;
 +
 +              written = generic_file_direct_write(iocb, iov, &nr_segs, pos,
 +                                                      ppos, count, ocount);
                if (written < 0 || written == count)
                        goto out;
                /*
                 */
                pos += written;
                count -= written;
 -      }
 +              written_buffered = generic_file_buffered_write(iocb, iov,
 +                                              nr_segs, pos, ppos, count,
 +                                              written);
 +              /*
 +               * If generic_file_buffered_write() retuned a synchronous error
 +               * then we want to return the number of bytes which were
 +               * direct-written, or the error code if that was zero.  Note
 +               * that this differs from normal direct-io semantics, which
 +               * will return -EFOO even if some bytes were written.
 +               */
 +              if (written_buffered < 0) {
 +                      err = written_buffered;
 +                      goto out;
 +              }
  
 -      written = generic_file_buffered_write(iocb, iov, nr_segs,
 -                      pos, ppos, count, written);
 +              /*
 +               * We need to ensure that the page cache pages are written to
 +               * disk and invalidated to preserve the expected O_DIRECT
 +               * semantics.
 +               */
 +              endbyte = pos + written_buffered - written - 1;
 +              err = do_sync_file_range(file, pos, endbyte,
 +                                       SYNC_FILE_RANGE_WAIT_BEFORE|
 +                                       SYNC_FILE_RANGE_WRITE|
 +                                       SYNC_FILE_RANGE_WAIT_AFTER);
 +              if (err == 0) {
 +                      written = written_buffered;
 +                      invalidate_mapping_pages(mapping,
 +                                               pos >> PAGE_CACHE_SHIFT,
 +                                               endbyte >> PAGE_CACHE_SHIFT);
 +              } else {
 +                      /*
 +                       * We don't know how much we wrote, so just return
 +                       * the number of bytes which were direct-written
 +                       */
 +              }
 +      } else {
 +              written = generic_file_buffered_write(iocb, iov, nr_segs,
 +                              pos, ppos, count, written);
 +      }
  out:
        current->backing_dev_info = NULL;
        return written ? written : err;