Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=c11... Commit: c11570abe26008d5c5328932f2adf312978c2130 Parent: 74f94cce6528c9f985f9ebb5c2134b63b054dea8 Author: Bob Peterson rpeterso@redhat.com AuthorDate: Wed Jul 21 14:37:56 2010 -0500 Committer: Bob Peterson rpeterso@redhat.com CommitterDate: Wed Jul 21 14:43:00 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#212203 --- gfs-kernel/src/gfs/ops_address.c | 21 ++++++++++----------- gfs-kernel/src/gfs/ops_export.c | 5 +---- gfs-kernel/src/gfs/ops_file.c | 5 +++++ 3 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/gfs-kernel/src/gfs/ops_address.c b/gfs-kernel/src/gfs/ops_address.c index 6661421..ae7359c 100644 --- a/gfs-kernel/src/gfs/ops_address.c +++ b/gfs-kernel/src/gfs/ops_address.c @@ -211,20 +211,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); @@ -386,20 +386,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) { 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 4cbc8e0..c9cfb54 100644 --- a/gfs-kernel/src/gfs/ops_export.c +++ b/gfs-kernel/src/gfs/ops_export.c @@ -62,9 +62,6 @@ gfs_decode_fh(struct super_block *sb, __u32 *fh, int fh_len, int fh_type,
atomic_inc(&vfs2sdp(sb)->sd_ops_export);
- if (fh_type != fh_len) - return NULL; - memset(&parent, 0, sizeof(struct inode_cookie));
switch (fh_type) { @@ -216,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 005b0b9..628ab99 100644 --- a/gfs-kernel/src/gfs/ops_file.c +++ b/gfs-kernel/src/gfs/ops_file.c @@ -984,6 +984,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]);
@@ -1030,6 +1031,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);
cluster-commits@lists.fedorahosted.org