forked from luck/tmp_suning_uos_patched
gfs2: new slab for transactions
This patch adds a new slab for gfs2 transactions. That allows us to reduce kernel memory fragmentation, have better organization of data for analysis of vmcore dumps. A new centralized function is added to free the slab objects, and it exposes use-after-free by giving warnings if a transaction is freed while it still has bd elements attached to its buffers or ail lists. We make sure to initialize those transaction ail lists so we can check their integrity when freeing. At a later time, we should add a slab initialization function to make it more efficient, but for this initial patch I wanted to minimize the impact. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
This commit is contained in:
parent
cbcc89b630
commit
b839dadae8
|
@ -30,6 +30,7 @@
|
|||
#include "util.h"
|
||||
#include "dir.h"
|
||||
#include "trace_gfs2.h"
|
||||
#include "trans.h"
|
||||
|
||||
static void gfs2_log_shutdown(struct gfs2_sbd *sdp);
|
||||
|
||||
|
@ -378,7 +379,7 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
|
|||
list_del(&tr->tr_list);
|
||||
gfs2_assert_warn(sdp, list_empty(&tr->tr_ail1_list));
|
||||
gfs2_assert_warn(sdp, list_empty(&tr->tr_ail2_list));
|
||||
kfree(tr);
|
||||
gfs2_trans_free(sdp, tr);
|
||||
}
|
||||
|
||||
spin_unlock(&sdp->sd_ail_lock);
|
||||
|
@ -863,14 +864,14 @@ static void ail_drain(struct gfs2_sbd *sdp)
|
|||
gfs2_ail_empty_tr(sdp, tr, &tr->tr_ail1_list);
|
||||
gfs2_ail_empty_tr(sdp, tr, &tr->tr_ail2_list);
|
||||
list_del(&tr->tr_list);
|
||||
kfree(tr);
|
||||
gfs2_trans_free(sdp, tr);
|
||||
}
|
||||
while (!list_empty(&sdp->sd_ail2_list)) {
|
||||
tr = list_first_entry(&sdp->sd_ail2_list, struct gfs2_trans,
|
||||
tr_list);
|
||||
gfs2_ail_empty_tr(sdp, tr, &tr->tr_ail2_list);
|
||||
list_del(&tr->tr_list);
|
||||
kfree(tr);
|
||||
gfs2_trans_free(sdp, tr);
|
||||
}
|
||||
spin_unlock(&sdp->sd_ail_lock);
|
||||
}
|
||||
|
@ -1008,7 +1009,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
|
|||
trace_gfs2_log_flush(sdp, 0, flags);
|
||||
up_write(&sdp->sd_log_flush_lock);
|
||||
|
||||
kfree(tr);
|
||||
gfs2_trans_free(sdp, tr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -143,6 +143,12 @@ static int __init init_gfs2_fs(void)
|
|||
if (!gfs2_qadata_cachep)
|
||||
goto fail_cachep7;
|
||||
|
||||
gfs2_trans_cachep = kmem_cache_create("gfs2_trans",
|
||||
sizeof(struct gfs2_trans),
|
||||
0, 0, NULL);
|
||||
if (!gfs2_trans_cachep)
|
||||
goto fail_cachep8;
|
||||
|
||||
error = register_shrinker(&gfs2_qd_shrinker);
|
||||
if (error)
|
||||
goto fail_shrinker;
|
||||
|
@ -194,6 +200,8 @@ static int __init init_gfs2_fs(void)
|
|||
fail_fs1:
|
||||
unregister_shrinker(&gfs2_qd_shrinker);
|
||||
fail_shrinker:
|
||||
kmem_cache_destroy(gfs2_trans_cachep);
|
||||
fail_cachep8:
|
||||
kmem_cache_destroy(gfs2_qadata_cachep);
|
||||
fail_cachep7:
|
||||
kmem_cache_destroy(gfs2_quotad_cachep);
|
||||
|
@ -236,6 +244,7 @@ static void __exit exit_gfs2_fs(void)
|
|||
rcu_barrier();
|
||||
|
||||
mempool_destroy(gfs2_page_pool);
|
||||
kmem_cache_destroy(gfs2_trans_cachep);
|
||||
kmem_cache_destroy(gfs2_qadata_cachep);
|
||||
kmem_cache_destroy(gfs2_quotad_cachep);
|
||||
kmem_cache_destroy(gfs2_rgrpd_cachep);
|
||||
|
|
|
@ -37,7 +37,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
|
|||
if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
|
||||
return -EROFS;
|
||||
|
||||
tr = kzalloc(sizeof(struct gfs2_trans), GFP_NOFS);
|
||||
tr = kmem_cache_zalloc(gfs2_trans_cachep, GFP_NOFS);
|
||||
if (!tr)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -67,7 +67,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
|
|||
|
||||
fail:
|
||||
sb_end_intwrite(sdp->sd_vfs);
|
||||
kfree(tr);
|
||||
kmem_cache_free(gfs2_trans_cachep, tr);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
|
|||
if (!test_bit(TR_TOUCHED, &tr->tr_flags)) {
|
||||
gfs2_log_release(sdp, tr->tr_reserved);
|
||||
if (alloced) {
|
||||
kfree(tr);
|
||||
gfs2_trans_free(sdp, tr);
|
||||
sb_end_intwrite(sdp->sd_vfs);
|
||||
}
|
||||
return;
|
||||
|
@ -111,7 +111,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
|
|||
|
||||
gfs2_log_commit(sdp, tr);
|
||||
if (alloced && !test_bit(TR_ATTACHED, &tr->tr_flags))
|
||||
kfree(tr);
|
||||
gfs2_trans_free(sdp, tr);
|
||||
up_read(&sdp->sd_log_flush_lock);
|
||||
|
||||
if (sdp->sd_vfs->s_flags & SB_SYNCHRONOUS)
|
||||
|
@ -278,3 +278,14 @@ void gfs2_trans_remove_revoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len)
|
|||
gfs2_log_unlock(sdp);
|
||||
}
|
||||
|
||||
void gfs2_trans_free(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
|
||||
{
|
||||
if (tr == NULL)
|
||||
return;
|
||||
|
||||
gfs2_assert_warn(sdp, list_empty(&tr->tr_ail1_list));
|
||||
gfs2_assert_warn(sdp, list_empty(&tr->tr_ail2_list));
|
||||
gfs2_assert_warn(sdp, list_empty(&tr->tr_databuf));
|
||||
gfs2_assert_warn(sdp, list_empty(&tr->tr_buf));
|
||||
kmem_cache_free(gfs2_trans_cachep, tr);
|
||||
}
|
||||
|
|
|
@ -42,5 +42,6 @@ extern void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh);
|
|||
extern void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh);
|
||||
extern void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
|
||||
extern void gfs2_trans_remove_revoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len);
|
||||
extern void gfs2_trans_free(struct gfs2_sbd *sdp, struct gfs2_trans *tr);
|
||||
|
||||
#endif /* __TRANS_DOT_H__ */
|
||||
|
|
|
@ -32,6 +32,7 @@ struct kmem_cache *gfs2_bufdata_cachep __read_mostly;
|
|||
struct kmem_cache *gfs2_rgrpd_cachep __read_mostly;
|
||||
struct kmem_cache *gfs2_quotad_cachep __read_mostly;
|
||||
struct kmem_cache *gfs2_qadata_cachep __read_mostly;
|
||||
struct kmem_cache *gfs2_trans_cachep __read_mostly;
|
||||
mempool_t *gfs2_page_pool __read_mostly;
|
||||
|
||||
void gfs2_assert_i(struct gfs2_sbd *sdp)
|
||||
|
|
|
@ -172,6 +172,7 @@ extern struct kmem_cache *gfs2_bufdata_cachep;
|
|||
extern struct kmem_cache *gfs2_rgrpd_cachep;
|
||||
extern struct kmem_cache *gfs2_quotad_cachep;
|
||||
extern struct kmem_cache *gfs2_qadata_cachep;
|
||||
extern struct kmem_cache *gfs2_trans_cachep;
|
||||
extern mempool_t *gfs2_page_pool;
|
||||
extern struct workqueue_struct *gfs2_control_wq;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user