[GFS2] Fix a bug: scheduling under a spinlock

At some stage, a mutex was added to gfs2_glock_put() without
checking all its call sites. Two of them were called from
under a spinlock causing random delays at various points and
crashes.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 4ed1378..32cc400 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -158,6 +158,7 @@
 	if (kref_put(&gl->gl_ref, kill_glock)) {
 		list_del_init(&gl->gl_list);
 		write_unlock(&bucket->hb_lock);
+		BUG_ON(spin_is_locked(&gl->gl_spin));
 		glock_free(gl);
 		rv = 1;
 		goto out;
@@ -353,13 +354,14 @@
  *
  */
 
-void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, int flags,
+void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
 		      struct gfs2_holder *gh)
 {
+	flags |= GL_NEVER_RECURSE;
 	INIT_LIST_HEAD(&gh->gh_list);
 	gh->gh_gl = gl;
 	gh->gh_ip = (unsigned long)__builtin_return_address(0);
-	gh->gh_owner = (flags & GL_NEVER_RECURSE) ? NULL : current;
+	gh->gh_owner = current;
 	gh->gh_state = state;
 	gh->gh_flags = flags;
 	gh->gh_error = 0;
@@ -382,10 +384,10 @@
  *
  */
 
-void gfs2_holder_reinit(unsigned int state, int flags, struct gfs2_holder *gh)
+void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *gh)
 {
 	gh->gh_state = state;
-	gh->gh_flags = flags;
+	gh->gh_flags = flags | GL_NEVER_RECURSE;
 	if (gh->gh_state == LM_ST_EXCLUSIVE)
 		gh->gh_flags |= GL_LOCAL_EXCL;
 
@@ -461,6 +463,8 @@
 	struct gfs2_holder *tmp_gh, *safe;
 	int found = 0;
 
+	BUG_ON(!spin_is_locked(&gl->gl_spin));
+
 	printk(KERN_INFO "recursion %016llx, %u\n", gl->gl_name.ln_number,
 		gl->gl_name.ln_type);
 
@@ -502,6 +506,8 @@
 	struct gfs2_holder *tmp_gh, *last_gh = NULL;
 	int found = 0;
 
+	BUG_ON(!spin_is_locked(&gl->gl_spin));
+
 	if (gfs2_assert_warn(sdp, gh->gh_owner))
 		return;
 
@@ -676,7 +682,6 @@
  * @gl: the glock
  *
  */
-
 static void run_queue(struct gfs2_glock *gl)
 {
 	struct gfs2_holder *gh;
@@ -779,6 +784,7 @@
 	spin_lock(&gl->gl_spin);
 	clear_bit(GLF_LOCK, &gl->gl_flags);
 	run_queue(gl);
+	BUG_ON(!spin_is_locked(&gl->gl_spin));
 	spin_unlock(&gl->gl_spin);
 }
 
@@ -1244,7 +1250,7 @@
 
 	return 0;
 
- fail:
+fail:
 	print_symbol(KERN_WARNING "GFS2: Existing holder from %s\n",
 		     existing->gh_ip);
 	print_symbol(KERN_WARNING "GFS2: New holder from %s\n", new->gh_ip);
@@ -1263,6 +1269,8 @@
 	struct gfs2_glock *gl = gh->gh_gl;
 	struct gfs2_holder *existing;
 
+	BUG_ON(!gh->gh_owner);
+
 	if (!gh->gh_owner)
 		goto out;
 
@@ -1331,7 +1339,7 @@
 	if (!(gh->gh_flags & GL_ASYNC)) {
 		error = glock_wait_internal(gh);
 		if (error == GLR_CANCELED) {
-			msleep(1000);
+			msleep(100);
 			goto restart;
 		}
 	}
@@ -1360,7 +1368,7 @@
 	else if (list_empty(&gh->gh_list)) {
 		if (gh->gh_error == GLR_CANCELED) {
 			spin_unlock(&gl->gl_spin);
-			msleep(1000);
+			msleep(100);
 			if (gfs2_glock_nq(gh))
 				return 1;
 			return 0;
@@ -1386,7 +1394,7 @@
 
 	error = glock_wait_internal(gh);
 	if (error == GLR_CANCELED) {
-		msleep(1000);
+		msleep(100);
 		gh->gh_flags &= ~GL_ASYNC;
 		error = gfs2_glock_nq(gh);
 	}
@@ -2217,10 +2225,12 @@
 	if (!list_empty(&gl->gl_reclaim)) {
 		list_del_init(&gl->gl_reclaim);
 		atomic_dec(&sdp->sd_reclaim_count);
+		spin_unlock(&sdp->sd_reclaim_lock);
 		released = gfs2_glock_put(gl);
 		gfs2_assert(sdp, !released);
+	} else {
+		spin_unlock(&sdp->sd_reclaim_lock);
 	}
-	spin_unlock(&sdp->sd_reclaim_lock);
 
 	if (gfs2_glmutex_trylock(gl)) {
 		if (gl->gl_ops == &gfs2_inode_glops) {
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index b6646e7..ed5bc3e 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -81,10 +81,10 @@
 		   int create, struct gfs2_glock **glp);
 void gfs2_glock_hold(struct gfs2_glock *gl);
 int gfs2_glock_put(struct gfs2_glock *gl);
-
-void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, int flags,
+void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
 		      struct gfs2_holder *gh);
-void gfs2_holder_reinit(unsigned int state, int flags, struct gfs2_holder *gh);
+void gfs2_holder_reinit(unsigned int state, unsigned flags,
+			struct gfs2_holder *gh);
 void gfs2_holder_uninit(struct gfs2_holder *gh);
 struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl, unsigned int state,
 				    int flags, gfp_t gfp_flags);
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 6140c24..fb5a4d0 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -409,8 +409,8 @@
 
 	spin_lock(&io_gl->gl_spin);
 	io_gl->gl_object = NULL;
-	gfs2_glock_put(i_gl);
 	spin_unlock(&io_gl->gl_spin);
+	gfs2_glock_put(i_gl);
 
 	gfs2_glock_dq_uninit(&ip->i_iopen_gh);
 
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index b0dd0b9..9e32e0f 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -578,6 +578,7 @@
 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf);
+	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_hdrs);
 	gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list));
 
 	sdp->sd_log_flush_head = sdp->sd_log_head;
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index 74cf28e..da49973 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -214,6 +214,8 @@
 	struct buffer_head *bh;
 	int retry;
 
+	BUG_ON(!spin_is_locked(&sdp->sd_log_lock));
+
 	do {
 		retry = 0;