aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@ZenIV.linux.org.uk>2011-03-04 12:14:37 -0500
committerroot <Chris Mason chris.mason@oracle.com>2011-03-28 05:37:55 -0400
commit92986796d84ef939e304099dece32572a755b280 (patch)
treed3356c2aa2bbc64166b09647c8760f7a6941df44 /fs
parentc2db1073fdf9757e6fd8b4a59d15b6ecc7a2af8a (diff)
btrfs: don't mess with i_nlink of unlocked inode in rename()
old_inode is not locked; it's not safe to play with its link count. Instead of bumping it and calling btrfs_unlink_inode(), add a variant of the latter that does not do btrfs_drop_nlink()/ btrfs_update_inode(), call it instead of btrfs_inc_nlink()/ btrfs_unlink_inode() and do btrfs_update_inode() ourselves. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/inode.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 04e9fffee8c..4822b313278 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2664,10 +2664,10 @@ failed:
2664 * recovery code. It remove a link in a directory with a given name, and 2664 * recovery code. It remove a link in a directory with a given name, and
2665 * also drops the back refs in the inode to the directory 2665 * also drops the back refs in the inode to the directory
2666 */ 2666 */
2667int btrfs_unlink_inode(struct btrfs_trans_handle *trans, 2667static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
2668 struct btrfs_root *root, 2668 struct btrfs_root *root,
2669 struct inode *dir, struct inode *inode, 2669 struct inode *dir, struct inode *inode,
2670 const char *name, int name_len) 2670 const char *name, int name_len)
2671{ 2671{
2672 struct btrfs_path *path; 2672 struct btrfs_path *path;
2673 int ret = 0; 2673 int ret = 0;
@@ -2739,12 +2739,25 @@ err:
2739 btrfs_i_size_write(dir, dir->i_size - name_len * 2); 2739 btrfs_i_size_write(dir, dir->i_size - name_len * 2);
2740 inode->i_ctime = dir->i_mtime = dir->i_ctime = CURRENT_TIME; 2740 inode->i_ctime = dir->i_mtime = dir->i_ctime = CURRENT_TIME;
2741 btrfs_update_inode(trans, root, dir); 2741 btrfs_update_inode(trans, root, dir);
2742 btrfs_drop_nlink(inode);
2743 ret = btrfs_update_inode(trans, root, inode);
2744out: 2742out:
2745 return ret; 2743 return ret;
2746} 2744}
2747 2745
2746int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
2747 struct btrfs_root *root,
2748 struct inode *dir, struct inode *inode,
2749 const char *name, int name_len)
2750{
2751 int ret;
2752 ret = __btrfs_unlink_inode(trans, root, dir, inode, name, name_len);
2753 if (!ret) {
2754 btrfs_drop_nlink(inode);
2755 ret = btrfs_update_inode(trans, root, inode);
2756 }
2757 return ret;
2758}
2759
2760
2748/* helper to check if there is any shared block in the path */ 2761/* helper to check if there is any shared block in the path */
2749static int check_path_shared(struct btrfs_root *root, 2762static int check_path_shared(struct btrfs_root *root,
2750 struct btrfs_path *path) 2763 struct btrfs_path *path)
@@ -6999,11 +7012,12 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
6999 old_dentry->d_name.name, 7012 old_dentry->d_name.name,
7000 old_dentry->d_name.len); 7013 old_dentry->d_name.len);
7001 } else { 7014 } else {
7002 btrfs_inc_nlink(old_dentry->d_inode); 7015 ret = __btrfs_unlink_inode(trans, root, old_dir,
7003 ret = btrfs_unlink_inode(trans, root, old_dir, 7016 old_dentry->d_inode,
7004 old_dentry->d_inode, 7017 old_dentry->d_name.name,
7005 old_dentry->d_name.name, 7018 old_dentry->d_name.len);
7006 old_dentry->d_name.len); 7019 if (!ret)
7020 ret = btrfs_update_inode(trans, root, old_inode);
7007 } 7021 }
7008 BUG_ON(ret); 7022 BUG_ON(ret);
7009 7023