Skip to content

Commit

Permalink
[GFS2] Fix for root inode ref count bug
Browse files Browse the repository at this point in the history
Umount is now working correctly again. The bug was due to
not getting an extra ref count when mounting the fs. We
should have bumped it by two (once for the internal pointer
to the root inode from the super block and once for the
inode hanging off the dcache entry for root).

Also this patch tidys up the code dealing with looking up
and creating inodes. We now pass Linux inodes (with gfs2_inodes
attached) rather than the other way around and this reduces code
duplication in various places.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
  • Loading branch information
Steven Whitehouse committed Feb 13, 2006
1 parent 18ec7d5 commit 7359a19
Show file tree
Hide file tree
Showing 12 changed files with 103 additions and 133 deletions.
4 changes: 2 additions & 2 deletions fs/gfs2/glops.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,13 +358,13 @@ static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
static void trans_go_xmote_bh(struct gfs2_glock *gl)
{
struct gfs2_sbd *sdp = gl->gl_sbd;
struct gfs2_glock *j_gl = sdp->sd_jdesc->jd_inode->i_gl;
struct gfs2_glock *j_gl = get_v2ip(sdp->sd_jdesc->jd_inode)->i_gl;
struct gfs2_log_header head;
int error;

if (gl->gl_state != LM_ST_UNLOCKED &&
test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
gfs2_meta_cache_flush(sdp->sd_jdesc->jd_inode);
gfs2_meta_cache_flush(get_v2ip(sdp->sd_jdesc->jd_inode));
j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA);

error = gfs2_find_jhead(sdp->sd_jdesc, &head);
Expand Down
2 changes: 1 addition & 1 deletion fs/gfs2/incore.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ struct gfs2_ail {
struct gfs2_jdesc {
struct list_head jd_list;

struct gfs2_inode *jd_inode;
struct inode *jd_inode;
unsigned int jd_jid;
int jd_dirty;

Expand Down
70 changes: 43 additions & 27 deletions fs/gfs2/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -711,24 +711,28 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
* Returns: errno
*/

int gfs2_lookupi(struct gfs2_inode *dip, struct qstr *name, int is_root,
struct gfs2_inode **ipp)
int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root,
struct inode **inodep)
{
struct gfs2_inode *ipp;
struct gfs2_inode *dip = get_v2ip(dir);
struct gfs2_sbd *sdp = dip->i_sbd;
struct gfs2_holder d_gh;
struct gfs2_inum inum;
unsigned int type;
struct gfs2_glock *gl;
int error;
int error = 0;

*inodep = NULL;

if (!name->len || name->len > GFS2_FNAMESIZE)
return -ENAMETOOLONG;

if (gfs2_filecmp(name, ".", 1) ||
(gfs2_filecmp(name, "..", 2) && dip == get_v2ip(sdp->sd_root_dir))) {
(gfs2_filecmp(name, "..", 2) && dir == sdp->sd_root_dir)) {
gfs2_inode_hold(dip);
*ipp = dip;
return 0;
ipp = dip;
goto done;
}

error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
Expand All @@ -750,15 +754,21 @@ int gfs2_lookupi(struct gfs2_inode *dip, struct qstr *name, int is_root,
if (error)
goto out;

error = gfs2_inode_get(gl, &inum, CREATE, ipp);
error = gfs2_inode_get(gl, &inum, CREATE, &ipp);
if (!error)
gfs2_inode_min_init(*ipp, type);
gfs2_inode_min_init(ipp, type);

gfs2_glock_put(gl);

out:
out:
gfs2_glock_dq_uninit(&d_gh);

done:
if (error == 0) {
*inodep = gfs2_ip2v(ipp);
if (!*inodep)
error = -ENOMEM;
gfs2_inode_put(ipp);
}
return error;
}

Expand Down Expand Up @@ -1171,27 +1181,28 @@ static int link_dinode(struct gfs2_inode *dip, struct qstr *name,
* @ghs[0] is an initialized holder for the directory
* @ghs[1] is the holder for the inode lock
*
* If the return value is 0, the glocks on both the directory and the new
* If the return value is not NULL, the glocks on both the directory and the new
* file are held. A transaction has been started and an inplace reservation
* is held, as well.
*
* Returns: errno
* Returns: An inode
*/

int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode)
struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode)
{
struct inode *inode;
struct gfs2_inode *dip = get_gl2ip(ghs->gh_gl);
struct gfs2_sbd *sdp = dip->i_sbd;
struct gfs2_unlinked *ul;
struct gfs2_inode *ip;
int error;

if (!name->len || name->len > GFS2_FNAMESIZE)
return -ENAMETOOLONG;
return ERR_PTR(-ENAMETOOLONG);

error = gfs2_unlinked_get(sdp, &ul);
if (error)
return error;
return ERR_PTR(error);

gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
error = gfs2_glock_nq(ghs);
Expand Down Expand Up @@ -1220,15 +1231,15 @@ int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode)
ghs + 1);
if (error) {
gfs2_unlinked_put(sdp, ul);
return error;
return ERR_PTR(error);
}

gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
error = gfs2_glock_nq(ghs);
if (error) {
gfs2_glock_dq_uninit(ghs + 1);
gfs2_unlinked_put(sdp, ul);
return error;
return ERR_PTR(error);
}

error = create_ok(dip, name, mode);
Expand Down Expand Up @@ -1266,7 +1277,11 @@ int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode)

