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>
This commit is contained in:
		
							parent
							
								
									918377b696
								
							
						
					
					
						commit
						0e4f6a791b
					
				| @ -38,19 +38,23 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp) | |||||||
| 
 | 
 | ||||||
| 	BUG_ON(!S_ISREG(inode->i_mode)); | 	BUG_ON(!S_ISREG(inode->i_mode)); | ||||||
| 
 | 
 | ||||||
| 	/* fast out for when nothing needs to be done */ |         if (atomic_add_unless(&REISERFS_I(inode)->openers, -1, 1)) | ||||||
| 	if ((atomic_read(&inode->i_count) > 1 || | 		return 0; | ||||||
| 	     !(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) || | 
 | ||||||
| 	     !tail_has_to_be_packed(inode)) && | 	mutex_lock(&(REISERFS_I(inode)->tailpack)); | ||||||
| 	    REISERFS_I(inode)->i_prealloc_count <= 0) { | 
 | ||||||
|  |         if (!atomic_dec_and_test(&REISERFS_I(inode)->openers)) { | ||||||
|  | 		mutex_unlock(&(REISERFS_I(inode)->tailpack)); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&inode->i_mutex); | 	/* fast out for when nothing needs to be done */ | ||||||
| 
 | 	if ((!(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) || | ||||||
| 	mutex_lock(&(REISERFS_I(inode)->i_mmap)); | 	     !tail_has_to_be_packed(inode)) && | ||||||
| 	if (REISERFS_I(inode)->i_flags & i_ever_mapped) | 	    REISERFS_I(inode)->i_prealloc_count <= 0) { | ||||||
| 		REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; | 		mutex_unlock(&(REISERFS_I(inode)->tailpack)); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	reiserfs_write_lock(inode->i_sb); | 	reiserfs_write_lock(inode->i_sb); | ||||||
| 	/* freeing preallocation only involves relogging blocks that
 | 	/* freeing preallocation only involves relogging blocks that
 | ||||||
| @ -94,9 +98,10 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp) | |||||||
| 	if (!err) | 	if (!err) | ||||||
| 		err = jbegin_failure; | 		err = jbegin_failure; | ||||||
| 
 | 
 | ||||||
| 	if (!err && atomic_read(&inode->i_count) <= 1 && | 	if (!err && | ||||||
| 	    (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) && | 	    (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) && | ||||||
| 	    tail_has_to_be_packed(inode)) { | 	    tail_has_to_be_packed(inode)) { | ||||||
|  | 
 | ||||||
| 		/* if regular file is released by last holder and it has been
 | 		/* if regular file is released by last holder and it has been
 | ||||||
| 		   appended (we append by unformatted node only) or its direct | 		   appended (we append by unformatted node only) or its direct | ||||||
| 		   item(s) had to be converted, then it may have to be | 		   item(s) had to be converted, then it may have to be | ||||||
| @ -104,27 +109,28 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp) | |||||||
| 		err = reiserfs_truncate_file(inode, 0); | 		err = reiserfs_truncate_file(inode, 0); | ||||||
| 	} | 	} | ||||||
|       out: |       out: | ||||||
| 	mutex_unlock(&(REISERFS_I(inode)->i_mmap)); |  | ||||||
| 	mutex_unlock(&inode->i_mutex); |  | ||||||
| 	reiserfs_write_unlock(inode->i_sb); | 	reiserfs_write_unlock(inode->i_sb); | ||||||
|  | 	mutex_unlock(&(REISERFS_I(inode)->tailpack)); | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int reiserfs_file_mmap(struct file *file, struct vm_area_struct *vma) | static int reiserfs_file_open(struct inode *inode, struct file *file) | ||||||
| { | { | ||||||
| 	struct inode *inode; | 	int err = dquot_file_open(inode, file); | ||||||
| 
 |         if (!atomic_inc_not_zero(&REISERFS_I(inode)->openers)) { | ||||||
| 	inode = file->f_path.dentry->d_inode; | 		/* somebody might be tailpacking on final close; wait for it */ | ||||||
| 	mutex_lock(&(REISERFS_I(inode)->i_mmap)); | 		mutex_lock(&(REISERFS_I(inode)->tailpack)); | ||||||
| 	REISERFS_I(inode)->i_flags |= i_ever_mapped; | 		atomic_inc(&REISERFS_I(inode)->openers); | ||||||
| 	mutex_unlock(&(REISERFS_I(inode)->i_mmap)); | 		mutex_unlock(&(REISERFS_I(inode)->tailpack)); | ||||||
| 
 | 	} | ||||||
| 	return generic_file_mmap(file, vma); | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void reiserfs_vfs_truncate_file(struct inode *inode) | static void reiserfs_vfs_truncate_file(struct inode *inode) | ||||||
| { | { | ||||||
|  | 	mutex_lock(&(REISERFS_I(inode)->tailpack)); | ||||||
| 	reiserfs_truncate_file(inode, 1); | 	reiserfs_truncate_file(inode, 1); | ||||||
|  | 	mutex_unlock(&(REISERFS_I(inode)->tailpack)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Sync a reiserfs file. */ | /* Sync a reiserfs file. */ | ||||||
| @ -288,8 +294,8 @@ const struct file_operations reiserfs_file_operations = { | |||||||
| #ifdef CONFIG_COMPAT | #ifdef CONFIG_COMPAT | ||||||
| 	.compat_ioctl = reiserfs_compat_ioctl, | 	.compat_ioctl = reiserfs_compat_ioctl, | ||||||
| #endif | #endif | ||||||
| 	.mmap = reiserfs_file_mmap, | 	.mmap = generic_file_mmap, | ||||||
| 	.open = dquot_file_open, | 	.open = reiserfs_file_open, | ||||||
| 	.release = reiserfs_file_release, | 	.release = reiserfs_file_release, | ||||||
| 	.fsync = reiserfs_sync_file, | 	.fsync = reiserfs_sync_file, | ||||||
| 	.aio_read = generic_file_aio_read, | 	.aio_read = generic_file_aio_read, | ||||||
|  | |||||||
| @ -1138,7 +1138,6 @@ static void init_inode(struct inode *inode, struct treepath *path) | |||||||
| 	REISERFS_I(inode)->i_prealloc_count = 0; | 	REISERFS_I(inode)->i_prealloc_count = 0; | ||||||
| 	REISERFS_I(inode)->i_trans_id = 0; | 	REISERFS_I(inode)->i_trans_id = 0; | ||||||
| 	REISERFS_I(inode)->i_jl = NULL; | 	REISERFS_I(inode)->i_jl = NULL; | ||||||
| 	mutex_init(&(REISERFS_I(inode)->i_mmap)); |  | ||||||
| 	reiserfs_init_xattr_rwsem(inode); | 	reiserfs_init_xattr_rwsem(inode); | ||||||
| 
 | 
 | ||||||
| 	if (stat_data_v1(ih)) { | 	if (stat_data_v1(ih)) { | ||||||
| @ -1841,7 +1840,6 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, | |||||||
| 	REISERFS_I(inode)->i_attrs = | 	REISERFS_I(inode)->i_attrs = | ||||||
| 	    REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; | 	    REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; | ||||||
| 	sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); | 	sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); | ||||||
| 	mutex_init(&(REISERFS_I(inode)->i_mmap)); |  | ||||||
| 	reiserfs_init_xattr_rwsem(inode); | 	reiserfs_init_xattr_rwsem(inode); | ||||||
| 
 | 
 | ||||||
| 	/* key to search for correct place for new stat data */ | 	/* key to search for correct place for new stat data */ | ||||||
|  | |||||||
| @ -525,6 +525,8 @@ static struct inode *reiserfs_alloc_inode(struct super_block *sb) | |||||||
| 	    kmem_cache_alloc(reiserfs_inode_cachep, GFP_KERNEL); | 	    kmem_cache_alloc(reiserfs_inode_cachep, GFP_KERNEL); | ||||||
| 	if (!ei) | 	if (!ei) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | 	atomic_set(&ei->openers, 0); | ||||||
|  | 	mutex_init(&ei->tailpack); | ||||||
| 	return &ei->vfs_inode; | 	return &ei->vfs_inode; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -25,7 +25,6 @@ typedef enum { | |||||||
| 	i_link_saved_truncate_mask = 0x0020, | 	i_link_saved_truncate_mask = 0x0020, | ||||||
| 	i_has_xattr_dir = 0x0040, | 	i_has_xattr_dir = 0x0040, | ||||||
| 	i_data_log = 0x0080, | 	i_data_log = 0x0080, | ||||||
| 	i_ever_mapped = 0x0100 |  | ||||||
| } reiserfs_inode_flags; | } reiserfs_inode_flags; | ||||||
| 
 | 
 | ||||||
| struct reiserfs_inode_info { | struct reiserfs_inode_info { | ||||||
| @ -53,7 +52,8 @@ struct reiserfs_inode_info { | |||||||
| 	 ** flushed */ | 	 ** flushed */ | ||||||
| 	unsigned int i_trans_id; | 	unsigned int i_trans_id; | ||||||
| 	struct reiserfs_journal_list *i_jl; | 	struct reiserfs_journal_list *i_jl; | ||||||
| 	struct mutex i_mmap; | 	atomic_t openers; | ||||||
|  | 	struct mutex tailpack; | ||||||
| #ifdef CONFIG_REISERFS_FS_XATTR | #ifdef CONFIG_REISERFS_FS_XATTR | ||||||
| 	struct rw_semaphore i_xattr_sem; | 	struct rw_semaphore i_xattr_sem; | ||||||
| #endif | #endif | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user