cluster: RHEL56 - GFS: genesis w/flocks on NFS over GFS causes corruption

Bob Peterson rpeterso at fedoraproject.org
Tue Jun 29 18:19:26 UTC 2010


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=c0d08ea227d2c502519abff654b6b2881f7891b6
Commit:        c0d08ea227d2c502519abff654b6b2881f7891b6
Parent:        08fd6f0c99e97b74db27643f93f70fd65b686e9f
Author:        Bob Peterson <rpeterso at redhat.com>
AuthorDate:    Tue Sep 22 16:17:39 2009 -0500
Committer:     Bob Peterson <rpeterso at redhat.com>
CommitterDate: Tue Jun 29 11:47:38 2010 -0500

GFS: genesis w/flocks on NFS over GFS causes corruption

This patch does a few things to avoid the NFS over GFS corruption on
small (stuffed) files:

1. kmap_atomic is used in place of kmap in stuffed_readpage and
   gfs_commit_write.
2. Function stuffed_readpage now flushes the dcache page after
   the page is updated in both of those functions as well.
3. In gfs_get_name there was a typo in an if clause.
4. In do_write_buf the new size is written into the incore inode
   if the file size has increased.

rhbz#245024
---
 gfs-kernel/src/gfs/ops_address.c |   25 +++++++++++++------------
 gfs-kernel/src/gfs/ops_export.c  |    2 +-
 gfs-kernel/src/gfs/ops_file.c    |    5 +++++
 3 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/gfs-kernel/src/gfs/ops_address.c b/gfs-kernel/src/gfs/ops_address.c
index c9ce4e5..7f5538d 100644
--- a/gfs-kernel/src/gfs/ops_address.c
+++ b/gfs-kernel/src/gfs/ops_address.c
@@ -204,20 +204,20 @@ static int
 stuffed_readpage(struct gfs_inode *ip, struct page *page)
 {
 	struct buffer_head *dibh;
-	void *kaddr;
+	char *kaddr;
 	int error;
 
 	error = gfs_get_inode_buffer(ip, &dibh);
 	if (!error) {
-		kaddr = kmap(page);
-		memcpy((char *)kaddr,
+		kaddr = (char *)kmap_atomic(page, KM_USER0);
+		memcpy(kaddr,
 		       dibh->b_data + sizeof(struct gfs_dinode),
 		       ip->i_di.di_size);
-		memset((char *)kaddr + ip->i_di.di_size,
+		memset(kaddr + ip->i_di.di_size,
 		       0,
 		       PAGE_CACHE_SIZE - ip->i_di.di_size);
-		kunmap(page);
-
+		kunmap_atomic(kaddr, KM_USER0);
+		flush_dcache_page(page);
 		brelse(dibh);
 
 		SetPageUptodate(page);
@@ -379,18 +379,19 @@ gfs_commit_write(struct file *file, struct page *page,
 
 		gfs_trans_add_bh(ip->i_gl, dibh);
 
-		kaddr = kmap(page);
+		kaddr = kmap_atomic(page, KM_USER0);
 		memcpy(dibh->b_data + sizeof(struct gfs_dinode) + from,
 		       (char *)kaddr + from,
 		       to - from);
-		kunmap(page);
-
-		brelse(dibh);
+		flush_dcache_page(page);
+		kunmap_atomic(kaddr, KM_USER0);
 
 		SetPageUptodate(page);
-
-		if (inode->i_size < file_size)
+		if (inode->i_size < file_size) {
 			i_size_write(inode, file_size);
+			mark_inode_dirty(inode);
+		}
+		brelse(dibh);
 	} else {
 		error = generic_commit_write(file, page, from, to);
 		if (error)
diff --git a/gfs-kernel/src/gfs/ops_export.c b/gfs-kernel/src/gfs/ops_export.c
index 2e8b5c4..e721c58 100644
--- a/gfs-kernel/src/gfs/ops_export.c
+++ b/gfs-kernel/src/gfs/ops_export.c
@@ -213,7 +213,7 @@ int gfs_get_name(struct dentry *parent, char *name,
 
 	gfs_glock_dq_uninit(&gh);
 
-	if (!error & !*name)
+	if (!error && !*name)
 		error = -ENOENT;
 
 	return error;
diff --git a/gfs-kernel/src/gfs/ops_file.c b/gfs-kernel/src/gfs/ops_file.c
index 150f328..455debb 100644
--- a/gfs-kernel/src/gfs/ops_file.c
+++ b/gfs-kernel/src/gfs/ops_file.c
@@ -976,6 +976,7 @@ do_write_buf(struct file *file,
 	size_t s;
 	ssize_t count = 0;
 	int error;
+	struct inode *inode = file->f_mapping->host;
 
 	gfs_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ghs[num_gh]);
 
@@ -1022,6 +1023,10 @@ do_write_buf(struct file *file,
 	}
 
 	error = 0;
+	if (inode->i_size < ip->i_di.di_size) {
+		i_size_write(inode, ip->i_di.di_size);
+		mark_inode_dirty(inode);
+	}
 
  out_gunlock:
 	gfs_glock_dq_m(num_gh + 1, ghs);


More information about the cluster-commits mailing list