diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/btrfs_inode.h | 3 | ||||
-rw-r--r-- | fs/btrfs/delayed-inode.c | 103 | ||||
-rw-r--r-- | fs/btrfs/delayed-inode.h | 2 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 55 |
4 files changed, 157 insertions, 6 deletions
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index ac0b39db27d1..661b0ac90e8f 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h | |||
@@ -135,6 +135,9 @@ struct btrfs_inode { | |||
135 | */ | 135 | */ |
136 | u64 index_cnt; | 136 | u64 index_cnt; |
137 | 137 | ||
138 | /* Cache the directory index number to speed the dir/file remove */ | ||
139 | u64 dir_index; | ||
140 | |||
138 | /* the fsync log has some corner cases that mean we have to check | 141 | /* the fsync log has some corner cases that mean we have to check |
139 | * directories to see if any unlinks have been done before | 142 | * directories to see if any unlinks have been done before |
140 | * the directory was logged. See tree-log.c for all the | 143 | * the directory was logged. See tree-log.c for all the |
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 222ca8cdc53a..451b00c86f6c 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c | |||
@@ -1015,6 +1015,18 @@ static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node) | |||
1015 | } | 1015 | } |
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | static void btrfs_release_delayed_iref(struct btrfs_delayed_node *delayed_node) | ||
1019 | { | ||
1020 | struct btrfs_delayed_root *delayed_root; | ||
1021 | |||
1022 | ASSERT(delayed_node->root); | ||
1023 | clear_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags); | ||
1024 | delayed_node->count--; | ||
1025 | |||
1026 | delayed_root = delayed_node->root->fs_info->delayed_root; | ||
1027 | finish_one_item(delayed_root); | ||
1028 | } | ||
1029 | |||
1018 | static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, | 1030 | static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, |
1019 | struct btrfs_root *root, | 1031 | struct btrfs_root *root, |
1020 | struct btrfs_path *path, | 1032 | struct btrfs_path *path, |
@@ -1023,13 +1035,19 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, | |||
1023 | struct btrfs_key key; | 1035 | struct btrfs_key key; |
1024 | struct btrfs_inode_item *inode_item; | 1036 | struct btrfs_inode_item *inode_item; |
1025 | struct extent_buffer *leaf; | 1037 | struct extent_buffer *leaf; |
1038 | int mod; | ||
1026 | int ret; | 1039 | int ret; |
1027 | 1040 | ||
1028 | key.objectid = node->inode_id; | 1041 | key.objectid = node->inode_id; |
1029 | btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); | 1042 | btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); |
1030 | key.offset = 0; | 1043 | key.offset = 0; |
1031 | 1044 | ||
1032 | ret = btrfs_lookup_inode(trans, root, path, &key, 1); | 1045 | if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &node->flags)) |
1046 | mod = -1; | ||
1047 | else | ||
1048 | mod = 1; | ||
1049 | |||
1050 | ret = btrfs_lookup_inode(trans, root, path, &key, mod); | ||
1033 | if (ret > 0) { | 1051 | if (ret > 0) { |
1034 | btrfs_release_path(path); | 1052 | btrfs_release_path(path); |
1035 | return -ENOENT; | 1053 | return -ENOENT; |
@@ -1037,19 +1055,58 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, | |||
1037 | return ret; | 1055 | return ret; |
1038 | } | 1056 | } |
1039 | 1057 | ||
1040 | btrfs_unlock_up_safe(path, 1); | ||
1041 | leaf = path->nodes[0]; | 1058 | leaf = path->nodes[0]; |
1042 | inode_item = btrfs_item_ptr(leaf, path->slots[0], | 1059 | inode_item = btrfs_item_ptr(leaf, path->slots[0], |
1043 | struct btrfs_inode_item); | 1060 | struct btrfs_inode_item); |
1044 | write_extent_buffer(leaf, &node->inode_item, (unsigned long)inode_item, | 1061 | write_extent_buffer(leaf, &node->inode_item, (unsigned long)inode_item, |
1045 | sizeof(struct btrfs_inode_item)); | 1062 | sizeof(struct btrfs_inode_item)); |
1046 | btrfs_mark_buffer_dirty(leaf); | 1063 | btrfs_mark_buffer_dirty(leaf); |
1047 | btrfs_release_path(path); | ||
1048 | 1064 | ||
1065 | if (!test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &node->flags)) | ||
1066 | goto no_iref; | ||
1067 | |||
1068 | path->slots[0]++; | ||
1069 | if (path->slots[0] >= btrfs_header_nritems(leaf)) | ||
1070 | goto search; | ||
1071 | again: | ||
1072 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||
1073 | if (key.objectid != node->inode_id) | ||
1074 | goto out; | ||
1075 | |||
1076 | if (key.type != BTRFS_INODE_REF_KEY && | ||
1077 | key.type != BTRFS_INODE_EXTREF_KEY) | ||
1078 | goto out; | ||
1079 | |||
1080 | /* | ||
1081 | * Delayed iref deletion is for the inode who has only one link, | ||
1082 | * so there is only one iref. The case that several irefs are | ||
1083 | * in the same item doesn't exist. | ||
1084 | */ | ||
1085 | btrfs_del_item(trans, root, path); | ||
1086 | out: | ||
1087 | btrfs_release_delayed_iref(node); | ||
1088 | no_iref: | ||
1089 | btrfs_release_path(path); | ||
1090 | err_out: | ||
1049 | btrfs_delayed_inode_release_metadata(root, node); | 1091 | btrfs_delayed_inode_release_metadata(root, node); |
1050 | btrfs_release_delayed_inode(node); | 1092 | btrfs_release_delayed_inode(node); |
1051 | 1093 | ||
1052 | return 0; | 1094 | return ret; |
1095 | |||
1096 | search: | ||
1097 | btrfs_release_path(path); | ||
1098 | |||
1099 | btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY); | ||
1100 | key.offset = -1; | ||
1101 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | ||
1102 | if (ret < 0) | ||
1103 | goto err_out; | ||
1104 | ASSERT(ret); | ||
1105 | |||
1106 | ret = 0; | ||
1107 | leaf = path->nodes[0]; | ||
1108 | path->slots[0]--; | ||
1109 | goto again; | ||
1053 | } | 1110 | } |
1054 | 1111 | ||
1055 | static inline int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, | 1112 | static inline int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, |
@@ -1793,6 +1850,41 @@ release_node: | |||
1793 | return ret; | 1850 | return ret; |
1794 | } | 1851 | } |
1795 | 1852 | ||
1853 | int btrfs_delayed_delete_inode_ref(struct inode *inode) | ||
1854 | { | ||
1855 | struct btrfs_delayed_node *delayed_node; | ||
1856 | |||
1857 | delayed_node = btrfs_get_or_create_delayed_node(inode); | ||
1858 | if (IS_ERR(delayed_node)) | ||
1859 | return PTR_ERR(delayed_node); | ||
1860 | |||
1861 | /* | ||
1862 | * We don't reserve space for inode ref deletion is because: | ||
1863 | * - We ONLY do async inode ref deletion for the inode who has only | ||
1864 | * one link(i_nlink == 1), it means there is only one inode ref. | ||
1865 | * And in most case, the inode ref and the inode item are in the | ||
1866 | * same leaf, and we will deal with them at the same time. | ||
1867 | * Since we are sure we will reserve the space for the inode item, | ||
1868 | * it is unnecessary to reserve space for inode ref deletion. | ||
1869 | * - If the inode ref and the inode item are not in the same leaf, | ||
1870 | * We also needn't worry about enospc problem, because we reserve | ||
1871 | * much more space for the inode update than it needs. | ||
1872 | * - At the worst, we can steal some space from the global reservation. | ||
1873 | * It is very rare. | ||
1874 | */ | ||
1875 | mutex_lock(&delayed_node->mutex); | ||
1876 | if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags)) | ||
1877 | goto release_node; | ||
1878 | |||
1879 | set_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags); | ||
1880 | delayed_node->count++; | ||
1881 | atomic_inc(&BTRFS_I(inode)->root->fs_info->delayed_root->items); | ||
1882 | release_node: | ||
1883 | mutex_unlock(&delayed_node->mutex); | ||
1884 | btrfs_release_delayed_node(delayed_node); | ||
1885 | return 0; | ||
1886 | } | ||
1887 | |||
1796 | static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node) | 1888 | static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node) |
1797 | { | 1889 | { |
1798 | struct btrfs_root *root = delayed_node->root; | 1890 | struct btrfs_root *root = delayed_node->root; |
@@ -1815,6 +1907,9 @@ static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node) | |||
1815 | btrfs_release_delayed_item(prev_item); | 1907 | btrfs_release_delayed_item(prev_item); |
1816 | } | 1908 | } |
1817 | 1909 | ||
1910 | if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags)) | ||
1911 | btrfs_release_delayed_iref(delayed_node); | ||
1912 | |||
1818 | if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) { | 1913 | if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) { |
1819 | btrfs_delayed_inode_release_metadata(root, delayed_node); | 1914 | btrfs_delayed_inode_release_metadata(root, delayed_node); |
1820 | btrfs_release_delayed_inode(delayed_node); | 1915 | btrfs_release_delayed_inode(delayed_node); |
diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h index a6a13f7e014d..f70119f25421 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h | |||
@@ -50,6 +50,7 @@ struct btrfs_delayed_root { | |||
50 | 50 | ||
51 | #define BTRFS_DELAYED_NODE_IN_LIST 0 | 51 | #define BTRFS_DELAYED_NODE_IN_LIST 0 |
52 | #define BTRFS_DELAYED_NODE_INODE_DIRTY 1 | 52 | #define BTRFS_DELAYED_NODE_INODE_DIRTY 1 |
53 | #define BTRFS_DELAYED_NODE_DEL_IREF 2 | ||
53 | 54 | ||
54 | struct btrfs_delayed_node { | 55 | struct btrfs_delayed_node { |
55 | u64 inode_id; | 56 | u64 inode_id; |
@@ -127,6 +128,7 @@ int btrfs_commit_inode_delayed_inode(struct inode *inode); | |||
127 | int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans, | 128 | int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans, |
128 | struct btrfs_root *root, struct inode *inode); | 129 | struct btrfs_root *root, struct inode *inode); |
129 | int btrfs_fill_inode(struct inode *inode, u32 *rdev); | 130 | int btrfs_fill_inode(struct inode *inode, u32 *rdev); |
131 | int btrfs_delayed_delete_inode_ref(struct inode *inode); | ||
130 | 132 | ||
131 | /* Used for drop dead root */ | 133 | /* Used for drop dead root */ |
132 | void btrfs_kill_all_delayed_nodes(struct btrfs_root *root); | 134 | void btrfs_kill_all_delayed_nodes(struct btrfs_root *root); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 06bcf5b53cb0..9eaa1c8ed385 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -3309,6 +3309,7 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
3309 | struct btrfs_timespec *tspec; | 3309 | struct btrfs_timespec *tspec; |
3310 | struct btrfs_root *root = BTRFS_I(inode)->root; | 3310 | struct btrfs_root *root = BTRFS_I(inode)->root; |
3311 | struct btrfs_key location; | 3311 | struct btrfs_key location; |
3312 | unsigned long ptr; | ||
3312 | int maybe_acls; | 3313 | int maybe_acls; |
3313 | u32 rdev; | 3314 | u32 rdev; |
3314 | int ret; | 3315 | int ret; |
@@ -3332,7 +3333,7 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
3332 | leaf = path->nodes[0]; | 3333 | leaf = path->nodes[0]; |
3333 | 3334 | ||
3334 | if (filled) | 3335 | if (filled) |
3335 | goto cache_acl; | 3336 | goto cache_index; |
3336 | 3337 | ||
3337 | inode_item = btrfs_item_ptr(leaf, path->slots[0], | 3338 | inode_item = btrfs_item_ptr(leaf, path->slots[0], |
3338 | struct btrfs_inode_item); | 3339 | struct btrfs_inode_item); |
@@ -3375,6 +3376,30 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
3375 | 3376 | ||
3376 | BTRFS_I(inode)->index_cnt = (u64)-1; | 3377 | BTRFS_I(inode)->index_cnt = (u64)-1; |
3377 | BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item); | 3378 | BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item); |
3379 | |||
3380 | cache_index: | ||
3381 | path->slots[0]++; | ||
3382 | if (inode->i_nlink != 1 || | ||
3383 | path->slots[0] >= btrfs_header_nritems(leaf)) | ||
3384 | goto cache_acl; | ||
3385 | |||
3386 | btrfs_item_key_to_cpu(leaf, &location, path->slots[0]); | ||
3387 | if (location.objectid != btrfs_ino(inode)) | ||
3388 | goto cache_acl; | ||
3389 | |||
3390 | ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); | ||
3391 | if (location.type == BTRFS_INODE_REF_KEY) { | ||
3392 | struct btrfs_inode_ref *ref; | ||
3393 | |||
3394 | ref = (struct btrfs_inode_ref *)ptr; | ||
3395 | BTRFS_I(inode)->dir_index = btrfs_inode_ref_index(leaf, ref); | ||
3396 | } else if (location.type == BTRFS_INODE_EXTREF_KEY) { | ||
3397 | struct btrfs_inode_extref *extref; | ||
3398 | |||
3399 | extref = (struct btrfs_inode_extref *)ptr; | ||
3400 | BTRFS_I(inode)->dir_index = btrfs_inode_extref_index(leaf, | ||
3401 | extref); | ||
3402 | } | ||
3378 | cache_acl: | 3403 | cache_acl: |
3379 | /* | 3404 | /* |
3380 | * try to precache a NULL acl entry for files that don't have | 3405 | * try to precache a NULL acl entry for files that don't have |
@@ -3587,6 +3612,24 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, | |||
3587 | goto err; | 3612 | goto err; |
3588 | btrfs_release_path(path); | 3613 | btrfs_release_path(path); |
3589 | 3614 | ||
3615 | /* | ||
3616 | * If we don't have dir index, we have to get it by looking up | ||
3617 | * the inode ref, since we get the inode ref, remove it directly, | ||
3618 | * it is unnecessary to do delayed deletion. | ||
3619 | * | ||
3620 | * But if we have dir index, needn't search inode ref to get it. | ||
3621 | * Since the inode ref is close to the inode item, it is better | ||
3622 | * that we delay to delete it, and just do this deletion when | ||
3623 | * we update the inode item. | ||
3624 | */ | ||
3625 | if (BTRFS_I(inode)->dir_index) { | ||
3626 | ret = btrfs_delayed_delete_inode_ref(inode); | ||
3627 | if (!ret) { | ||
3628 | index = BTRFS_I(inode)->dir_index; | ||
3629 | goto skip_backref; | ||
3630 | } | ||
3631 | } | ||
3632 | |||
3590 | ret = btrfs_del_inode_ref(trans, root, name, name_len, ino, | 3633 | ret = btrfs_del_inode_ref(trans, root, name, name_len, ino, |
3591 | dir_ino, &index); | 3634 | dir_ino, &index); |
3592 | if (ret) { | 3635 | if (ret) { |
@@ -3596,7 +3639,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, | |||
3596 | btrfs_abort_transaction(trans, root, ret); | 3639 | btrfs_abort_transaction(trans, root, ret); |
3597 | goto err; | 3640 | goto err; |
3598 | } | 3641 | } |
3599 | 3642 | skip_backref: | |
3600 | ret = btrfs_delete_delayed_dir_index(trans, root, dir, index); | 3643 | ret = btrfs_delete_delayed_dir_index(trans, root, dir, index); |
3601 | if (ret) { | 3644 | if (ret) { |
3602 | btrfs_abort_transaction(trans, root, ret); | 3645 | btrfs_abort_transaction(trans, root, ret); |
@@ -5465,6 +5508,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
5465 | * number | 5508 | * number |
5466 | */ | 5509 | */ |
5467 | BTRFS_I(inode)->index_cnt = 2; | 5510 | BTRFS_I(inode)->index_cnt = 2; |
5511 | BTRFS_I(inode)->dir_index = *index; | ||
5468 | BTRFS_I(inode)->root = root; | 5512 | BTRFS_I(inode)->root = root; |
5469 | BTRFS_I(inode)->generation = trans->transid; | 5513 | BTRFS_I(inode)->generation = trans->transid; |
5470 | inode->i_generation = BTRFS_I(inode)->generation; | 5514 | inode->i_generation = BTRFS_I(inode)->generation; |
@@ -5809,6 +5853,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, | |||
5809 | goto fail; | 5853 | goto fail; |
5810 | } | 5854 | } |
5811 | 5855 | ||
5856 | /* There are several dir indexes for this inode, clear the cache. */ | ||
5857 | BTRFS_I(inode)->dir_index = 0ULL; | ||
5812 | inc_nlink(inode); | 5858 | inc_nlink(inode); |
5813 | inode_inc_iversion(inode); | 5859 | inode_inc_iversion(inode); |
5814 | inode->i_ctime = CURRENT_TIME; | 5860 | inode->i_ctime = CURRENT_TIME; |
@@ -7861,6 +7907,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) | |||
7861 | ei->flags = 0; | 7907 | ei->flags = 0; |
7862 | ei->csum_bytes = 0; | 7908 | ei->csum_bytes = 0; |
7863 | ei->index_cnt = (u64)-1; | 7909 | ei->index_cnt = (u64)-1; |
7910 | ei->dir_index = 0; | ||
7864 | ei->last_unlink_trans = 0; | 7911 | ei->last_unlink_trans = 0; |
7865 | ei->last_log_commit = 0; | 7912 | ei->last_log_commit = 0; |
7866 | 7913 | ||
@@ -8148,6 +8195,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
8148 | if (ret) | 8195 | if (ret) |
8149 | goto out_fail; | 8196 | goto out_fail; |
8150 | 8197 | ||
8198 | BTRFS_I(old_inode)->dir_index = 0ULL; | ||
8151 | if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) { | 8199 | if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) { |
8152 | /* force full log commit if subvolume involved. */ | 8200 | /* force full log commit if subvolume involved. */ |
8153 | root->fs_info->last_trans_log_full_commit = trans->transid; | 8201 | root->fs_info->last_trans_log_full_commit = trans->transid; |
@@ -8236,6 +8284,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
8236 | goto out_fail; | 8284 | goto out_fail; |
8237 | } | 8285 | } |
8238 | 8286 | ||
8287 | if (old_inode->i_nlink == 1) | ||
8288 | BTRFS_I(old_inode)->dir_index = index; | ||
8289 | |||
8239 | if (old_ino != BTRFS_FIRST_FREE_OBJECTID) { | 8290 | if (old_ino != BTRFS_FIRST_FREE_OBJECTID) { |
8240 | struct dentry *parent = new_dentry->d_parent; | 8291 | struct dentry *parent = new_dentry->d_parent; |
8241 | btrfs_log_new_name(trans, old_inode, old_dir, parent); | 8292 | btrfs_log_new_name(trans, old_inode, old_dir, parent); |