Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7359a19c authored by Steven Whitehouse's avatar Steven Whitehouse
Browse files

[GFS2] Fix for root inode ref count bug



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: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 18ec7d5c
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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;

+43 −27
Original line number Diff line number Diff line
@@ -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);
@@ -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:
	gfs2_glock_dq_uninit(&d_gh);

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

@@ -1171,15 +1181,16 @@ 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;
@@ -1187,11 +1198,11 @@ int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode)
	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);
@@ -1220,7 +1231,7 @@ 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);
@@ -1228,7 +1239,7 @@ int gfs2_createi(struct gfs2_holder *ghs, struct qstr *name, unsigned int mode)
		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);
@@ -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);
@@ -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);
}

/**
@@ -1445,7 +1460,8 @@ 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;

@@ -1453,27 +1469,27 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
	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;
}
+4 −11
Original line number Diff line number Diff line
@@ -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,
@@ -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;
}

+1 −1
Original line number Diff line number Diff line
@@ -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;
Loading