Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Fix reiserfs_file_release()

a) count file openers correctly; i_count use was completely wrong
b) use new mutex for exclusion between final close/open/truncate,
to protect tailpacking logics. i_mutex use was wrong and resulted
in deadlocks.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 0e4f6a79 918377b6

+34 -28
+30 -24
fs/reiserfs/file.c
··· 38 38 39 39 BUG_ON(!S_ISREG(inode->i_mode)); 40 40 41 - /* fast out for when nothing needs to be done */ 42 - if ((atomic_read(&inode->i_count) > 1 || 43 - !(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) || 44 - !tail_has_to_be_packed(inode)) && 45 - REISERFS_I(inode)->i_prealloc_count <= 0) { 41 + if (atomic_add_unless(&REISERFS_I(inode)->openers, -1, 1)) 42 + return 0; 43 + 44 + mutex_lock(&(REISERFS_I(inode)->tailpack)); 45 + 46 + if (!atomic_dec_and_test(&REISERFS_I(inode)->openers)) { 47 + mutex_unlock(&(REISERFS_I(inode)->tailpack)); 46 48 return 0; 47 49 } 48 50 49 - mutex_lock(&inode->i_mutex); 50 - 51 - mutex_lock(&(REISERFS_I(inode)->i_mmap)); 52 - if (REISERFS_I(inode)->i_flags & i_ever_mapped) 53 - REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; 51 + /* fast out for when nothing needs to be done */ 52 + if ((!(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) || 53 + !tail_has_to_be_packed(inode)) && 54 + REISERFS_I(inode)->i_prealloc_count <= 0) { 55 + mutex_unlock(&(REISERFS_I(inode)->tailpack)); 56 + return 0; 57 + } 54 58 55 59 reiserfs_write_lock(inode->i_sb); 56 60 /* freeing preallocation only involves relogging blocks that ··· 98 94 if (!err) 99 95 err = jbegin_failure; 100 96 101 - if (!err && atomic_read(&inode->i_count) <= 1 && 97 + if (!err && 102 98 (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) && 103 99 tail_has_to_be_packed(inode)) { 100 + 104 101 /* if regular file is released by last holder and it has been 105 102 appended (we append by unformatted node only) or its direct 106 103 item(s) had to be converted, then it may have to be ··· 109 104 err = reiserfs_truncate_file(inode, 0); 110 105 } 111 106 out: 112 - mutex_unlock(&(REISERFS_I(inode)->i_mmap)); 113 - mutex_unlock(&inode->i_mutex); 114 107 reiserfs_write_unlock(inode->i_sb); 108 + mutex_unlock(&(REISERFS_I(inode)->tailpack)); 115 109 return err; 116 110 } 117 111 118 - static int reiserfs_file_mmap(struct file *file, struct vm_area_struct *vma) 112 + static int reiserfs_file_open(struct inode *inode, struct file *file) 119 113 { 120 - struct inode *inode; 121 - 122 - inode = file->f_path.dentry->d_inode; 123 - mutex_lock(&(REISERFS_I(inode)->i_mmap)); 124 - REISERFS_I(inode)->i_flags |= i_ever_mapped; 125 - mutex_unlock(&(REISERFS_I(inode)->i_mmap)); 126 - 127 - return generic_file_mmap(file, vma); 114 + int err = dquot_file_open(inode, file); 115 + if (!atomic_inc_not_zero(&REISERFS_I(inode)->openers)) { 116 + /* somebody might be tailpacking on final close; wait for it */ 117 + mutex_lock(&(REISERFS_I(inode)->tailpack)); 118 + atomic_inc(&REISERFS_I(inode)->openers); 119 + mutex_unlock(&(REISERFS_I(inode)->tailpack)); 120 + } 121 + return err; 128 122 } 129 123 130 124 static void reiserfs_vfs_truncate_file(struct inode *inode) 131 125 { 126 + mutex_lock(&(REISERFS_I(inode)->tailpack)); 132 127 reiserfs_truncate_file(inode, 1); 128 + mutex_unlock(&(REISERFS_I(inode)->tailpack)); 133 129 } 134 130 135 131 /* Sync a reiserfs file. */ ··· 294 288 #ifdef CONFIG_COMPAT 295 289 .compat_ioctl = reiserfs_compat_ioctl, 296 290 #endif 297 - .mmap = reiserfs_file_mmap, 298 - .open = dquot_file_open, 291 + .mmap = generic_file_mmap, 292 + .open = reiserfs_file_open, 299 293 .release = reiserfs_file_release, 300 294 .fsync = reiserfs_sync_file, 301 295 .aio_read = generic_file_aio_read,
-2
fs/reiserfs/inode.c
··· 1138 1138 REISERFS_I(inode)->i_prealloc_count = 0; 1139 1139 REISERFS_I(inode)->i_trans_id = 0; 1140 1140 REISERFS_I(inode)->i_jl = NULL; 1141 - mutex_init(&(REISERFS_I(inode)->i_mmap)); 1142 1141 reiserfs_init_xattr_rwsem(inode); 1143 1142 1144 1143 if (stat_data_v1(ih)) { ··· 1840 1841 REISERFS_I(inode)->i_attrs = 1841 1842 REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; 1842 1843 sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); 1843 - mutex_init(&(REISERFS_I(inode)->i_mmap)); 1844 1844 reiserfs_init_xattr_rwsem(inode); 1845 1845 1846 1846 /* key to search for correct place for new stat data */
+2
fs/reiserfs/super.c
··· 525 525 kmem_cache_alloc(reiserfs_inode_cachep, GFP_KERNEL); 526 526 if (!ei) 527 527 return NULL; 528 + atomic_set(&ei->openers, 0); 529 + mutex_init(&ei->tailpack); 528 530 return &ei->vfs_inode; 529 531 } 530 532
+2 -2
include/linux/reiserfs_fs_i.h
··· 25 25 i_link_saved_truncate_mask = 0x0020, 26 26 i_has_xattr_dir = 0x0040, 27 27 i_data_log = 0x0080, 28 - i_ever_mapped = 0x0100 29 28 } reiserfs_inode_flags; 30 29 31 30 struct reiserfs_inode_info { ··· 52 53 ** flushed */ 53 54 unsigned int i_trans_id; 54 55 struct reiserfs_journal_list *i_jl; 55 - struct mutex i_mmap; 56 + atomic_t openers; 57 + struct mutex tailpack; 56 58 #ifdef CONFIG_REISERFS_FS_XATTR 57 59 struct rw_semaphore i_xattr_sem; 58 60 #endif