Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 77899
b: refs/heads/master
c: 0e855ac
h: refs/heads/master
i:
  77897: 0600b09
  77895: 459e032
v: v3
  • Loading branch information
Aneesh Kumar K.V authored and Theodore Ts'o committed Jan 29, 2008
1 parent b945547 commit 88f0eaa
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 44 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c278bfecebfb1ed67c326ef472660878baa745cd
refs/heads/master: 0e855ac8b103ef579052936b59fe7c599ac422a4
2 changes: 1 addition & 1 deletion trunk/fs/ext4/balloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ static inline int rsv_is_empty(struct ext4_reserve_window *rsv)
* when setting the reservation window size through ioctl before the file
* is open for write (needs block allocation).
*
* Needs truncate_mutex protection prior to call this function.
* Needs down_write(i_data_sem) protection prior to call this function.
*/
void ext4_init_block_alloc_info(struct inode *inode)
{
Expand Down
13 changes: 7 additions & 6 deletions trunk/fs/ext4/extents.c
Original file line number Diff line number Diff line change
Expand Up @@ -1565,7 +1565,7 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
* This routine returns max. credits that the extent tree can consume.
* It should be OK for low-performance paths like ->writepage()
* To allow many writing processes to fit into a single transaction,
* the caller should calculate credits under truncate_mutex and
* the caller should calculate credits under i_data_sem and
* pass the actual path.
*/
int ext4_ext_calc_credits_for_insert(struct inode *inode,
Expand Down Expand Up @@ -2131,7 +2131,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,

/*
* Need to be called with
* mutex_lock(&EXT4_I(inode)->truncate_mutex);
* down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block
* (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem)
*/
int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
ext4_lblk_t iblock,
Expand Down Expand Up @@ -2350,7 +2351,7 @@ void ext4_ext_truncate(struct inode * inode, struct page *page)
if (page)
ext4_block_truncate_page(handle, page, mapping, inode->i_size);

mutex_lock(&EXT4_I(inode)->truncate_mutex);
down_write(&EXT4_I(inode)->i_data_sem);
ext4_ext_invalidate_cache(inode);

/*
Expand Down Expand Up @@ -2386,7 +2387,7 @@ void ext4_ext_truncate(struct inode * inode, struct page *page)
if (inode->i_nlink)
ext4_orphan_del(handle, inode);

mutex_unlock(&EXT4_I(inode)->truncate_mutex);
up_write(&EXT4_I(inode)->i_data_sem);
ext4_journal_stop(handle);
}

Expand Down Expand Up @@ -2450,7 +2451,7 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
* modify 1 super block, 1 block bitmap and 1 group descriptor.
*/
credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3;
mutex_lock(&EXT4_I(inode)->truncate_mutex)
down_write((&EXT4_I(inode)->i_data_sem));
retry:
while (ret >= 0 && ret < max_blocks) {
block = block + ret;
Expand Down Expand Up @@ -2507,7 +2508,7 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
goto retry;

mutex_unlock(&EXT4_I(inode)->truncate_mutex)
up_write((&EXT4_I(inode)->i_data_sem));
/*
* Time to update the file size.
* Update only when preallocation was requested beyond the file size.
Expand Down
4 changes: 2 additions & 2 deletions trunk/fs/ext4/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ static int ext4_release_file (struct inode * inode, struct file * filp)
if ((filp->f_mode & FMODE_WRITE) &&
(atomic_read(&inode->i_writecount) == 1))
{
mutex_lock(&EXT4_I(inode)->truncate_mutex);
down_write(&EXT4_I(inode)->i_data_sem);
ext4_discard_reservation(inode);
mutex_unlock(&EXT4_I(inode)->truncate_mutex);
up_write(&EXT4_I(inode)->i_data_sem);
}
if (is_dx(inode) && filp->private_data)
ext4_htree_free_dir_info(filp->private_data);
Expand Down
40 changes: 33 additions & 7 deletions trunk/fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ static int ext4_block_to_path(struct inode *inode,
final = ptrs;
} else {
ext4_warning(inode->i_sb, "ext4_block_to_path",
"block %u > max",
"block %lu > max",
i_block + direct_blocks +
indirect_blocks + double_blocks);
}
Expand Down Expand Up @@ -345,7 +345,7 @@ static int ext4_block_to_path(struct inode *inode,
* the whole chain, all way to the data (returns %NULL, *err == 0).
*
* Need to be called with
* mutex_lock(&EXT4_I(inode)->truncate_mutex)
* down_read(&EXT4_I(inode)->i_data_sem)
*/
static Indirect *ext4_get_branch(struct inode *inode, int depth,
ext4_lblk_t *offsets,
Expand Down Expand Up @@ -777,7 +777,8 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
*
*
* Need to be called with
* mutex_lock(&EXT4_I(inode)->truncate_mutex)
* down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block
* (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem)
*/
int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
ext4_lblk_t iblock, unsigned long maxblocks,
Expand Down Expand Up @@ -865,7 +866,7 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
err = ext4_splice_branch(handle, inode, iblock,
partial, indirect_blks, count);
/*
* i_disksize growing is protected by truncate_mutex. Don't forget to
* i_disksize growing is protected by i_data_sem. Don't forget to
* protect it if you're about to implement concurrent
* ext4_get_block() -bzzz
*/
Expand Down Expand Up @@ -895,6 +896,31 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,

#define DIO_CREDITS (EXT4_RESERVE_TRANS_BLOCKS + 32)

int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
unsigned long max_blocks, struct buffer_head *bh,
int create, int extend_disksize)
{
int retval;
if (create) {
down_write((&EXT4_I(inode)->i_data_sem));
} else {
down_read((&EXT4_I(inode)->i_data_sem));
}
if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
retval = ext4_ext_get_blocks(handle, inode, block, max_blocks,
bh, create, extend_disksize);
} else {
retval = ext4_get_blocks_handle(handle, inode, block,
max_blocks, bh, create, extend_disksize);
}
if (create) {
up_write((&EXT4_I(inode)->i_data_sem));
} else {
up_read((&EXT4_I(inode)->i_data_sem));
}
return retval;
}

static int ext4_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
Expand Down Expand Up @@ -1399,7 +1425,7 @@ static int jbd2_journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
* ext4_file_write() -> generic_file_write() -> __alloc_pages() -> ...
*
* Same applies to ext4_get_block(). We will deadlock on various things like
* lock_journal and i_truncate_mutex.
* lock_journal and i_data_sem
*
* Setting PF_MEMALLOC here doesn't work - too many internal memory
* allocations fail.
Expand Down Expand Up @@ -2325,7 +2351,7 @@ void ext4_truncate(struct inode *inode)
* From here we block out all ext4_get_block() callers who want to
* modify the block allocation tree.
*/
mutex_lock(&ei->truncate_mutex);
down_write(&ei->i_data_sem);

if (n == 1) { /* direct blocks */
ext4_free_data(handle, inode, NULL, i_data+offsets[0],
Expand Down Expand Up @@ -2389,7 +2415,7 @@ void ext4_truncate(struct inode *inode)

ext4_discard_reservation(inode);

mutex_unlock(&ei->truncate_mutex);
up_write(&ei->i_data_sem);
inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);

Expand Down
4 changes: 2 additions & 2 deletions trunk/fs/ext4/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,15 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
* need to allocate reservation structure for this inode
* before set the window size
*/
mutex_lock(&ei->truncate_mutex);
down_write(&ei->i_data_sem);
if (!ei->i_block_alloc_info)
ext4_init_block_alloc_info(inode);

if (ei->i_block_alloc_info){
struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
rsv->rsv_goal_size = rsv_window_size;
}
mutex_unlock(&ei->truncate_mutex);
up_write(&ei->i_data_sem);
return 0;
}
case EXT4_IOC_GROUP_EXTEND: {
Expand Down
2 changes: 1 addition & 1 deletion trunk/fs/ext4/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ static void init_once(struct kmem_cache *cachep, void *foo)
#ifdef CONFIG_EXT4DEV_FS_XATTR
init_rwsem(&ei->xattr_sem);
#endif
mutex_init(&ei->truncate_mutex);
init_rwsem(&ei->i_data_sem);
inode_init_once(&ei->vfs_inode);
}

Expand Down
25 changes: 4 additions & 21 deletions trunk/include/linux/ext4_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1107,27 +1107,10 @@ extern void ext4_ext_init(struct super_block *);
extern void ext4_ext_release(struct super_block *);
extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset,
loff_t len);
static inline int
ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
unsigned long max_blocks, struct buffer_head *bh,
int create, int extend_disksize)
{
int retval;
mutex_lock(&EXT4_I(inode)->truncate_mutex);
if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
retval = ext4_ext_get_blocks(handle, inode,
(ext4_lblk_t)block, max_blocks,
bh, create, extend_disksize);
} else {
retval = ext4_get_blocks_handle(handle, inode,
(ext4_lblk_t)block, max_blocks,
bh, create, extend_disksize);
}
mutex_unlock(&EXT4_I(inode)->truncate_mutex);
return retval;
}


extern int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode,
sector_t block, unsigned long max_blocks,
struct buffer_head *bh, int create,
int extend_disksize);
#endif /* __KERNEL__ */

#endif /* _LINUX_EXT4_FS_H */
6 changes: 3 additions & 3 deletions trunk/include/linux/ext4_fs_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,16 @@ struct ext4_inode_info {
__u16 i_extra_isize;

/*
* truncate_mutex is for serialising ext4_truncate() against
* i_data_sem is for serialising ext4_truncate() against
* ext4_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
* ext4 because whenever we perform intermediate commits during
* truncate, the inode and all the metadata blocks *must* be in a
* consistent state which allows truncation of the orphans to restart
* during recovery. Hence we must fix the get_block-vs-truncate race
* by other means, so we have truncate_mutex.
* by other means, so we have i_data_sem.
*/
struct mutex truncate_mutex;
struct rw_semaphore i_data_sem;
struct inode vfs_inode;

unsigned long i_ext_generation;
Expand Down

0 comments on commit 88f0eaa

Please sign in to comment.