Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97461518 authored by Arjan van de Ven's avatar Arjan van de Ven Committed by Linus Torvalds
Browse files

[PATCH] convert ext3's truncate_sem to a mutex



ext3's truncate_sem is always released in the same function it's taken
and it otherwise is a mutex as well..

Signed-off-by: default avatarArjan van de Ven <arjan@infradead.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7bf6d78d
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -37,9 +37,9 @@ static int ext3_release_file (struct inode * inode, struct file * filp)
	if ((filp->f_mode & FMODE_WRITE) &&
	if ((filp->f_mode & FMODE_WRITE) &&
			(atomic_read(&inode->i_writecount) == 1))
			(atomic_read(&inode->i_writecount) == 1))
	{
	{
		down(&EXT3_I(inode)->truncate_sem);
		mutex_lock(&EXT3_I(inode)->truncate_mutex);
		ext3_discard_reservation(inode);
		ext3_discard_reservation(inode);
		up(&EXT3_I(inode)->truncate_sem);
		mutex_unlock(&EXT3_I(inode)->truncate_mutex);
	}
	}
	if (is_dx(inode) && filp->private_data)
	if (is_dx(inode) && filp->private_data)
		ext3_htree_free_dir_info(filp->private_data);
		ext3_htree_free_dir_info(filp->private_data);
+7 −7
Original line number Original line Diff line number Diff line
@@ -702,7 +702,7 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock,
	if (!create || err == -EIO)
	if (!create || err == -EIO)
		goto cleanup;
		goto cleanup;


	down(&ei->truncate_sem);
	mutex_lock(&ei->truncate_mutex);


	/*
	/*
	 * If the indirect block is missing while we are reading
	 * If the indirect block is missing while we are reading
@@ -723,7 +723,7 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock,
		}
		}
		partial = ext3_get_branch(inode, depth, offsets, chain, &err);
		partial = ext3_get_branch(inode, depth, offsets, chain, &err);
		if (!partial) {
		if (!partial) {
			up(&ei->truncate_sem);
			mutex_unlock(&ei->truncate_mutex);
			if (err)
			if (err)
				goto cleanup;
				goto cleanup;
			clear_buffer_new(bh_result);
			clear_buffer_new(bh_result);
@@ -759,13 +759,13 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock,
		err = ext3_splice_branch(handle, inode, iblock, chain,
		err = ext3_splice_branch(handle, inode, iblock, chain,
					 partial, left);
					 partial, left);
	/*
	/*
	 * i_disksize growing is protected by truncate_sem.  Don't forget to
	 * i_disksize growing is protected by truncate_mutex.  Don't forget to
	 * protect it if you're about to implement concurrent
	 * protect it if you're about to implement concurrent
	 * ext3_get_block() -bzzz
	 * ext3_get_block() -bzzz
	*/
	*/
	if (!err && extend_disksize && inode->i_size > ei->i_disksize)
	if (!err && extend_disksize && inode->i_size > ei->i_disksize)
		ei->i_disksize = inode->i_size;
		ei->i_disksize = inode->i_size;
	up(&ei->truncate_sem);
	mutex_unlock(&ei->truncate_mutex);
	if (err)
	if (err)
		goto cleanup;
		goto cleanup;


@@ -1227,7 +1227,7 @@ static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
 *	ext3_file_write() -> generic_file_write() -> __alloc_pages() -> ...
 *	ext3_file_write() -> generic_file_write() -> __alloc_pages() -> ...
 *
 *
 * Same applies to ext3_get_block().  We will deadlock on various things like
 * Same applies to ext3_get_block().  We will deadlock on various things like
 * lock_journal and i_truncate_sem.
 * lock_journal and i_truncate_mutex.
 *
 *
 * Setting PF_MEMALLOC here doesn't work - too many internal memory
 * Setting PF_MEMALLOC here doesn't work - too many internal memory
 * allocations fail.
 * allocations fail.
