aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2012-03-08 07:10:23 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2012-03-08 07:10:23 -0500
commit75ca61c101601a7071d93571920be9697b3fda9b (patch)
treeaaf42da2b6086a58d84efd4ef39a312f03cfbefb /fs
parent35e478f42271673f79066a1ed008c6604621c6fe (diff)
GFS2: Remove a __GFP_NOFAIL allocation
In order to ensure that we've got enough buffer heads for flushing the journal, the orignal code used __GFP_NOFAIL when performing this allocation. Here we dispense with that in favour of using a mempool. This should improve efficiency in low memory conditions since flushing the journal is a good way to get memory back, we don't want to be spinning, waiting on memory allocations. The buffers which are allocated via this mempool are fairly short lived, so that we'll recycle them pretty quickly. Although there are other memory allocations which occur during the journal flush process, this is the one which can potentially require the most memory, so the most important one to fix. The amount of memory reserved is a fixed amount, and we should not need to scale it when there are a greater number of filesystems in use. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/lops.c5
-rw-r--r--fs/gfs2/main.c18
-rw-r--r--fs/gfs2/util.c1
-rw-r--r--fs/gfs2/util.h3
4 files changed, 25 insertions, 2 deletions
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index fe369bd9e10c..87e6e0d66bb7 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -12,6 +12,7 @@
12#include <linux/spinlock.h> 12#include <linux/spinlock.h>
13#include <linux/completion.h> 13#include <linux/completion.h>
14#include <linux/buffer_head.h> 14#include <linux/buffer_head.h>
15#include <linux/mempool.h>
15#include <linux/gfs2_ondisk.h> 16#include <linux/gfs2_ondisk.h>
16#include <linux/bio.h> 17#include <linux/bio.h>
17#include <linux/fs.h> 18#include <linux/fs.h>
@@ -199,7 +200,7 @@ static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate)
199 struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd; 200 struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd;
200 201
201 end_buffer_write_sync(bh, uptodate); 202 end_buffer_write_sync(bh, uptodate);
202 free_buffer_head(bh); 203 mempool_free(bh, gfs2_bh_pool);
203 unlock_buffer(real_bh); 204 unlock_buffer(real_bh);
204 brelse(real_bh); 205 brelse(real_bh);
205 if (atomic_dec_and_test(&sdp->sd_log_in_flight)) 206 if (atomic_dec_and_test(&sdp->sd_log_in_flight))
@@ -220,7 +221,7 @@ static struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
220 u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head); 221 u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head);
221 struct buffer_head *bh; 222 struct buffer_head *bh;
222 223
223 bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); 224 bh = mempool_alloc(gfs2_bh_pool, GFP_NOFS);
224 atomic_set(&bh->b_count, 1); 225 atomic_set(&bh->b_count, 1);
225 bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock); 226 bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock);
226 set_bh_page(bh, real->b_page, bh_offset(real)); 227 set_bh_page(bh, real->b_page, bh_offset(real));
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index a8d9bcd0e19c..754426b1e52c 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -17,6 +17,7 @@
17#include <linux/rcupdate.h> 17#include <linux/rcupdate.h>
18#include <linux/rculist_bl.h> 18#include <linux/rculist_bl.h>
19#include <linux/atomic.h> 19#include <linux/atomic.h>
20#include <linux/mempool.h>
20 21
21#include "gfs2.h" 22#include "gfs2.h"
22#include "incore.h" 23#include "incore.h"
@@ -69,6 +70,16 @@ static void gfs2_init_gl_aspace_once(void *foo)
69 address_space_init_once(mapping); 70 address_space_init_once(mapping);
70} 71}
71 72
73static void *gfs2_bh_alloc(gfp_t mask, void *data)
74{
75 return alloc_buffer_head(mask);
76}
77
78static void gfs2_bh_free(void *ptr, void *data)
79{
80 return free_buffer_head(ptr);
81}
82
72/** 83/**
73 * init_gfs2_fs - Register GFS2 as a filesystem 84 * init_gfs2_fs - Register GFS2 as a filesystem
74 * 85 *
@@ -151,6 +162,10 @@ static int __init init_gfs2_fs(void)
151 gfs2_control_wq = alloc_workqueue("gfs2_control", 162 gfs2_control_wq = alloc_workqueue("gfs2_control",
152 WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0); 163 WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0);
153 if (!gfs2_control_wq) 164 if (!gfs2_control_wq)
165 goto fail_recovery;
166
167 gfs2_bh_pool = mempool_create(1024, gfs2_bh_alloc, gfs2_bh_free, NULL);
168 if (!gfs2_bh_pool)
154 goto fail_control; 169 goto fail_control;
155 170
156 gfs2_register_debugfs(); 171 gfs2_register_debugfs();
@@ -160,6 +175,8 @@ static int __init init_gfs2_fs(void)
160 return 0; 175 return 0;
161 176
162fail_control: 177fail_control:
178 destroy_workqueue(gfs2_control_wq);
179fail_recovery:
163 destroy_workqueue(gfs_recovery_wq); 180 destroy_workqueue(gfs_recovery_wq);
164fail_wq: 181fail_wq:
165 unregister_filesystem(&gfs2meta_fs_type); 182 unregister_filesystem(&gfs2meta_fs_type);
@@ -208,6 +225,7 @@ static void __exit exit_gfs2_fs(void)
208 225
209 rcu_barrier(); 226 rcu_barrier();
210 227
228 mempool_destroy(gfs2_bh_pool);
211 kmem_cache_destroy(gfs2_quotad_cachep); 229 kmem_cache_destroy(gfs2_quotad_cachep);
212 kmem_cache_destroy(gfs2_rgrpd_cachep); 230 kmem_cache_destroy(gfs2_rgrpd_cachep);
213 kmem_cache_destroy(gfs2_bufdata_cachep); 231 kmem_cache_destroy(gfs2_bufdata_cachep);
diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c
index 53511291fe36..9e7765e8e7b0 100644
--- a/fs/gfs2/util.c
+++ b/fs/gfs2/util.c
@@ -25,6 +25,7 @@ struct kmem_cache *gfs2_inode_cachep __read_mostly;
25struct kmem_cache *gfs2_bufdata_cachep __read_mostly; 25struct kmem_cache *gfs2_bufdata_cachep __read_mostly;
26struct kmem_cache *gfs2_rgrpd_cachep __read_mostly; 26struct kmem_cache *gfs2_rgrpd_cachep __read_mostly;
27struct kmem_cache *gfs2_quotad_cachep __read_mostly; 27struct kmem_cache *gfs2_quotad_cachep __read_mostly;
28mempool_t *gfs2_bh_pool __read_mostly;
28 29
29void gfs2_assert_i(struct gfs2_sbd *sdp) 30void gfs2_assert_i(struct gfs2_sbd *sdp)
30{ 31{
diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h
index b432e04600de..a4ce76c67dbb 100644
--- a/fs/gfs2/util.h
+++ b/fs/gfs2/util.h
@@ -10,6 +10,8 @@
10#ifndef __UTIL_DOT_H__ 10#ifndef __UTIL_DOT_H__
11#define __UTIL_DOT_H__ 11#define __UTIL_DOT_H__
12 12
13#include <linux/mempool.h>
14
13#include "incore.h" 15#include "incore.h"
14 16
15#define fs_printk(level, fs, fmt, arg...) \ 17#define fs_printk(level, fs, fmt, arg...) \
@@ -150,6 +152,7 @@ extern struct kmem_cache *gfs2_inode_cachep;
150extern struct kmem_cache *gfs2_bufdata_cachep; 152extern struct kmem_cache *gfs2_bufdata_cachep;
151extern struct kmem_cache *gfs2_rgrpd_cachep; 153extern struct kmem_cache *gfs2_rgrpd_cachep;
152extern struct kmem_cache *gfs2_quotad_cachep; 154extern struct kmem_cache *gfs2_quotad_cachep;
155extern mempool_t *gfs2_bh_pool;
153 156
154static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt, 157static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
155 unsigned int *p) 158 unsigned int *p)