Gitweb:
http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: c0d08ea227d2c502519abff654b6b2881f7891b6
Parent: 08fd6f0c99e97b74db27643f93f70fd65b686e9f
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Sep 22 16:17:39 2009 -0500
Committer: Bob Peterson <rpeterso(a)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);