Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1121

kernel-2.6.18-238.el5.src.rpm

From: Jeff Layton <jlayton@redhat.com>
Date: Mon, 13 Apr 2009 11:06:04 -0400
Subject: [fs] nfs: convert to new aops
Message-id: 1239635165-16102-3-git-send-email-jlayton@redhat.com
O-Subject: [RHEL5.4 PATCH 2/3] BZ#476224: nfs: convert to new aops
Bugzilla: 476224
RH-Acked-by: Steve Dickson <SteveD@redhat.com>
RH-Acked-by: Peter Staubach <staubach@redhat.com>

From: Nick Piggin <npiggin@suse.de>

Backported from 4899f9c852564ce7b6d0ca932ac6674bf471fd28

This patch converts NFS to use the new address_space_operations that
Josef's patchset for BZ#445433 introduce. While the old address space
ops basically work, those patches will cause those codepaths to incur a
greater performance penalty. To avoid this, we'll want to convert
filesystems to use the new aops.

Tested by me using the usual gamut of connectathon, fsstress, fsx, etc.
in a kernel with Josef's patchset for BZ#445433. Obviously, this patch
shouldn't be applied until Josef's patches are committed.

diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 38bb21a..a63e4ee 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -296,27 +296,50 @@ nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
 }
 
 /*
- * This does the "real" work of the write. The generic routine has
- * allocated the page, locked it, done all the page alignment stuff
- * calculations etc. Now we should just copy the data from user
- * space and write it back to the real medium..
+ * This does the "real" work of the write. We must allocate and lock the
+ * page to be sent back to the generic routine, which then copies the
+ * data from user space.
  *
  * If the writer ends up delaying the write, the writer needs to
  * increment the page use counts until he is done with the page.
  */
-static int nfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+static int nfs_write_begin(struct file *file, struct address_space *mapping,
+			loff_t pos, unsigned len, unsigned flags,
+			struct page **pagep, void **fsdata)
 {
-	return nfs_flush_incompatible(file, page);
+	int ret;
+	pgoff_t index;
+	struct page *page;
+	index = pos >> PAGE_CACHE_SHIFT;
+
+	page = grab_cache_page_write_begin(mapping, index, flags);
+	if (!page)
+		return -ENOMEM;
+	*pagep = page;
+
+	ret = nfs_flush_incompatible(file, page);
+	if (ret) {
+		unlock_page(page);
+		page_cache_release(page);
+	}
+	return ret;
 }
 
-static int nfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+static int nfs_write_end(struct file *file, struct address_space *mapping,
+			loff_t pos, unsigned len, unsigned copied,
+			struct page *page, void *fsdata)
 {
-	long status;
+	unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
+	int status;
 
 	lock_kernel();
-	status = nfs_updatepage(file, page, offset, to-offset);
+	status = nfs_updatepage(file, page, offset, copied);
 	unlock_kernel();
-	return status;
+
+	unlock_page(page);
+	page_cache_release(page);
+
+	return status < 0 ? status : copied;
 }
 
 static void nfs_invalidate_page(struct page *page, unsigned long offset)
@@ -362,22 +385,22 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
  * fscache, we have to override extra address space ops to prevent fs/buffer.c
  * from getting confused, even though we may not have asked its opinion
  */
-const struct address_space_operations nfs_file_aops = {
-	.readpage = nfs_readpage,
-	.readpages = nfs_readpages,
-	.set_page_dirty = __set_page_dirty_nobuffers,
-	.writepage = nfs_writepage,
-	.writepages = nfs_writepages,
-	.prepare_write = nfs_prepare_write,
-	.commit_write = nfs_commit_write,
-	.invalidatepage = nfs_invalidate_page,
-	.releasepage = nfs_release_page,
+const struct address_space_operations_ext nfs_file_aops = {
+	.orig_aops.readpage = nfs_readpage,
+	.orig_aops.readpages = nfs_readpages,
+	.orig_aops.set_page_dirty = __set_page_dirty_nobuffers,
+	.orig_aops.writepage = nfs_writepage,
+	.orig_aops.writepages = nfs_writepages,
+	.orig_aops.invalidatepage = nfs_invalidate_page,
+	.orig_aops.releasepage = nfs_release_page,
 #ifdef CONFIG_NFS_DIRECTIO
-	.direct_IO = nfs_direct_IO,
+	.orig_aops.direct_IO = nfs_direct_IO,
 #endif
 #ifdef CONFIG_NFS_FSCACHE
-	.sync_page	= block_sync_page,
+	.orig_aops.sync_page = block_sync_page,
 #endif
+	.write_begin = nfs_write_begin,
+	.write_end = nfs_write_end,
 };
 
 /* 
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 33c1a52..6df2d14 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -271,7 +271,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 		inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops;
 		if (S_ISREG(inode->i_mode)) {
 			inode->i_fop = &nfs_file_operations;
-			inode->i_data.a_ops = &nfs_file_aops;
+			inode->i_data.a_ops = (struct address_space_operations *) &nfs_file_aops;
 			inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info;
 		} else if (S_ISDIR(inode->i_mode)) {
 			inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 82d4ad1..7e113ae 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -562,7 +562,7 @@ static inline void nfs_initialise_sb(struct super_block *sb)
 
 	sb->s_magic = NFS_SUPER_MAGIC;
 
-	sb->s_flags |= MS_NO_LEASES;
+	sb->s_flags |= (MS_NO_LEASES|MS_HAS_NEW_AOPS);
 
 	/* We probably want something more informative here */
 	snprintf(sb->s_id, sizeof(sb->s_id),
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 67413ce..be3ec3e 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -357,7 +357,7 @@ extern struct inode_operations nfs_file_inode_operations;
 extern struct inode_operations nfs3_file_inode_operations;
 #endif /* CONFIG_NFS_V3 */
 extern const struct file_operations nfs_file_operations;
-extern const struct address_space_operations nfs_file_aops;
+extern const struct address_space_operations_ext nfs_file_aops;
 
 static inline struct rpc_cred *nfs_file_cred(struct file *file)
 {