aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2
diff options
context:
space:
mode:
authorBob Peterson <rpeterso@redhat.com>2013-05-30 09:48:56 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2013-06-03 11:39:44 -0400
commite8830d8856e3ad61067dd46c05438b0d75a0441a (patch)
tree33756e349db97fffa55aac324135c7aff914f70b /fs/gfs2
parent2b3dcf35810ff02ad0e785527a25c1b13bf82b19 (diff)
GFS2: Fall back to vmalloc if kmalloc fails for dir hash tables
This version has one more correction: the vmalloc calls are replaced by __vmalloc calls to preserve the GFP_NOFS flag. When GFS2's directory management code allocates buffers for a directory hash table, if it can't get the memory it needs, it currently gives a bad return code. Rather than giving an error, this patch allows it to use virtual memory rather than kernel memory for the hash table. This should make it possible for directories to function properly, even when kernel memory becomes very fragmented. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r--fs/gfs2/dir.c43
1 files changed, 33 insertions, 10 deletions
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index c3e82bd23179..b631c9043460 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -354,22 +354,31 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip)
354 return ERR_PTR(-EIO); 354 return ERR_PTR(-EIO);
355 } 355 }
356 356
357 hc = kmalloc(hsize, GFP_NOFS); 357 hc = kmalloc(hsize, GFP_NOFS | __GFP_NOWARN);
358 ret = -ENOMEM; 358 if (hc == NULL)
359 hc = __vmalloc(hsize, GFP_NOFS, PAGE_KERNEL);
360
359 if (hc == NULL) 361 if (hc == NULL)
360 return ERR_PTR(-ENOMEM); 362 return ERR_PTR(-ENOMEM);
361 363
362 ret = gfs2_dir_read_data(ip, hc, hsize); 364 ret = gfs2_dir_read_data(ip, hc, hsize);
363 if (ret < 0) { 365 if (ret < 0) {
364 kfree(hc); 366 if (is_vmalloc_addr(hc))
367 vfree(hc);
368 else
369 kfree(hc);
365 return ERR_PTR(ret); 370 return ERR_PTR(ret);
366 } 371 }
367 372
368 spin_lock(&inode->i_lock); 373 spin_lock(&inode->i_lock);
369 if (ip->i_hash_cache) 374 if (ip->i_hash_cache) {
370 kfree(hc); 375 if (is_vmalloc_addr(hc))
371 else 376 vfree(hc);
377 else
378 kfree(hc);
379 } else {
372 ip->i_hash_cache = hc; 380 ip->i_hash_cache = hc;
381 }
373 spin_unlock(&inode->i_lock); 382 spin_unlock(&inode->i_lock);
374 383
375 return ip->i_hash_cache; 384 return ip->i_hash_cache;
@@ -385,7 +394,10 @@ void gfs2_dir_hash_inval(struct gfs2_inode *ip)
385{ 394{
386 __be64 *hc = ip->i_hash_cache; 395 __be64 *hc = ip->i_hash_cache;
387 ip->i_hash_cache = NULL; 396 ip->i_hash_cache = NULL;
388 kfree(hc); 397 if (is_vmalloc_addr(hc))
398 vfree(hc);
399 else
400 kfree(hc);
389} 401}
390 402
391static inline int gfs2_dirent_sentinel(const struct gfs2_dirent *dent) 403static inline int gfs2_dirent_sentinel(const struct gfs2_dirent *dent)
@@ -1113,7 +1125,10 @@ static int dir_double_exhash(struct gfs2_inode *dip)
1113 if (IS_ERR(hc)) 1125 if (IS_ERR(hc))
1114 return PTR_ERR(hc); 1126 return PTR_ERR(hc);
1115 1127
1116 h = hc2 = kmalloc(hsize_bytes * 2, GFP_NOFS); 1128 h = hc2 = kmalloc(hsize_bytes * 2, GFP_NOFS | __GFP_NOWARN);
1129 if (hc2 == NULL)
1130 hc2 = __vmalloc(hsize_bytes * 2, GFP_NOFS, PAGE_KERNEL);
1131
1117 if (!hc2) 1132 if (!hc2)
1118 return -ENOMEM; 1133 return -ENOMEM;
1119 1134
@@ -1145,7 +1160,10 @@ fail:
1145 gfs2_dinode_out(dip, dibh->b_data); 1160 gfs2_dinode_out(dip, dibh->b_data);
1146 brelse(dibh); 1161 brelse(dibh);
1147out_kfree: 1162out_kfree:
1148 kfree(hc2); 1163 if (is_vmalloc_addr(hc2))
1164 vfree(hc2);
1165 else
1166 kfree(hc2);
1149 return error; 1167 return error;
1150} 1168}
1151 1169
@@ -1846,6 +1864,8 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
1846 memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); 1864 memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
1847 1865
1848 ht = kzalloc(size, GFP_NOFS); 1866 ht = kzalloc(size, GFP_NOFS);
1867 if (ht == NULL)
1868 ht = vzalloc(size);
1849 if (!ht) 1869 if (!ht)
1850 return -ENOMEM; 1870 return -ENOMEM;
1851 1871
@@ -1933,7 +1953,10 @@ out_rlist:
1933 gfs2_rlist_free(&rlist); 1953 gfs2_rlist_free(&rlist);
1934 gfs2_quota_unhold(dip); 1954 gfs2_quota_unhold(dip);
1935out: 1955out:
1936 kfree(ht); 1956 if (is_vmalloc_addr(ht))
1957 vfree(ht);
1958 else
1959 kfree(ht);
1937 return error; 1960 return error;
1938} 1961}
1939 1962