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

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
...@@ -697,6 +697,13 @@ struct gfs2_pcpu_lkstats { ...@@ -697,6 +697,13 @@ struct gfs2_pcpu_lkstats {
struct gfs2_lkstats lkstats[10]; 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 gfs2_sbd {
struct super_block *sd_vfs; struct super_block *sd_vfs;
struct gfs2_pcpu_lkstats __percpu *sd_lkstats; struct gfs2_pcpu_lkstats __percpu *sd_lkstats;
...@@ -748,6 +755,7 @@ struct gfs2_sbd { ...@@ -748,6 +755,7 @@ struct gfs2_sbd {
struct inode *sd_jindex; struct inode *sd_jindex;
struct inode *sd_statfs_inode; struct inode *sd_statfs_inode;
struct inode *sd_sc_inode; struct inode *sd_sc_inode;
struct list_head sd_sc_inodes_list;
struct inode *sd_qc_inode; struct inode *sd_qc_inode;
struct inode *sd_rindex; struct inode *sd_rindex;
struct inode *sd_quota_inode; struct inode *sd_quota_inode;
......
...@@ -110,6 +110,8 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) ...@@ -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_trunc_lock);
spin_lock_init(&sdp->sd_bitmap_lock); spin_lock_init(&sdp->sd_bitmap_lock);
INIT_LIST_HEAD(&sdp->sd_sc_inodes_list);
mapping = &sdp->sd_aspace; mapping = &sdp->sd_aspace;
address_space_init_once(mapping); address_space_init_once(mapping);
...@@ -608,6 +610,90 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) ...@@ -608,6 +610,90 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
return error; 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) static int init_journal(struct gfs2_sbd *sdp, int undo)
{ {
struct inode *master = d_inode(sdp->sd_master_dir); struct inode *master = d_inode(sdp->sd_master_dir);
...@@ -694,6 +780,11 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ...@@ -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)); 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) { if (sdp->sd_lockstruct.ls_first) {
unsigned int x; unsigned int x;
for (x = 0; x < sdp->sd_journals; x++) { for (x = 0; x < sdp->sd_journals; x++) {
...@@ -702,14 +793,14 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ...@@ -702,14 +793,14 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
if (sdp->sd_args.ar_spectator) { if (sdp->sd_args.ar_spectator) {
error = check_journal_clean(sdp, jd, true); error = check_journal_clean(sdp, jd, true);
if (error) if (error)
goto fail_jinode_gh; goto fail_statfs;
continue; continue;
} }
error = gfs2_recover_journal(jd, true); error = gfs2_recover_journal(jd, true);
if (error) { if (error) {
fs_err(sdp, "error recovering journal %u: %d\n", fs_err(sdp, "error recovering journal %u: %d\n",
x, error); x, error);
goto fail_jinode_gh; goto fail_statfs;
} }
} }
...@@ -718,7 +809,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ...@@ -718,7 +809,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
error = gfs2_recover_journal(sdp->sd_jdesc, true); error = gfs2_recover_journal(sdp->sd_jdesc, true);
if (error) { if (error) {
fs_err(sdp, "error recovering my journal: %d\n", 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) ...@@ -729,6 +820,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
INIT_WORK(&sdp->sd_freeze_work, gfs2_freeze_func); INIT_WORK(&sdp->sd_freeze_work, gfs2_freeze_func);
return 0; return 0;
fail_statfs:
uninit_statfs(sdp);
fail_jinode_gh: fail_jinode_gh:
/* A withdraw may have done dq/uninit so now we need to check it */ /* A withdraw may have done dq/uninit so now we need to check it */
if (!sdp->sd_args.ar_spectator && if (!sdp->sd_args.ar_spectator &&
...@@ -762,20 +855,12 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) ...@@ -762,20 +855,12 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
if (error) if (error)
goto fail; 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 */ /* Read in the resource index inode */
sdp->sd_rindex = gfs2_lookup_simple(master, "rindex"); sdp->sd_rindex = gfs2_lookup_simple(master, "rindex");
if (IS_ERR(sdp->sd_rindex)) { if (IS_ERR(sdp->sd_rindex)) {
error = PTR_ERR(sdp->sd_rindex); error = PTR_ERR(sdp->sd_rindex);
fs_err(sdp, "can't get resource index inode: %d\n", error); fs_err(sdp, "can't get resource index inode: %d\n", error);
goto fail_statfs; goto fail_journal;
} }
sdp->sd_rindex_uptodate = 0; sdp->sd_rindex_uptodate = 0;
...@@ -804,8 +889,6 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) ...@@ -804,8 +889,6 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
fail_rindex: fail_rindex:
gfs2_clear_rgrpd(sdp); gfs2_clear_rgrpd(sdp);
iput(sdp->sd_rindex); iput(sdp->sd_rindex);
fail_statfs:
iput(sdp->sd_statfs_inode);
fail_journal: fail_journal:
init_journal(sdp, UNDO); init_journal(sdp, UNDO);
fail: fail:
...@@ -833,14 +916,6 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) ...@@ -833,14 +916,6 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo)
return error; 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); sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid);
sdp->sd_qc_inode = gfs2_lookup_simple(pn, buf); sdp->sd_qc_inode = gfs2_lookup_simple(pn, buf);
if (IS_ERR(sdp->sd_qc_inode)) { if (IS_ERR(sdp->sd_qc_inode)) {
...@@ -852,33 +927,21 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) ...@@ -852,33 +927,21 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo)
iput(pn); iput(pn);
pn = NULL; 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); ip = GFS2_I(sdp->sd_qc_inode);
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0,
&sdp->sd_qc_gh); &sdp->sd_qc_gh);
if (error) { if (error) {
fs_err(sdp, "can't lock local \"qc\" file: %d\n", error); fs_err(sdp, "can't lock local \"qc\" file: %d\n", error);
goto fail_ut_gh; goto fail_qc_i;
} }
return 0; return 0;
fail_qc_gh: fail_qc_gh:
gfs2_glock_dq_uninit(&sdp->sd_qc_gh); gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
fail_ut_gh:
gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
fail_qc_i: fail_qc_i:
iput(sdp->sd_qc_inode); iput(sdp->sd_qc_inode);
fail_ut_i: fail_ut_i:
iput(sdp->sd_sc_inode);
fail:
iput(pn); iput(pn);
return error; return error;
} }
......
...@@ -729,7 +729,7 @@ static void gfs2_put_super(struct super_block *sb) ...@@ -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_jinode_gh);
gfs2_glock_dq_uninit(&sdp->sd_sc_gh); gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
gfs2_glock_dq_uninit(&sdp->sd_qc_gh); gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
iput(sdp->sd_sc_inode); free_local_statfs_inodes(sdp);
iput(sdp->sd_qc_inode); iput(sdp->sd_qc_inode);
} }
...@@ -1561,6 +1561,35 @@ static void gfs2_free_inode(struct inode *inode) ...@@ -1561,6 +1561,35 @@ static void gfs2_free_inode(struct inode *inode)
kmem_cache_free(gfs2_inode_cachep, GFS2_I(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 = { const struct super_operations gfs2_super_ops = {
.alloc_inode = gfs2_alloc_inode, .alloc_inode = gfs2_alloc_inode,
.free_inode = gfs2_free_inode, .free_inode = gfs2_free_inode,
......
...@@ -44,6 +44,9 @@ extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, ...@@ -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 int gfs2_statfs_sync(struct super_block *sb, int type);
extern void gfs2_freeze_func(struct work_struct *work); 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 void free_sbd(struct gfs2_sbd *sdp);
extern struct file_system_type gfs2_fs_type; extern struct file_system_type gfs2_fs_type;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment