diff options
Diffstat (limited to 'fs/btrfs')
-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 | ||