aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/glops.c
diff options
context:
space:
mode:
authorBenjamin Marzinski <bmarzins@redhat.com>2014-05-01 23:26:55 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2014-05-14 05:04:34 -0400
commit24972557b12ce8fd5b6c6847d0e2ee1837ddc13b (patch)
treefb82edff8bfab9d4d1c4df6dd7784dd3c9f85c1b /fs/gfs2/glops.c
parent5a7c6690c2759d686d2c299402327e92ed92ab6c (diff)
GFS2: remove transaction glock
GFS2 has a transaction glock, which must be grabbed for every transaction, whose purpose is to deal with freezing the filesystem. Aside from this involving a large amount of locking, it is very easy to make the current fsfreeze code hang on unfreezing. This patch rewrites how gfs2 handles freezing the filesystem. The transaction glock is removed. In it's place is a freeze glock, which is cached (but not held) in a shared state by every node in the cluster when the filesystem is mounted. This lock only needs to be grabbed on freezing, and actions which need to be safe from freezing, like recovery. When a node wants to freeze the filesystem, it grabs this glock exclusively. When the freeze glock state changes on the nodes (either from shared to unlocked, or shared to exclusive), the filesystem does a special log flush. gfs2_log_flush() does all the work for flushing out the and shutting down the incore log, and then it tries to grab the freeze glock in a shared state again. Since the filesystem is stuck in gfs2_log_flush, no new transaction can start, and nothing can be written to disk. Unfreezing the filesytem simply involes dropping the freeze glock, allowing gfs2_log_flush() to grab and then release the shared lock, so it is cached for next time. However, in order for the unfreezing ioctl to occur, gfs2 needs to get a shared lock on the filesystem root directory inode to check permissions. If that glock has already been grabbed exclusively, fsfreeze will be unable to get the shared lock and unfreeze the filesystem. In order to allow the unfreeze, this patch makes gfs2 grab a shared lock on the filesystem root directory during the freeze, and hold it until it unfreezes the filesystem. The functions which need to grab a shared lock in order to allow the unfreeze ioctl to be issued now use the lock grabbed by the freeze code instead. The freeze and unfreeze code take care to make sure that this shared lock will not be dropped while another process is using it. Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/glops.c')
-rw-r--r--fs/gfs2/glops.c51
1 files changed, 32 insertions, 19 deletions
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 54b66809e818..0b527939c46f 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -89,18 +89,23 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
89 if (!tr.tr_revokes) 89 if (!tr.tr_revokes)
90 return; 90 return;
91 91
92 /* A shortened, inline version of gfs2_trans_begin() */ 92 /* A shortened, inline version of gfs2_trans_begin()
93 * tr->alloced is not set since the transaction structure is
94 * on the stack */
93 tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64)); 95 tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64));
94 tr.tr_ip = (unsigned long)__builtin_return_address(0); 96 tr.tr_ip = (unsigned long)__builtin_return_address(0);
95 sb_start_intwrite(sdp->sd_vfs); 97 sb_start_intwrite(sdp->sd_vfs);
96 gfs2_log_reserve(sdp, tr.tr_reserved); 98 if (gfs2_log_reserve(sdp, tr.tr_reserved) < 0) {
99 sb_end_intwrite(sdp->sd_vfs);
100 return;
101 }
97 WARN_ON_ONCE(current->journal_info); 102 WARN_ON_ONCE(current->journal_info);
98 current->journal_info = &tr; 103 current->journal_info = &tr;
99 104
100 __gfs2_ail_flush(gl, 0, tr.tr_revokes); 105 __gfs2_ail_flush(gl, 0, tr.tr_revokes);
101 106
102 gfs2_trans_end(sdp); 107 gfs2_trans_end(sdp);
103 gfs2_log_flush(sdp, NULL); 108 gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
104} 109}
105 110
106void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) 111void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
@@ -121,7 +126,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
121 return; 126 return;
122 __gfs2_ail_flush(gl, fsync, max_revokes); 127 __gfs2_ail_flush(gl, fsync, max_revokes);
123 gfs2_trans_end(sdp); 128 gfs2_trans_end(sdp);
124 gfs2_log_flush(sdp, NULL); 129 gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
125} 130}
126 131
127/** 132/**
@@ -144,7 +149,7 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
144 return; 149 return;
145 GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); 150 GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE);
146 151
147 gfs2_log_flush(sdp, gl); 152 gfs2_log_flush(sdp, gl, NORMAL_FLUSH);
148 filemap_fdatawrite_range(mapping, gl->gl_vm.start, gl->gl_vm.end); 153 filemap_fdatawrite_range(mapping, gl->gl_vm.start, gl->gl_vm.end);
149 error = filemap_fdatawait_range(mapping, gl->gl_vm.start, gl->gl_vm.end); 154 error = filemap_fdatawait_range(mapping, gl->gl_vm.start, gl->gl_vm.end);
150 mapping_set_error(mapping, error); 155 mapping_set_error(mapping, error);
@@ -206,7 +211,7 @@ static void inode_go_sync(struct gfs2_glock *gl)
206 211
207 GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); 212 GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE);
208 213
209 gfs2_log_flush(gl->gl_sbd, gl); 214 gfs2_log_flush(gl->gl_sbd, gl, NORMAL_FLUSH);
210 filemap_fdatawrite(metamapping); 215 filemap_fdatawrite(metamapping);
211 if (ip) { 216 if (ip) {
212 struct address_space *mapping = ip->i_inode.i_mapping; 217 struct address_space *mapping = ip->i_inode.i_mapping;
@@ -253,7 +258,7 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)
253 } 258 }
254 259
255 if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) { 260 if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) {
256 gfs2_log_flush(gl->gl_sbd, NULL); 261 gfs2_log_flush(gl->gl_sbd, NULL, NORMAL_FLUSH);
257 gl->gl_sbd->sd_rindex_uptodate = 0; 262 gl->gl_sbd->sd_rindex_uptodate = 0;
258 } 263 }
259 if (ip && S_ISREG(ip->i_inode.i_mode)) 264 if (ip && S_ISREG(ip->i_inode.i_mode))
@@ -455,31 +460,39 @@ static void inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
455} 460}
456 461
457/** 462/**
458 * trans_go_sync - promote/demote the transaction glock 463 * freeze_go_sync - promote/demote the freeze glock
459 * @gl: the glock 464 * @gl: the glock
460 * @state: the requested state 465 * @state: the requested state
461 * @flags: 466 * @flags:
462 * 467 *
463 */ 468 */
464 469
465static void trans_go_sync(struct gfs2_glock *gl) 470static void freeze_go_sync(struct gfs2_glock *gl)
466{ 471{
467 struct gfs2_sbd *sdp = gl->gl_sbd; 472 struct gfs2_sbd *sdp = gl->gl_sbd;
473 DEFINE_WAIT(wait);
468 474
469 if (gl->gl_state != LM_ST_UNLOCKED && 475 if (gl->gl_state == LM_ST_SHARED &&
470 test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { 476 test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
471 gfs2_meta_syncfs(sdp); 477 atomic_set(&sdp->sd_log_freeze, 1);
472 gfs2_log_shutdown(sdp); 478 wake_up(&sdp->sd_logd_waitq);
479 do {
480 prepare_to_wait(&sdp->sd_log_frozen_wait, &wait,
481 TASK_UNINTERRUPTIBLE);
482 if (atomic_read(&sdp->sd_log_freeze))
483 io_schedule();
484 } while(atomic_read(&sdp->sd_log_freeze));
485 finish_wait(&sdp->sd_log_frozen_wait, &wait);
473 } 486 }
474} 487}
475 488
476/** 489/**
477 * trans_go_xmote_bh - After promoting/demoting the transaction glock 490 * freeze_go_xmote_bh - After promoting/demoting the freeze glock
478 * @gl: the glock 491 * @gl: the glock
479 * 492 *
480 */ 493 */
481 494
482static int trans_go_xmote_bh(struct gfs2_glock *gl, struct gfs2_holder *gh) 495static int freeze_go_xmote_bh(struct gfs2_glock *gl, struct gfs2_holder *gh)
483{ 496{
484 struct gfs2_sbd *sdp = gl->gl_sbd; 497 struct gfs2_sbd *sdp = gl->gl_sbd;
485 struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode); 498 struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
@@ -512,7 +525,7 @@ static int trans_go_xmote_bh(struct gfs2_glock *gl, struct gfs2_holder *gh)
512 * Always returns 0 525 * Always returns 0
513 */ 526 */
514 527
515static int trans_go_demote_ok(const struct gfs2_glock *gl) 528static int freeze_go_demote_ok(const struct gfs2_glock *gl)
516{ 529{
517 return 0; 530 return 0;
518} 531}
@@ -563,10 +576,10 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
563 .go_flags = GLOF_LVB, 576 .go_flags = GLOF_LVB,
564}; 577};
565 578
566const struct gfs2_glock_operations gfs2_trans_glops = { 579const struct gfs2_glock_operations gfs2_freeze_glops = {
567 .go_sync = trans_go_sync, 580 .go_sync = freeze_go_sync,
568 .go_xmote_bh = trans_go_xmote_bh, 581 .go_xmote_bh = freeze_go_xmote_bh,
569 .go_demote_ok = trans_go_demote_ok, 582 .go_demote_ok = freeze_go_demote_ok,
570 .go_type = LM_TYPE_NONDISK, 583 .go_type = LM_TYPE_NONDISK,
571}; 584};
572 585