gfs2_unlinked_put(sdp, ul);

return 0;
inode = gfs2_ip2v(ip);
gfs2_inode_put(ip);
if (!inode)
return ERR_PTR(-ENOMEM);
return inode;

fail_iput:
gfs2_inode_put(ip);
Expand All @@ -1280,7 +1295,7 @@ int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode)
fail:
gfs2_unlinked_put(sdp, ul);

return error;
return ERR_PTR(error);
}

/**
Expand Down Expand Up @@ -1445,35 +1460,36 @@ int gfs2_unlink_ok(struct gfs2_inode *dip, struct qstr *name,
int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
{
struct gfs2_sbd *sdp = this->i_sbd;
struct gfs2_inode *tmp;
struct inode *dir = to->i_vnode;
struct inode *tmp;
struct qstr dotdot;
int error = 0;

memset(&dotdot, 0, sizeof(struct qstr));
dotdot.name = "..";
dotdot.len = 2;

gfs2_inode_hold(to);
igrab(dir);

for (;;) {
if (to == this) {
if (dir == this->i_vnode) {
error = -EINVAL;
break;
}
if (to == get_v2ip(sdp->sd_root_dir)) {
if (dir == sdp->sd_root_dir) {
error = 0;
break;
}

error = gfs2_lookupi(to, &dotdot, 1, &tmp);
error = gfs2_lookupi(dir, &dotdot, 1, &tmp);
if (error)
break;

gfs2_inode_put(to);
to = tmp;
iput(dir);
dir = tmp;
}

gfs2_inode_put(to);
iput(dir);

return error;
}
Expand Down
15 changes: 4 additions & 11 deletions fs/gfs2/inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ void gfs2_inode_destroy(struct gfs2_inode *ip);
int gfs2_inode_dealloc(struct gfs2_sbd *sdp, struct gfs2_unlinked *ul);

int gfs2_change_nlink(struct gfs2_inode *ip, int diff);
int gfs2_lookupi(struct gfs2_inode *dip, struct qstr *name, int is_root,
struct gfs2_inode **ipp);
int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode);
int gfs2_lookupi(struct inode *dir, struct qstr *name, int is_root,
struct inode **ipp);
struct inode *gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode);
int gfs2_unlinki(struct gfs2_inode *dip, struct qstr *name,
struct gfs2_inode *ip, struct gfs2_unlinked *ul);
int gfs2_rmdiri(struct gfs2_inode *dip, struct qstr *name,
Expand All @@ -68,19 +68,12 @@ int gfs2_repermission(struct inode *inode, int mask, struct nameidata *nd);
static inline int gfs2_lookup_simple(struct inode *dip, char *name,
struct inode **ipp)
{
struct gfs2_inode *ip;
struct qstr qstr;
int err;
memset(&qstr, 0, sizeof(struct qstr));
qstr.name = name;
qstr.len = strlen(name);
err = gfs2_lookupi(get_v2ip(dip), &qstr, 1, &ip);
if (err == 0) {
*ipp = gfs2_ip2v(ip);
gfs2_inode_put(ip);
if (*ipp == NULL)
err = -ENOMEM;
}
err = gfs2_lookupi(dip, &qstr, 1, ipp);
return err;
}

Expand Down
2 changes: 1 addition & 1 deletion fs/gfs2/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
uint64_t dbn;
int error;

error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, &new, &dbn, NULL);
error = gfs2_block_map(get_v2ip(sdp->sd_jdesc->jd_inode), lbn, &new, &dbn, NULL);
gfs2_assert_withdraw(sdp, !error && dbn);

return dbn;
Expand Down
30 changes: 14 additions & 16 deletions fs/gfs2/lops.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
static void buf_lo_before_scan(struct gfs2_jdesc *jd,
struct gfs2_log_header *head, int pass)
{
struct gfs2_sbd *sdp = jd->jd_inode->i_sbd;
struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd;

if (pass != 0)
return;
Expand All @@ -190,8 +190,8 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
struct gfs2_log_descriptor *ld, __be64 *ptr,
int pass)
{
struct gfs2_sbd *sdp = jd->jd_inode->i_sbd;
struct gfs2_glock *gl = jd->jd_inode->i_gl;
struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd;
struct gfs2_glock *gl = get_v2ip(jd->jd_inode)->i_gl;
unsigned int blks = be32_to_cpu(ld->ld_data1);
struct buffer_head *bh_log, *bh_ip;
uint64_t blkno;
Expand Down Expand Up @@ -236,16 +236,16 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,

static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
{
struct gfs2_sbd *sdp = jd->jd_inode->i_sbd;
struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd;

if (error) {
gfs2_meta_sync(jd->jd_inode->i_gl, DIO_START | DIO_WAIT);
gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, DIO_START | DIO_WAIT);
return;
}
if (pass != 1)
return;

gfs2_meta_sync(jd->jd_inode->i_gl, DIO_START | DIO_WAIT);
gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, DIO_START | DIO_WAIT);

fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n",
jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks);
Expand Down Expand Up @@ -320,7 +320,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
static void revoke_lo_before_scan(struct gfs2_jdesc *jd,
struct gfs2_log_header *head, int pass)
{
struct gfs2_sbd *sdp = jd->jd_inode->i_sbd;
struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd;

if (pass != 0)
return;
Expand All @@ -333,7 +333,7 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
struct gfs2_log_descriptor *ld, __be64 *ptr,
int pass)
{
struct gfs2_sbd *sdp = jd->jd_inode->i_sbd;
struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd;
unsigned int blks = be32_to_cpu(ld->ld_length);
unsigned int revokes = be32_to_cpu(ld->ld_data1);
struct buffer_head *bh;
Expand Down Expand Up @@ -379,7 +379,7 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,

static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
{
struct gfs2_sbd *sdp = jd->jd_inode->i_sbd;
struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd;

if (error) {
gfs2_revoke_clean(sdp);
Expand Down Expand Up @@ -458,8 +458,6 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
gfs2_trans_add_gl(bd->bd_gl);
list_add(&bd->bd_list_tr, &tr->tr_list_buf);
gfs2_pin(sdp, bd->bd_bh);
} else {
clear_buffer_pinned(bd->bd_bh);
}
gfs2_log_lock(sdp);
if (ip->i_di.di_flags & GFS2_DIF_JDATA)
Expand Down Expand Up @@ -630,8 +628,8 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
struct gfs2_log_descriptor *ld,
__be64 *ptr, int pass)
{
struct gfs2_sbd *sdp = jd->jd_inode->i_sbd;
struct gfs2_glock *gl = jd->jd_inode->i_gl;
struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd;
struct gfs2_glock *gl = get_v2ip(jd->jd_inode)->i_gl;
unsigned int blks = be32_to_cpu(ld->ld_data1);
struct buffer_head *bh_log, *bh_ip;
uint64_t blkno;
Expand Down Expand Up @@ -680,17 +678,17 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,

static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
{
struct gfs2_sbd *sdp = jd->jd_inode->i_sbd;
struct gfs2_sbd *sdp = get_v2ip(jd->jd_inode)->i_sbd;

if (error) {
gfs2_meta_sync(jd->jd_inode->i_gl, DIO_START | DIO_WAIT);
gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, DIO_START | DIO_WAIT);
return;
}
if (pass != 1)
return;

/* data sync? */
gfs2_meta_sync(jd->jd_inode->i_gl, DIO_START | DIO_WAIT);
gfs2_meta_sync(get_v2ip(jd->jd_inode)->i_gl, DIO_START | DIO_WAIT);

