Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=de14569f94513279e3d44d9571a421e9da1759ae
Commit:     de14569f94513279e3d44d9571a421e9da1759ae
Parent:     30150f8d7b76f25b1127a5079528b7a17307f995
Author:     Vladimir Saveliev <[EMAIL PROTECTED]>
AuthorDate: Mon Jan 22 20:40:46 2007 -0800
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Tue Jan 23 07:52:06 2007 -0800

    [PATCH] resierfs: avoid tail packing if an inode was ever mmapped
    
    This patch fixes a confusion reiserfs has for a long time.
    
    On release file operation reiserfs used to try to pack file data stored in
    last incomplete page of some files into metadata blocks.  After packing the
    page got cleared with clear_page_dirty.  It did not take into account that
    the page may be mmaped into other process's address space.  Recent
    replacement for clear_page_dirty cancel_dirty_page found the confusion with
    sanity check that page has to be not mapped.
    
    The patch fixes the confusion by making reiserfs avoid tail packing if an
    inode was ever mmapped.  reiserfs_mmap and reiserfs_file_release are
    serialized with mutex in reiserfs specific inode.  reiserfs_mmap locks the
    mutex and sets a bit in reiserfs specific inode flags.
    reiserfs_file_release checks the bit having the mutex locked.  If bit is
    set - tail packing is avoided.  This eliminates a possibility that mmapped
    page gets cancel_page_dirty-ed.
    
    Signed-off-by: Vladimir Saveliev <[EMAIL PROTECTED]>
    Cc: Jeff Mahoney <[EMAIL PROTECTED]>
    Cc: Chris Mason <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 fs/reiserfs/file.c            |   20 +++++++++++++++++++-
 fs/reiserfs/inode.c           |    2 ++
 include/linux/reiserfs_fs_i.h |    2 ++
 3 files changed, 23 insertions(+), 1 deletions(-)

diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 99b6f32..5109f1d 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -48,6 +48,11 @@ static int reiserfs_file_release(struct inode *inode, struct 
file *filp)
        }
 
        mutex_lock(&inode->i_mutex);
+
+       mutex_lock(&(REISERFS_I(inode)->i_mmap));
+       if (REISERFS_I(inode)->i_flags & i_ever_mapped)
+               REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
+
        reiserfs_write_lock(inode->i_sb);
        /* freeing preallocation only involves relogging blocks that
         * are already in the current transaction.  preallocation gets
@@ -100,11 +105,24 @@ static int reiserfs_file_release(struct inode *inode, 
struct file *filp)
                err = reiserfs_truncate_file(inode, 0);
        }
       out:
+       mutex_unlock(&(REISERFS_I(inode)->i_mmap));
        mutex_unlock(&inode->i_mutex);
        reiserfs_write_unlock(inode->i_sb);
        return err;
 }
 
+static int reiserfs_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct inode *inode;
+
+       inode = file->f_path.dentry->d_inode;
+       mutex_lock(&(REISERFS_I(inode)->i_mmap));
+       REISERFS_I(inode)->i_flags |= i_ever_mapped;
+       mutex_unlock(&(REISERFS_I(inode)->i_mmap));
+
+       return generic_file_mmap(file, vma);
+}
+
 static void reiserfs_vfs_truncate_file(struct inode *inode)
 {
        reiserfs_truncate_file(inode, 1);
@@ -1527,7 +1545,7 @@ const struct file_operations reiserfs_file_operations = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl = reiserfs_compat_ioctl,
 #endif
-       .mmap = generic_file_mmap,
+       .mmap = reiserfs_file_mmap,
        .open = generic_file_open,
        .release = reiserfs_file_release,
        .fsync = reiserfs_sync_file,
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index f3d1c4a..9fcbfe3 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1125,6 +1125,7 @@ static void init_inode(struct inode *inode, struct 
treepath *path)
        REISERFS_I(inode)->i_prealloc_count = 0;
        REISERFS_I(inode)->i_trans_id = 0;
        REISERFS_I(inode)->i_jl = NULL;
+       mutex_init(&(REISERFS_I(inode)->i_mmap));
        reiserfs_init_acl_access(inode);
        reiserfs_init_acl_default(inode);
        reiserfs_init_xattr_rwsem(inode);
@@ -1832,6 +1833,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle 
*th,
        REISERFS_I(inode)->i_attrs =
            REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK;
        sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode);
+       mutex_init(&(REISERFS_I(inode)->i_mmap));
        reiserfs_init_acl_access(inode);
        reiserfs_init_acl_default(inode);
        reiserfs_init_xattr_rwsem(inode);
diff --git a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h
index 5b3b297..ce3663f 100644
--- a/include/linux/reiserfs_fs_i.h
+++ b/include/linux/reiserfs_fs_i.h
@@ -25,6 +25,7 @@ typedef enum {
        i_link_saved_truncate_mask = 0x0020,
        i_has_xattr_dir = 0x0040,
        i_data_log = 0x0080,
+       i_ever_mapped = 0x0100
 } reiserfs_inode_flags;
 
 struct reiserfs_inode_info {
@@ -52,6 +53,7 @@ struct reiserfs_inode_info {
         ** flushed */
        unsigned long i_trans_id;
        struct reiserfs_journal_list *i_jl;
+       struct mutex i_mmap;
 #ifdef CONFIG_REISERFS_FS_POSIX_ACL
        struct posix_acl *i_acl_access;
        struct posix_acl *i_acl_default;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to