From: Miklos Szeredi <miklos@szeredi.hu>

Eric W.  Biederman suggested using a separate set of file operations for
direct I/O.  This patch implements this cleanup.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 fs/fuse/file.c |   78 ++++++++++++++++++++++++---------------------------------
 1 files changed, 33 insertions(+), 45 deletions(-)

diff -puN fs/fuse/file.c~fuse-direct-i-o-cleanup fs/fuse/file.c
--- devel/fs/fuse/file.c~fuse-direct-i-o-cleanup	2005-07-29 23:26:13.000000000 -0700
+++ devel-akpm/fs/fuse/file.c	2005-07-29 23:26:13.000000000 -0700
@@ -457,44 +457,26 @@ static ssize_t fuse_direct_io(struct fil
 	return res;
 }
 
-static ssize_t fuse_file_read(struct file *file, char __user *buf,
-			      size_t count, loff_t *ppos)
+static ssize_t fuse_direct_read(struct file *file, char __user *buf,
+				     size_t count, loff_t *ppos)
 {
-	struct inode *inode = file->f_dentry->d_inode;
-	struct fuse_conn *fc = get_fuse_conn(inode);
-
-	if (fc->flags & FUSE_DIRECT_IO)
-		return fuse_direct_io(file, buf, count, ppos, 0);
-	else
-		return generic_file_read(file, buf, count, ppos);
+	return fuse_direct_io(file, buf, count, ppos, 0);
 }
 
-static ssize_t fuse_file_write(struct file *file, const char __user *buf,
-			       size_t count, loff_t *ppos)
+static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	struct fuse_conn *fc = get_fuse_conn(inode);
-
-	if (fc->flags & FUSE_DIRECT_IO) {
-		ssize_t res;
-		/* Don't allow parallel writes to the same file */
-		down(&inode->i_sem);
-		res = fuse_direct_io(file, buf, count, ppos, 1);
-		up(&inode->i_sem);
-		return res;
-	}
-	else
-		return generic_file_write(file, buf, count, ppos);
+	ssize_t res;
+	/* Don't allow parallel writes to the same file */
+	down(&inode->i_sem);
+	res = fuse_direct_io(file, buf, count, ppos, 1);
+	up(&inode->i_sem);
+	return res;
 }
 
 static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct inode *inode = file->f_dentry->d_inode;
-	struct fuse_conn *fc = get_fuse_conn(inode);
-
-	if (fc->flags & FUSE_DIRECT_IO)
-		return -ENODEV;
-
 	if ((vma->vm_flags & VM_SHARED)) {
 		if ((vma->vm_flags & VM_WRITE))
 			return -ENODEV;
@@ -504,17 +486,6 @@ static int fuse_file_mmap(struct file *f
 	return generic_file_mmap(file, vma);
 }
 
-static ssize_t fuse_file_sendfile(struct file *file, loff_t *ppos,
-				  size_t count, read_actor_t actor,
-				  void *target)
-{
-	struct fuse_conn *fc = get_fuse_conn(file->f_dentry->d_inode);
-	if (fc->flags & FUSE_DIRECT_IO)
-		return -EINVAL;
-	else
-		return generic_file_sendfile(file, ppos, count, actor, target);
-}
-
 static int fuse_set_page_dirty(struct page *page)
 {
 	printk("fuse_set_page_dirty: should not happen\n");
@@ -524,14 +495,25 @@ static int fuse_set_page_dirty(struct pa
 
 static struct file_operations fuse_file_operations = {
 	.llseek		= generic_file_llseek,
-	.read		= fuse_file_read,
-	.write		= fuse_file_write,
+	.read		= generic_file_read,
+	.write		= generic_file_write,
 	.mmap		= fuse_file_mmap,
 	.open		= fuse_open,
 	.flush		= fuse_flush,
 	.release	= fuse_release,
 	.fsync		= fuse_fsync,
-	.sendfile	= fuse_file_sendfile,
+	.sendfile	= generic_file_sendfile,
+};
+
+static struct file_operations fuse_direct_io_file_operations = {
+	.llseek		= generic_file_llseek,
+	.read		= fuse_direct_read,
+	.write		= fuse_direct_write,
+	.open		= fuse_open,
+	.flush		= fuse_flush,
+	.release	= fuse_release,
+	.fsync		= fuse_fsync,
+	/* no mmap and sendfile */
 };
 
 static struct address_space_operations fuse_file_aops  = {
@@ -544,6 +526,12 @@ static struct address_space_operations f
 
 void fuse_init_file_inode(struct inode *inode)
 {
-	inode->i_fop = &fuse_file_operations;
-	inode->i_data.a_ops = &fuse_file_aops;
+	struct fuse_conn *fc = get_fuse_conn(inode);
+
+	if (fc->flags & FUSE_DIRECT_IO)
+		inode->i_fop = &fuse_direct_io_file_operations;
+	else {
+		inode->i_fop = &fuse_file_operations;
+		inode->i_data.a_ops = &fuse_file_aops;
+	}
 }
_