diff options
Diffstat (limited to 'fs/gfs2/lops.c')
-rw-r--r-- | fs/gfs2/lops.c | 470 |
1 files changed, 235 insertions, 235 deletions
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 3b395c41b2f3..6c27cea761c6 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c | |||
@@ -27,7 +27,104 @@ | |||
27 | #include "trans.h" | 27 | #include "trans.h" |
28 | #include "util.h" | 28 | #include "util.h" |
29 | 29 | ||
30 | static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) | 30 | /** |
31 | * gfs2_pin - Pin a buffer in memory | ||
32 | * @sdp: The superblock | ||
33 | * @bh: The buffer to be pinned | ||
34 | * | ||
35 | * The log lock must be held when calling this function | ||
36 | */ | ||
37 | static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) | ||
38 | { | ||
39 | struct gfs2_bufdata *bd; | ||
40 | |||
41 | gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)); | ||
42 | |||
43 | clear_buffer_dirty(bh); | ||
44 | if (test_set_buffer_pinned(bh)) | ||
45 | gfs2_assert_withdraw(sdp, 0); | ||
46 | if (!buffer_uptodate(bh)) | ||
47 | gfs2_io_error_bh(sdp, bh); | ||
48 | bd = bh->b_private; | ||
49 | /* If this buffer is in the AIL and it has already been written | ||
50 | * to in-place disk block, remove it from the AIL. | ||
51 | */ | ||
52 | if (bd->bd_ail) | ||
53 | list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); | ||
54 | get_bh(bh); | ||
55 | } | ||
56 | |||
57 | /** | ||
58 | * gfs2_unpin - Unpin a buffer | ||
59 | * @sdp: the filesystem the buffer belongs to | ||
60 | * @bh: The buffer to unpin | ||
61 | * @ai: | ||
62 | * | ||
63 | */ | ||
64 | |||
65 | static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, | ||
66 | struct gfs2_ail *ai) | ||
67 | { | ||
68 | struct gfs2_bufdata *bd = bh->b_private; | ||
69 | |||
70 | gfs2_assert_withdraw(sdp, buffer_uptodate(bh)); | ||
71 | |||
72 | if (!buffer_pinned(bh)) | ||
73 | gfs2_assert_withdraw(sdp, 0); | ||
74 | |||
75 | lock_buffer(bh); | ||
76 | mark_buffer_dirty(bh); | ||
77 | clear_buffer_pinned(bh); | ||
78 | |||
79 | gfs2_log_lock(sdp); | ||
80 | if (bd->bd_ail) { | ||
81 | list_del(&bd->bd_ail_st_list); | ||
82 | brelse(bh); | ||
83 | } else { | ||
84 | struct gfs2_glock *gl = bd->bd_gl; | ||
85 | list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list); | ||
86 | atomic_inc(&gl->gl_ail_count); | ||
87 | } | ||
88 | bd->bd_ail = ai; | ||
89 | list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); | ||
90 | gfs2_log_unlock(sdp); | ||
91 | unlock_buffer(bh); | ||
92 | } | ||
93 | |||
94 | |||
95 | static inline struct gfs2_log_descriptor *bh_log_desc(struct buffer_head *bh) | ||
96 | { | ||
97 | return (struct gfs2_log_descriptor *)bh->b_data; | ||
98 | } | ||
99 | |||
100 | static inline __be64 *bh_log_ptr(struct buffer_head *bh) | ||
101 | { | ||
102 | struct gfs2_log_descriptor *ld = bh_log_desc(bh); | ||
103 | return (__force __be64 *)(ld + 1); | ||
104 | } | ||
105 | |||
106 | static inline __be64 *bh_ptr_end(struct buffer_head *bh) | ||
107 | { | ||
108 | return (__force __be64 *)(bh->b_data + bh->b_size); | ||
109 | } | ||
110 | |||
111 | |||
112 | static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type) | ||
113 | { | ||
114 | struct buffer_head *bh = gfs2_log_get_buf(sdp); | ||
115 | struct gfs2_log_descriptor *ld = bh_log_desc(bh); | ||
116 | ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); | ||
117 | ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); | ||
118 | ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); | ||
119 | ld->ld_type = cpu_to_be32(ld_type); | ||
120 | ld->ld_length = 0; | ||
121 | ld->ld_data1 = 0; | ||
122 | ld->ld_data2 = 0; | ||
123 | memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); | ||
124 | return bh; | ||
125 | } | ||
126 | |||
127 | static void __glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) | ||
31 | { | 128 | { |
32 | struct gfs2_glock *gl; | 129 | struct gfs2_glock *gl; |
33 | struct gfs2_trans *tr = current->journal_info; | 130 | struct gfs2_trans *tr = current->journal_info; |
@@ -38,15 +135,19 @@ static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) | |||
38 | if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl))) | 135 | if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl))) |
39 | return; | 136 | return; |
40 | 137 | ||
41 | gfs2_log_lock(sdp); | 138 | if (!list_empty(&le->le_list)) |
42 | if (!list_empty(&le->le_list)){ | ||
43 | gfs2_log_unlock(sdp); | ||
44 | return; | 139 | return; |
45 | } | 140 | |
46 | gfs2_glock_hold(gl); | 141 | gfs2_glock_hold(gl); |
47 | set_bit(GLF_DIRTY, &gl->gl_flags); | 142 | set_bit(GLF_DIRTY, &gl->gl_flags); |
48 | sdp->sd_log_num_gl++; | 143 | sdp->sd_log_num_gl++; |
49 | list_add(&le->le_list, &sdp->sd_log_le_gl); | 144 | list_add(&le->le_list, &sdp->sd_log_le_gl); |
145 | } | ||
146 | |||
147 | static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) | ||
148 | { | ||
149 | gfs2_log_lock(sdp); | ||
150 | __glock_lo_add(sdp, le); | ||
50 | gfs2_log_unlock(sdp); | 151 | gfs2_log_unlock(sdp); |
51 | } | 152 | } |
52 | 153 | ||
@@ -71,30 +172,25 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) | |||
71 | struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); | 172 | struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); |
72 | struct gfs2_trans *tr; | 173 | struct gfs2_trans *tr; |
73 | 174 | ||
175 | lock_buffer(bd->bd_bh); | ||
74 | gfs2_log_lock(sdp); | 176 | gfs2_log_lock(sdp); |
75 | if (!list_empty(&bd->bd_list_tr)) { | 177 | if (!list_empty(&bd->bd_list_tr)) |
76 | gfs2_log_unlock(sdp); | 178 | goto out; |
77 | return; | ||
78 | } | ||
79 | tr = current->journal_info; | 179 | tr = current->journal_info; |
80 | tr->tr_touched = 1; | 180 | tr->tr_touched = 1; |
81 | tr->tr_num_buf++; | 181 | tr->tr_num_buf++; |
82 | list_add(&bd->bd_list_tr, &tr->tr_list_buf); | 182 | list_add(&bd->bd_list_tr, &tr->tr_list_buf); |
83 | gfs2_log_unlock(sdp); | ||
84 | |||
85 | if (!list_empty(&le->le_list)) | 183 | if (!list_empty(&le->le_list)) |
86 | return; | 184 | goto out; |
87 | 185 | __glock_lo_add(sdp, &bd->bd_gl->gl_le); | |
88 | gfs2_trans_add_gl(bd->bd_gl); | ||
89 | |||
90 | gfs2_meta_check(sdp, bd->bd_bh); | 186 | gfs2_meta_check(sdp, bd->bd_bh); |
91 | gfs2_pin(sdp, bd->bd_bh); | 187 | gfs2_pin(sdp, bd->bd_bh); |
92 | gfs2_log_lock(sdp); | ||
93 | sdp->sd_log_num_buf++; | 188 | sdp->sd_log_num_buf++; |
94 | list_add(&le->le_list, &sdp->sd_log_le_buf); | 189 | list_add(&le->le_list, &sdp->sd_log_le_buf); |
95 | gfs2_log_unlock(sdp); | ||
96 | |||
97 | tr->tr_num_buf_new++; | 190 | tr->tr_num_buf_new++; |
191 | out: | ||
192 | gfs2_log_unlock(sdp); | ||
193 | unlock_buffer(bd->bd_bh); | ||
98 | } | 194 | } |
99 | 195 | ||
100 | static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) | 196 | static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) |
@@ -117,8 +213,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) | |||
117 | struct buffer_head *bh; | 213 | struct buffer_head *bh; |
118 | struct gfs2_log_descriptor *ld; | 214 | struct gfs2_log_descriptor *ld; |
119 | struct gfs2_bufdata *bd1 = NULL, *bd2; | 215 | struct gfs2_bufdata *bd1 = NULL, *bd2; |
120 | unsigned int total = sdp->sd_log_num_buf; | 216 | unsigned int total; |
121 | unsigned int offset = BUF_OFFSET; | ||
122 | unsigned int limit; | 217 | unsigned int limit; |
123 | unsigned int num; | 218 | unsigned int num; |
124 | unsigned n; | 219 | unsigned n; |
@@ -127,22 +222,20 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) | |||
127 | limit = buf_limit(sdp); | 222 | limit = buf_limit(sdp); |
128 | /* for 4k blocks, limit = 503 */ | 223 | /* for 4k blocks, limit = 503 */ |
129 | 224 | ||
225 | gfs2_log_lock(sdp); | ||
226 | total = sdp->sd_log_num_buf; | ||
130 | bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list); | 227 | bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list); |
131 | while(total) { | 228 | while(total) { |
132 | num = total; | 229 | num = total; |
133 | if (total > limit) | 230 | if (total > limit) |
134 | num = limit; | 231 | num = limit; |
135 | bh = gfs2_log_get_buf(sdp); | 232 | gfs2_log_unlock(sdp); |
136 | ld = (struct gfs2_log_descriptor *)bh->b_data; | 233 | bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_METADATA); |
137 | ptr = (__be64 *)(bh->b_data + offset); | 234 | gfs2_log_lock(sdp); |
138 | ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); | 235 | ld = bh_log_desc(bh); |
139 | ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); | 236 | ptr = bh_log_ptr(bh); |
140 | ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); | ||
141 | ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_METADATA); | ||
142 | ld->ld_length = cpu_to_be32(num + 1); | 237 | ld->ld_length = cpu_to_be32(num + 1); |
143 | ld->ld_data1 = cpu_to_be32(num); | 238 | ld->ld_data1 = cpu_to_be32(num); |
144 | ld->ld_data2 = cpu_to_be32(0); | ||
145 | memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); | ||
146 | 239 | ||
147 | n = 0; | 240 | n = 0; |
148 | list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf, | 241 | list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf, |
@@ -152,21 +245,27 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp) | |||
152 | break; | 245 | break; |
153 | } | 246 | } |
154 | 247 | ||
155 | set_buffer_dirty(bh); | 248 | gfs2_log_unlock(sdp); |
156 | ll_rw_block(WRITE, 1, &bh); | 249 | submit_bh(WRITE, bh); |
250 | gfs2_log_lock(sdp); | ||
157 | 251 | ||
158 | n = 0; | 252 | n = 0; |
159 | list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf, | 253 | list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf, |
160 | bd_le.le_list) { | 254 | bd_le.le_list) { |
255 | get_bh(bd2->bd_bh); | ||
256 | gfs2_log_unlock(sdp); | ||
257 | lock_buffer(bd2->bd_bh); | ||
161 | bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); | 258 | bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); |
162 | set_buffer_dirty(bh); | 259 | submit_bh(WRITE, bh); |
163 | ll_rw_block(WRITE, 1, &bh); | 260 | gfs2_log_lock(sdp); |
164 | if (++n >= num) | 261 | if (++n >= num) |
165 | break; | 262 | break; |
166 | } | 263 | } |
167 | 264 | ||
265 | BUG_ON(total < num); | ||
168 | total -= num; | 266 | total -= num; |
169 | } | 267 | } |
268 | gfs2_log_unlock(sdp); | ||
170 | } | 269 | } |
171 | 270 | ||
172 | static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | 271 | static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) |
@@ -270,11 +369,8 @@ static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) | |||
270 | tr = current->journal_info; | 369 | tr = current->journal_info; |
271 | tr->tr_touched = 1; | 370 | tr->tr_touched = 1; |
272 | tr->tr_num_revoke++; | 371 | tr->tr_num_revoke++; |
273 | |||
274 | gfs2_log_lock(sdp); | ||
275 | sdp->sd_log_num_revoke++; | 372 | sdp->sd_log_num_revoke++; |
276 | list_add(&le->le_list, &sdp->sd_log_le_revoke); | 373 | list_add(&le->le_list, &sdp->sd_log_le_revoke); |
277 | gfs2_log_unlock(sdp); | ||
278 | } | 374 | } |
279 | 375 | ||
280 | static void revoke_lo_before_commit(struct gfs2_sbd *sdp) | 376 | static void revoke_lo_before_commit(struct gfs2_sbd *sdp) |
@@ -284,32 +380,25 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) | |||
284 | struct buffer_head *bh; | 380 | struct buffer_head *bh; |
285 | unsigned int offset; | 381 | unsigned int offset; |
286 | struct list_head *head = &sdp->sd_log_le_revoke; | 382 | struct list_head *head = &sdp->sd_log_le_revoke; |
287 | struct gfs2_revoke *rv; | 383 | struct gfs2_bufdata *bd; |
288 | 384 | ||
289 | if (!sdp->sd_log_num_revoke) | 385 | if (!sdp->sd_log_num_revoke) |
290 | return; | 386 | return; |
291 | 387 | ||
292 | bh = gfs2_log_get_buf(sdp); | 388 | bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_REVOKE); |
293 | ld = (struct gfs2_log_descriptor *)bh->b_data; | 389 | ld = bh_log_desc(bh); |
294 | ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); | ||
295 | ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); | ||
296 | ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); | ||
297 | ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_REVOKE); | ||
298 | ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke, | 390 | ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke, |
299 | sizeof(u64))); | 391 | sizeof(u64))); |
300 | ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke); | 392 | ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke); |
301 | ld->ld_data2 = cpu_to_be32(0); | ||
302 | memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); | ||
303 | offset = sizeof(struct gfs2_log_descriptor); | 393 | offset = sizeof(struct gfs2_log_descriptor); |
304 | 394 | ||
305 | while (!list_empty(head)) { | 395 | while (!list_empty(head)) { |
306 | rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list); | 396 | bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); |
307 | list_del_init(&rv->rv_le.le_list); | 397 | list_del_init(&bd->bd_le.le_list); |
308 | sdp->sd_log_num_revoke--; | 398 | sdp->sd_log_num_revoke--; |
309 | 399 | ||
310 | if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) { | 400 | if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) { |
311 | set_buffer_dirty(bh); | 401 | submit_bh(WRITE, bh); |
312 | ll_rw_block(WRITE, 1, &bh); | ||
313 | 402 | ||
314 | bh = gfs2_log_get_buf(sdp); | 403 | bh = gfs2_log_get_buf(sdp); |
315 | mh = (struct gfs2_meta_header *)bh->b_data; | 404 | mh = (struct gfs2_meta_header *)bh->b_data; |
@@ -319,15 +408,14 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) | |||
319 | offset = sizeof(struct gfs2_meta_header); | 408 | offset = sizeof(struct gfs2_meta_header); |
320 | } | 409 | } |
321 | 410 | ||
322 | *(__be64 *)(bh->b_data + offset) = cpu_to_be64(rv->rv_blkno); | 411 | *(__be64 *)(bh->b_data + offset) = cpu_to_be64(bd->bd_blkno); |
323 | kfree(rv); | 412 | kmem_cache_free(gfs2_bufdata_cachep, bd); |
324 | 413 | ||
325 | offset += sizeof(u64); | 414 | offset += sizeof(u64); |
326 | } | 415 | } |
327 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); | 416 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); |
328 | 417 | ||
329 | set_buffer_dirty(bh); | 418 | submit_bh(WRITE, bh); |
330 | ll_rw_block(WRITE, 1, &bh); | ||
331 | } | 419 | } |
332 | 420 | ||
333 | static void revoke_lo_before_scan(struct gfs2_jdesc *jd, | 421 | static void revoke_lo_before_scan(struct gfs2_jdesc *jd, |
@@ -466,222 +554,136 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) | |||
466 | struct address_space *mapping = bd->bd_bh->b_page->mapping; | 554 | struct address_space *mapping = bd->bd_bh->b_page->mapping; |
467 | struct gfs2_inode *ip = GFS2_I(mapping->host); | 555 | struct gfs2_inode *ip = GFS2_I(mapping->host); |
468 | 556 | ||
557 | lock_buffer(bd->bd_bh); | ||
469 | gfs2_log_lock(sdp); | 558 | gfs2_log_lock(sdp); |
470 | if (!list_empty(&bd->bd_list_tr)) { | 559 | if (!list_empty(&bd->bd_list_tr)) |
471 | gfs2_log_unlock(sdp); | 560 | goto out; |
472 | return; | ||
473 | } | ||
474 | tr->tr_touched = 1; | 561 | tr->tr_touched = 1; |
475 | if (gfs2_is_jdata(ip)) { | 562 | if (gfs2_is_jdata(ip)) { |
476 | tr->tr_num_buf++; | 563 | tr->tr_num_buf++; |
477 | list_add(&bd->bd_list_tr, &tr->tr_list_buf); | 564 | list_add(&bd->bd_list_tr, &tr->tr_list_buf); |
478 | } | 565 | } |
479 | gfs2_log_unlock(sdp); | ||
480 | if (!list_empty(&le->le_list)) | 566 | if (!list_empty(&le->le_list)) |
481 | return; | 567 | goto out; |
482 | 568 | ||
483 | gfs2_trans_add_gl(bd->bd_gl); | 569 | __glock_lo_add(sdp, &bd->bd_gl->gl_le); |
484 | if (gfs2_is_jdata(ip)) { | 570 | if (gfs2_is_jdata(ip)) { |
485 | sdp->sd_log_num_jdata++; | ||
486 | gfs2_pin(sdp, bd->bd_bh); | 571 | gfs2_pin(sdp, bd->bd_bh); |
487 | tr->tr_num_databuf_new++; | 572 | tr->tr_num_databuf_new++; |
573 | sdp->sd_log_num_databuf++; | ||
574 | list_add(&le->le_list, &sdp->sd_log_le_databuf); | ||
575 | } else { | ||
576 | list_add(&le->le_list, &sdp->sd_log_le_ordered); | ||
488 | } | 577 | } |
489 | gfs2_log_lock(sdp); | 578 | out: |
490 | sdp->sd_log_num_databuf++; | ||
491 | list_add(&le->le_list, &sdp->sd_log_le_databuf); | ||
492 | gfs2_log_unlock(sdp); | 579 | gfs2_log_unlock(sdp); |
580 | unlock_buffer(bd->bd_bh); | ||
493 | } | 581 | } |
494 | 582 | ||
495 | static int gfs2_check_magic(struct buffer_head *bh) | 583 | static void gfs2_check_magic(struct buffer_head *bh) |
496 | { | 584 | { |
497 | struct page *page = bh->b_page; | ||
498 | void *kaddr; | 585 | void *kaddr; |
499 | __be32 *ptr; | 586 | __be32 *ptr; |
500 | int rv = 0; | ||
501 | 587 | ||
502 | kaddr = kmap_atomic(page, KM_USER0); | 588 | clear_buffer_escaped(bh); |
589 | kaddr = kmap_atomic(bh->b_page, KM_USER0); | ||
503 | ptr = kaddr + bh_offset(bh); | 590 | ptr = kaddr + bh_offset(bh); |
504 | if (*ptr == cpu_to_be32(GFS2_MAGIC)) | 591 | if (*ptr == cpu_to_be32(GFS2_MAGIC)) |
505 | rv = 1; | 592 | set_buffer_escaped(bh); |
506 | kunmap_atomic(kaddr, KM_USER0); | 593 | kunmap_atomic(kaddr, KM_USER0); |
507 | |||
508 | return rv; | ||
509 | } | 594 | } |
510 | 595 | ||
511 | /** | 596 | static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh, |
512 | * databuf_lo_before_commit - Scan the data buffers, writing as we go | 597 | struct list_head *list, struct list_head *done, |
513 | * | 598 | unsigned int n) |
514 | * Here we scan through the lists of buffers and make the assumption | ||
515 | * that any buffer thats been pinned is being journaled, and that | ||
516 | * any unpinned buffer is an ordered write data buffer and therefore | ||
517 | * will be written back rather than journaled. | ||
518 | */ | ||
519 | static void databuf_lo_before_commit(struct gfs2_sbd *sdp) | ||
520 | { | 599 | { |
521 | LIST_HEAD(started); | 600 | struct buffer_head *bh1; |
522 | struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt; | ||
523 | struct buffer_head *bh = NULL,*bh1 = NULL; | ||
524 | struct gfs2_log_descriptor *ld; | 601 | struct gfs2_log_descriptor *ld; |
525 | unsigned int limit; | 602 | struct gfs2_bufdata *bd; |
526 | unsigned int total_dbuf; | 603 | __be64 *ptr; |
527 | unsigned int total_jdata = sdp->sd_log_num_jdata; | 604 | |
528 | unsigned int num, n; | 605 | if (!bh) |
529 | __be64 *ptr = NULL; | 606 | return; |
530 | 607 | ||
531 | limit = databuf_limit(sdp); | 608 | ld = bh_log_desc(bh); |
609 | ld->ld_length = cpu_to_be32(n + 1); | ||
610 | ld->ld_data1 = cpu_to_be32(n); | ||
532 | 611 | ||
533 | /* | 612 | ptr = bh_log_ptr(bh); |
534 | * Start writing ordered buffers, write journaled buffers | 613 | |
535 | * into the log along with a header | 614 | get_bh(bh); |
536 | */ | 615 | submit_bh(WRITE, bh); |
537 | gfs2_log_lock(sdp); | 616 | gfs2_log_lock(sdp); |
538 | total_dbuf = sdp->sd_log_num_databuf; | 617 | while(!list_empty(list)) { |
539 | bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf, | 618 | bd = list_entry(list->next, struct gfs2_bufdata, bd_le.le_list); |
540 | bd_le.le_list); | 619 | list_move_tail(&bd->bd_le.le_list, done); |
541 | while(total_dbuf) { | 620 | get_bh(bd->bd_bh); |
542 | num = total_jdata; | 621 | while (be64_to_cpu(*ptr) != bd->bd_bh->b_blocknr) { |
543 | if (num > limit) | 622 | gfs2_log_incr_head(sdp); |
544 | num = limit; | 623 | ptr += 2; |
545 | n = 0; | ||
546 | list_for_each_entry_safe_continue(bd1, bdt, | ||
547 | &sdp->sd_log_le_databuf, | ||
548 | bd_le.le_list) { | ||
549 | /* store off the buffer head in a local ptr since | ||
550 | * gfs2_bufdata might change when we drop the log lock | ||
551 | */ | ||
552 | bh1 = bd1->bd_bh; | ||
553 | |||
554 | /* An ordered write buffer */ | ||
555 | if (bh1 && !buffer_pinned(bh1)) { | ||
556 | list_move(&bd1->bd_le.le_list, &started); | ||
557 | if (bd1 == bd2) { | ||
558 | bd2 = NULL; | ||
559 | bd2 = list_prepare_entry(bd2, | ||
560 | &sdp->sd_log_le_databuf, | ||
561 | bd_le.le_list); | ||
562 | } | ||
563 | total_dbuf--; | ||
564 | if (bh1) { | ||
565 | if (buffer_dirty(bh1)) { | ||
566 | get_bh(bh1); | ||
567 | |||
568 | gfs2_log_unlock(sdp); | ||
569 | |||
570 | ll_rw_block(SWRITE, 1, &bh1); | ||
571 | brelse(bh1); | ||
572 | |||
573 | gfs2_log_lock(sdp); | ||
574 | } | ||
575 | continue; | ||
576 | } | ||
577 | continue; | ||
578 | } else if (bh1) { /* A journaled buffer */ | ||
579 | int magic; | ||
580 | gfs2_log_unlock(sdp); | ||
581 | if (!bh) { | ||
582 | bh = gfs2_log_get_buf(sdp); | ||
583 | ld = (struct gfs2_log_descriptor *) | ||
584 | bh->b_data; | ||
585 | ptr = (__be64 *)(bh->b_data + | ||
586 | DATABUF_OFFSET); | ||
587 | ld->ld_header.mh_magic = | ||
588 | cpu_to_be32(GFS2_MAGIC); | ||
589 | ld->ld_header.mh_type = | ||
590 | cpu_to_be32(GFS2_METATYPE_LD); | ||
591 | ld->ld_header.mh_format = | ||
592 | cpu_to_be32(GFS2_FORMAT_LD); | ||
593 | ld->ld_type = | ||
594 | cpu_to_be32(GFS2_LOG_DESC_JDATA); | ||
595 | ld->ld_length = cpu_to_be32(num + 1); | ||
596 | ld->ld_data1 = cpu_to_be32(num); | ||
597 | ld->ld_data2 = cpu_to_be32(0); | ||
598 | memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); | ||
599 | } | ||
600 | magic = gfs2_check_magic(bh1); | ||
601 | *ptr++ = cpu_to_be64(bh1->b_blocknr); | ||
602 | *ptr++ = cpu_to_be64((__u64)magic); | ||
603 | clear_buffer_escaped(bh1); | ||
604 | if (unlikely(magic != 0)) | ||
605 | set_buffer_escaped(bh1); | ||
606 | gfs2_log_lock(sdp); | ||
607 | if (++n >= num) | ||
608 | break; | ||
609 | } else if (!bh1) { | ||
610 | total_dbuf--; | ||
611 | sdp->sd_log_num_databuf--; | ||
612 | list_del_init(&bd1->bd_le.le_list); | ||
613 | if (bd1 == bd2) { | ||
614 | bd2 = NULL; | ||
615 | bd2 = list_prepare_entry(bd2, | ||
616 | &sdp->sd_log_le_databuf, | ||
617 | bd_le.le_list); | ||
618 | } | ||
619 | kmem_cache_free(gfs2_bufdata_cachep, bd1); | ||
620 | } | ||
621 | } | 624 | } |
622 | gfs2_log_unlock(sdp); | 625 | gfs2_log_unlock(sdp); |
623 | if (bh) { | 626 | lock_buffer(bd->bd_bh); |
624 | set_buffer_mapped(bh); | 627 | if (buffer_escaped(bd->bd_bh)) { |
625 | set_buffer_dirty(bh); | 628 | void *kaddr; |
626 | ll_rw_block(WRITE, 1, &bh); | 629 | bh1 = gfs2_log_get_buf(sdp); |
627 | bh = NULL; | 630 | kaddr = kmap_atomic(bd->bd_bh->b_page, KM_USER0); |
631 | memcpy(bh1->b_data, kaddr + bh_offset(bd->bd_bh), | ||
632 | bh1->b_size); | ||
633 | kunmap_atomic(kaddr, KM_USER0); | ||
634 | *(__be32 *)bh1->b_data = 0; | ||
635 | clear_buffer_escaped(bd->bd_bh); | ||
636 | unlock_buffer(bd->bd_bh); | ||
637 | brelse(bd->bd_bh); | ||
638 | } else { | ||
639 | bh1 = gfs2_log_fake_buf(sdp, bd->bd_bh); | ||
628 | } | 640 | } |
629 | n = 0; | 641 | submit_bh(WRITE, bh1); |
630 | gfs2_log_lock(sdp); | 642 | gfs2_log_lock(sdp); |
631 | list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf, | 643 | ptr += 2; |
632 | bd_le.le_list) { | ||
633 | if (!bd2->bd_bh) | ||
634 | continue; | ||
635 | /* copy buffer if it needs escaping */ | ||
636 | gfs2_log_unlock(sdp); | ||
637 | if (unlikely(buffer_escaped(bd2->bd_bh))) { | ||
638 | void *kaddr; | ||
639 | struct page *page = bd2->bd_bh->b_page; | ||
640 | bh = gfs2_log_get_buf(sdp); | ||
641 | kaddr = kmap_atomic(page, KM_USER0); | ||
642 | memcpy(bh->b_data, | ||
643 | kaddr + bh_offset(bd2->bd_bh), | ||
644 | sdp->sd_sb.sb_bsize); | ||
645 | kunmap_atomic(kaddr, KM_USER0); | ||
646 | *(__be32 *)bh->b_data = 0; | ||
647 | } else { | ||
648 | bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); | ||
649 | } | ||
650 | set_buffer_dirty(bh); | ||
651 | ll_rw_block(WRITE, 1, &bh); | ||
652 | gfs2_log_lock(sdp); | ||
653 | if (++n >= num) | ||
654 | break; | ||
655 | } | ||
656 | bh = NULL; | ||
657 | BUG_ON(total_dbuf < num); | ||
658 | total_dbuf -= num; | ||
659 | total_jdata -= num; | ||
660 | } | 644 | } |
661 | gfs2_log_unlock(sdp); | 645 | gfs2_log_unlock(sdp); |
646 | brelse(bh); | ||
647 | } | ||
662 | 648 | ||
663 | /* Wait on all ordered buffers */ | 649 | /** |
664 | while (!list_empty(&started)) { | 650 | * databuf_lo_before_commit - Scan the data buffers, writing as we go |
665 | gfs2_log_lock(sdp); | 651 | * |
666 | bd1 = list_entry(started.next, struct gfs2_bufdata, | 652 | */ |
667 | bd_le.le_list); | ||
668 | list_del_init(&bd1->bd_le.le_list); | ||
669 | sdp->sd_log_num_databuf--; | ||
670 | bh = bd1->bd_bh; | ||
671 | if (bh) { | ||
672 | bh->b_private = NULL; | ||
673 | get_bh(bh); | ||
674 | gfs2_log_unlock(sdp); | ||
675 | wait_on_buffer(bh); | ||
676 | brelse(bh); | ||
677 | } else | ||
678 | gfs2_log_unlock(sdp); | ||
679 | 653 | ||
680 | kmem_cache_free(gfs2_bufdata_cachep, bd1); | 654 | static void databuf_lo_before_commit(struct gfs2_sbd *sdp) |
681 | } | 655 | { |
656 | struct gfs2_bufdata *bd = NULL; | ||
657 | struct buffer_head *bh = NULL; | ||
658 | unsigned int n = 0; | ||
659 | __be64 *ptr = NULL, *end = NULL; | ||
660 | LIST_HEAD(processed); | ||
661 | LIST_HEAD(in_progress); | ||
682 | 662 | ||
683 | /* We've removed all the ordered write bufs here, so only jdata left */ | 663 | gfs2_log_lock(sdp); |
684 | gfs2_assert_warn(sdp, sdp->sd_log_num_databuf == sdp->sd_log_num_jdata); | 664 | while (!list_empty(&sdp->sd_log_le_databuf)) { |
665 | if (ptr == end) { | ||
666 | gfs2_log_unlock(sdp); | ||
667 | gfs2_write_blocks(sdp, bh, &in_progress, &processed, n); | ||
668 | n = 0; | ||
669 | bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_JDATA); | ||
670 | ptr = bh_log_ptr(bh); | ||
671 | end = bh_ptr_end(bh) - 1; | ||
672 | gfs2_log_lock(sdp); | ||
673 | continue; | ||
674 | } | ||
675 | bd = list_entry(sdp->sd_log_le_databuf.next, struct gfs2_bufdata, bd_le.le_list); | ||
676 | list_move_tail(&bd->bd_le.le_list, &in_progress); | ||
677 | gfs2_check_magic(bd->bd_bh); | ||
678 | *ptr++ = cpu_to_be64(bd->bd_bh->b_blocknr); | ||
679 | *ptr++ = cpu_to_be64(buffer_escaped(bh) ? 1 : 0); | ||
680 | n++; | ||
681 | } | ||
682 | gfs2_log_unlock(sdp); | ||
683 | gfs2_write_blocks(sdp, bh, &in_progress, &processed, n); | ||
684 | gfs2_log_lock(sdp); | ||
685 | list_splice(&processed, &sdp->sd_log_le_databuf); | ||
686 | gfs2_log_unlock(sdp); | ||
685 | } | 687 | } |
686 | 688 | ||
687 | static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, | 689 | static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, |
@@ -765,11 +767,9 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |||
765 | bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); | 767 | bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); |
766 | list_del_init(&bd->bd_le.le_list); | 768 | list_del_init(&bd->bd_le.le_list); |
767 | sdp->sd_log_num_databuf--; | 769 | sdp->sd_log_num_databuf--; |
768 | sdp->sd_log_num_jdata--; | ||
769 | gfs2_unpin(sdp, bd->bd_bh, ai); | 770 | gfs2_unpin(sdp, bd->bd_bh, ai); |
770 | } | 771 | } |
771 | gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf); | 772 | gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf); |
772 | gfs2_assert_warn(sdp, !sdp->sd_log_num_jdata); | ||
773 | } | 773 | } |
774 | 774 | ||
775 | 775 | ||
@@ -817,10 +817,10 @@ const struct gfs2_log_operations gfs2_databuf_lops = { | |||
817 | 817 | ||
818 | const struct gfs2_log_operations *gfs2_log_ops[] = { | 818 | const struct gfs2_log_operations *gfs2_log_ops[] = { |
819 | &gfs2_glock_lops, | 819 | &gfs2_glock_lops, |
820 | &gfs2_databuf_lops, | ||
820 | &gfs2_buf_lops, | 821 | &gfs2_buf_lops, |
821 | &gfs2_revoke_lops, | ||
822 | &gfs2_rg_lops, | 822 | &gfs2_rg_lops, |
823 | &gfs2_databuf_lops, | 823 | &gfs2_revoke_lops, |
824 | NULL, | 824 | NULL, |
825 | }; | 825 | }; |
826 | 826 | ||