Skip to content

Commit

Permalink
GFS2: Clean up log write code path
Browse files Browse the repository at this point in the history
Prior to this patch, we have two ways of sending i/o to the log.
One of those is used when we need to allocate both the data
to be written itself and also a buffer head to submit it. This
is done via sb_getblk and friends. This is used mostly for writing
log headers.

The other method is used when writing blocks which have some
in-place counterpart. This is the case for all the metadata
blocks which are journalled, and when journaled data is in use,
for unescaped journalled data blocks.

This patch replaces both of those two methods, and about half
a dozen separate i/o submission points with a single i/o
submission function. We also go direct to bio rather than
using buffer heads, since this allows us to build i/o
requests of the maximum size for the block device in
question. It also reduces the memory required for flushing
the log, which can be very useful in low memory situations.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
  • Loading branch information
Steven Whitehouse committed Apr 24, 2012
1 parent 2f7ee35 commit e8c92ed
Show file tree
Hide file tree
Showing 8 changed files with 264 additions and 172 deletions.
2 changes: 2 additions & 0 deletions fs/gfs2/incore.h
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,9 @@ struct gfs2_sbd {

struct rw_semaphore sd_log_flush_lock;
atomic_t sd_log_in_flight;
struct bio *sd_log_bio;
wait_queue_head_t sd_log_flush_wait;
int sd_log_error;

unsigned int sd_log_flush_head;
u64 sd_log_flush_wrapped;
Expand Down
57 changes: 11 additions & 46 deletions fs/gfs2/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,18 +357,6 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
return 0;
}

u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
{
struct gfs2_journal_extent *je;

list_for_each_entry(je, &sdp->sd_jdesc->extent_list, extent_list) {
if (lbn >= je->lblock && lbn < je->lblock + je->blocks)
return je->dblock + lbn - je->lblock;
}

return -1;
}

/**
* log_distance - Compute distance between two journal blocks
* @sdp: The GFS2 superblock
Expand Down Expand Up @@ -464,17 +452,6 @@ static unsigned int current_tail(struct gfs2_sbd *sdp)
return tail;
}

void gfs2_log_incr_head(struct gfs2_sbd *sdp)
{
BUG_ON((sdp->sd_log_flush_head == sdp->sd_log_tail) &&
(sdp->sd_log_flush_head != sdp->sd_log_head));

if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) {
sdp->sd_log_flush_head = 0;
sdp->sd_log_flush_wrapped = 1;
}
}

static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
{
unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail);
Expand Down Expand Up @@ -580,23 +557,17 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp)

static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
{
u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head);
struct buffer_head *bh;
struct gfs2_log_header *lh;
unsigned int tail;
u32 hash;

bh = sb_getblk(sdp->sd_vfs, blkno);
lock_buffer(bh);
memset(bh->b_data, 0, bh->b_size);
set_buffer_uptodate(bh);
clear_buffer_dirty(bh);
int rw = WRITE_FLUSH_FUA | REQ_META;
struct page *page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
lh = page_address(page);
clear_page(lh);

gfs2_ail1_empty(sdp);
tail = current_tail(sdp);

lh = (struct gfs2_log_header *)bh->b_data;
memset(lh, 0, sizeof(struct gfs2_log_header));
lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
lh->lh_header.__pad0 = cpu_to_be64(0);
Expand All @@ -606,29 +577,22 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
lh->lh_flags = cpu_to_be32(flags);
lh->lh_tail = cpu_to_be32(tail);
lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head);
hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
hash = gfs2_disk_hash(page_address(page), sizeof(struct gfs2_log_header));
lh->lh_hash = cpu_to_be32(hash);

bh->b_end_io = end_buffer_write_sync;
get_bh(bh);
if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) {
gfs2_ordered_wait(sdp);
log_flush_wait(sdp);
submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh);
} else {
submit_bh(WRITE_FLUSH_FUA | REQ_META, bh);
rw = WRITE_SYNC | REQ_META | REQ_PRIO;
}
wait_on_buffer(bh);

if (!buffer_uptodate(bh))
gfs2_io_error_bh(sdp, bh);
brelse(bh);
sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
gfs2_log_write_page(sdp, page);
gfs2_log_flush_bio(sdp, rw);
log_flush_wait(sdp);

if (sdp->sd_log_tail != tail)
log_pull_tail(sdp, tail);

sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
gfs2_log_incr_head(sdp);
}

/**
Expand Down Expand Up @@ -674,6 +638,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)

gfs2_ordered_write(sdp);
lops_before_commit(sdp);
gfs2_log_flush_bio(sdp, WRITE);

if (sdp->sd_log_head != sdp->sd_log_flush_head) {
log_write_header(sdp, 0);
Expand Down
2 changes: 0 additions & 2 deletions fs/gfs2/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
unsigned int ssize);

extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
extern void gfs2_log_incr_head(struct gfs2_sbd *sdp);
extern u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn);
extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
Expand Down
Loading

0 comments on commit e8c92ed

Please sign in to comment.