Commit 40129b8c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gfs2-v5.9-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2

Pull gfs2 fix from Andreas Gruenbacher:
 "Fix a memory leak on filesystem withdraw.

  We didn't detect this bug because we have slab merging on by default
  (CONFIG_SLAB_MERGE_DEFAULT). Adding 'slub_nomerge' to the kernel
  command line exposed the problem"

* tag 'gfs2-v5.9-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: add some much needed cleanup for log flushes that fail
parents b0bfd5ec 462582b9
...@@ -901,6 +901,36 @@ static void empty_ail1_list(struct gfs2_sbd *sdp) ...@@ -901,6 +901,36 @@ static void empty_ail1_list(struct gfs2_sbd *sdp)
} }
} }
/**
* drain_bd - drain the buf and databuf queue for a failed transaction
* @tr: the transaction to drain
*
* When this is called, we're taking an error exit for a log write that failed
* but since we bypassed the after_commit functions, we need to remove the
* items from the buf and databuf queue.
*/
static void trans_drain(struct gfs2_trans *tr)
{
struct gfs2_bufdata *bd;
struct list_head *head;
if (!tr)
return;
head = &tr->tr_buf;
while (!list_empty(head)) {
bd = list_first_entry(head, struct gfs2_bufdata, bd_list);
list_del_init(&bd->bd_list);
kmem_cache_free(gfs2_bufdata_cachep, bd);
}
head = &tr->tr_databuf;
while (!list_empty(head)) {
bd = list_first_entry(head, struct gfs2_bufdata, bd_list);
list_del_init(&bd->bd_list);
kmem_cache_free(gfs2_bufdata_cachep, bd);
}
}
/** /**
* gfs2_log_flush - flush incore transaction(s) * gfs2_log_flush - flush incore transaction(s)
* @sdp: the filesystem * @sdp: the filesystem
...@@ -1005,6 +1035,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ...@@ -1005,6 +1035,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
out: out:
if (gfs2_withdrawn(sdp)) { if (gfs2_withdrawn(sdp)) {
trans_drain(tr);
/** /**
* If the tr_list is empty, we're withdrawing during a log * If the tr_list is empty, we're withdrawing during a log
* flush that targets a transaction, but the transaction was * flush that targets a transaction, but the transaction was
......
...@@ -67,6 +67,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks, ...@@ -67,6 +67,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
tr->tr_reserved += gfs2_struct2blk(sdp, revokes); tr->tr_reserved += gfs2_struct2blk(sdp, revokes);
INIT_LIST_HEAD(&tr->tr_databuf); INIT_LIST_HEAD(&tr->tr_databuf);
INIT_LIST_HEAD(&tr->tr_buf); INIT_LIST_HEAD(&tr->tr_buf);
INIT_LIST_HEAD(&tr->tr_list);
INIT_LIST_HEAD(&tr->tr_ail1_list); INIT_LIST_HEAD(&tr->tr_ail1_list);
INIT_LIST_HEAD(&tr->tr_ail2_list); INIT_LIST_HEAD(&tr->tr_ail2_list);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment