Commit 97fd734b authored by Abhi Das's avatar Abhi Das Committed by Andreas Gruenbacher
Browse files

gfs2: lookup local statfs inodes prior to journal recovery



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: default avatarAbhi Das <adas@redhat.com>
Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
parent 73092698
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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;
+98 −35
Original line number Diff line number Diff line
@@ -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 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
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;
}
+30 −1
Original line number Diff line number Diff line
@@ -729,7 +729,7 @@ static void gfs2_put_super(struct super_block *sb)
			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,
+3 −0
Original line number Diff line number Diff line
@@ -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;