Skip to content

Commit 2a5f14f

Browse files
Abhi DasAndreas Gruenbacher
authored andcommitted
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>
1 parent 40e0e61 commit 2a5f14f

File tree

8 files changed

+192
-134
lines changed

8 files changed

+192
-134
lines changed

fs/gfs2/glops.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "util.h"
2929
#include "trans.h"
3030
#include "dir.h"
31+
#include "lops.h"
3132

3233
struct workqueue_struct *gfs2_freeze_wq;
3334

fs/gfs2/log.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
734734
lh->lh_crc = cpu_to_be32(crc);
735735

736736
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);
738738
log_flush_wait(sdp);
739739
}
740740

@@ -811,7 +811,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
811811

812812
gfs2_ordered_write(sdp);
813813
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);
815815

816816
if (sdp->sd_log_head != sdp->sd_log_flush_head) {
817817
log_flush_wait(sdp);

fs/gfs2/lops.c

Lines changed: 184 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include <linux/bio.h>
1818
#include <linux/fs.h>
1919
#include <linux/list_sort.h>
20+
#include <linux/blkdev.h>
2021

22+
#include "bmap.h"
2123
#include "dir.h"
2224
#include "gfs2.h"
2325
#include "incore.h"
@@ -193,7 +195,6 @@ static void gfs2_end_log_write_bh(struct gfs2_sbd *sdp, struct bio_vec *bvec,
193195
/**
194196
* gfs2_end_log_write - end of i/o to the log
195197
* @bio: The bio
196-
* @error: Status of i/o request
197198
*
198199
* Each bio_vec contains either data from the pagecache or data
199200
* 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)
230231
/**
231232
* gfs2_log_submit_bio - Submit any pending log bio
232233
* @biop: Address of the bio pointer
233-
* @op: REQ_OP
234-
* @op_flags: req_flag_bits
234+
* @opf: REQ_OP | op_flags
235235
*
236236
* Submit any pending part-built or full bio to the block device. If
237237
* there is no pending bio, then this is a no-op.
238238
*/
239239

240-
void gfs2_log_submit_bio(struct bio **biop, int op, int op_flags)
240+
void gfs2_log_submit_bio(struct bio **biop, int opf)
241241
{
242242
struct bio *bio = *biop;
243243
if (bio) {
244244
struct gfs2_sbd *sdp = bio->bi_private;
245245
atomic_inc(&sdp->sd_log_in_flight);
246-
bio_set_op_attrs(bio, op, op_flags);
246+
bio->bi_opf = opf;
247247
submit_bio(bio);
248248
*biop = NULL;
249249
}
@@ -304,7 +304,7 @@ static struct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno,
304304
nblk >>= sdp->sd_fsb2bb_shift;
305305
if (blkno == nblk && !flush)
306306
return bio;
307-
gfs2_log_submit_bio(biop, op, 0);
307+
gfs2_log_submit_bio(biop, op);
308308
}
309309

310310
*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)
375375
gfs2_log_bmap(sdp));
376376
}
377377

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+
386+
static 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+
414+
static 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+
457+
static 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+
487+
int 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+
532+
page_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+
544+
out:
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+
378556
static struct page *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type,
379557
u32 ld_length, u32 ld_data1)
380558
{

fs/gfs2/lops.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ extern u64 gfs2_log_bmap(struct gfs2_sbd *sdp);
3030
extern void gfs2_log_write(struct gfs2_sbd *sdp, struct page *page,
3131
unsigned size, unsigned offset, u64 blkno);
3232
extern void gfs2_log_write_page(struct gfs2_sbd *sdp, struct page *page);
33-
extern void gfs2_log_submit_bio(struct bio **biop, int op, int op_flags);
33+
extern void gfs2_log_submit_bio(struct bio **biop, int opf);
3434
extern void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
35+
extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
36+
struct gfs2_log_header_host *head);
3537

3638
static inline unsigned int buf_limit(struct gfs2_sbd *sdp)
3739
{

fs/gfs2/ops_fstype.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "dir.h"
4242
#include "meta_io.h"
4343
#include "trace_gfs2.h"
44+
#include "lops.h"
4445

4546
#define DO 0
4647
#define UNDO 1

0 commit comments

Comments
 (0)