diff options
author | Al Viro <viro@ZenIV.linux.org.uk> | 2011-03-04 12:14:37 -0500 |
---|---|---|
committer | root <Chris Mason chris.mason@oracle.com> | 2011-03-28 05:37:55 -0400 |
commit | 92986796d84ef939e304099dece32572a755b280 (patch) | |
tree | d3356c2aa2bbc64166b09647c8760f7a6941df44 /fs/btrfs/inode.c | |
parent | c2db1073fdf9757e6fd8b4a59d15b6ecc7a2af8a (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/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 36 |
1 files changed, 25 insertions, 11 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 04e9fffee8cc..4822b3132784 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 | */ |
2667 | int btrfs_unlink_inode(struct btrfs_trans_handle *trans, | 2667 | static 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); | ||
2744 | out: | 2742 | out: |
2745 | return ret; | 2743 | return ret; |
2746 | } | 2744 | } |
2747 | 2745 | ||
2746 | int 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 */ |
2749 | static int check_path_shared(struct btrfs_root *root, | 2762 | static 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 | ||