[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: Steven Whitehouse <swhiteho@redhat.com>
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 4c193e3..2a00b96 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -711,24 +711,28 @@
  * 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 @@
 	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;
 }
 
@@ -1171,15 +1181,16 @@
  * @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 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 @@
 					  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 @@
 		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 @@
 
 	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 @@
  fail:
 	gfs2_unlinked_put(sdp, ul);
 
-	return error;
+	return ERR_PTR(error);
 }
 
 /**
@@ -1445,7 +1460,8 @@
 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 @@
 	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;
 }