gfs2: replace sd_aspace with sd_inode
authorAndreas Gruenbacher <agruenba@redhat.com>
Sat, 5 Apr 2025 22:31:37 +0000 (00:31 +0200)
committerAndreas Gruenbacher <agruenba@redhat.com>
Mon, 21 Apr 2025 16:20:36 +0000 (18:20 +0200)
Currently, sdp->sd_aspace and the per-inode metadata address spaces use
sb->s_bdev->bd_mapping->host as their ->host; folios in those address
spaces will thus appear to be on bdev rather than on gfs2 filesystems.
This is a problem because gfs2 doesn't support cgroup writeback
(SB_I_CGROUPWB), but bdev does.

Fix that by using a "dummy" gfs2 inode as ->host in those address
spaces.  When coming from a folio, folio->mapping->host->i_sb will then
be a gfs2 super block and the SB_I_CGROUPWB flag will not be set in
sb->s_iflags.

Based on a previous version from Bob Peterson from several years ago.
Thanks to Tetsuo Handa, Jan Kara, and Rafael Aquini for helping figure
this out.

Fixes: aaa2cacf8184 ("writeback: add lockdep annotation to inode_to_wb()")
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
fs/gfs2/glock.c
fs/gfs2/glops.c
fs/gfs2/incore.h
fs/gfs2/meta_io.c
fs/gfs2/meta_io.h
fs/gfs2/ops_fstype.c
fs/gfs2/super.c

