diff options
Diffstat (limited to 'fs/gfs2/glops.c')
-rw-r--r-- | fs/gfs2/glops.c | 89 |
1 files changed, 42 insertions, 47 deletions
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index da21ecaafcc2..78418b4fa857 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c | |||
@@ -28,40 +28,55 @@ | |||
28 | #include "trans.h" | 28 | #include "trans.h" |
29 | #include "dir.h" | 29 | #include "dir.h" |
30 | 30 | ||
31 | static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh) | ||
32 | { | ||
33 | fs_err(gl->gl_sbd, "AIL buffer %p: blocknr %llu state 0x%08lx mapping %p page state 0x%lx\n", | ||
34 | bh, (unsigned long long)bh->b_blocknr, bh->b_state, | ||
35 | bh->b_page->mapping, bh->b_page->flags); | ||
36 | fs_err(gl->gl_sbd, "AIL glock %u:%llu mapping %p\n", | ||
37 | gl->gl_name.ln_type, gl->gl_name.ln_number, | ||
38 | gfs2_glock2aspace(gl)); | ||
39 | gfs2_lm_withdraw(gl->gl_sbd, "AIL error\n"); | ||
40 | } | ||
41 | |||
31 | /** | 42 | /** |
32 | * __gfs2_ail_flush - remove all buffers for a given lock from the AIL | 43 | * __gfs2_ail_flush - remove all buffers for a given lock from the AIL |
33 | * @gl: the glock | 44 | * @gl: the glock |
45 | * @fsync: set when called from fsync (not all buffers will be clean) | ||
34 | * | 46 | * |
35 | * None of the buffers should be dirty, locked, or pinned. | 47 | * None of the buffers should be dirty, locked, or pinned. |
36 | */ | 48 | */ |
37 | 49 | ||
38 | static void __gfs2_ail_flush(struct gfs2_glock *gl) | 50 | static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) |
39 | { | 51 | { |
40 | struct gfs2_sbd *sdp = gl->gl_sbd; | 52 | struct gfs2_sbd *sdp = gl->gl_sbd; |
41 | struct list_head *head = &gl->gl_ail_list; | 53 | struct list_head *head = &gl->gl_ail_list; |
42 | struct gfs2_bufdata *bd; | 54 | struct gfs2_bufdata *bd, *tmp; |
43 | struct buffer_head *bh; | 55 | struct buffer_head *bh; |
56 | const unsigned long b_state = (1UL << BH_Dirty)|(1UL << BH_Pinned)|(1UL << BH_Lock); | ||
57 | sector_t blocknr; | ||
44 | 58 | ||
59 | gfs2_log_lock(sdp); | ||
45 | spin_lock(&sdp->sd_ail_lock); | 60 | spin_lock(&sdp->sd_ail_lock); |
46 | while (!list_empty(head)) { | 61 | list_for_each_entry_safe(bd, tmp, head, bd_ail_gl_list) { |
47 | bd = list_entry(head->next, struct gfs2_bufdata, | ||
48 | bd_ail_gl_list); | ||
49 | bh = bd->bd_bh; | 62 | bh = bd->bd_bh; |
50 | gfs2_remove_from_ail(bd); | 63 | if (bh->b_state & b_state) { |
51 | bd->bd_bh = NULL; | 64 | if (fsync) |
65 | continue; | ||
66 | gfs2_ail_error(gl, bh); | ||
67 | } | ||
68 | blocknr = bh->b_blocknr; | ||
52 | bh->b_private = NULL; | 69 | bh->b_private = NULL; |
53 | spin_unlock(&sdp->sd_ail_lock); | 70 | gfs2_remove_from_ail(bd); /* drops ref on bh */ |
54 | 71 | ||
55 | bd->bd_blkno = bh->b_blocknr; | 72 | bd->bd_bh = NULL; |
56 | gfs2_log_lock(sdp); | 73 | bd->bd_blkno = blocknr; |
57 | gfs2_assert_withdraw(sdp, !buffer_busy(bh)); | ||
58 | gfs2_trans_add_revoke(sdp, bd); | ||
59 | gfs2_log_unlock(sdp); | ||
60 | 74 | ||
61 | spin_lock(&sdp->sd_ail_lock); | 75 | gfs2_trans_add_revoke(sdp, bd); |
62 | } | 76 | } |
63 | gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); | 77 | BUG_ON(!fsync && atomic_read(&gl->gl_ail_count)); |
64 | spin_unlock(&sdp->sd_ail_lock); | 78 | spin_unlock(&sdp->sd_ail_lock); |
79 | gfs2_log_unlock(sdp); | ||
65 | } | 80 | } |
66 | 81 | ||
67 | 82 | ||
@@ -84,13 +99,13 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) | |||
84 | BUG_ON(current->journal_info); | 99 | BUG_ON(current->journal_info); |
85 | current->journal_info = &tr; | 100 | current->journal_info = &tr; |
86 | 101 | ||
87 | __gfs2_ail_flush(gl); | 102 | __gfs2_ail_flush(gl, 0); |
88 | 103 | ||
89 | gfs2_trans_end(sdp); | 104 | gfs2_trans_end(sdp); |
90 | gfs2_log_flush(sdp, NULL); | 105 | gfs2_log_flush(sdp, NULL); |
91 | } | 106 | } |
92 | 107 | ||
93 | void gfs2_ail_flush(struct gfs2_glock *gl) | 108 | void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) |
94 | { | 109 | { |
95 | struct gfs2_sbd *sdp = gl->gl_sbd; | 110 | struct gfs2_sbd *sdp = gl->gl_sbd; |
96 | unsigned int revokes = atomic_read(&gl->gl_ail_count); | 111 | unsigned int revokes = atomic_read(&gl->gl_ail_count); |
@@ -102,7 +117,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl) | |||
102 | ret = gfs2_trans_begin(sdp, 0, revokes); | 117 | ret = gfs2_trans_begin(sdp, 0, revokes); |
103 | if (ret) | 118 | if (ret) |
104 | return; | 119 | return; |
105 | __gfs2_ail_flush(gl); | 120 | __gfs2_ail_flush(gl, fsync); |
106 | gfs2_trans_end(sdp); | 121 | gfs2_trans_end(sdp); |
107 | gfs2_log_flush(sdp, NULL); | 122 | gfs2_log_flush(sdp, NULL); |
108 | } | 123 | } |
@@ -119,6 +134,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl) | |||
119 | static void rgrp_go_sync(struct gfs2_glock *gl) | 134 | static void rgrp_go_sync(struct gfs2_glock *gl) |
120 | { | 135 | { |
121 | struct address_space *metamapping = gfs2_glock2aspace(gl); | 136 | struct address_space *metamapping = gfs2_glock2aspace(gl); |
137 | struct gfs2_rgrpd *rgd; | ||
122 | int error; | 138 | int error; |
123 | 139 | ||
124 | if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) | 140 | if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) |
@@ -130,6 +146,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl) | |||
130 | error = filemap_fdatawait(metamapping); | 146 | error = filemap_fdatawait(metamapping); |
131 | mapping_set_error(metamapping, error); | 147 | mapping_set_error(metamapping, error); |
132 | gfs2_ail_empty_gl(gl); | 148 | gfs2_ail_empty_gl(gl); |
149 | |||
150 | spin_lock(&gl->gl_spin); | ||
151 | rgd = gl->gl_object; | ||
152 | if (rgd) | ||
153 | gfs2_free_clones(rgd); | ||
154 | spin_unlock(&gl->gl_spin); | ||
133 | } | 155 | } |
134 | 156 | ||
135 | /** | 157 | /** |
@@ -430,33 +452,6 @@ static int inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl) | |||
430 | } | 452 | } |
431 | 453 | ||
432 | /** | 454 | /** |
433 | * rgrp_go_lock - operation done after an rgrp lock is locked by | ||
434 | * a first holder on this node. | ||
435 | * @gl: the glock | ||
436 | * @flags: | ||
437 | * | ||
438 | * Returns: errno | ||
439 | */ | ||
440 | |||
441 | static int rgrp_go_lock(struct gfs2_holder *gh) | ||
442 | { | ||
443 | return gfs2_rgrp_bh_get(gh->gh_gl->gl_object); | ||
444 | } | ||
445 | |||
446 | /** | ||
447 | * rgrp_go_unlock - operation done before an rgrp lock is unlocked by | ||
448 | * a last holder on this node. | ||
449 | * @gl: the glock | ||
450 | * @flags: | ||
451 | * | ||
452 | */ | ||
453 | |||
454 | static void rgrp_go_unlock(struct gfs2_holder *gh) | ||
455 | { | ||
456 | gfs2_rgrp_bh_put(gh->gh_gl->gl_object); | ||
457 | } | ||
458 | |||
459 | /** | ||
460 | * trans_go_sync - promote/demote the transaction glock | 455 | * trans_go_sync - promote/demote the transaction glock |
461 | * @gl: the glock | 456 | * @gl: the glock |
462 | * @state: the requested state | 457 | * @state: the requested state |
@@ -558,8 +553,8 @@ const struct gfs2_glock_operations gfs2_inode_glops = { | |||
558 | const struct gfs2_glock_operations gfs2_rgrp_glops = { | 553 | const struct gfs2_glock_operations gfs2_rgrp_glops = { |
559 | .go_xmote_th = rgrp_go_sync, | 554 | .go_xmote_th = rgrp_go_sync, |
560 | .go_inval = rgrp_go_inval, | 555 | .go_inval = rgrp_go_inval, |
561 | .go_lock = rgrp_go_lock, | 556 | .go_lock = gfs2_rgrp_go_lock, |
562 | .go_unlock = rgrp_go_unlock, | 557 | .go_unlock = gfs2_rgrp_go_unlock, |
563 | .go_dump = gfs2_rgrp_dump, | 558 | .go_dump = gfs2_rgrp_dump, |
564 | .go_type = LM_TYPE_RGRP, | 559 | .go_type = LM_TYPE_RGRP, |
565 | .go_flags = GLOF_ASPACE, | 560 | .go_flags = GLOF_ASPACE, |