gfs2: lookup local statfs inodes prior to journal recovery
authorAbhi Das <adas@redhat.com>
Tue, 20 Oct 2020 20:58:04 +0000 (15:58 -0500)
committerAndreas Gruenbacher <agruenba@redhat.com>
Fri, 23 Oct 2020 13:47:14 +0000 (15:47 +0200)
We need to lookup the master statfs inode and the local statfs
inodes earlier in the mount process (in init_journal) so journal
recovery can use them when it attempts to recover the statfs info.
We lookup all the local statfs inodes and store them in a linked
list to allow a node to recover statfs info for other nodes in the
cluster.

Signed-off-by: Abhi Das <adas@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
fs/gfs2/incore.h
fs/gfs2/ops_fstype.c
fs/gfs2/super.c
fs/gfs2/super.h

index e34183e..d770730 100644 (file)
@@ -697,6 +697,13 @@ struct gfs2_pcpu_lkstats {
        struct gfs2_lkstats lkstats[10];
 };
 
+/* List of local (per node) statfs inodes */
+struct local_statfs_inode {
+       struct list_head si_list;
+       struct inode *si_sc_inode;
+       unsigned int si_jid; /* journal id this statfs inode corresponds to */
+};
+
 struct gfs2_sbd {
        struct super_block *sd_vfs;
        struct gfs2_pcpu_lkstats __percpu *sd_lkstats;
@@ -748,6 +755,7 @@ struct gfs2_sbd {
        struct inode *sd_jindex;
        struct inode *sd_statfs_inode;
        struct inode *sd_sc_inode;
+       struct list_head sd_sc_inodes_list;
        struct inode *sd_qc_inode;
        struct inode *sd_rindex;
        struct inode *sd_quota_inode;
index 03c33fc..7a7e3c1 100644 (file)
@@ -110,6 +110,8 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
        spin_lock_init(&sdp->sd_trunc_lock);
        spin_lock_init(&sdp->sd_bitmap_lock);
 
+       INIT_LIST_HEAD(&sdp->sd_sc_inodes_list);
+
        mapping = &sdp->sd_aspace;
 
        address_space_init_once(mapping);
@@ -608,6 +610,90 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
        return error;
 }
 
+/**
+ * init_statfs - look up and initialize master and local (per node) statfs inodes
+ * @sdp: The GFS2 superblock
+ *
+ * This should be called after the jindex is initialized in init_journal() and
+ * before gfs2_journal_recovery() is called because we need to be able to write
+ * to these inodes during recovery.
+ *
+ * Returns: errno
+ */
+static int init_statfs(struct gfs2_sbd *sdp)
+{
+       int error = 0;
+       struct inode *master = d_inode(sdp->sd_master_dir);
+       struct inode *pn = NULL;
+       char buf[30];
+       struct gfs2_jdesc *jd;
+       struct gfs2_inode *ip;
+
+       sdp->sd_statfs_inode = gfs2_lookup_simple(master, "statfs");
+       if (IS_ERR(sdp->sd_statfs_inode)) {
+               error = PTR_ERR(sdp->sd_statfs_inode);
+               fs_err(sdp, "can't read in statfs inode: %d\n", error);
+               goto fail;
+       }
+
+       pn = gfs2_lookup_simple(master, "per_node");
+       if (IS_ERR(pn)) {
+               error = PTR_ERR(pn);
+               fs_err(sdp, "can't find per_node directory: %d\n", error);
+               goto put_statfs;
+       }
+
+       /* For each jid, lookup the corresponding local statfs inode in the
+        * per_node metafs directory and save it in the sdp->sd_sc_inodes_list. */
+       list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
+               struct local_statfs_inode *lsi =
+                       kmalloc(sizeof(struct local_statfs_inode), GFP_NOFS);
+               if (!lsi) {
+                       error = -ENOMEM;
+                       goto free_local;
+               }
+               sprintf(buf, "statfs_change%u", jd->jd_jid);
+               lsi->si_sc_inode = gfs2_lookup_simple(pn, buf);
+               if (IS_ERR(lsi->si_sc_inode)) {
+                       error = PTR_ERR(lsi->si_sc_inode);
+                       fs_err(sdp, "can't find local \"sc\" file#%u: %d\n",
+                              jd->jd_jid, error);
+                       goto free_local;
+               }
+               lsi->si_jid = jd->jd_jid;
+               if (jd->jd_jid == sdp->sd_jdesc->jd_jid)
+                       sdp->sd_sc_inode = lsi->si_sc_inode;
+
+               list_add_tail(&lsi->si_list, &sdp->sd_sc_inodes_list);
+       }
+
+       iput(pn);
+       ip = GFS2_I(sdp->sd_sc_inode);
+       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0,
+                                  &sdp->sd_sc_gh);
+       if (error) {
+               fs_err(sdp, "can't lock local \"sc\" file: %d\n", error);
+               goto free_local;
+       }
+       return 0;
+
+free_local:
+       free_local_statfs_inodes(sdp);
+       iput(pn);
+put_statfs:
+       iput(sdp->sd_statfs_inode);
+fail:
+       return error;
+}
+
+/* Uninitialize and free up memory used by the list of statfs inodes */
+static void uninit_statfs(struct gfs2_sbd *sdp)
+{
+       gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
+       free_local_statfs_inodes(sdp);
+       iput(sdp->sd_statfs_inode);
+}
+
 static int init_journal(struct gfs2_sbd *sdp, int undo)
 {
        struct inode *master = d_inode(sdp->sd_master_dir);
@@ -694,6 +780,11 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
        }
        trace_gfs2_log_blocks(sdp, atomic_read(&sdp->sd_log_blks_free));
 
