Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 9aef86a809680f3cb51add95512bfdf2 > files > 9

gfs-kmod-0.1.34-15.el5.src.rpm

commit 7dfc82bc15db1f2b92526010eb17b46efecb19f1
Author: Benjamin Marzinski <bmarzins@redhat.com>
Date:   Wed Jul 28 17:17:04 2010 -0500

    gfs-kernel: assertion "!get_transaction" fails on mmaps between gfs filesystems
    
    The gfs walk_vm() code only checked that the buffer which got passed in was not
    mmaped to a file on the same filesystem as the file being written to.  However,
    if that buffer was from a file on another GFS filesystem, and that file did
    not have blocks allocated for all of the area mapped to the buffer, GFS
    would need to start a transaction when it tried to read from the buffer.
    Since gfs had already started a transaction, the !get_transaction assert
    would fail.  Furthermore, gfs is not able to safely hold glocks on files in
    two seperate filesystems at the same time, since inode numbers are used for
    lock ordering, and these are not unique across filesystems. Because of this
    there is no way to guarantee that the necessary blocks won't be removed from
    the mmaped file via a truncate before gfs needs to read them in.  This fix
    simply reads the buffer in before doing any locking, if gfs notices that the
    buffer is mmaped to a file on another gfs filesystem. This should fix the
    problem except in corner cases, where the mmaped file is being truncated at
    the same time.
    
    Resolves: rhbz#617339
    
    Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>

diff --git a/gfs-kernel/src/gfs/ops_file.c b/gfs-kernel/src/gfs/ops_file.c
index 455debb..3d748b6 100644
--- a/gfs-kernel/src/gfs/ops_file.c
+++ b/gfs-kernel/src/gfs/ops_file.c
@@ -192,6 +192,37 @@ walk_vm_hard(struct file *file, char *buf, size_t size, loff_t *offset,
 }
 
 /**
+ * grope_mapping - feel up a mapping that needs to be written
+ * @buf: the start of the memory to be written
+ * @size: the size of the memory to be written
+ *
+ * We do this after acquiring the locks on the mapping,
+ * but before starting the write transaction.  We need to make
+ * sure that we don't cause recursive transactions if blocks
+ * need to be allocated to the file backing the mapping.
+ *
+ * Returns: errno
+ */
+
+static int
+grope_mapping(char *buf, size_t size)
+{
+	unsigned long start = (unsigned long)buf;
+	unsigned long stop = start + size;
+	char c;
+
+	while (start < stop) {
+		if (copy_from_user(&c, (char *)start, 1))
+			return -EFAULT;
+
+		start += PAGE_CACHE_SIZE;
+		start &= PAGE_CACHE_MASK;
+	}
+
+	return 0;
+}
+
+/**
  * walk_vm - Walk the vmas associated with a buffer for read or write.
  *    If any of them are gfs, pass the gfs inode down to the read/write
  *    worker function so that locks can be acquired in the correct order.
@@ -211,8 +242,11 @@ walk_vm(struct file *file, char *buf, size_t size, loff_t *offset,
 	struct kiocb *iocb,	
 	do_rw_t operation)
 {
+	int needs_groping = 0;
+
 	if (current->mm) {
 		struct super_block *sb = file->f_dentry->d_inode->i_sb;
+		struct file_system_type *type = file->f_dentry->d_inode->i_sb->s_type;
 		struct mm_struct *mm = current->mm;
 		struct vm_area_struct *vma;
 		unsigned long start = (unsigned long)buf;
@@ -228,6 +262,9 @@ walk_vm(struct file *file, char *buf, size_t size, loff_t *offset,
 			if (vma->vm_file &&
 			    vma->vm_file->f_dentry->d_inode->i_sb == sb)
 				goto do_locks;
+			else if (vma->vm_file &&
+				 vma->vm_file->f_dentry->d_inode->i_sb->s_type == type)
+				needs_groping = 1;
 		}
 
 		if (!dumping)
@@ -236,6 +273,8 @@ walk_vm(struct file *file, char *buf, size_t size, loff_t *offset,
 
 	{
 		struct gfs_holder gh;
+		if (needs_groping)
+			grope_mapping(buf, size);
 		return operation(file, buf, size, offset, iocb, 0, &gh);
 	}
 
@@ -284,37 +323,6 @@ do_read_readi(struct file *file, char *buf, size_t size, loff_t *offset,
 }
 
 /**
- * grope_mapping - feel up a mapping that needs to be written
- * @buf: the start of the memory to be written
- * @size: the size of the memory to be written
- *
- * We do this after acquiring the locks on the mapping,
- * but before starting the write transaction.  We need to make
- * sure that we don't cause recursive transactions if blocks
- * need to be allocated to the file backing the mapping.
- *
- * Returns: errno
- */
-
-static int
-grope_mapping(char *buf, size_t size)
-{
-	unsigned long start = (unsigned long)buf;
-	unsigned long stop = start + size;
-	char c;
-
-	while (start < stop) {
-		if (copy_from_user(&c, (char *)start, 1))
-			return -EFAULT;
-
-		start += PAGE_CACHE_SIZE;
-		start &= PAGE_CACHE_MASK;
-	}
-
-	return 0;
-}
-
-/**
  * do_read_direct - Read bytes from a file
  * @file: The file to read from
  * @buf: The buffer to copy into