reiserfs: avoid tail packing if an inode was ever mmapped
authorVladimir Saveliev <vs@namesys.com>
Sat, 3 Feb 2007 01:38:47 +0000 (02:38 +0100)
committerAdrian Bunk <bunk@stusta.de>
Sat, 3 Feb 2007 01:38:47 +0000 (02:38 +0100)
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 <vs@namesys.com>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
fs/reiserfs/file.c
fs/reiserfs/inode.c
include/linux/reiserfs_fs_i.h

index be12879bb179ac881134a1c7ed9dc0d577d7b061..fdd96365218b06f267d646c6bc66a0b44ff82e3f 100644 (file)
@@ -50,6 +50,11 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp)
 
        reiserfs_write_lock(inode->i_sb);
        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;
        /* freeing preallocation only involves relogging blocks that
         * are already in the current transaction.  preallocation gets
         * freed at the end of each transaction, so it is impossible for
@@ -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_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);
@@ -1570,7 +1588,7 @@ struct file_operations reiserfs_file_operations = {
        .read = generic_file_read,
        .write = reiserfs_file_write,
        .ioctl = reiserfs_ioctl,
-       .mmap = generic_file_mmap,
+       .mmap = reiserfs_file_mmap,
        .release = reiserfs_file_release,
        .fsync = reiserfs_sync_file,
        .sendfile = generic_file_sendfile,
index d60f6238c66a48184fa7c35ec749ba8e6f110456..4cb01689aecf44dd61bcbb7a8954dd5ae8f052f8 100644 (file)
@@ -1140,6 +1140,7 @@ static void init_inode(struct inode *inode, struct path *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_I(inode)->i_acl_access = NULL;
        REISERFS_I(inode)->i_acl_default = NULL;
        init_rwsem(&REISERFS_I(inode)->xattr_sem);
@@ -1847,6 +1848,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_I(inode)->i_acl_access = NULL;
        REISERFS_I(inode)->i_acl_default = NULL;
        init_rwsem(&REISERFS_I(inode)->xattr_sem);
index 149be8d9a0c9fe200f59ff809e8005b3ecca3ebc..547bbf3a119015511c4f2c98e62cee43f233731f 100644 (file)
@@ -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;
 
        struct posix_acl *i_acl_access;
        struct posix_acl *i_acl_default;