Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+25 -2
+3 -2
fs/gfs2/lops.c
··· 12 12 #include <linux/spinlock.h> 13 13 #include <linux/completion.h> 14 14 #include <linux/buffer_head.h> 15 + #include <linux/mempool.h> 15 16 #include <linux/gfs2_ondisk.h> 16 17 #include <linux/bio.h> 17 18 #include <linux/fs.h> ··· 200 199 struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd; 201 200 202 201 end_buffer_write_sync(bh, uptodate); 203 - free_buffer_head(bh); 202 + mempool_free(bh, gfs2_bh_pool); 204 203 unlock_buffer(real_bh); 205 204 brelse(real_bh); 206 205 if (atomic_dec_and_test(&sdp->sd_log_in_flight)) ··· 221 220 u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head); 222 221 struct buffer_head *bh; 223 222 224 - bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); 223 + bh = mempool_alloc(gfs2_bh_pool, GFP_NOFS); 225 224 atomic_set(&bh->b_count, 1); 226 225 bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock); 227 226 set_bh_page(bh, real->b_page, bh_offset(real));
+18
fs/gfs2/main.c
··· 17 17 #include <linux/rcupdate.h> 18 18 #include <linux/rculist_bl.h> 19 19 #include <linux/atomic.h> 20 + #include <linux/mempool.h> 20 21 21 22 #include "gfs2.h" 22 23 #include "incore.h" ··· 68 67 69 68 gfs2_init_glock_once(gl); 70 69 address_space_init_once(mapping); 70 + } 71 + 72 + static void *gfs2_bh_alloc(gfp_t mask, void *data) 73 + { 74 + return alloc_buffer_head(mask); 75 + } 76 + 77 + static void gfs2_bh_free(void *ptr, void *data) 78 + { 79 + return free_buffer_head(ptr); 71 80 } 72 81 73 82 /** ··· 162 151 gfs2_control_wq = alloc_workqueue("gfs2_control", 163 152 WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0); 164 153 if (!gfs2_control_wq) 154 + goto fail_recovery; 155 + 156 + gfs2_bh_pool = mempool_create(1024, gfs2_bh_alloc, gfs2_bh_free, NULL); 157 + if (!gfs2_bh_pool) 165 158 goto fail_control; 166 159 167 160 gfs2_register_debugfs(); ··· 175 160 return 0; 176 161 177 162 fail_control: 163 + destroy_workqueue(gfs2_control_wq); 164 + fail_recovery: 178 165 destroy_workqueue(gfs_recovery_wq); 179 166 fail_wq: 180 167 unregister_filesystem(&gfs2meta_fs_type); ··· 225 208 226 209 rcu_barrier(); 227 210 211 + mempool_destroy(gfs2_bh_pool); 228 212 kmem_cache_destroy(gfs2_quotad_cachep); 229 213 kmem_cache_destroy(gfs2_rgrpd_cachep); 230 214 kmem_cache_destroy(gfs2_bufdata_cachep);
+1
fs/gfs2/util.c
··· 25 25 struct kmem_cache *gfs2_bufdata_cachep __read_mostly; 26 26 struct kmem_cache *gfs2_rgrpd_cachep __read_mostly; 27 27 struct kmem_cache *gfs2_quotad_cachep __read_mostly; 28 + mempool_t *gfs2_bh_pool __read_mostly; 28 29 29 30 void gfs2_assert_i(struct gfs2_sbd *sdp) 30 31 {
+3
fs/gfs2/util.h
··· 10 10 #ifndef __UTIL_DOT_H__ 11 11 #define __UTIL_DOT_H__ 12 12 13 + #include <linux/mempool.h> 14 + 13 15 #include "incore.h" 14 16 15 17 #define fs_printk(level, fs, fmt, arg...) \ ··· 152 150 extern struct kmem_cache *gfs2_bufdata_cachep; 153 151 extern struct kmem_cache *gfs2_rgrpd_cachep; 154 152 extern struct kmem_cache *gfs2_quotad_cachep; 153 + extern mempool_t *gfs2_bh_pool; 155 154 156 155 static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt, 157 156 unsigned int *p)