Skip to content

Commit

Permalink
vfs: pull ext4's double-i_mutex-locking into common code
Browse files Browse the repository at this point in the history
We want to do this elsewhere as well.

Also catch any attempts to use it for directories (where this ordering
would conflict with ancestor-first directory ordering in lock_rename).

Cc: Andreas Dilger <[email protected]>
Cc: Dave Chinner <[email protected]>
Acked-by: Jeff Layton <[email protected]>
Acked-by: "Theodore Ts'o" <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
J. Bruce Fields authored and Al Viro committed Nov 9, 2013
1 parent f27c929 commit 375e289
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 42 deletions.
2 changes: 0 additions & 2 deletions fs/ext4/ext4.h
Original file line number Diff line number Diff line change
Expand Up @@ -2734,8 +2734,6 @@ extern void ext4_double_down_write_data_sem(struct inode *first,
struct inode *second);
extern void ext4_double_up_write_data_sem(struct inode *orig_inode,
struct inode *donor_inode);
void ext4_inode_double_lock(struct inode *inode1, struct inode *inode2);
void ext4_inode_double_unlock(struct inode *inode1, struct inode *inode2);
extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
__u64 start_orig, __u64 start_donor,
__u64 len, __u64 *moved_len);
Expand Down
4 changes: 2 additions & 2 deletions fs/ext4/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ static long swap_inode_boot_loader(struct super_block *sb,

/* Protect orig inodes against a truncate and make sure,
* that only 1 swap_inode_boot_loader is running. */
ext4_inode_double_lock(inode, inode_bl);
lock_two_nondirectories(inode, inode_bl);

truncate_inode_pages(&inode->i_data, 0);
truncate_inode_pages(&inode_bl->i_data, 0);
Expand Down Expand Up @@ -205,7 +205,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
ext4_inode_resume_unlocked_dio(inode);
ext4_inode_resume_unlocked_dio(inode_bl);

ext4_inode_double_unlock(inode, inode_bl);
unlock_two_nondirectories(inode, inode_bl);

iput(inode_bl);

Expand Down
40 changes: 2 additions & 38 deletions fs/ext4/move_extent.c
Original file line number Diff line number Diff line change
Expand Up @@ -1202,42 +1202,6 @@ mext_check_arguments(struct inode *orig_inode,
return 0;
}

/**
* ext4_inode_double_lock - Lock i_mutex on both @inode1 and @inode2
*
* @inode1: the inode structure
* @inode2: the inode structure
*
* Lock two inodes' i_mutex
*/
void
ext4_inode_double_lock(struct inode *inode1, struct inode *inode2)
{
BUG_ON(inode1 == inode2);
if (inode1 < inode2) {
mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
} else {
mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT);
mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD);
}
}

/**
* ext4_inode_double_unlock - Release i_mutex on both @inode1 and @inode2
*
* @inode1: the inode that is released first
* @inode2: the inode that is released second
*
*/

void
ext4_inode_double_unlock(struct inode *inode1, struct inode *inode2)
{
mutex_unlock(&inode1->i_mutex);
mutex_unlock(&inode2->i_mutex);
}

/**
* ext4_move_extents - Exchange the specified range of a file
*
Expand Down Expand Up @@ -1327,7 +1291,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
return -EINVAL;
}
/* Protect orig and donor inodes against a truncate */
ext4_inode_double_lock(orig_inode, donor_inode);
lock_two_nondirectories(orig_inode, donor_inode);

/* Wait for all existing dio workers */
ext4_inode_block_unlocked_dio(orig_inode);
Expand Down Expand Up @@ -1535,7 +1499,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
ext4_double_up_write_data_sem(orig_inode, donor_inode);
ext4_inode_resume_unlocked_dio(orig_inode);
ext4_inode_resume_unlocked_dio(donor_inode);
ext4_inode_double_unlock(orig_inode, donor_inode);
unlock_two_nondirectories(orig_inode, donor_inode);

return ret;
}
36 changes: 36 additions & 0 deletions fs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,42 @@ void unlock_new_inode(struct inode *inode)
}
EXPORT_SYMBOL(unlock_new_inode);

/**
* lock_two_nondirectories - take two i_mutexes on non-directory objects
* @inode1: first inode to lock
* @inode2: second inode to lock
*/
void lock_two_nondirectories(struct inode *inode1, struct inode *inode2)
{
WARN_ON_ONCE(S_ISDIR(inode1->i_mode));
if (inode1 == inode2 || !inode2) {
mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
return;
}
WARN_ON_ONCE(S_ISDIR(inode2->i_mode));
if (inode1 < inode2) {
mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
} else {
mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT);
mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD);
}
}
EXPORT_SYMBOL(lock_two_nondirectories);

/**
* unlock_two_nondirectories - release locks from lock_two_nondirectories()
* @inode1: first inode to unlock
* @inode2: second inode to unlock
*/
void unlock_two_nondirectories(struct inode *inode1, struct inode *inode2)
{
mutex_unlock(&inode1->i_mutex);
if (inode2 && inode2 != inode1)
mutex_unlock(&inode2->i_mutex);
}
EXPORT_SYMBOL(unlock_two_nondirectories);

/**
* iget5_locked - obtain an inode from a mounted file system
* @sb: super block of file system
Expand Down
3 changes: 3 additions & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,9 @@ enum inode_i_mutex_lock_class
I_MUTEX_QUOTA
};

void lock_two_nondirectories(struct inode *, struct inode*);
void unlock_two_nondirectories(struct inode *, struct inode*);

/*
* NOTE: in a 32bit arch with a preemptable kernel and
* an UP compile the i_size_read/write must be atomic
Expand Down

0 comments on commit 375e289

Please sign in to comment.