gfs2: per-filesystem bufdata

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index e79ad08..932c484b 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -693,7 +693,7 @@ bool gfs2_release_folio(struct folio *folio, gfp_t gfp_mask)
 			if (!bd->bd_blkno && !list_empty(&bd->bd_list))
 				list_del_init(&bd->bd_list);
 			if (list_empty(&bd->bd_list))
-				kmem_cache_free(gfs2_bufdata_cachep, bd);
+				kmem_cache_free(sdp->sd_bufdata, bd);
 		}
 
 		bh = bh->b_this_page;
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 6146577..dec6bcc 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -847,6 +847,7 @@ struct gfs2_sbd {
 
 	unsigned long sd_last_warning;
 	struct dentry *debugfs_dir;    /* debugfs directory */
+	struct kmem_cache *sd_bufdata;
 };
 
 #define glock_sbd(gl) ((gl)->gl_name.ln_sbd)
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 347df29..b730870 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -985,13 +985,14 @@ static void empty_ail1_list(struct gfs2_sbd *sdp)
 
 /**
  * trans_drain - drain the buf and databuf queue for a failed transaction
+ * @sdp: Pointer to GFS2 superblock
  * @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)
+static void trans_drain(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
 {
 	struct gfs2_bufdata *bd;
 	struct list_head *head;
@@ -1005,7 +1006,7 @@ static void trans_drain(struct gfs2_trans *tr)
 		list_del_init(&bd->bd_list);
 		if (!list_empty(&bd->bd_ail_st_list))
 			gfs2_remove_from_ail(bd);
-		kmem_cache_free(gfs2_bufdata_cachep, bd);
+		kmem_cache_free(sdp->sd_bufdata, bd);
 	}
 	head = &tr->tr_databuf;
 	while (!list_empty(head)) {
@@ -1013,7 +1014,7 @@ static void trans_drain(struct gfs2_trans *tr)
 		list_del_init(&bd->bd_list);
 		if (!list_empty(&bd->bd_ail_st_list))
 			gfs2_remove_from_ail(bd);
-		kmem_cache_free(gfs2_bufdata_cachep, bd);
+		kmem_cache_free(sdp->sd_bufdata, bd);
 	}
 }
 
@@ -1151,7 +1152,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
 	return;
 
 out_withdraw:
-	trans_drain(tr);
+	trans_drain(sdp, tr);
 	/**
 	 * If the tr_list is empty, we're withdrawing during a log
 	 * flush that targets a transaction, but the transaction was
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index e03928d..d7e93668 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -894,7 +894,7 @@ void gfs2_drain_revokes(struct gfs2_sbd *sdp)
 		list_del_init(&bd->bd_list);
 		gl = bd->bd_gl;
 		gfs2_glock_remove_revoke(gl);
-		kmem_cache_free(gfs2_bufdata_cachep, bd);
+		kmem_cache_free(sdp->sd_bufdata, bd);
 	}
 }
 
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index 9d65719..1b38d73 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -115,12 +115,6 @@ static int __init init_gfs2_fs(void)
 	if (!gfs2_inode_cachep)
 		goto fail_cachep3;
 
-	gfs2_bufdata_cachep = kmem_cache_create("gfs2_bufdata",
-						sizeof(struct gfs2_bufdata),
-					        0, 0, NULL);
-	if (!gfs2_bufdata_cachep)
-		goto fail_cachep4;
-
 	gfs2_rgrpd_cachep = kmem_cache_create("gfs2_rgrpd",
 					      sizeof(struct gfs2_rgrpd),
 					      0, 0, NULL);
@@ -205,8 +199,6 @@ static int __init init_gfs2_fs(void)
 fail_cachep6:
 	kmem_cache_destroy(gfs2_rgrpd_cachep);
 fail_cachep5:
-	kmem_cache_destroy(gfs2_bufdata_cachep);
-fail_cachep4:
 	kmem_cache_destroy(gfs2_inode_cachep);
 fail_cachep3:
 	kmem_cache_destroy(gfs2_glock_aspace_cachep);
@@ -245,7 +237,6 @@ static void __exit exit_gfs2_fs(void)
 	kmem_cache_destroy(gfs2_qadata_cachep);
 	kmem_cache_destroy(gfs2_quotad_cachep);
 	kmem_cache_destroy(gfs2_rgrpd_cachep);
-	kmem_cache_destroy(gfs2_bufdata_cachep);
 	kmem_cache_destroy(gfs2_inode_cachep);
 	kmem_cache_destroy(gfs2_glock_aspace_cachep);
 	kmem_cache_destroy(gfs2_glock_cachep);
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index 3c8e455..7e90dec 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -363,7 +363,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, int meta)
 			gfs2_trans_add_revoke(sdp, bd);
 		} else if (was_pinned) {
 			bh->b_private = NULL;
-			kmem_cache_free(gfs2_bufdata_cachep, bd);
+			kmem_cache_free(sdp->sd_bufdata, bd);
 		} else if (!list_empty(&bd->bd_ail_st_list) &&
 					!list_empty(&bd->bd_ail_gl_list)) {
 			gfs2_remove_from_ail(bd);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index e7a88b7..2e4f3c6 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1198,9 +1198,19 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
 	if (!sdp->sd_delete_wq)
 		goto fail_glock_wq;
 
+	char *bufdata_name = kasprintf(GFP_KERNEL, "gfs2-bufdata/%s", sdp->sd_fsname);
+	if (!bufdata_name)
+		goto fail_delete_wq;
+	sdp->sd_bufdata = kmem_cache_create(bufdata_name,
+					    sizeof(struct gfs2_bufdata),
+					    0, 0, NULL);
+	kfree(bufdata_name);
+	if (!sdp->sd_bufdata)
+		goto fail_delete_wq;
+
 	error = gfs2_sys_fs_add(sdp);
 	if (error)
-		goto fail_delete_wq;
+		goto fail_bufdata;
 
 	gfs2_create_debugfs_file(sdp);
 
@@ -1305,6 +1315,8 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
 fail_debug:
 	gfs2_delete_debugfs_file(sdp);
 	gfs2_sys_fs_del(sdp);
+fail_bufdata:
+	kmem_cache_destroy(sdp->sd_bufdata);
 fail_delete_wq:
 	destroy_workqueue(sdp->sd_delete_wq);
 fail_glock_wq:
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index f6cd907..0d847bf 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -638,6 +638,7 @@ static void gfs2_put_super(struct super_block *sb)
 	gfs2_gl_hash_clear(sdp);
 	iput(sdp->sd_inode);
 	gfs2_delete_debugfs_file(sdp);
+	kmem_cache_destroy(sdp->sd_bufdata);
 
 	gfs2_sys_fs_del(sdp);
 	free_sbd(sdp);
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
index 95f2632..742d061 100644
--- a/fs/gfs2/trans.c
+++ b/fs/gfs2/trans.c
@@ -168,9 +168,10 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
 static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl,
 					       struct buffer_head *bh)
 {
+	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
 	struct gfs2_bufdata *bd;
 
-	bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL);
+	bd = kmem_cache_zalloc(sdp->sd_bufdata, GFP_NOFS | __GFP_NOFAIL);
 	bd->bd_bh = bh;
 	bd->bd_gl = gl;
 	INIT_LIST_HEAD(&bd->bd_list);
@@ -337,7 +338,7 @@ void gfs2_trans_remove_revoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len)
 			sdp->sd_log_num_revoke--;
 			if (bd->bd_gl)
 				gfs2_glock_remove_revoke(bd->bd_gl);
-			kmem_cache_free(gfs2_bufdata_cachep, bd);
+			kmem_cache_free(sdp->sd_bufdata, bd);
 			gfs2_log_release_revokes(sdp, 1);
 			if (--n == 0)
 				break;
diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c
index 0260320..c35c882 100644
--- a/fs/gfs2/util.c
+++ b/fs/gfs2/util.c
@@ -29,7 +29,6 @@
 struct kmem_cache *gfs2_glock_cachep __read_mostly;
 struct kmem_cache *gfs2_glock_aspace_cachep __read_mostly;
 struct kmem_cache *gfs2_inode_cachep __read_mostly;
-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;
diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h
index ffcc47d..940dc45 100644
--- a/fs/gfs2/util.h
+++ b/fs/gfs2/util.h
@@ -160,7 +160,6 @@ gfs2_io_error_bh_i((sdp), (bh), __func__, __FILE__, __LINE__)
 extern struct kmem_cache *gfs2_glock_cachep;
 extern struct kmem_cache *gfs2_glock_aspace_cachep;
 extern struct kmem_cache *gfs2_inode_cachep;
-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;