Skip to content
/ linux Public
forked from torvalds/linux

Commit

Permalink
gfs2: lookup local statfs inodes prior to journal recovery
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Andreas Gruenbacher <[email protected]>
  • Loading branch information
Abhi Das authored and Andreas Gruenbacher committed Oct 23, 2020
1 parent 7309269 commit 97fd734
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 36 deletions.
8 changes: 8 additions & 0 deletions fs/gfs2/incore.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
133 changes: 98 additions & 35 deletions fs/gfs2/ops_fstype.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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++) {
Expand All @@ -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;
}
}

Expand All @@ -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;
}
}

Expand All @@ -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 &&
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)) {
Expand All @@ -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;
}
Expand Down
31 changes: 30 additions & 1 deletion fs/gfs2/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions fs/gfs2/super.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 97fd734

Please sign in to comment.