| @@ -20,6 +20,7 @@ · 19 unmodified lines |
| 20 | 20 | #include <linux/writeback.h> |
| 21 | 21 | #include <linux/blkdev.h> |
| 22 | 22 | #include <linux/sort.h> |
| 23 | +#include <linux/rcupdate.h> |
| 23 | 24 | #include "compat.h" |
| 24 | 25 | #include "hash.h" |
| 25 | 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 | 332 | struct list_head *head = &info->space_info; |
| 332 | 333 | struct btrfs_space_info *found; |
| 333 | | − list_for_each_entry(found, head, list) { |
| 334 | | − if (found->flags == flags) |
| 334 | + |
| 335 | + rcu_read_lock(); |
| 336 | + list_for_each_entry_rcu(found, head, list) { |
| 337 | + if (found->flags == flags) { |
| 338 | + rcu_read_unlock(); |
| 335 | 339 | return found; |
| 340 | + } |
| 336 | 341 | } |
| 342 | + rcu_read_unlock(); |
| 337 | 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 | 361 | static u64 div_factor(u64 num, int factor) |
| 341 | 362 | { |
| 342 | 363 | if (factor == 10) |
| @@ -1903,7 +1924,6 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, · 1560 unmodified lines |
| 1903 | 1924 | if (!found) |
| 1904 | 1925 | return -ENOMEM; |
| 1905 | 1926 | |
| 1906 | | − list_add(&found->list, &info->space_info); |
| 1907 | 1927 | INIT_LIST_HEAD(&found->block_groups); |
| 1908 | 1928 | init_rwsem(&found->groups_sem); |
| 1909 | 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 | 1937 | found->full = 0; |
| 1918 | 1938 | found->force_alloc = 0; |
| 1919 | 1939 | *space_info = found; |
| 1940 | + list_add_rcu(&found->list, &info->space_info); |
| 1920 | 1941 | return 0; |
| 1921 | 1942 | } |
| 1922 | 1943 | |
| @@ -6320,6 +6341,7 @@ out: · 4397 unmodified lines |
| 6320 | 6341 | int btrfs_free_block_groups(struct btrfs_fs_info *info) |
| 6321 | 6342 | { |
| 6322 | 6343 | struct btrfs_block_group_cache *block_group; |
| 6344 | + struct btrfs_space_info *space_info; |
| 6323 | 6345 | struct rb_node *n; |
| 6324 | 6346 | |
| 6325 | 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 | 6363 | spin_lock(&info->block_group_cache_lock); |
| 6342 | 6364 | } |
| 6343 | 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 | 6383 | return 0; |
| 6345 | 6384 | } |
| 6346 | 6385 | |