diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 71 |
1 files changed, 53 insertions, 18 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 790f4b61a3d7..a4f531047c4a 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -41,6 +41,7 @@ | |||
41 | 41 | ||
42 | static struct extent_io_ops btree_extent_io_ops; | 42 | static struct extent_io_ops btree_extent_io_ops; |
43 | static void end_workqueue_fn(struct btrfs_work *work); | 43 | static void end_workqueue_fn(struct btrfs_work *work); |
44 | static void free_fs_root(struct btrfs_root *root); | ||
44 | 45 | ||
45 | static atomic_t btrfs_bdi_num = ATOMIC_INIT(0); | 46 | static atomic_t btrfs_bdi_num = ATOMIC_INIT(0); |
46 | 47 | ||
@@ -951,14 +952,16 @@ static int find_and_setup_root(struct btrfs_root *tree_root, | |||
951 | root, fs_info, objectid); | 952 | root, fs_info, objectid); |
952 | ret = btrfs_find_last_root(tree_root, objectid, | 953 | ret = btrfs_find_last_root(tree_root, objectid, |
953 | &root->root_item, &root->root_key); | 954 | &root->root_item, &root->root_key); |
955 | if (ret > 0) | ||
956 | return -ENOENT; | ||
954 | BUG_ON(ret); | 957 | BUG_ON(ret); |
955 | 958 | ||
956 | generation = btrfs_root_generation(&root->root_item); | 959 | generation = btrfs_root_generation(&root->root_item); |
957 | blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); | 960 | blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); |
958 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), | 961 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), |
959 | blocksize, generation); | 962 | blocksize, generation); |
960 | root->commit_root = btrfs_root_node(root); | ||
961 | BUG_ON(!root->node); | 963 | BUG_ON(!root->node); |
964 | root->commit_root = btrfs_root_node(root); | ||
962 | return 0; | 965 | return 0; |
963 | } | 966 | } |
964 | 967 | ||
@@ -1176,39 +1179,66 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, | |||
1176 | return fs_info->dev_root; | 1179 | return fs_info->dev_root; |
1177 | if (location->objectid == BTRFS_CSUM_TREE_OBJECTID) | 1180 | if (location->objectid == BTRFS_CSUM_TREE_OBJECTID) |
1178 | return fs_info->csum_root; | 1181 | return fs_info->csum_root; |
1179 | 1182 | again: | |
1183 | spin_lock(&fs_info->fs_roots_radix_lock); | ||
1180 | root = radix_tree_lookup(&fs_info->fs_roots_radix, | 1184 | root = radix_tree_lookup(&fs_info->fs_roots_radix, |
1181 | (unsigned long)location->objectid); | 1185 | (unsigned long)location->objectid); |
1186 | spin_unlock(&fs_info->fs_roots_radix_lock); | ||
1182 | if (root) | 1187 | if (root) |
1183 | return root; | 1188 | return root; |
1184 | 1189 | ||
1190 | ret = btrfs_find_orphan_item(fs_info->tree_root, location->objectid); | ||
1191 | if (ret == 0) | ||
1192 | ret = -ENOENT; | ||
1193 | if (ret < 0) | ||
1194 | return ERR_PTR(ret); | ||
1195 | |||
1185 | root = btrfs_read_fs_root_no_radix(fs_info->tree_root, location); | 1196 | root = btrfs_read_fs_root_no_radix(fs_info->tree_root, location); |
1186 | if (IS_ERR(root)) | 1197 | if (IS_ERR(root)) |
1187 | return root; | 1198 | return root; |
1188 | 1199 | ||
1200 | WARN_ON(btrfs_root_refs(&root->root_item) == 0); | ||
1189 | set_anon_super(&root->anon_super, NULL); | 1201 | set_anon_super(&root->anon_super, NULL); |
1190 | 1202 | ||
1203 | ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM); | ||
1204 | if (ret) | ||
1205 | goto fail; | ||
1206 | |||
1207 | spin_lock(&fs_info->fs_roots_radix_lock); | ||
1191 | ret = radix_tree_insert(&fs_info->fs_roots_radix, | 1208 | ret = radix_tree_insert(&fs_info->fs_roots_radix, |
1192 | (unsigned long)root->root_key.objectid, | 1209 | (unsigned long)root->root_key.objectid, |
1193 | root); | 1210 | root); |
1211 | if (ret == 0) | ||
1212 | root->in_radix = 1; | ||
1213 | spin_unlock(&fs_info->fs_roots_radix_lock); | ||
1214 | radix_tree_preload_end(); | ||
1194 | if (ret) { | 1215 | if (ret) { |
1195 | free_extent_buffer(root->node); | 1216 | if (ret == -EEXIST) { |
1196 | kfree(root); | 1217 | free_fs_root(root); |
1197 | return ERR_PTR(ret); | 1218 | goto again; |
1219 | } | ||
1220 | goto fail; | ||
1198 | } | 1221 | } |
1199 | if (!(fs_info->sb->s_flags & MS_RDONLY)) { | 1222 | |
1200 | ret = btrfs_find_dead_roots(fs_info->tree_root, | 1223 | ret = btrfs_find_dead_roots(fs_info->tree_root, |
1201 | root->root_key.objectid); | 1224 | root->root_key.objectid); |
1202 | BUG_ON(ret); | 1225 | WARN_ON(ret); |
1226 | |||
1227 | if (!(fs_info->sb->s_flags & MS_RDONLY)) | ||
1203 | btrfs_orphan_cleanup(root); | 1228 | btrfs_orphan_cleanup(root); |
1204 | } | 1229 | |
1205 | return root; | 1230 | return root; |
1231 | fail: | ||
1232 | free_fs_root(root); | ||
1233 | return ERR_PTR(ret); | ||
1206 | } | 1234 | } |
1207 | 1235 | ||
1208 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | 1236 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, |
1209 | struct btrfs_key *location, | 1237 | struct btrfs_key *location, |
1210 | const char *name, int namelen) | 1238 | const char *name, int namelen) |
1211 | { | 1239 | { |
1240 | return btrfs_read_fs_root_no_name(fs_info, location); | ||
1241 | #if 0 | ||
1212 | struct btrfs_root *root; | 1242 | struct btrfs_root *root; |
1213 | int ret; | 1243 | int ret; |
1214 | 1244 | ||
@@ -1225,7 +1255,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | |||
1225 | kfree(root); | 1255 | kfree(root); |
1226 | return ERR_PTR(ret); | 1256 | return ERR_PTR(ret); |
1227 | } | 1257 | } |
1228 | #if 0 | 1258 | |
1229 | ret = btrfs_sysfs_add_root(root); | 1259 | ret = btrfs_sysfs_add_root(root); |
1230 | if (ret) { | 1260 | if (ret) { |
1231 | free_extent_buffer(root->node); | 1261 | free_extent_buffer(root->node); |
@@ -1233,9 +1263,9 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | |||
1233 | kfree(root); | 1263 | kfree(root); |
1234 | return ERR_PTR(ret); | 1264 | return ERR_PTR(ret); |
1235 | } | 1265 | } |
1236 | #endif | ||
1237 | root->in_sysfs = 1; | 1266 | root->in_sysfs = 1; |
1238 | return root; | 1267 | return root; |
1268 | #endif | ||
1239 | } | 1269 | } |
1240 | 1270 | ||
1241 | static int btrfs_congested_fn(void *congested_data, int bdi_bits) | 1271 | static int btrfs_congested_fn(void *congested_data, int bdi_bits) |
@@ -2229,20 +2259,25 @@ int write_ctree_super(struct btrfs_trans_handle *trans, | |||
2229 | 2259 | ||
2230 | int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | 2260 | int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) |
2231 | { | 2261 | { |
2232 | WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); | 2262 | spin_lock(&fs_info->fs_roots_radix_lock); |
2233 | radix_tree_delete(&fs_info->fs_roots_radix, | 2263 | radix_tree_delete(&fs_info->fs_roots_radix, |
2234 | (unsigned long)root->root_key.objectid); | 2264 | (unsigned long)root->root_key.objectid); |
2265 | spin_unlock(&fs_info->fs_roots_radix_lock); | ||
2266 | free_fs_root(root); | ||
2267 | return 0; | ||
2268 | } | ||
2269 | |||
2270 | static void free_fs_root(struct btrfs_root *root) | ||
2271 | { | ||
2272 | WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); | ||
2235 | if (root->anon_super.s_dev) { | 2273 | if (root->anon_super.s_dev) { |
2236 | down_write(&root->anon_super.s_umount); | 2274 | down_write(&root->anon_super.s_umount); |
2237 | kill_anon_super(&root->anon_super); | 2275 | kill_anon_super(&root->anon_super); |
2238 | } | 2276 | } |
2239 | if (root->node) | 2277 | free_extent_buffer(root->node); |
2240 | free_extent_buffer(root->node); | 2278 | free_extent_buffer(root->commit_root); |
2241 | if (root->commit_root) | ||
2242 | free_extent_buffer(root->commit_root); | ||
2243 | kfree(root->name); | 2279 | kfree(root->name); |
2244 | kfree(root); | 2280 | kfree(root); |
2245 | return 0; | ||
2246 | } | 2281 | } |
2247 | 2282 | ||
2248 | static int del_fs_roots(struct btrfs_fs_info *fs_info) | 2283 | static int del_fs_roots(struct btrfs_fs_info *fs_info) |