index d7220a6fe8f55ea77350cb02e4b7078c9e703723..ba25b884169e501dfe2c2ef6d0fccd3d6b0c165c 100644 (file)
@@ -1166,7 +1166,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
                   const struct gfs2_glock_operations *glops, int create,
                   struct gfs2_glock **glp)
 {
-       struct super_block *s = sdp->sd_vfs;
        struct lm_lockname name = { .ln_number = number,
                                    .ln_type = glops->go_type,
                                    .ln_sbd = sdp };
@@ -1229,7 +1228,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
        mapping = gfs2_glock2aspace(gl);
        if (mapping) {
                 mapping->a_ops = &gfs2_meta_aops;
-               mapping->host = s->s_bdev->bd_mapping->host;
+               mapping->host = sdp->sd_inode;
                mapping->flags = 0;
                mapping_set_gfp_mask(mapping, GFP_NOFS);
                mapping->i_private_data = NULL;
index eb4714f299efb61f5573efe541840471dfd1ffa3..116efe335c321282b575b05e7f7b420a509341ed 100644 (file)
@@ -168,7 +168,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
 static int gfs2_rgrp_metasync(struct gfs2_glock *gl)
 {
        struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
-       struct address_space *metamapping = &sdp->sd_aspace;
+       struct address_space *metamapping = gfs2_aspace(sdp);
        struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(gl);
        const unsigned bsize = sdp->sd_sb.sb_bsize;
        loff_t start = (rgd->rd_addr * bsize) & PAGE_MASK;
@@ -225,7 +225,7 @@ static int rgrp_go_sync(struct gfs2_glock *gl)
 static void rgrp_go_inval(struct gfs2_glock *gl, int flags)
 {
        struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
-       struct address_space *mapping = &sdp->sd_aspace;
+       struct address_space *mapping = gfs2_aspace(sdp);
        struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(gl);
        const unsigned bsize = sdp->sd_sb.sb_bsize;
        loff_t start, end;
index 74abbd4970f80b4c577088b7bf68f42584be2b4e..0a41c4e76b3267ae129d343487a4ca7bfa18dad5 100644 (file)
@@ -795,7 +795,7 @@ struct gfs2_sbd {
 
        /* Log stuff */
 
-       struct address_space sd_aspace;
+       struct inode *sd_inode;
 
        spinlock_t sd_log_lock;
 
@@ -851,6 +851,13 @@ struct gfs2_sbd {
        unsigned long sd_glock_dqs_held;
 };
 
+#define GFS2_BAD_INO 1
+
+static inline struct address_space *gfs2_aspace(struct gfs2_sbd *sdp)
+{
+       return sdp->sd_inode->i_mapping;
+}
+
 static inline void gfs2_glstats_inc(struct gfs2_glock *gl, int which)
 {
        gl->gl_stats.stats[which]++;
index 198cc70566375565fff82326c886e75f29efdc9f..9dc8885c95d072de9e3c76dd6cad0d5c59b533b7 100644 (file)
@@ -132,7 +132,7 @@ struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, int create)
        unsigned int bufnum;
 
        if (mapping == NULL)
-               mapping = &sdp->sd_aspace;
+               mapping = gfs2_aspace(sdp);
 
        shift = PAGE_SHIFT - sdp->sd_sb.sb_bsize_shift;
        index = blkno >> shift;             /* convert block to page */
index 831d988c2ceb74f31f33beb05b792f3df8bec47a..b7c8a6684d0249ab7ee1b90d4728f4747e10d031 100644 (file)
@@ -44,9 +44,7 @@ static inline struct gfs2_sbd *gfs2_mapping2sbd(struct address_space *mapping)
                struct gfs2_glock_aspace *gla =
                        container_of(mapping, struct gfs2_glock_aspace, mapping);
                return gla->glock.gl_name.ln_sbd;
-       } else if (mapping->a_ops == &gfs2_rgrp_aops)
-               return container_of(mapping, struct gfs2_sbd, sd_aspace);
-       else
+       } else
                return inode->i_sb->s_fs_info;
 }
 
index e83d293c361423493ca94059ad64e089859746af..6ce475e1c6d64cc154777a43d8788fb286dc3b67 100644 (file)
@@ -72,7 +72,6 @@ void free_sbd(struct gfs2_sbd *sdp)
 static struct gfs2_sbd *init_sbd(struct super_block *sb)
 {
        struct gfs2_sbd *sdp;
-       struct address_space *mapping;
 
        sdp = kzalloc(sizeof(struct gfs2_sbd), GFP_KERNEL);
        if (!sdp)
@@ -109,16 +108,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
 
        INIT_LIST_HEAD(&sdp->sd_sc_inodes_list);
 
-       mapping = &sdp->sd_aspace;
-
-       address_space_init_once(mapping);
-       mapping->a_ops = &gfs2_rgrp_aops;
-       mapping->host = sb->s_bdev->bd_mapping->host;
-       mapping->flags = 0;
-       mapping_set_gfp_mask(mapping, GFP_NOFS);
-       mapping->i_private_data = NULL;
-       mapping->writeback_index = 0;
-
        spin_lock_init(&sdp->sd_log_lock);
        atomic_set(&sdp->sd_log_pinned, 0);
        INIT_LIST_HEAD(&sdp->sd_log_revokes);
@@ -1135,6 +1124,7 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
        int silent = fc->sb_flags & SB_SILENT;
        struct gfs2_sbd *sdp;
        struct gfs2_holder mount_gh;
+       struct address_space *mapping;
        int error;
 
        sdp = init_sbd(sb);
@@ -1156,6 +1146,7 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
        sb->s_flags |= SB_NOSEC;
        sb->s_magic = GFS2_MAGIC;
        sb->s_op = &gfs2_super_ops;
+
        sb->s_d_op = &gfs2_dops;
        sb->s_export_op = &gfs2_export_ops;
        sb->s_qcop = &gfs2_quotactl_ops;
@@ -1181,9 +1172,21 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
                sdp->sd_tune.gt_statfs_quantum = 30;
        }
 
+       /* Set up an address space for metadata writes */
+       sdp->sd_inode = new_inode(sb);
+       error = -ENOMEM;
+       if (!sdp->sd_inode)
+               goto fail_free;
+       sdp->sd_inode->i_ino = GFS2_BAD_INO;
+       sdp->sd_inode->i_size = OFFSET_MAX;
+
+       mapping = gfs2_aspace(sdp);
+       mapping->a_ops = &gfs2_rgrp_aops;
+       mapping_set_gfp_mask(mapping, GFP_NOFS);
+
        error = init_names(sdp, silent);
        if (error)
-               goto fail_free;
+               goto fail_iput;
 
        snprintf(sdp->sd_fsname, sizeof(sdp->sd_fsname), "%s", sdp->sd_table_name);
 
@@ -1192,7 +1195,7 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
                        WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 0,
                        sdp->sd_fsname);
        if (!sdp->sd_glock_wq)
-               goto fail_free;
+               goto fail_iput;
 
        sdp->sd_delete_wq = alloc_workqueue("gfs2-delete/%s",
                        WQ_MEM_RECLAIM | WQ_FREEZABLE, 0, sdp->sd_fsname);
@@ -1309,6 +1312,8 @@ fail_delete_wq:
 fail_glock_wq:
        if (sdp->sd_glock_wq)
                destroy_workqueue(sdp->sd_glock_wq);
+fail_iput:
+       iput(sdp->sd_inode);
 fail_free:
        free_sbd(sdp);
        sb->s_fs_info = NULL;
index 44e5658b896c88ae4ccae610a49152fc05a2b06b..4529b7dda8ca2e285fdd42131a28f4fa400762a5 100644 (file)
@@ -648,7 +648,7 @@ restart:
        gfs2_jindex_free(sdp);
        /*  Take apart glock structures and buffer lists  */
        gfs2_gl_hash_clear(sdp);
-       truncate_inode_pages_final(&sdp->sd_aspace);
+       iput(sdp->sd_inode);
        gfs2_delete_debugfs_file(sdp);
 
        gfs2_sys_fs_del(sdp);