Merge branch 'fix/misc' into for-linus
[pandora-kernel.git] / fs / nfs / file.c
index ec7e27d..0506232 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/aio.h>
 
 #include <asm/uaccess.h>
@@ -48,6 +47,9 @@ static ssize_t nfs_file_splice_read(struct file *filp, loff_t *ppos,
                                        size_t count, unsigned int flags);
 static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos);
+static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
+                                       struct file *filp, loff_t *ppos,
+                                       size_t count, unsigned int flags);
 static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos);
 static int  nfs_file_flush(struct file *, fl_owner_t id);
@@ -73,6 +75,7 @@ const struct file_operations nfs_file_operations = {
        .lock           = nfs_lock,
        .flock          = nfs_flock,
        .splice_read    = nfs_file_splice_read,
+       .splice_write   = nfs_file_splice_write,
        .check_flags    = nfs_check_flags,
        .setlease       = nfs_setlease,
 };
@@ -587,12 +590,38 @@ out_swapfile:
        goto out;
 }
 
+static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
+                                    struct file *filp, loff_t *ppos,
+                                    size_t count, unsigned int flags)
+{
+       struct dentry *dentry = filp->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       ssize_t ret;
+
+       dprintk("NFS splice_write(%s/%s, %lu@%llu)\n",
+               dentry->d_parent->d_name.name, dentry->d_name.name,
+               (unsigned long) count, (unsigned long long) *ppos);
+
+       /*
+        * The combination of splice and an O_APPEND destination is disallowed.
+        */
+
+       nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count);
+
+       ret = generic_file_splice_write(pipe, filp, ppos, count, flags);
+       if (ret >= 0 && nfs_need_sync_write(filp, inode)) {
+               int err = nfs_do_fsync(nfs_file_open_context(filp), inode);
+               if (err < 0)
+                       ret = err;
+       }
+       return ret;
+}
+
 static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
 {
        struct inode *inode = filp->f_mapping->host;
        int status = 0;
 
-       lock_kernel();
        /* Try local locking first */
        posix_test_lock(filp, fl);
        if (fl->fl_type != F_UNLCK) {
@@ -608,7 +637,6 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
 
        status = NFS_PROTO(inode)->lock(filp, cmd, fl);
 out:
-       unlock_kernel();
        return status;
 out_noconflict:
        fl->fl_type = F_UNLCK;
@@ -650,13 +678,11 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
         *      If we're signalled while cleaning up locks on process exit, we
         *      still need to complete the unlock.
         */
-       lock_kernel();
        /* Use local locking if mounted with "-onolock" */
        if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
                status = NFS_PROTO(inode)->lock(filp, cmd, fl);
        else
                status = do_vfs_lock(filp, fl);
-       unlock_kernel();
        return status;
 }
 
@@ -673,13 +699,11 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
        if (status != 0)
                goto out;
 
-       lock_kernel();
        /* Use local locking if mounted with "-onolock" */
        if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
                status = NFS_PROTO(inode)->lock(filp, cmd, fl);
        else
                status = do_vfs_lock(filp, fl);
-       unlock_kernel();
        if (status < 0)
                goto out;
        /*