+       /* Lookup statfs inodes here so journal recovery can use them. */
+       error = init_statfs(sdp);
+       if (error)
+               goto fail_jinode_gh;
+
        if (sdp->sd_lockstruct.ls_first) {
                unsigned int x;
                for (x = 0; x < sdp->sd_journals; x++) {
@@ -702,14 +793,14 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
                        if (sdp->sd_args.ar_spectator) {
                                error = check_journal_clean(sdp, jd, true);
                                if (error)
-                                       goto fail_jinode_gh;
+                                       goto fail_statfs;
                                continue;
                        }
                        error = gfs2_recover_journal(jd, true);
                        if (error) {
                                fs_err(sdp, "error recovering journal %u: %d\n",
                                       x, error);
-                               goto fail_jinode_gh;
+                               goto fail_statfs;
                        }
                }
 
@@ -718,7 +809,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
                error = gfs2_recover_journal(sdp->sd_jdesc, true);
                if (error) {
                        fs_err(sdp, "error recovering my journal: %d\n", error);
-                       goto fail_jinode_gh;
+                       goto fail_statfs;
                }
        }
 
@@ -729,6 +820,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
        INIT_WORK(&sdp->sd_freeze_work, gfs2_freeze_func);
        return 0;
 
+fail_statfs:
+       uninit_statfs(sdp);
 fail_jinode_gh:
        /* A withdraw may have done dq/uninit so now we need to check it */
        if (!sdp->sd_args.ar_spectator &&
@@ -762,20 +855,12 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
        if (error)
                goto fail;
 
-       /* Read in the master statfs inode */
-       sdp->sd_statfs_inode = gfs2_lookup_simple(master, "statfs");
-       if (IS_ERR(sdp->sd_statfs_inode)) {
-               error = PTR_ERR(sdp->sd_statfs_inode);
-               fs_err(sdp, "can't read in statfs inode: %d\n", error);
-               goto fail_journal;
-       }
-
        /* Read in the resource index inode */
        sdp->sd_rindex = gfs2_lookup_simple(master, "rindex");
        if (IS_ERR(sdp->sd_rindex)) {
                error = PTR_ERR(sdp->sd_rindex);
                fs_err(sdp, "can't get resource index inode: %d\n", error);
-               goto fail_statfs;
+               goto fail_journal;
        }
        sdp->sd_rindex_uptodate = 0;
 
@@ -804,8 +889,6 @@ fail_qinode:
 fail_rindex:
        gfs2_clear_rgrpd(sdp);
        iput(sdp->sd_rindex);
-fail_statfs:
-       iput(sdp->sd_statfs_inode);
 fail_journal:
        init_journal(sdp, UNDO);
 fail:
@@ -833,14 +916,6 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo)
                return error;
        }
 
