]>
Commit | Line | Data |
---|---|---|
b3b94faa DT |
1 | /* |
2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
3a8a9a10 | 3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
b3b94faa DT |
4 | * |
5 | * This copyrighted material is made available to anyone wishing to use, | |
6 | * modify, copy, or redistribute it subject to the terms and conditions | |
e9fc2aa0 | 7 | * of the GNU General Public License version 2. |
b3b94faa DT |
8 | */ |
9 | ||
10 | #include <linux/sched.h> | |
11 | #include <linux/slab.h> | |
12 | #include <linux/spinlock.h> | |
13 | #include <linux/completion.h> | |
14 | #include <linux/buffer_head.h> | |
5c676f6d | 15 | #include <linux/gfs2_ondisk.h> |
c969f58c SW |
16 | #include <linux/bio.h> |
17 | #include <linux/fs.h> | |
b3b94faa DT |
18 | |
19 | #include "gfs2.h" | |
5c676f6d | 20 | #include "incore.h" |
2332c443 | 21 | #include "inode.h" |
b3b94faa DT |
22 | #include "glock.h" |
23 | #include "log.h" | |
24 | #include "lops.h" | |
25 | #include "meta_io.h" | |
26 | #include "recovery.h" | |
27 | #include "rgrp.h" | |
28 | #include "trans.h" | |
5c676f6d | 29 | #include "util.h" |
63997775 | 30 | #include "trace_gfs2.h" |
b3b94faa | 31 | |
9b9107a5 SW |
32 | /** |
33 | * gfs2_pin - Pin a buffer in memory | |
34 | * @sdp: The superblock | |
35 | * @bh: The buffer to be pinned | |
36 | * | |
37 | * The log lock must be held when calling this function | |
38 | */ | |
39 | static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) | |
40 | { | |
41 | struct gfs2_bufdata *bd; | |
42 | ||
29687a2a | 43 | BUG_ON(!current->journal_info); |
9b9107a5 SW |
44 | |
45 | clear_buffer_dirty(bh); | |
46 | if (test_set_buffer_pinned(bh)) | |
47 | gfs2_assert_withdraw(sdp, 0); | |
48 | if (!buffer_uptodate(bh)) | |
49 | gfs2_io_error_bh(sdp, bh); | |
50 | bd = bh->b_private; | |
51 | /* If this buffer is in the AIL and it has already been written | |
52 | * to in-place disk block, remove it from the AIL. | |
53 | */ | |
c618e87a | 54 | spin_lock(&sdp->sd_ail_lock); |
9b9107a5 SW |
55 | if (bd->bd_ail) |
56 | list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list); | |
c618e87a | 57 | spin_unlock(&sdp->sd_ail_lock); |
9b9107a5 | 58 | get_bh(bh); |
5e687eac | 59 | atomic_inc(&sdp->sd_log_pinned); |
63997775 | 60 | trace_gfs2_pin(bd, 1); |
9b9107a5 SW |
61 | } |
62 | ||
7c9ca621 BP |
63 | static bool buffer_is_rgrp(const struct gfs2_bufdata *bd) |
64 | { | |
65 | return bd->bd_gl->gl_name.ln_type == LM_TYPE_RGRP; | |
66 | } | |
67 | ||
68 | static void maybe_release_space(struct gfs2_bufdata *bd) | |
69 | { | |
70 | struct gfs2_glock *gl = bd->bd_gl; | |
71 | struct gfs2_sbd *sdp = gl->gl_sbd; | |
72 | struct gfs2_rgrpd *rgd = gl->gl_object; | |
73 | unsigned int index = bd->bd_bh->b_blocknr - gl->gl_name.ln_number; | |
74 | struct gfs2_bitmap *bi = rgd->rd_bits + index; | |
75 | ||
76 | if (bi->bi_clone == 0) | |
77 | return; | |
78 | if (sdp->sd_args.ar_discard) | |
79 | gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi); | |
80 | memcpy(bi->bi_clone + bi->bi_offset, | |
81 | bd->bd_bh->b_data + bi->bi_offset, bi->bi_len); | |
82 | clear_bit(GBF_FULL, &bi->bi_flags); | |
83 | rgd->rd_free_clone = rgd->rd_free; | |
84 | } | |
85 | ||
9b9107a5 SW |
86 | /** |
87 | * gfs2_unpin - Unpin a buffer | |
88 | * @sdp: the filesystem the buffer belongs to | |
89 | * @bh: The buffer to unpin | |
90 | * @ai: | |
29687a2a | 91 | * @flags: The inode dirty flags |
9b9107a5 SW |
92 | * |
93 | */ | |
94 | ||
95 | static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, | |
96 | struct gfs2_ail *ai) | |
97 | { | |
98 | struct gfs2_bufdata *bd = bh->b_private; | |
99 | ||
29687a2a SW |
100 | BUG_ON(!buffer_uptodate(bh)); |
101 | BUG_ON(!buffer_pinned(bh)); | |
9b9107a5 SW |
102 | |
103 | lock_buffer(bh); | |
104 | mark_buffer_dirty(bh); | |
105 | clear_buffer_pinned(bh); | |
106 | ||
7c9ca621 BP |
107 | if (buffer_is_rgrp(bd)) |
108 | maybe_release_space(bd); | |
109 | ||
d6a079e8 | 110 | spin_lock(&sdp->sd_ail_lock); |
9b9107a5 SW |
111 | if (bd->bd_ail) { |
112 | list_del(&bd->bd_ail_st_list); | |
113 | brelse(bh); | |
114 | } else { | |
115 | struct gfs2_glock *gl = bd->bd_gl; | |
116 | list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list); | |
117 | atomic_inc(&gl->gl_ail_count); | |
118 | } | |
119 | bd->bd_ail = ai; | |
120 | list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); | |
d6a079e8 DC |
121 | spin_unlock(&sdp->sd_ail_lock); |
122 | ||
29687a2a | 123 | clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); |
63997775 | 124 | trace_gfs2_pin(bd, 0); |
9b9107a5 | 125 | unlock_buffer(bh); |
5e687eac | 126 | atomic_dec(&sdp->sd_log_pinned); |
9b9107a5 SW |
127 | } |
128 | ||
16615be1 SW |
129 | |
130 | static inline struct gfs2_log_descriptor *bh_log_desc(struct buffer_head *bh) | |
131 | { | |
132 | return (struct gfs2_log_descriptor *)bh->b_data; | |
133 | } | |
134 | ||
135 | static inline __be64 *bh_log_ptr(struct buffer_head *bh) | |
136 | { | |
137 | struct gfs2_log_descriptor *ld = bh_log_desc(bh); | |
138 | return (__force __be64 *)(ld + 1); | |
139 | } | |
140 | ||
141 | static inline __be64 *bh_ptr_end(struct buffer_head *bh) | |
142 | { | |
143 | return (__force __be64 *)(bh->b_data + bh->b_size); | |
144 | } | |
145 | ||
47ac5537 SW |
146 | /** |
147 | * gfs2_log_write_endio - End of I/O for a log buffer | |
148 | * @bh: The buffer head | |
149 | * @uptodate: I/O Status | |
150 | * | |
151 | */ | |
152 | ||
153 | static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate) | |
154 | { | |
155 | struct gfs2_sbd *sdp = bh->b_private; | |
156 | bh->b_private = NULL; | |
157 | ||
158 | end_buffer_write_sync(bh, uptodate); | |
159 | if (atomic_dec_and_test(&sdp->sd_log_in_flight)) | |
160 | wake_up(&sdp->sd_log_flush_wait); | |
161 | } | |
162 | ||
163 | /** | |
164 | * gfs2_log_get_buf - Get and initialize a buffer to use for log control data | |
165 | * @sdp: The GFS2 superblock | |
166 | * | |
167 | * tReturns: the buffer_head | |
168 | */ | |
169 | ||
170 | static struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) | |
171 | { | |
172 | u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head); | |
173 | struct buffer_head *bh; | |
174 | ||
175 | bh = sb_getblk(sdp->sd_vfs, blkno); | |
176 | lock_buffer(bh); | |
177 | memset(bh->b_data, 0, bh->b_size); | |
178 | set_buffer_uptodate(bh); | |
179 | clear_buffer_dirty(bh); | |
180 | gfs2_log_incr_head(sdp); | |
181 | atomic_inc(&sdp->sd_log_in_flight); | |
182 | bh->b_private = sdp; | |
183 | bh->b_end_io = gfs2_log_write_endio; | |
184 | ||
185 | return bh; | |
186 | } | |
187 | ||
188 | /** | |
189 | * gfs2_fake_write_endio - | |
190 | * @bh: The buffer head | |
191 | * @uptodate: The I/O Status | |
192 | * | |
193 | */ | |
194 | ||
195 | static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate) | |
196 | { | |
197 | struct buffer_head *real_bh = bh->b_private; | |
198 | struct gfs2_bufdata *bd = real_bh->b_private; | |
199 | struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd; | |
200 | ||
201 | end_buffer_write_sync(bh, uptodate); | |
202 | free_buffer_head(bh); | |
203 | unlock_buffer(real_bh); | |
204 | brelse(real_bh); | |
205 | if (atomic_dec_and_test(&sdp->sd_log_in_flight)) | |
206 | wake_up(&sdp->sd_log_flush_wait); | |
207 | } | |
208 | ||
209 | /** | |
210 | * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log | |
211 | * @sdp: the filesystem | |
212 | * @data: the data the buffer_head should point to | |
213 | * | |
214 | * Returns: the log buffer descriptor | |
215 | */ | |
216 | ||
217 | static struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, | |
218 | struct buffer_head *real) | |
219 | { | |
220 | u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head); | |
221 | struct buffer_head *bh; | |
222 | ||
223 | bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); | |
224 | atomic_set(&bh->b_count, 1); | |
225 | bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock); | |
226 | set_bh_page(bh, real->b_page, bh_offset(real)); | |
227 | bh->b_blocknr = blkno; | |
228 | bh->b_size = sdp->sd_sb.sb_bsize; | |
229 | bh->b_bdev = sdp->sd_vfs->s_bdev; | |
230 | bh->b_private = real; | |
231 | bh->b_end_io = gfs2_fake_write_endio; | |
232 | ||
233 | gfs2_log_incr_head(sdp); | |
234 | atomic_inc(&sdp->sd_log_in_flight); | |
235 | ||
236 | return bh; | |
237 | } | |
16615be1 SW |
238 | |
239 | static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type) | |
240 | { | |
241 | struct buffer_head *bh = gfs2_log_get_buf(sdp); | |
242 | struct gfs2_log_descriptor *ld = bh_log_desc(bh); | |
243 | ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC); | |
244 | ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD); | |
245 | ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD); | |
246 | ld->ld_type = cpu_to_be32(ld_type); | |
247 | ld->ld_length = 0; | |
248 | ld->ld_data1 = 0; | |
249 | ld->ld_data2 = 0; | |
250 | memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved)); | |
251 | return bh; | |
252 | } | |
253 | ||
b3b94faa DT |
254 | static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) |
255 | { | |
256 | struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); | |
0ab7d13f | 257 | struct gfs2_meta_header *mh; |
b3b94faa DT |
258 | struct gfs2_trans *tr; |
259 | ||
9b9107a5 | 260 | lock_buffer(bd->bd_bh); |
8bd95727 | 261 | gfs2_log_lock(sdp); |
9b9107a5 SW |
262 | if (!list_empty(&bd->bd_list_tr)) |
263 | goto out; | |
5c676f6d | 264 | tr = current->journal_info; |
b3b94faa DT |
265 | tr->tr_touched = 1; |
266 | tr->tr_num_buf++; | |
267 | list_add(&bd->bd_list_tr, &tr->tr_list_buf); | |
b3b94faa | 268 | if (!list_empty(&le->le_list)) |
9b9107a5 | 269 | goto out; |
2bcd610d SW |
270 | set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); |
271 | set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); | |
b3b94faa | 272 | gfs2_meta_check(sdp, bd->bd_bh); |
a98ab220 | 273 | gfs2_pin(sdp, bd->bd_bh); |
0ab7d13f SW |
274 | mh = (struct gfs2_meta_header *)bd->bd_bh->b_data; |
275 | mh->__pad0 = cpu_to_be64(0); | |
276 | mh->mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); | |
b3b94faa DT |
277 | sdp->sd_log_num_buf++; |
278 | list_add(&le->le_list, &sdp->sd_log_le_buf); | |
b3b94faa | 279 | tr->tr_num_buf_new++; |
9b9107a5 SW |
280 | out: |
281 | gfs2_log_unlock(sdp); | |
282 | unlock_buffer(bd->bd_bh); | |
b3b94faa DT |
283 | } |
284 | ||
b3b94faa DT |
285 | static void buf_lo_before_commit(struct gfs2_sbd *sdp) |
286 | { | |
287 | struct buffer_head *bh; | |
288 | struct gfs2_log_descriptor *ld; | |
289 | struct gfs2_bufdata *bd1 = NULL, *bd2; | |
905d2aef | 290 | unsigned int total; |
b3b94faa DT |
291 | unsigned int limit; |
292 | unsigned int num; | |
293 | unsigned n; | |
294 | __be64 *ptr; | |
295 | ||
2332c443 | 296 | limit = buf_limit(sdp); |
b3b94faa DT |
297 | /* for 4k blocks, limit = 503 */ |
298 | ||
905d2aef BP |
299 | gfs2_log_lock(sdp); |
300 | total = sdp->sd_log_num_buf; | |
b3b94faa DT |
301 | bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list); |
302 | while(total) { | |
303 | num = total; | |
304 | if (total > limit) | |
305 | num = limit; | |
905d2aef | 306 | gfs2_log_unlock(sdp); |
16615be1 | 307 | bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_METADATA); |
905d2aef | 308 | gfs2_log_lock(sdp); |
16615be1 SW |
309 | ld = bh_log_desc(bh); |
310 | ptr = bh_log_ptr(bh); | |
b3b94faa DT |
311 | ld->ld_length = cpu_to_be32(num + 1); |
312 | ld->ld_data1 = cpu_to_be32(num); | |
b3b94faa DT |
313 | |
314 | n = 0; | |
568f4c96 SW |
315 | list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf, |
316 | bd_le.le_list) { | |
b3b94faa DT |
317 | *ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr); |
318 | if (++n >= num) | |
319 | break; | |
320 | } | |
321 | ||
905d2aef | 322 | gfs2_log_unlock(sdp); |
721a9602 | 323 | submit_bh(WRITE_SYNC, bh); |
905d2aef | 324 | gfs2_log_lock(sdp); |
b3b94faa DT |
325 | |
326 | n = 0; | |
568f4c96 SW |
327 | list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf, |
328 | bd_le.le_list) { | |
16615be1 | 329 | get_bh(bd2->bd_bh); |
905d2aef | 330 | gfs2_log_unlock(sdp); |
16615be1 | 331 | lock_buffer(bd2->bd_bh); |
b3b94faa | 332 | bh = gfs2_log_fake_buf(sdp, bd2->bd_bh); |
721a9602 | 333 | submit_bh(WRITE_SYNC, bh); |
905d2aef | 334 | gfs2_log_lock(sdp); |
b3b94faa DT |
335 | if (++n >= num) |
336 | break; | |
337 | } | |
338 | ||
905d2aef | 339 | BUG_ON(total < num); |
b3b94faa DT |
340 | total -= num; |
341 | } | |
905d2aef | 342 | gfs2_log_unlock(sdp); |
b3b94faa DT |
343 | } |
344 | ||
345 | static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |
346 | { | |
347 | struct list_head *head = &sdp->sd_log_le_buf; | |
348 | struct gfs2_bufdata *bd; | |
349 | ||
350 | while (!list_empty(head)) { | |
351 | bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); | |
352 | list_del_init(&bd->bd_le.le_list); | |
353 | sdp->sd_log_num_buf--; | |
354 | ||
a98ab220 | 355 | gfs2_unpin(sdp, bd->bd_bh, ai); |
b3b94faa DT |
356 | } |
357 | gfs2_assert_warn(sdp, !sdp->sd_log_num_buf); | |
358 | } | |
359 | ||
360 | static void buf_lo_before_scan(struct gfs2_jdesc *jd, | |
55167622 | 361 | struct gfs2_log_header_host *head, int pass) |
b3b94faa | 362 | { |
feaa7bba | 363 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
b3b94faa DT |
364 | |
365 | if (pass != 0) | |
366 | return; | |
367 | ||
368 | sdp->sd_found_blocks = 0; | |
369 | sdp->sd_replayed_blocks = 0; | |
370 | } | |
371 | ||
372 | static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, | |
373 | struct gfs2_log_descriptor *ld, __be64 *ptr, | |
374 | int pass) | |
375 | { | |
feaa7bba SW |
376 | struct gfs2_inode *ip = GFS2_I(jd->jd_inode); |
377 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); | |
5c676f6d | 378 | struct gfs2_glock *gl = ip->i_gl; |
b3b94faa DT |
379 | unsigned int blks = be32_to_cpu(ld->ld_data1); |
380 | struct buffer_head *bh_log, *bh_ip; | |
cd915493 | 381 | u64 blkno; |
b3b94faa DT |
382 | int error = 0; |
383 | ||
384 | if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_METADATA) | |
385 | return 0; | |
386 | ||
387 | gfs2_replay_incr_blk(sdp, &start); | |
388 | ||
389 | for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) { | |
390 | blkno = be64_to_cpu(*ptr++); | |
391 | ||
392 | sdp->sd_found_blocks++; | |
393 | ||
394 | if (gfs2_revoke_check(sdp, blkno, start)) | |
395 | continue; | |
396 | ||
397 | error = gfs2_replay_read_block(jd, start, &bh_log); | |
82ffa516 SW |
398 | if (error) |
399 | return error; | |
b3b94faa DT |
400 | |
401 | bh_ip = gfs2_meta_new(gl, blkno); | |
402 | memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size); | |
403 | ||
404 | if (gfs2_meta_check(sdp, bh_ip)) | |
405 | error = -EIO; | |
406 | else | |
407 | mark_buffer_dirty(bh_ip); | |
408 | ||
409 | brelse(bh_log); | |
410 | brelse(bh_ip); | |
411 | ||
412 | if (error) | |
413 | break; | |
414 | ||
415 | sdp->sd_replayed_blocks++; | |
416 | } | |
417 | ||
418 | return error; | |
419 | } | |
420 | ||
421 | static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) | |
422 | { | |
feaa7bba SW |
423 | struct gfs2_inode *ip = GFS2_I(jd->jd_inode); |
424 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); | |
b3b94faa DT |
425 | |
426 | if (error) { | |
7276b3b0 | 427 | gfs2_meta_sync(ip->i_gl); |
b3b94faa DT |
428 | return; |
429 | } | |
430 | if (pass != 1) | |
431 | return; | |
432 | ||
7276b3b0 | 433 | gfs2_meta_sync(ip->i_gl); |
b3b94faa DT |
434 | |
435 | fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n", | |
436 | jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); | |
437 | } | |
438 | ||
439 | static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) | |
440 | { | |
f42ab085 SW |
441 | struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); |
442 | struct gfs2_glock *gl = bd->bd_gl; | |
b3b94faa DT |
443 | struct gfs2_trans *tr; |
444 | ||
5c676f6d | 445 | tr = current->journal_info; |
b3b94faa DT |
446 | tr->tr_touched = 1; |
447 | tr->tr_num_revoke++; | |
b3b94faa | 448 | sdp->sd_log_num_revoke++; |
f42ab085 SW |
449 | atomic_inc(&gl->gl_revokes); |
450 | set_bit(GLF_LFLUSH, &gl->gl_flags); | |
b3b94faa | 451 | list_add(&le->le_list, &sdp->sd_log_le_revoke); |
b3b94faa DT |
452 | } |
453 | ||
454 | static void revoke_lo_before_commit(struct gfs2_sbd *sdp) | |
455 | { | |
456 | struct gfs2_log_descriptor *ld; | |
457 | struct gfs2_meta_header *mh; | |
458 | struct buffer_head *bh; | |
459 | unsigned int offset; | |
460 | struct list_head *head = &sdp->sd_log_le_revoke; | |
82e86087 | 461 | struct gfs2_bufdata *bd; |
b3b94faa DT |
462 | |
463 | if (!sdp->sd_log_num_revoke) | |
464 | return; | |
465 | ||
16615be1 SW |
466 | bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_REVOKE); |
467 | ld = bh_log_desc(bh); | |
568f4c96 | 468 | ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke, |
cd915493 | 469 | sizeof(u64))); |
b3b94faa | 470 | ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke); |
b3b94faa DT |
471 | offset = sizeof(struct gfs2_log_descriptor); |
472 | ||
f42ab085 | 473 | list_for_each_entry(bd, head, bd_le.le_list) { |
b3b94faa DT |
474 | sdp->sd_log_num_revoke--; |
475 | ||
cd915493 | 476 | if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) { |
721a9602 | 477 | submit_bh(WRITE_SYNC, bh); |
b3b94faa DT |
478 | |
479 | bh = gfs2_log_get_buf(sdp); | |
480 | mh = (struct gfs2_meta_header *)bh->b_data; | |
481 | mh->mh_magic = cpu_to_be32(GFS2_MAGIC); | |
e3167ded SW |
482 | mh->mh_type = cpu_to_be32(GFS2_METATYPE_LB); |
483 | mh->mh_format = cpu_to_be32(GFS2_FORMAT_LB); | |
b3b94faa DT |
484 | offset = sizeof(struct gfs2_meta_header); |
485 | } | |
486 | ||
82e86087 | 487 | *(__be64 *)(bh->b_data + offset) = cpu_to_be64(bd->bd_blkno); |
cd915493 | 488 | offset += sizeof(u64); |
b3b94faa DT |
489 | } |
490 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); | |
491 | ||
721a9602 | 492 | submit_bh(WRITE_SYNC, bh); |
b3b94faa DT |
493 | } |
494 | ||
f42ab085 SW |
495 | static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) |
496 | { | |
497 | struct list_head *head = &sdp->sd_log_le_revoke; | |
498 | struct gfs2_bufdata *bd; | |
499 | struct gfs2_glock *gl; | |
500 | ||
501 | while (!list_empty(head)) { | |
502 | bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); | |
503 | list_del_init(&bd->bd_le.le_list); | |
504 | gl = bd->bd_gl; | |
505 | atomic_dec(&gl->gl_revokes); | |
506 | clear_bit(GLF_LFLUSH, &gl->gl_flags); | |
507 | kmem_cache_free(gfs2_bufdata_cachep, bd); | |
508 | } | |
509 | } | |
510 | ||
b3b94faa | 511 | static void revoke_lo_before_scan(struct gfs2_jdesc *jd, |
55167622 | 512 | struct gfs2_log_header_host *head, int pass) |
b3b94faa | 513 | { |
feaa7bba | 514 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
b3b94faa DT |
515 | |
516 | if (pass != 0) | |
517 | return; | |
518 | ||
519 | sdp->sd_found_revokes = 0; | |
520 | sdp->sd_replay_tail = head->lh_tail; | |
521 | } | |
522 | ||
523 | static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, | |
524 | struct gfs2_log_descriptor *ld, __be64 *ptr, | |
525 | int pass) | |
526 | { | |
feaa7bba | 527 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
b3b94faa DT |
528 | unsigned int blks = be32_to_cpu(ld->ld_length); |
529 | unsigned int revokes = be32_to_cpu(ld->ld_data1); | |
530 | struct buffer_head *bh; | |
531 | unsigned int offset; | |
cd915493 | 532 | u64 blkno; |
b3b94faa DT |
533 | int first = 1; |
534 | int error; | |
535 | ||
536 | if (pass != 0 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_REVOKE) | |
537 | return 0; | |
538 | ||
539 | offset = sizeof(struct gfs2_log_descriptor); | |
540 | ||
541 | for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) { | |
542 | error = gfs2_replay_read_block(jd, start, &bh); | |
543 | if (error) | |
544 | return error; | |
545 | ||
546 | if (!first) | |
547 | gfs2_metatype_check(sdp, bh, GFS2_METATYPE_LB); | |
548 | ||
cd915493 | 549 | while (offset + sizeof(u64) <= sdp->sd_sb.sb_bsize) { |
b3b94faa DT |
550 | blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset)); |
551 | ||
552 | error = gfs2_revoke_add(sdp, blkno, start); | |
3ad62e87 BP |
553 | if (error < 0) { |
554 | brelse(bh); | |
b3b94faa | 555 | return error; |
3ad62e87 | 556 | } |
b3b94faa DT |
557 | else if (error) |
558 | sdp->sd_found_revokes++; | |
559 | ||
560 | if (!--revokes) | |
561 | break; | |
cd915493 | 562 | offset += sizeof(u64); |
b3b94faa DT |
563 | } |
564 | ||
565 | brelse(bh); | |
566 | offset = sizeof(struct gfs2_meta_header); | |
567 | first = 0; | |
568 | } | |
569 | ||
570 | return 0; | |
571 | } | |
572 | ||
573 | static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) | |
574 | { | |
feaa7bba | 575 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
b3b94faa DT |
576 | |
577 | if (error) { | |
578 | gfs2_revoke_clean(sdp); | |
579 | return; | |
580 | } | |
581 | if (pass != 1) | |
582 | return; | |
583 | ||
584 | fs_info(sdp, "jid=%u: Found %u revoke tags\n", | |
585 | jd->jd_jid, sdp->sd_found_revokes); | |
586 | ||
587 | gfs2_revoke_clean(sdp); | |
588 | } | |
589 | ||
18ec7d5c SW |
590 | /** |
591 | * databuf_lo_add - Add a databuf to the transaction. | |
592 | * | |
593 | * This is used in two distinct cases: | |
594 | * i) In ordered write mode | |
595 | * We put the data buffer on a list so that we can ensure that its | |
596 | * synced to disk at the right time | |
597 | * ii) In journaled data mode | |
598 | * We need to journal the data block in the same way as metadata in | |
599 | * the functions above. The difference is that here we have a tag | |
600 | * which is two __be64's being the block number (as per meta data) | |
601 | * and a flag which says whether the data block needs escaping or | |
602 | * not. This means we need a new log entry for each 251 or so data | |
603 | * blocks, which isn't an enormous overhead but twice as much as | |
604 | * for normal metadata blocks. | |
605 | */ | |
b3b94faa DT |
606 | static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) |
607 | { | |
18ec7d5c | 608 | struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); |
5c676f6d | 609 | struct gfs2_trans *tr = current->journal_info; |
18ec7d5c | 610 | struct address_space *mapping = bd->bd_bh->b_page->mapping; |
feaa7bba | 611 | struct gfs2_inode *ip = GFS2_I(mapping->host); |
b3b94faa | 612 | |
9b9107a5 | 613 | lock_buffer(bd->bd_bh); |
8bd95727 | 614 | gfs2_log_lock(sdp); |
9ff8ec32 SW |
615 | if (tr) { |
616 | if (!list_empty(&bd->bd_list_tr)) | |
617 | goto out; | |
618 | tr->tr_touched = 1; | |
619 | if (gfs2_is_jdata(ip)) { | |
620 | tr->tr_num_buf++; | |
621 | list_add(&bd->bd_list_tr, &tr->tr_list_buf); | |
622 | } | |
773ed1a0 | 623 | } |
2332c443 | 624 | if (!list_empty(&le->le_list)) |
9b9107a5 | 625 | goto out; |
2332c443 | 626 | |
2bcd610d SW |
627 | set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); |
628 | set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); | |
2332c443 | 629 | if (gfs2_is_jdata(ip)) { |
2332c443 RP |
630 | gfs2_pin(sdp, bd->bd_bh); |
631 | tr->tr_num_databuf_new++; | |
d7b616e2 | 632 | sdp->sd_log_num_databuf++; |
e5884636 | 633 | list_add_tail(&le->le_list, &sdp->sd_log_le_databuf); |
d7b616e2 | 634 | } else { |
e5884636 | 635 | list_add_tail(&le->le_list, &sdp->sd_log_le_ordered); |
9b9107a5 | 636 | } |
9b9107a5 | 637 | out: |
b3b94faa | 638 | gfs2_log_unlock(sdp); |
9b9107a5 | 639 | unlock_buffer(bd->bd_bh); |
b3b94faa DT |
640 | } |
641 | ||
16615be1 | 642 | static void gfs2_check_magic(struct buffer_head *bh) |
18ec7d5c | 643 | { |
18ec7d5c SW |
644 | void *kaddr; |
645 | __be32 *ptr; | |
18ec7d5c | 646 | |
16615be1 SW |
647 | clear_buffer_escaped(bh); |
648 | kaddr = kmap_atomic(bh->b_page, KM_USER0); | |
18ec7d5c SW |
649 | ptr = kaddr + bh_offset(bh); |
650 | if (*ptr == cpu_to_be32(GFS2_MAGIC)) | |
16615be1 | 651 | set_buffer_escaped(bh); |
c312c4fd | 652 | kunmap_atomic(kaddr, KM_USER0); |
18ec7d5c SW |
653 | } |
654 | ||
16615be1 SW |
655 | static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh, |
656 | struct list_head *list, struct list_head *done, | |
657 | unsigned int n) | |
b3b94faa | 658 | { |
16615be1 | 659 | struct buffer_head *bh1; |
18ec7d5c | 660 | struct gfs2_log_descriptor *ld; |
16615be1 SW |
661 | struct gfs2_bufdata *bd; |
662 | __be64 *ptr; | |
d7b616e2 | 663 | |
16615be1 SW |
664 | if (!bh) |
665 | return; | |
b3b94faa | 666 | |
16615be1 SW |
667 | ld = bh_log_desc(bh); |
668 | ld->ld_length = cpu_to_be32(n + 1); | |
669 | ld->ld_data1 = cpu_to_be32(n); | |
b3b94faa | 670 | |
16615be1 SW |
671 | ptr = bh_log_ptr(bh); |
672 | ||
673 | get_bh(bh); | |
721a9602 | 674 | submit_bh(WRITE_SYNC, bh); |
f55ab26a | 675 | gfs2_log_lock(sdp); |
16615be1 SW |
676 | while(!list_empty(list)) { |
677 | bd = list_entry(list->next, struct gfs2_bufdata, bd_le.le_list); | |
678 | list_move_tail(&bd->bd_le.le_list, done); | |
679 | get_bh(bd->bd_bh); | |
680 | while (be64_to_cpu(*ptr) != bd->bd_bh->b_blocknr) { | |
681 | gfs2_log_incr_head(sdp); | |
682 | ptr += 2; | |
18ec7d5c | 683 | } |
f55ab26a | 684 | gfs2_log_unlock(sdp); |
16615be1 SW |
685 | lock_buffer(bd->bd_bh); |
686 | if (buffer_escaped(bd->bd_bh)) { | |
687 | void *kaddr; | |
688 | bh1 = gfs2_log_get_buf(sdp); | |
689 | kaddr = kmap_atomic(bd->bd_bh->b_page, KM_USER0); | |
690 | memcpy(bh1->b_data, kaddr + bh_offset(bd->bd_bh), | |
691 | bh1->b_size); | |
692 | kunmap_atomic(kaddr, KM_USER0); | |
693 | *(__be32 *)bh1->b_data = 0; | |
694 | clear_buffer_escaped(bd->bd_bh); | |
695 | unlock_buffer(bd->bd_bh); | |
696 | brelse(bd->bd_bh); | |
697 | } else { | |
698 | bh1 = gfs2_log_fake_buf(sdp, bd->bd_bh); | |
18ec7d5c | 699 | } |
721a9602 | 700 | submit_bh(WRITE_SYNC, bh1); |
f55ab26a | 701 | gfs2_log_lock(sdp); |
16615be1 SW |
702 | ptr += 2; |
703 | } | |
704 | gfs2_log_unlock(sdp); | |
705 | brelse(bh); | |
706 | } | |
707 | ||
708 | /** | |
709 | * databuf_lo_before_commit - Scan the data buffers, writing as we go | |
710 | * | |
711 | */ | |
712 | ||
713 | static void databuf_lo_before_commit(struct gfs2_sbd *sdp) | |
714 | { | |
715 | struct gfs2_bufdata *bd = NULL; | |
716 | struct buffer_head *bh = NULL; | |
717 | unsigned int n = 0; | |
718 | __be64 *ptr = NULL, *end = NULL; | |
719 | LIST_HEAD(processed); | |
720 | LIST_HEAD(in_progress); | |
721 | ||
722 | gfs2_log_lock(sdp); | |
723 | while (!list_empty(&sdp->sd_log_le_databuf)) { | |
724 | if (ptr == end) { | |
f55ab26a | 725 | gfs2_log_unlock(sdp); |
16615be1 SW |
726 | gfs2_write_blocks(sdp, bh, &in_progress, &processed, n); |
727 | n = 0; | |
728 | bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_JDATA); | |
729 | ptr = bh_log_ptr(bh); | |
730 | end = bh_ptr_end(bh) - 1; | |
f55ab26a | 731 | gfs2_log_lock(sdp); |
16615be1 | 732 | continue; |
18ec7d5c | 733 | } |
16615be1 SW |
734 | bd = list_entry(sdp->sd_log_le_databuf.next, struct gfs2_bufdata, bd_le.le_list); |
735 | list_move_tail(&bd->bd_le.le_list, &in_progress); | |
736 | gfs2_check_magic(bd->bd_bh); | |
737 | *ptr++ = cpu_to_be64(bd->bd_bh->b_blocknr); | |
738 | *ptr++ = cpu_to_be64(buffer_escaped(bh) ? 1 : 0); | |
739 | n++; | |
b3b94faa | 740 | } |
f55ab26a | 741 | gfs2_log_unlock(sdp); |
16615be1 SW |
742 | gfs2_write_blocks(sdp, bh, &in_progress, &processed, n); |
743 | gfs2_log_lock(sdp); | |
744 | list_splice(&processed, &sdp->sd_log_le_databuf); | |
745 | gfs2_log_unlock(sdp); | |
18ec7d5c SW |
746 | } |
747 | ||
748 | static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, | |
749 | struct gfs2_log_descriptor *ld, | |
750 | __be64 *ptr, int pass) | |
751 | { | |
feaa7bba SW |
752 | struct gfs2_inode *ip = GFS2_I(jd->jd_inode); |
753 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); | |
5c676f6d | 754 | struct gfs2_glock *gl = ip->i_gl; |
18ec7d5c SW |
755 | unsigned int blks = be32_to_cpu(ld->ld_data1); |
756 | struct buffer_head *bh_log, *bh_ip; | |
cd915493 SW |
757 | u64 blkno; |
758 | u64 esc; | |
18ec7d5c SW |
759 | int error = 0; |
760 | ||
761 | if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_JDATA) | |
762 | return 0; | |
763 | ||
764 | gfs2_replay_incr_blk(sdp, &start); | |
765 | for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) { | |
766 | blkno = be64_to_cpu(*ptr++); | |
767 | esc = be64_to_cpu(*ptr++); | |
768 | ||
769 | sdp->sd_found_blocks++; | |
770 | ||
771 | if (gfs2_revoke_check(sdp, blkno, start)) | |
772 | continue; | |
773 | ||
774 | error = gfs2_replay_read_block(jd, start, &bh_log); | |
775 | if (error) | |
776 | return error; | |
777 | ||
778 | bh_ip = gfs2_meta_new(gl, blkno); | |
779 | memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size); | |
780 | ||
781 | /* Unescape */ | |
782 | if (esc) { | |
783 | __be32 *eptr = (__be32 *)bh_ip->b_data; | |
784 | *eptr = cpu_to_be32(GFS2_MAGIC); | |
785 | } | |
786 | mark_buffer_dirty(bh_ip); | |
787 | ||
788 | brelse(bh_log); | |
789 | brelse(bh_ip); | |
18ec7d5c SW |
790 | |
791 | sdp->sd_replayed_blocks++; | |
792 | } | |
793 | ||
794 | return error; | |
795 | } | |
796 | ||
797 | /* FIXME: sort out accounting for log blocks etc. */ | |
798 | ||
799 | static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) | |
800 | { | |
feaa7bba SW |
801 | struct gfs2_inode *ip = GFS2_I(jd->jd_inode); |
802 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); | |
18ec7d5c SW |
803 | |
804 | if (error) { | |
7276b3b0 | 805 | gfs2_meta_sync(ip->i_gl); |
18ec7d5c SW |
806 | return; |
807 | } | |
808 | if (pass != 1) | |
809 | return; | |
810 | ||
811 | /* data sync? */ | |
7276b3b0 | 812 | gfs2_meta_sync(ip->i_gl); |
18ec7d5c SW |
813 | |
814 | fs_info(sdp, "jid=%u: Replayed %u of %u data blocks\n", | |
815 | jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks); | |
816 | } | |
817 | ||
818 | static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |
819 | { | |
820 | struct list_head *head = &sdp->sd_log_le_databuf; | |
821 | struct gfs2_bufdata *bd; | |
822 | ||
823 | while (!list_empty(head)) { | |
824 | bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); | |
b8e1aabf | 825 | list_del_init(&bd->bd_le.le_list); |
18ec7d5c | 826 | sdp->sd_log_num_databuf--; |
18ec7d5c | 827 | gfs2_unpin(sdp, bd->bd_bh, ai); |
18ec7d5c | 828 | } |
b3b94faa DT |
829 | gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf); |
830 | } | |
831 | ||
18ec7d5c | 832 | |
b09e593d | 833 | const struct gfs2_log_operations gfs2_buf_lops = { |
b3b94faa | 834 | .lo_add = buf_lo_add, |
b3b94faa DT |
835 | .lo_before_commit = buf_lo_before_commit, |
836 | .lo_after_commit = buf_lo_after_commit, | |
837 | .lo_before_scan = buf_lo_before_scan, | |
838 | .lo_scan_elements = buf_lo_scan_elements, | |
839 | .lo_after_scan = buf_lo_after_scan, | |
ea67eedb | 840 | .lo_name = "buf", |
b3b94faa DT |
841 | }; |
842 | ||
b09e593d | 843 | const struct gfs2_log_operations gfs2_revoke_lops = { |
b3b94faa DT |
844 | .lo_add = revoke_lo_add, |
845 | .lo_before_commit = revoke_lo_before_commit, | |
f42ab085 | 846 | .lo_after_commit = revoke_lo_after_commit, |
b3b94faa DT |
847 | .lo_before_scan = revoke_lo_before_scan, |
848 | .lo_scan_elements = revoke_lo_scan_elements, | |
849 | .lo_after_scan = revoke_lo_after_scan, | |
ea67eedb | 850 | .lo_name = "revoke", |
b3b94faa DT |
851 | }; |
852 | ||
b09e593d | 853 | const struct gfs2_log_operations gfs2_rg_lops = { |
ea67eedb | 854 | .lo_name = "rg", |
b3b94faa DT |
855 | }; |
856 | ||
b09e593d | 857 | const struct gfs2_log_operations gfs2_databuf_lops = { |
b3b94faa DT |
858 | .lo_add = databuf_lo_add, |
859 | .lo_before_commit = databuf_lo_before_commit, | |
18ec7d5c SW |
860 | .lo_after_commit = databuf_lo_after_commit, |
861 | .lo_scan_elements = databuf_lo_scan_elements, | |
862 | .lo_after_scan = databuf_lo_after_scan, | |
ea67eedb | 863 | .lo_name = "databuf", |
b3b94faa DT |
864 | }; |
865 | ||
b09e593d | 866 | const struct gfs2_log_operations *gfs2_log_ops[] = { |
16615be1 | 867 | &gfs2_databuf_lops, |
b3b94faa | 868 | &gfs2_buf_lops, |
b3b94faa | 869 | &gfs2_rg_lops, |
16615be1 | 870 | &gfs2_revoke_lops, |
ea67eedb | 871 | NULL, |
b3b94faa DT |
872 | }; |
873 |