| @@ -20,6 +20,7 @@ · 19 unmodified lines |
| 20 | #include <linux/writeback.h> | 20 | #include <linux/writeback.h> |
| 21 | #include <linux/blkdev.h> | 21 | #include <linux/blkdev.h> |
| 22 | #include <linux/sort.h> | 22 | #include <linux/sort.h> |
| | 23 | #include <linux/rcupdate.h> |
| 23 | #include "compat.h" | 24 | #include "compat.h" |
| 24 | #include "hash.h" | 25 | #include "hash.h" |
| 25 | #include "crc32c.h" | 26 | #include "crc32c.h" |
| @@ -330,13 +331,33 @@ static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, · 304 unmodified lines |
| 330 | { | 331 | { |
| 331 | struct list_head *head = &info->space_info; | 332 | struct list_head *head = &info->space_info; |
| 332 | struct btrfs_space_info *found; | 333 | struct btrfs_space_info *found; |
| 333 | list_for_each_entry(found, head, list) { | 334 | |
| 334 | if (found->flags == flags) | 335 | rcu_read_lock(); |
| | 336 | list_for_each_entry_rcu(found, head, list) { |
| | 337 | if (found->flags == flags) { |
| | 338 | rcu_read_unlock(); |
| 335 | return found; | 339 | return found; |
| | 340 | } |
| 336 | } | 341 | } |
| | 342 | rcu_read_unlock(); |
| 337 | return NULL; | 343 | return NULL; |
| 338 | } | 344 | } |
| 339 | | 345 | |
| | 346 | /* |
| | 347 | * after adding space to the filesystem, we need to clear the full flags |
| | 348 | * on all the space infos. |
| | 349 | */ |
| | 350 | void btrfs_clear_space_info_full(struct btrfs_fs_info *info) |
| | 351 | { |
| | 352 | struct list_head *head = &info->space_info; |
| | 353 | struct btrfs_space_info *found; |
| | 354 | |
| | 355 | rcu_read_lock(); |
| | 356 | list_for_each_entry_rcu(found, head, list) |
| | 357 | found->full = 0; |
| | 358 | rcu_read_unlock(); |
| | 359 | } |
| | 360 | |
| 340 | static u64 div_factor(u64 num, int factor) | 361 | static u64 div_factor(u64 num, int factor) |
| 341 | { | 362 | { |
| 342 | if (factor == 10) | 363 | if (factor == 10) |
| @@ -1903,7 +1924,6 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, · 1560 unmodified lines |
| 1903 | if (!found) | 1924 | if (!found) |
| 1904 | return -ENOMEM; | 1925 | return -ENOMEM; |
| 1905 | | 1926 | |
| 1906 | list_add(&found->list, &info->space_info); | | |
| 1907 | INIT_LIST_HEAD(&found->block_groups); | 1927 | INIT_LIST_HEAD(&found->block_groups); |
| 1908 | init_rwsem(&found->groups_sem); | 1928 | init_rwsem(&found->groups_sem); |
| 1909 | spin_lock_init(&found->lock); | 1929 | spin_lock_init(&found->lock); |
| @@ -1917,6 +1937,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, · 7 unmodified lines |
| 1917 | found->full = 0; | 1937 | found->full = 0; |
| 1918 | found->force_alloc = 0; | 1938 | found->force_alloc = 0; |
| 1919 | *space_info = found; | 1939 | *space_info = found; |
| | 1940 | list_add_rcu(&found->list, &info->space_info); |
| 1920 | return 0; | 1941 | return 0; |
| 1921 | } | 1942 | } |
| 1922 | | 1943 | |
| @@ -6320,6 +6341,7 @@ out: · 4397 unmodified lines |
| 6320 | int btrfs_free_block_groups(struct btrfs_fs_info *info) | 6341 | int btrfs_free_block_groups(struct btrfs_fs_info *info) |
| 6321 | { | 6342 | { |
| 6322 | struct btrfs_block_group_cache *block_group; | 6343 | struct btrfs_block_group_cache *block_group; |
| | 6344 | struct btrfs_space_info *space_info; |
| 6323 | struct rb_node *n; | 6345 | struct rb_node *n; |
| 6324 | | 6346 | |
| 6325 | spin_lock(&info->block_group_cache_lock); | 6347 | spin_lock(&info->block_group_cache_lock); |
| @@ -6341,6 +6363,23 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) · 15 unmodified lines |
| 6341 | spin_lock(&info->block_group_cache_lock); | 6363 | spin_lock(&info->block_group_cache_lock); |
| 6342 | } | 6364 | } |
| 6343 | spin_unlock(&info->block_group_cache_lock); | 6365 | spin_unlock(&info->block_group_cache_lock); |
| | 6366 | |
| | 6367 | /* now that all the block groups are freed, go through and |
| | 6368 | * free all the space_info structs. This is only called during |
| | 6369 | * the final stages of unmount, and so we know nobody is |
| | 6370 | * using them. We call synchronize_rcu() once before we start, |
| | 6371 | * just to be on the safe side. |
| | 6372 | */ |
| | 6373 | synchronize_rcu(); |
| | 6374 | |
| | 6375 | while(!list_empty(&info->space_info)) { |
| | 6376 | space_info = list_entry(info->space_info.next, |
| | 6377 | struct btrfs_space_info, |
| | 6378 | list); |
| | 6379 | |
| | 6380 | list_del(&space_info->list); |
| | 6381 | kfree(space_info); |
| | 6382 | } |
| 6344 | return 0; | 6383 | return 0; |
| 6345 | } | 6384 | } |
| 6346 | | 6385 | |