@@ -2161,7 +2161,7 @@ void ext3_truncate(struct inode * inode)
	 * From here we block out all ext3_get_block() callers who want to
	 * From here we block out all ext3_get_block() callers who want to
	 * modify the block allocation tree.
	 * modify the block allocation tree.
	 */
	 */
	down(&ei->truncate_sem);
	mutex_lock(&ei->truncate_mutex);


	if (n == 1) {		/* direct blocks */
	if (n == 1) {		/* direct blocks */
		ext3_free_data(handle, inode, NULL, i_data+offsets[0],
		ext3_free_data(handle, inode, NULL, i_data+offsets[0],
@@ -2228,7 +2228,7 @@ void ext3_truncate(struct inode * inode)


	ext3_discard_reservation(inode);
	ext3_discard_reservation(inode);


	up(&ei->truncate_sem);
	mutex_unlock(&ei->truncate_mutex);
	inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
	inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
	ext3_mark_inode_dirty(handle, inode);
	ext3_mark_inode_dirty(handle, inode);


+2 −2
Original line number Original line Diff line number Diff line
@@ -182,7 +182,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
		 * need to allocate reservation structure for this inode
		 * need to allocate reservation structure for this inode
		 * before set the window size
		 * before set the window size
		 */
		 */
		down(&ei->truncate_sem);
		mutex_lock(&ei->truncate_mutex);
		if (!ei->i_block_alloc_info)
		if (!ei->i_block_alloc_info)
			ext3_init_block_alloc_info(inode);
			ext3_init_block_alloc_info(inode);


@@ -190,7 +190,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
			struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
			struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
			rsv->rsv_goal_size = rsv_window_size;
			rsv->rsv_goal_size = rsv_window_size;
		}
		}
		up(&ei->truncate_sem);
		mutex_unlock(&ei->truncate_mutex);
		return 0;
		return 0;
	}
	}
	case EXT3_IOC_GROUP_EXTEND: {
	case EXT3_IOC_GROUP_EXTEND: {
+1 −1
Original line number Original line Diff line number Diff line
@@ -472,7 +472,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
#ifdef CONFIG_EXT3_FS_XATTR
#ifdef CONFIG_EXT3_FS_XATTR
		init_rwsem(&ei->xattr_sem);
		init_rwsem(&ei->xattr_sem);
#endif
#endif
		init_MUTEX(&ei->truncate_sem);
		mutex_init(&ei->truncate_mutex);
		inode_init_once(&ei->vfs_inode);
		inode_init_once(&ei->vfs_inode);
	}
	}
}
}
+4 −3
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/rwsem.h>
#include <linux/rwsem.h>
#include <linux/rbtree.h>
#include <linux/rbtree.h>
#include <linux/seqlock.h>
#include <linux/seqlock.h>
#include <linux/mutex.h>


struct ext3_reserve_window {
struct ext3_reserve_window {
	__u32			_rsv_start;	/* First byte reserved */
	__u32			_rsv_start;	/* First byte reserved */
@@ -122,16 +123,16 @@ struct ext3_inode_info {
	__u16 i_extra_isize;
	__u16 i_extra_isize;


	/*
	/*
	 * truncate_sem is for serialising ext3_truncate() against
	 * truncate_mutex is for serialising ext3_truncate() against
	 * ext3_getblock().  In the 2.4 ext2 design, great chunks of inode's
	 * ext3_getblock().  In the 2.4 ext2 design, great chunks of inode's
	 * data tree are chopped off during truncate. We can't do that in
	 * data tree are chopped off during truncate. We can't do that in
	 * ext3 because whenever we perform intermediate commits during
	 * ext3 because whenever we perform intermediate commits during
	 * truncate, the inode and all the metadata blocks *must* be in a
	 * truncate, the inode and all the metadata blocks *must* be in a
	 * consistent state which allows truncation of the orphans to restart
	 * consistent state which allows truncation of the orphans to restart
	 * during recovery.  Hence we must fix the get_block-vs-truncate race
	 * during recovery.  Hence we must fix the get_block-vs-truncate race
	 * by other means, so we have truncate_sem.
	 * by other means, so we have truncate_mutex.
	 */
	 */
	struct semaphore truncate_sem;
	struct mutex truncate_mutex;
	struct inode vfs_inode;
	struct inode vfs_inode;
};
};