-       sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid);
-       sdp->sd_sc_inode = gfs2_lookup_simple(pn, buf);
-       if (IS_ERR(sdp->sd_sc_inode)) {
-               error = PTR_ERR(sdp->sd_sc_inode);
-               fs_err(sdp, "can't find local \"sc\" file: %d\n", error);
-               goto fail;
-       }
-
        sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid);
        sdp->sd_qc_inode = gfs2_lookup_simple(pn, buf);
        if (IS_ERR(sdp->sd_qc_inode)) {
@@ -852,33 +927,21 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo)
        iput(pn);
        pn = NULL;
 
-       ip = GFS2_I(sdp->sd_sc_inode);
-       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0,
-                                  &sdp->sd_sc_gh);
-       if (error) {
-               fs_err(sdp, "can't lock local \"sc\" file: %d\n", error);
-               goto fail_qc_i;
-       }
-
        ip = GFS2_I(sdp->sd_qc_inode);
        error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0,
                                   &sdp->sd_qc_gh);
        if (error) {
                fs_err(sdp, "can't lock local \"qc\" file: %d\n", error);
-               goto fail_ut_gh;
+               goto fail_qc_i;
        }
 
        return 0;
 
 fail_qc_gh:
        gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
-fail_ut_gh:
-       gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
 fail_qc_i:
        iput(sdp->sd_qc_inode);
 fail_ut_i:
-       iput(sdp->sd_sc_inode);
-fail:
        iput(pn);
        return error;
 }
index e17961e..b285192 100644 (file)
@@ -729,7 +729,7 @@ restart:
                        gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
                gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
                gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
-               iput(sdp->sd_sc_inode);
+               free_local_statfs_inodes(sdp);
                iput(sdp->sd_qc_inode);
        }
 
@@ -1561,6 +1561,35 @@ static void gfs2_free_inode(struct inode *inode)
        kmem_cache_free(gfs2_inode_cachep, GFS2_I(inode));
 }
 
+extern void free_local_statfs_inodes(struct gfs2_sbd *sdp)
+{
+       struct local_statfs_inode *lsi, *safe;
+
+       /* Run through the statfs inodes list to iput and free memory */
+       list_for_each_entry_safe(lsi, safe, &sdp->sd_sc_inodes_list, si_list) {
+               if (lsi->si_jid == sdp->sd_jdesc->jd_jid)
+                       sdp->sd_sc_inode = NULL; /* belongs to this node */
+               if (lsi->si_sc_inode)
+                       iput(lsi->si_sc_inode);
+               list_del(&lsi->si_list);
+               kfree(lsi);
+       }
+}
+
+extern struct inode *find_local_statfs_inode(struct gfs2_sbd *sdp,
+                                            unsigned int index)
+{
+       struct local_statfs_inode *lsi;
+
+       /* Return the local (per node) statfs inode in the
+        * sdp->sd_sc_inodes_list corresponding to the 'index'. */
+       list_for_each_entry(lsi, &sdp->sd_sc_inodes_list, si_list) {
+               if (lsi->si_jid == index)
+                       return lsi->si_sc_inode;
+       }
+       return NULL;
+}
+
 const struct super_operations gfs2_super_ops = {
        .alloc_inode            = gfs2_alloc_inode,
        .free_inode             = gfs2_free_inode,
index ed4f5cb..c9fb2a6 100644 (file)
@@ -44,6 +44,9 @@ extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh,
 extern int gfs2_statfs_sync(struct super_block *sb, int type);
 extern void gfs2_freeze_func(struct work_struct *work);
 
+extern void free_local_statfs_inodes(struct gfs2_sbd *sdp);
+extern struct inode *find_local_statfs_inode(struct gfs2_sbd *sdp,
+                                            unsigned int index);
 extern void free_sbd(struct gfs2_sbd *sdp);
 
 extern struct file_system_type gfs2_fs_type;