aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAbhi Das <adas@redhat.com>2018-11-09 10:57:20 -0500
committerAndreas Gruenbacher <agruenba@redhat.com>2018-12-11 11:50:36 -0500
commit2a5f14f279f59143139bcd1606903f2f80a34241 (patch)
tree5e64aff0058b401e2c8f9b39f3995abf3f5ddd6e
parent40e0e61e366bed56b71edb3b970245165090ec9a (diff)
gfs2: read journal in large chunks to locate the head
Use bio(s) to read in the journal sequentially in large chunks and locate the head of the journal. This version addresses the issues Christoph pointed out w.r.t error handling and using deprecated API. Signed-off-by: Abhi Das <adas@redhat.com> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> Signed-off-by: Bob Peterson <rpeterso@redhat.com> Cc: Christoph Hellwig <hch@infradead.org>
-rw-r--r--fs/gfs2/glops.c1
-rw-r--r--fs/gfs2/log.c4
-rw-r--r--fs/gfs2/lops.c190
-rw-r--r--fs/gfs2/lops.h4
-rw-r--r--fs/gfs2/ops_fstype.c1
-rw-r--r--fs/gfs2/recovery.c123
-rw-r--r--fs/gfs2/recovery.h2
-rw-r--r--fs/gfs2/super.c1
8 files changed, 192 insertions, 134 deletions
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index c63bee9adb6a..f79ef9525e33 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -28,6 +28,7 @@
28#include "util.h" 28#include "util.h"
29#include "trans.h" 29#include "trans.h"
30#include "dir.h" 30#include "dir.h"
31#include "lops.h"
31 32
32struct workqueue_struct *gfs2_freeze_wq; 33struct workqueue_struct *gfs2_freeze_wq;
33 34
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index e7c6e9fc62b5..4dcd2b48189e 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -734,7 +734,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
734 lh->lh_crc = cpu_to_be32(crc); 734 lh->lh_crc = cpu_to_be32(crc);
735 735
736 gfs2_log_write(sdp, page, sb->s_blocksize, 0, addr); 736 gfs2_log_write(sdp, page, sb->s_blocksize, 0, addr);
737 gfs2_log_submit_bio(&sdp->sd_log_bio, REQ_OP_WRITE, op_flags); 737 gfs2_log_submit_bio(&sdp->sd_log_bio, REQ_OP_WRITE | op_flags);
738 log_flush_wait(sdp); 738 log_flush_wait(sdp);
739} 739}
740 740
@@ -811,7 +811,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
811 811
812 gfs2_ordered_write(sdp); 812 gfs2_ordered_write(sdp);
813 lops_before_commit(sdp, tr); 813 lops_before_commit(sdp, tr);
814 gfs2_log_submit_bio(&sdp->sd_log_bio, REQ_OP_WRITE, 0); 814 gfs2_log_submit_bio(&sdp->sd_log_bio, REQ_OP_WRITE);
815 815
816 if (sdp->sd_log_head != sdp->sd_log_flush_head) { 816 if (sdp->sd_log_head != sdp->sd_log_flush_head) {
817 log_flush_wait(sdp); 817 log_flush_wait(sdp);
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 2295042bc625..94dcab655bc0 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -17,7 +17,9 @@
17#include <linux/bio.h> 17#include <linux/bio.h>
18#include <linux/fs.h> 18#include <linux/fs.h>
19#include <linux/list_sort.h> 19#include <linux/list_sort.h>
20#include <linux/blkdev.h>
20 21
22#include "bmap.h"
21#include "dir.h" 23#include "dir.h"
22#include "gfs2.h" 24#include "gfs2.h"
23#include "incore.h" 25#include "incore.h"
@@ -193,7 +195,6 @@ static void gfs2_end_log_write_bh(struct gfs2_sbd *sdp, struct bio_vec *bvec,
193/** 195/**
194 * gfs2_end_log_write - end of i/o to the log 196 * gfs2_end_log_write - end of i/o to the log
195 * @bio: The bio 197 * @bio: The bio
196 * @error: Status of i/o request
197 * 198 *
198 * Each bio_vec contains either data from the pagecache or data 199 * Each bio_vec contains either data from the pagecache or data
199 * relating to the log itself. Here we iterate over the bio_vec 200 * relating to the log itself. Here we iterate over the bio_vec
@@ -230,20 +231,19 @@ static void gfs2_end_log_write(struct bio *bio)
230/** 231/**
231 * gfs2_log_submit_bio - Submit any pending log bio 232 * gfs2_log_submit_bio - Submit any pending log bio
232 * @biop: Address of the bio pointer 233 * @biop: Address of the bio pointer
233 * @op: REQ_OP 234 * @opf: REQ_OP | op_flags
234 * @op_flags: req_flag_bits
235 * 235 *
236 * Submit any pending part-built or full bio to the block device. If 236 * Submit any pending part-built or full bio to the block device. If
237 * there is no pending bio, then this is a no-op. 237 * there is no pending bio, then this is a no-op.
238 */ 238 */
239 239
240void gfs2_log_submit_bio(struct bio **biop, int op, int op_flags) 240void gfs2_log_submit_bio(struct bio **biop, int opf)
241{ 241{
242 struct bio *bio = *biop; 242 struct bio *bio = *biop;
243 if (bio) { 243 if (bio) {
244 struct gfs2_sbd *sdp = bio->bi_private; 244 struct gfs2_sbd *sdp = bio->bi_private;
245 atomic_inc(&sdp->sd_log_in_flight); 245 atomic_inc(&sdp->sd_log_in_flight);
246 bio_set_op_attrs(bio, op, op_flags); 246 bio->bi_opf = opf;
247 submit_bio(bio); 247 submit_bio(bio);
248 *biop = NULL; 248 *biop = NULL;
249 } 249 }
@@ -304,7 +304,7 @@ static struct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno,
304 nblk >>= sdp->sd_fsb2bb_shift; 304 nblk >>= sdp->sd_fsb2bb_shift;
305 if (blkno == nblk && !flush) 305 if (blkno == nblk && !flush)
306 return bio; 306 return bio;
307 gfs2_log_submit_bio(biop, op, 0); 307 gfs2_log_submit_bio(biop, op);
308 } 308 }
309 309
310 *biop = gfs2_log_alloc_bio(sdp, blkno, end_io); 310 *biop = gfs2_log_alloc_bio(sdp, blkno, end_io);
@@ -375,6 +375,184 @@ void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page)
375 gfs2_log_bmap(sdp)); 375 gfs2_log_bmap(sdp));
376} 376}
377 377
378/**
379 * gfs2_end_log_read - end I/O callback for reads from the log
380 * @bio: The bio
381 *
382 * Simply unlock the pages in the bio. The main thread will wait on them and
383 * process them in order as necessary.
384 */
385
386static void gfs2_end_log_read(struct bio *bio)
387{
388 struct page *page;
389 struct bio_vec *bvec;
390 int i;
391
392 bio_for_each_segment_all(bvec, bio, i) {
393 page = bvec->bv_page;
394 if (bio->bi_status) {
395 int err = blk_status_to_errno(bio->bi_status);
396
397 SetPageError(page);
398 mapping_set_error(page->mapping, err);
399 }
400 unlock_page(page);
401 }
402
403 bio_put(bio);
404}
405
406/**
407 * gfs2_jhead_pg_srch - Look for the journal head in a given page.
408 * @jd: The journal descriptor
409 * @page: The page to look in
410 *
411 * Returns: 1 if found, 0 otherwise.
412 */
413
414static bool gfs2_jhead_pg_srch(struct gfs2_jdesc *jd,
415 struct gfs2_log_header_host *head,
416 struct page *page)
417{
418 struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
419 struct gfs2_log_header_host uninitialized_var(lh);
420 void *kaddr = kmap_atomic(page);
421 unsigned int offset;
422 bool ret = false;
423
424 for (offset = 0; offset < PAGE_SIZE; offset += sdp->sd_sb.sb_bsize) {
425 if (!__get_log_header(sdp, kaddr + offset, 0, &lh)) {
426 if (lh.lh_sequence > head->lh_sequence)
427 *head = lh;
428 else {
429 ret = true;
430 break;
431 }
432 }
433 }
434 kunmap_atomic(kaddr);
435 return ret;
436}
437
438/**
439 * gfs2_jhead_process_page - Search/cleanup a page
440 * @jd: The journal descriptor
441 * @index: Index of the page to look into
442 * @done: If set, perform only cleanup, else search and set if found.
443 *
444 * Find the page with 'index' in the journal's mapping. Search the page for
445 * the journal head if requested (cleanup == false). Release refs on the
446 * page so the page cache can reclaim it (put_page() twice). We grabbed a
447 * reference on this page two times, first when we did a find_or_create_page()
448 * to obtain the page to add it to the bio and second when we do a
449 * find_get_page() here to get the page to wait on while I/O on it is being
450 * completed.
451 * This function is also used to free up a page we might've grabbed but not
452 * used. Maybe we added it to a bio, but not submitted it for I/O. Or we
453 * submitted the I/O, but we already found the jhead so we only need to drop
454 * our references to the page.
455 */
456
457static void gfs2_jhead_process_page(struct gfs2_jdesc *jd, unsigned long index,
458 struct gfs2_log_header_host *head,
459 bool *done)
460{
461 struct page *page;
462
463 page = find_get_page(jd->jd_inode->i_mapping, index);
464 wait_on_page_locked(page);
465
466 if (PageError(page))
467 *done = true;
468
469 if (!*done)
470 *done = gfs2_jhead_pg_srch(jd, head, page);
471
472 put_page(page); /* Once for find_get_page */
473 put_page(page); /* Once more for find_or_create_page */
474}
475
476/**
477 * gfs2_find_jhead - find the head of a log
478 * @jd: The journal descriptor
479 * @head: The log descriptor for the head of the log is returned here
480 *
481 * Do a search of a journal by reading it in large chunks using bios and find
482 * the valid log entry with the highest sequence number. (i.e. the log head)
483 *
484 * Returns: 0 on success, errno otherwise
485 */
486
487int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
488{
489 struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
490 struct address_space *mapping = jd->jd_inode->i_mapping;
491 struct gfs2_journal_extent *je;
492 u32 block, read_idx = 0, submit_idx = 0, index = 0;
493 int shift = PAGE_SHIFT - sdp->sd_sb.sb_bsize_shift;
494 int blocks_per_page = 1 << shift, sz, ret = 0;
495 struct bio *bio = NULL;
496 struct page *page;
497 bool done = false;
498 errseq_t since;
499
500 memset(head, 0, sizeof(*head));
501 if (list_empty(&jd->extent_list))
502 gfs2_map_journal_extents(sdp, jd);
503
504 since = filemap_sample_wb_err(mapping);
505 list_for_each_entry(je, &jd->extent_list, list) {
506 for (block = 0; block < je->blocks; block += blocks_per_page) {
507 index = (je->lblock + block) >> shift;
508
509 page = find_or_create_page(mapping, index, GFP_NOFS);
510 if (!page) {
511 ret = -ENOMEM;
512 done = true;
513 goto out;
514 }
515
516 if (bio) {
517 sz = bio_add_page(bio, page, PAGE_SIZE, 0);
518 if (sz == PAGE_SIZE)
519 goto page_added;
520 submit_idx = index;
521 submit_bio(bio);
522 bio = NULL;
523 }
524
525 bio = gfs2_log_alloc_bio(sdp,
526 je->dblock + (index << shift),
527 gfs2_end_log_read);
528 bio->bi_opf = REQ_OP_READ;
529 sz = bio_add_page(bio, page, PAGE_SIZE, 0);
530 gfs2_assert_warn(sdp, sz == PAGE_SIZE);
531
532page_added:
533 if (submit_idx <= read_idx + BIO_MAX_PAGES) {
534 /* Keep at least one bio in flight */
535 continue;
536 }
537
538 gfs2_jhead_process_page(jd, read_idx++, head, &done);
539 if (done)
540 goto out; /* found */
541 }
542 }
543
544out:
545 if (bio)
546 submit_bio(bio);
547 while (read_idx <= index)
548 gfs2_jhead_process_page(jd, read_idx++, head, &done);
549
550 if (!ret)
551 ret = filemap_check_wb_err(mapping, since);
552
553 return ret;
554}
555
378static struct page *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type, 556static struct page *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type,
379 u32 ld_length, u32 ld_data1) 557 u32 ld_length, u32 ld_data1)
380{ 558{
diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h
index 711c4d89c063..331160fc568b 100644
--- a/fs/gfs2/lops.h
+++ b/fs/gfs2/lops.h
@@ -30,8 +30,10 @@ extern u64 gfs2_log_bmap(struct gfs2_sbd *sdp);
30extern void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page, 30extern void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page,
31 unsigned size, unsigned offset, u64 blkno); 31 unsigned size, unsigned offset, u64 blkno);
32extern void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page); 32extern void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page);
33extern void gfs2_log_submit_bio(struct bio **biop, int op, int op_flags); 33extern void gfs2_log_submit_bio(struct bio **biop, int opf);
34extern void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh); 34extern void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
35extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
36 struct gfs2_log_header_host *head);
35 37
36static inline unsigned int buf_limit(struct gfs2_sbd *sdp) 38static inline unsigned int buf_limit(struct gfs2_sbd *sdp)
37{ 39{
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index b041cb8ae383..1179763f6370 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -41,6 +41,7 @@
41#include "dir.h" 41#include "dir.h"
42#include "meta_io.h" 42#include "meta_io.h"
43#include "trace_gfs2.h" 43#include "trace_gfs2.h"
44#include "lops.h"
44 45
45#define DO 0 46#define DO 0
46#define UNDO 1 47#define UNDO 1
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index 2dac43065382..7389e445a7a7 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -182,129 +182,6 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk,
182} 182}
183 183
184/** 184/**
185 * find_good_lh - find a good log header
186 * @jd: the journal
187 * @blk: the segment to start searching from
188 * @lh: the log header to fill in
189 * @forward: if true search forward in the log, else search backward
190 *
191 * Call get_log_header() to get a log header for a segment, but if the
192 * segment is bad, either scan forward or backward until we find a good one.
193 *
194 * Returns: errno
195 */
196
197static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk,
198 struct gfs2_log_header_host *head)
199{
200 unsigned int orig_blk = *blk;
201 int error;
202
203 for (;;) {
204 error = get_log_header(jd, *blk, head);
205 if (error <= 0)
206 return error;
207
208 if (++*blk == jd->jd_blocks)
209 *blk = 0;
210
211 if (*blk == orig_blk) {
212 gfs2_consist_inode(GFS2_I(jd->jd_inode));
213 return -EIO;
214 }
215 }
216}
217
218/**
219 * jhead_scan - make sure we've found the head of the log
220 * @jd: the journal
221 * @head: this is filled in with the log descriptor of the head
222 *
223 * At this point, seg and lh should be either the head of the log or just
224 * before. Scan forward until we find the head.
225 *
226 * Returns: errno
227 */
228
229static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
230{
231 unsigned int blk = head->lh_blkno;
232 struct gfs2_log_header_host lh;
233 int error;
234
235 for (;;) {
236 if (++blk == jd->jd_blocks)
237 blk = 0;
238
239 error = get_log_header(jd, blk, &lh);
240 if (error < 0)
241 return error;
242 if (error == 1)
243 continue;
244
245 if (lh.lh_sequence == head->lh_sequence) {
246 gfs2_consist_inode(GFS2_I(jd->jd_inode));
247 return -EIO;
248 }
249 if (lh.lh_sequence < head->lh_sequence)
250 break;
251
252 *head = lh;
253 }
254
255 return 0;
256}
257
258/**
259 * gfs2_find_jhead - find the head of a log
260 * @jd: the journal
261 * @head: the log descriptor for the head of the log is returned here
262 *
263 * Do a binary search of a journal and find the valid log entry with the
264 * highest sequence number. (i.e. the log head)
265 *
266 * Returns: errno
267 */
268
269int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
270{
271 struct gfs2_log_header_host lh_1, lh_m;
272 u32 blk_1, blk_2, blk_m;
273 int error;
274
275 blk_1 = 0;
276 blk_2 = jd->jd_blocks - 1;
277
278 for (;;) {
279 blk_m = (blk_1 + blk_2) / 2;
280
281 error = find_good_lh(jd, &blk_1, &lh_1);
282 if (error)
283 return error;
284
285 error = find_good_lh(jd, &blk_m, &lh_m);
286 if (error)
287 return error;
288
289 if (blk_1 == blk_m || blk_m == blk_2)
290 break;
291
292 if (lh_1.lh_sequence <= lh_m.lh_sequence)
293 blk_1 = blk_m;
294 else
295 blk_2 = blk_m;
296 }
297
298 error = jhead_scan(jd, &lh_1);
299 if (error)
300 return error;
301
302 *head = lh_1;
303
304 return error;
305}
306
307/**
308 * foreach_descriptor - go through the active part of the log 185 * foreach_descriptor - go through the active part of the log
309 * @jd: the journal 186 * @jd: the journal
310 * @start: the first log header in the active region 187 * @start: the first log header in the active region
diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h
index 11d81248be85..99575ab81202 100644
--- a/fs/gfs2/recovery.h
+++ b/fs/gfs2/recovery.h
@@ -27,8 +27,6 @@ extern int gfs2_revoke_add(struct gfs2_jdesc *jd, u64 blkno, unsigned int where)
27extern int gfs2_revoke_check(struct gfs2_jdesc *jd, u64 blkno, unsigned int where); 27extern int gfs2_revoke_check(struct gfs2_jdesc *jd, u64 blkno, unsigned int where);
28extern void gfs2_revoke_clean(struct gfs2_jdesc *jd); 28extern void gfs2_revoke_clean(struct gfs2_jdesc *jd);
29 29
30extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
31 struct gfs2_log_header_host *head);
32extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd, bool wait); 30extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd, bool wait);
33extern void gfs2_recover_func(struct work_struct *work); 31extern void gfs2_recover_func(struct work_struct *work);
34extern int __get_log_header(struct gfs2_sbd *sdp, 32extern int __get_log_header(struct gfs2_sbd *sdp,
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index ca71163ff7cf..d4b11c903971 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -45,6 +45,7 @@
45#include "util.h" 45#include "util.h"
46#include "sys.h" 46#include "sys.h"
47#include "xattr.h" 47#include "xattr.h"
48#include "lops.h"
48 49
49#define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x) 50#define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x)
50 51