fs_info(sdp, "jid=%u: Replayed %u of %u data blocks\n",
jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks);
Expand Down
9 changes: 1 addition & 8 deletions fs/gfs2/ops_export.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,23 +169,16 @@ static struct dentry *gfs2_get_parent(struct dentry *child)
{
struct gfs2_inode *dip = get_v2ip(child->d_inode);
struct qstr dotdot = { .name = "..", .len = 2 };
struct gfs2_inode *ip;
struct inode *inode;
struct dentry *dentry;
int error;

atomic_inc(&dip->i_sbd->sd_ops_export);

error = gfs2_lookupi(dip, &dotdot, 1, &ip);
error = gfs2_lookupi(child->d_inode, &dotdot, 1, &inode);
if (error)
return ERR_PTR(error);

inode = gfs2_ip2v(ip);
gfs2_inode_put(ip);

if (!inode)
return ERR_PTR(-ENOMEM);

dentry = d_alloc_anon(inode);
if (!dentry) {
iput(inode);
Expand Down
3 changes: 2 additions & 1 deletion fs/gfs2/ops_fstype.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)
goto out_rooti;
}

igrab(inode);
sb->s_root = d_alloc_root(inode);
if (!sb->s_root) {
fs_err(sdp, "can't get root dentry\n");
Expand Down Expand Up @@ -434,7 +435,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
goto fail_jindex;
}

error = gfs2_glock_nq_init(sdp->sd_jdesc->jd_inode->i_gl,
error = gfs2_glock_nq_init(get_v2ip(sdp->sd_jdesc->jd_inode)->i_gl,
LM_ST_SHARED,
LM_FLAG_NOEXP | GL_EXACT,
&sdp->sd_jinode_gh);
Expand Down
Loading

0 comments on commit 7359a19

Please sign in to comment.