diff options
Diffstat (limited to 'fs/gfs2/glops.c')
-rw-r--r-- | fs/gfs2/glops.c | 160 |
1 files changed, 76 insertions, 84 deletions
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 8522d3aa64fc..bf23a62aa925 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/completion.h> | 12 | #include <linux/completion.h> |
13 | #include <linux/buffer_head.h> | 13 | #include <linux/buffer_head.h> |
14 | #include <linux/gfs2_ondisk.h> | 14 | #include <linux/gfs2_ondisk.h> |
15 | #include <linux/lm_interface.h> | ||
16 | #include <linux/bio.h> | 15 | #include <linux/bio.h> |
17 | 16 | ||
18 | #include "gfs2.h" | 17 | #include "gfs2.h" |
@@ -38,20 +37,25 @@ | |||
38 | static void gfs2_ail_empty_gl(struct gfs2_glock *gl) | 37 | static void gfs2_ail_empty_gl(struct gfs2_glock *gl) |
39 | { | 38 | { |
40 | struct gfs2_sbd *sdp = gl->gl_sbd; | 39 | struct gfs2_sbd *sdp = gl->gl_sbd; |
41 | unsigned int blocks; | ||
42 | struct list_head *head = &gl->gl_ail_list; | 40 | struct list_head *head = &gl->gl_ail_list; |
43 | struct gfs2_bufdata *bd; | 41 | struct gfs2_bufdata *bd; |
44 | struct buffer_head *bh; | 42 | struct buffer_head *bh; |
45 | int error; | 43 | struct gfs2_trans tr; |
46 | 44 | ||
47 | blocks = atomic_read(&gl->gl_ail_count); | 45 | memset(&tr, 0, sizeof(tr)); |
48 | if (!blocks) | 46 | tr.tr_revokes = atomic_read(&gl->gl_ail_count); |
49 | return; | ||
50 | 47 | ||
51 | error = gfs2_trans_begin(sdp, 0, blocks); | 48 | if (!tr.tr_revokes) |
52 | if (gfs2_assert_withdraw(sdp, !error)) | ||
53 | return; | 49 | return; |
54 | 50 | ||
51 | /* A shortened, inline version of gfs2_trans_begin() */ | ||
52 | tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64)); | ||
53 | tr.tr_ip = (unsigned long)__builtin_return_address(0); | ||
54 | INIT_LIST_HEAD(&tr.tr_list_buf); | ||
55 | gfs2_log_reserve(sdp, tr.tr_reserved); | ||
56 | BUG_ON(current->journal_info); | ||
57 | current->journal_info = &tr; | ||
58 | |||
55 | gfs2_log_lock(sdp); | 59 | gfs2_log_lock(sdp); |
56 | while (!list_empty(head)) { | 60 | while (!list_empty(head)) { |
57 | bd = list_entry(head->next, struct gfs2_bufdata, | 61 | bd = list_entry(head->next, struct gfs2_bufdata, |
@@ -72,29 +76,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) | |||
72 | } | 76 | } |
73 | 77 | ||
74 | /** | 78 | /** |
75 | * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock | 79 | * rgrp_go_sync - sync out the metadata for this glock |
76 | * @gl: the glock | ||
77 | * | ||
78 | */ | ||
79 | |||
80 | static void gfs2_pte_inval(struct gfs2_glock *gl) | ||
81 | { | ||
82 | struct gfs2_inode *ip; | ||
83 | struct inode *inode; | ||
84 | |||
85 | ip = gl->gl_object; | ||
86 | inode = &ip->i_inode; | ||
87 | if (!ip || !S_ISREG(inode->i_mode)) | ||
88 | return; | ||
89 | |||
90 | unmap_shared_mapping_range(inode->i_mapping, 0, 0); | ||
91 | if (test_bit(GIF_SW_PAGED, &ip->i_flags)) | ||
92 | set_bit(GLF_DIRTY, &gl->gl_flags); | ||
93 | |||
94 | } | ||
95 | |||
96 | /** | ||
97 | * meta_go_sync - sync out the metadata for this glock | ||
98 | * @gl: the glock | 80 | * @gl: the glock |
99 | * | 81 | * |
100 | * Called when demoting or unlocking an EX glock. We must flush | 82 | * Called when demoting or unlocking an EX glock. We must flush |
@@ -102,36 +84,42 @@ static void gfs2_pte_inval(struct gfs2_glock *gl) | |||
102 | * not return to caller to demote/unlock the glock until I/O is complete. | 84 | * not return to caller to demote/unlock the glock until I/O is complete. |
103 | */ | 85 | */ |
104 | 86 | ||
105 | static void meta_go_sync(struct gfs2_glock *gl) | 87 | static void rgrp_go_sync(struct gfs2_glock *gl) |
106 | { | 88 | { |
107 | if (gl->gl_state != LM_ST_EXCLUSIVE) | 89 | struct address_space *metamapping = gl->gl_aspace->i_mapping; |
90 | int error; | ||
91 | |||
92 | if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) | ||
108 | return; | 93 | return; |
94 | BUG_ON(gl->gl_state != LM_ST_EXCLUSIVE); | ||
109 | 95 | ||
110 | if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) { | 96 | gfs2_log_flush(gl->gl_sbd, gl); |
111 | gfs2_log_flush(gl->gl_sbd, gl); | 97 | filemap_fdatawrite(metamapping); |
112 | gfs2_meta_sync(gl); | 98 | error = filemap_fdatawait(metamapping); |
113 | gfs2_ail_empty_gl(gl); | 99 | mapping_set_error(metamapping, error); |
114 | } | 100 | gfs2_ail_empty_gl(gl); |
115 | } | 101 | } |
116 | 102 | ||
117 | /** | 103 | /** |
118 | * meta_go_inval - invalidate the metadata for this glock | 104 | * rgrp_go_inval - invalidate the metadata for this glock |
119 | * @gl: the glock | 105 | * @gl: the glock |
120 | * @flags: | 106 | * @flags: |
121 | * | 107 | * |
108 | * We never used LM_ST_DEFERRED with resource groups, so that we | ||
109 | * should always see the metadata flag set here. | ||
110 | * | ||
122 | */ | 111 | */ |
123 | 112 | ||
124 | static void meta_go_inval(struct gfs2_glock *gl, int flags) | 113 | static void rgrp_go_inval(struct gfs2_glock *gl, int flags) |
125 | { | 114 | { |
126 | if (!(flags & DIO_METADATA)) | 115 | struct address_space *mapping = gl->gl_aspace->i_mapping; |
127 | return; | ||
128 | 116 | ||
129 | gfs2_meta_inval(gl); | 117 | BUG_ON(!(flags & DIO_METADATA)); |
130 | if (gl->gl_object == GFS2_I(gl->gl_sbd->sd_rindex)) | 118 | gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count)); |
131 | gl->gl_sbd->sd_rindex_uptodate = 0; | 119 | truncate_inode_pages(mapping, 0); |
132 | else if (gl->gl_ops == &gfs2_rgrp_glops && gl->gl_object) { | ||
133 | struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object; | ||
134 | 120 | ||
121 | if (gl->gl_object) { | ||
122 | struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object; | ||
135 | rgd->rd_flags &= ~GFS2_RDF_UPTODATE; | 123 | rgd->rd_flags &= ~GFS2_RDF_UPTODATE; |
136 | } | 124 | } |
137 | } | 125 | } |
@@ -148,48 +136,54 @@ static void inode_go_sync(struct gfs2_glock *gl) | |||
148 | struct address_space *metamapping = gl->gl_aspace->i_mapping; | 136 | struct address_space *metamapping = gl->gl_aspace->i_mapping; |
149 | int error; | 137 | int error; |
150 | 138 | ||
151 | if (gl->gl_state != LM_ST_UNLOCKED) | ||
152 | gfs2_pte_inval(gl); | ||
153 | if (gl->gl_state != LM_ST_EXCLUSIVE) | ||
154 | return; | ||
155 | |||
156 | if (ip && !S_ISREG(ip->i_inode.i_mode)) | 139 | if (ip && !S_ISREG(ip->i_inode.i_mode)) |
157 | ip = NULL; | 140 | ip = NULL; |
141 | if (ip && test_and_clear_bit(GIF_SW_PAGED, &ip->i_flags)) | ||
142 | unmap_shared_mapping_range(ip->i_inode.i_mapping, 0, 0); | ||
143 | if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) | ||
144 | return; | ||
158 | 145 | ||
159 | if (test_bit(GLF_DIRTY, &gl->gl_flags)) { | 146 | BUG_ON(gl->gl_state != LM_ST_EXCLUSIVE); |
160 | gfs2_log_flush(gl->gl_sbd, gl); | 147 | |
161 | filemap_fdatawrite(metamapping); | 148 | gfs2_log_flush(gl->gl_sbd, gl); |
162 | if (ip) { | 149 | filemap_fdatawrite(metamapping); |
163 | struct address_space *mapping = ip->i_inode.i_mapping; | 150 | if (ip) { |
164 | filemap_fdatawrite(mapping); | 151 | struct address_space *mapping = ip->i_inode.i_mapping; |
165 | error = filemap_fdatawait(mapping); | 152 | filemap_fdatawrite(mapping); |
166 | mapping_set_error(mapping, error); | 153 | error = filemap_fdatawait(mapping); |
167 | } | 154 | mapping_set_error(mapping, error); |
168 | error = filemap_fdatawait(metamapping); | ||
169 | mapping_set_error(metamapping, error); | ||
170 | clear_bit(GLF_DIRTY, &gl->gl_flags); | ||
171 | gfs2_ail_empty_gl(gl); | ||
172 | } | 155 | } |
156 | error = filemap_fdatawait(metamapping); | ||
157 | mapping_set_error(metamapping, error); | ||
158 | gfs2_ail_empty_gl(gl); | ||
173 | } | 159 | } |
174 | 160 | ||
175 | /** | 161 | /** |
176 | * inode_go_inval - prepare a inode glock to be released | 162 | * inode_go_inval - prepare a inode glock to be released |
177 | * @gl: the glock | 163 | * @gl: the glock |
178 | * @flags: | 164 | * @flags: |
165 | * | ||
166 | * Normally we invlidate everything, but if we are moving into | ||
167 | * LM_ST_DEFERRED from LM_ST_SHARED or LM_ST_EXCLUSIVE then we | ||
168 | * can keep hold of the metadata, since it won't have changed. | ||
179 | * | 169 | * |
180 | */ | 170 | */ |
181 | 171 | ||
182 | static void inode_go_inval(struct gfs2_glock *gl, int flags) | 172 | static void inode_go_inval(struct gfs2_glock *gl, int flags) |
183 | { | 173 | { |
184 | struct gfs2_inode *ip = gl->gl_object; | 174 | struct gfs2_inode *ip = gl->gl_object; |
185 | int meta = (flags & DIO_METADATA); | ||
186 | 175 | ||
187 | if (meta) { | 176 | gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count)); |
188 | gfs2_meta_inval(gl); | 177 | |
178 | if (flags & DIO_METADATA) { | ||
179 | struct address_space *mapping = gl->gl_aspace->i_mapping; | ||
180 | truncate_inode_pages(mapping, 0); | ||
189 | if (ip) | 181 | if (ip) |
190 | set_bit(GIF_INVALID, &ip->i_flags); | 182 | set_bit(GIF_INVALID, &ip->i_flags); |
191 | } | 183 | } |
192 | 184 | ||
185 | if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) | ||
186 | gl->gl_sbd->sd_rindex_uptodate = 0; | ||
193 | if (ip && S_ISREG(ip->i_inode.i_mode)) | 187 | if (ip && S_ISREG(ip->i_inode.i_mode)) |
194 | truncate_inode_pages(ip->i_inode.i_mapping, 0); | 188 | truncate_inode_pages(ip->i_inode.i_mapping, 0); |
195 | } | 189 | } |
@@ -390,20 +384,7 @@ static int trans_go_demote_ok(const struct gfs2_glock *gl) | |||
390 | return 0; | 384 | return 0; |
391 | } | 385 | } |
392 | 386 | ||
393 | /** | ||
394 | * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock | ||
395 | * @gl: the glock | ||
396 | * | ||
397 | * Returns: 1 if it's ok | ||
398 | */ | ||
399 | |||
400 | static int quota_go_demote_ok(const struct gfs2_glock *gl) | ||
401 | { | ||
402 | return !atomic_read(&gl->gl_lvb_count); | ||
403 | } | ||
404 | |||
405 | const struct gfs2_glock_operations gfs2_meta_glops = { | 387 | const struct gfs2_glock_operations gfs2_meta_glops = { |
406 | .go_xmote_th = meta_go_sync, | ||
407 | .go_type = LM_TYPE_META, | 388 | .go_type = LM_TYPE_META, |
408 | }; | 389 | }; |
409 | 390 | ||
@@ -418,8 +399,8 @@ const struct gfs2_glock_operations gfs2_inode_glops = { | |||
418 | }; | 399 | }; |
419 | 400 | ||
420 | const struct gfs2_glock_operations gfs2_rgrp_glops = { | 401 | const struct gfs2_glock_operations gfs2_rgrp_glops = { |
421 | .go_xmote_th = meta_go_sync, | 402 | .go_xmote_th = rgrp_go_sync, |
422 | .go_inval = meta_go_inval, | 403 | .go_inval = rgrp_go_inval, |
423 | .go_demote_ok = rgrp_go_demote_ok, | 404 | .go_demote_ok = rgrp_go_demote_ok, |
424 | .go_lock = rgrp_go_lock, | 405 | .go_lock = rgrp_go_lock, |
425 | .go_unlock = rgrp_go_unlock, | 406 | .go_unlock = rgrp_go_unlock, |
@@ -448,7 +429,6 @@ const struct gfs2_glock_operations gfs2_nondisk_glops = { | |||
448 | }; | 429 | }; |
449 | 430 | ||
450 | const struct gfs2_glock_operations gfs2_quota_glops = { | 431 | const struct gfs2_glock_operations gfs2_quota_glops = { |
451 | .go_demote_ok = quota_go_demote_ok, | ||
452 | .go_type = LM_TYPE_QUOTA, | 432 | .go_type = LM_TYPE_QUOTA, |
453 | }; | 433 | }; |
454 | 434 | ||
@@ -456,3 +436,15 @@ const struct gfs2_glock_operations gfs2_journal_glops = { | |||
456 | .go_type = LM_TYPE_JOURNAL, | 436 | .go_type = LM_TYPE_JOURNAL, |
457 | }; | 437 | }; |
458 | 438 | ||
439 | const struct gfs2_glock_operations *gfs2_glops_list[] = { | ||
440 | [LM_TYPE_META] = &gfs2_meta_glops, | ||
441 | [LM_TYPE_INODE] = &gfs2_inode_glops, | ||
442 | [LM_TYPE_RGRP] = &gfs2_rgrp_glops, | ||
443 | [LM_TYPE_NONDISK] = &gfs2_trans_glops, | ||
444 | [LM_TYPE_IOPEN] = &gfs2_iopen_glops, | ||
445 | [LM_TYPE_FLOCK] = &gfs2_flock_glops, | ||
446 | [LM_TYPE_NONDISK] = &gfs2_nondisk_glops, | ||
447 | [LM_TYPE_QUOTA] = &gfs2_quota_glops, | ||
448 | [LM_TYPE_JOURNAL] = &gfs2_journal_glops, | ||
449 | }; | ||
450 | |||