diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/btrfs/disk-io.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/raid56.c | 31 |
2 files changed, 26 insertions, 7 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 5031e6dd5938..02369a3c162e 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -2197,7 +2197,7 @@ int open_ctree(struct super_block *sb, | |||
| 2197 | 2197 | ||
| 2198 | ret = btrfs_alloc_stripe_hash_table(fs_info); | 2198 | ret = btrfs_alloc_stripe_hash_table(fs_info); |
| 2199 | if (ret) { | 2199 | if (ret) { |
| 2200 | err = -ENOMEM; | 2200 | err = ret; |
| 2201 | goto fail_alloc; | 2201 | goto fail_alloc; |
| 2202 | } | 2202 | } |
| 2203 | 2203 | ||
diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index e34e568534d9..07222053c7d8 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c | |||
| @@ -188,13 +188,25 @@ int btrfs_alloc_stripe_hash_table(struct btrfs_fs_info *info) | |||
| 188 | struct btrfs_stripe_hash *h; | 188 | struct btrfs_stripe_hash *h; |
| 189 | int num_entries = 1 << BTRFS_STRIPE_HASH_TABLE_BITS; | 189 | int num_entries = 1 << BTRFS_STRIPE_HASH_TABLE_BITS; |
| 190 | int i; | 190 | int i; |
| 191 | int table_size; | ||
| 191 | 192 | ||
| 192 | if (info->stripe_hash_table) | 193 | if (info->stripe_hash_table) |
| 193 | return 0; | 194 | return 0; |
| 194 | 195 | ||
| 195 | table = kzalloc(sizeof(*table) + sizeof(*h) * num_entries, GFP_NOFS); | 196 | /* |
| 196 | if (!table) | 197 | * The table is large, starting with order 4 and can go as high as |
| 197 | return -ENOMEM; | 198 | * order 7 in case lock debugging is turned on. |
| 199 | * | ||
| 200 | * Try harder to allocate and fallback to vmalloc to lower the chance | ||
| 201 | * of a failing mount. | ||
| 202 | */ | ||
| 203 | table_size = sizeof(*table) + sizeof(*h) * num_entries; | ||
| 204 | table = kzalloc(table_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); | ||
| 205 | if (!table) { | ||
| 206 | table = vzalloc(table_size); | ||
| 207 | if (!table) | ||
| 208 | return -ENOMEM; | ||
| 209 | } | ||
| 198 | 210 | ||
| 199 | spin_lock_init(&table->cache_lock); | 211 | spin_lock_init(&table->cache_lock); |
| 200 | INIT_LIST_HEAD(&table->stripe_cache); | 212 | INIT_LIST_HEAD(&table->stripe_cache); |
| @@ -209,8 +221,12 @@ int btrfs_alloc_stripe_hash_table(struct btrfs_fs_info *info) | |||
| 209 | } | 221 | } |
| 210 | 222 | ||
| 211 | x = cmpxchg(&info->stripe_hash_table, NULL, table); | 223 | x = cmpxchg(&info->stripe_hash_table, NULL, table); |
| 212 | if (x) | 224 | if (x) { |
| 213 | kfree(x); | 225 | if (is_vmalloc_addr(x)) |
| 226 | vfree(x); | ||
| 227 | else | ||
| 228 | kfree(x); | ||
| 229 | } | ||
| 214 | return 0; | 230 | return 0; |
| 215 | } | 231 | } |
| 216 | 232 | ||
| @@ -420,7 +436,10 @@ void btrfs_free_stripe_hash_table(struct btrfs_fs_info *info) | |||
| 420 | if (!info->stripe_hash_table) | 436 | if (!info->stripe_hash_table) |
| 421 | return; | 437 | return; |
| 422 | btrfs_clear_rbio_cache(info); | 438 | btrfs_clear_rbio_cache(info); |
| 423 | kfree(info->stripe_hash_table); | 439 | if (is_vmalloc_addr(info->stripe_hash_table)) |
| 440 | vfree(info->stripe_hash_table); | ||
| 441 | else | ||
| 442 | kfree(info->stripe_hash_table); | ||
| 424 | info->stripe_hash_table = NULL; | 443 | info->stripe_hash_table = NULL; |
| 425 | } | 444 | } |
| 426 | 445 | ||
