[GFS2] Fix lock ordering bug in page fault path

Mmapped files were able to trigger a lock ordering bug. Private
maps do not need to take the glock so early on. Shared maps do
unfortunately, however we can get around that by adding a flag
into the flags for the struct gfs2_file. This only works because
we are taking an exclusive lock at this point, so we know that
nobody else can be racing with us.

Fixes Red Hat bugzilla: #201196

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index fca69f1..bdd4d6b4 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -237,14 +237,22 @@
 	struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
 	struct gfs2_holder gh;
 	int error;
+	int do_unlock = 0;
 
 	if (likely(file != &gfs2_internal_file_sentinal)) {
+		if (file) {
+			struct gfs2_file *gf = file->private_data;
+			if (test_bit(GFF_EXLOCK, &gf->f_flags))
+				goto skip_lock;
+		}
 		gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh);
+		do_unlock = 1;
 		error = gfs2_glock_nq_m_atime(1, &gh);
 		if (unlikely(error))
 			goto out_unlock;
 	}
 
+skip_lock:
 	if (gfs2_is_stuffed(ip)) {
 		error = stuffed_readpage(ip, page);
 		unlock_page(page);
@@ -262,7 +270,7 @@
 	return error;
 out_unlock:
 	unlock_page(page);
-	if (file != &gfs2_internal_file_sentinal)
+	if (do_unlock)
 		gfs2_holder_uninit(&gh);
 	goto out;
 }
@@ -291,17 +299,24 @@
 	struct gfs2_holder gh;
 	unsigned page_idx;
 	int ret;
+	int do_unlock = 0;
 
 	if (likely(file != &gfs2_internal_file_sentinal)) {
+		if (file) {
+			struct gfs2_file *gf = file->private_data;
+			if (test_bit(GFF_EXLOCK, &gf->f_flags))
+				goto skip_lock;
+		}
 		gfs2_holder_init(ip->i_gl, LM_ST_SHARED,
 				 LM_FLAG_TRY_1CB|GL_ATIME|GL_AOP, &gh);
+		do_unlock = 1;
 		ret = gfs2_glock_nq_m_atime(1, &gh);
 		if (ret == GLR_TRYFAILED) 
 			goto out_noerror;
 		if (unlikely(ret))
 			goto out_unlock;
 	}
-
+skip_lock:
 	if (gfs2_is_stuffed(ip)) {
 		struct pagevec lru_pvec;
 		pagevec_init(&lru_pvec, 0);
@@ -326,7 +341,7 @@
 		ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
 	}
 
-	if (likely(file != &gfs2_internal_file_sentinal)) {
+	if (do_unlock) {
 		gfs2_glock_dq_m(1, &gh);
 		gfs2_holder_uninit(&gh);
 	}
@@ -344,7 +359,7 @@
 		unlock_page(page);
 		page_cache_release(page);
 	}
-	if (likely(file != &gfs2_internal_file_sentinal))
+	if (do_unlock)
 		gfs2_holder_uninit(&gh);
 	goto out;
 }