Skip to content

Commit

Permalink
Merge tag 'gfs2-4.11.fixes' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/gfs2/linux-gfs2

Pull GFS2 updates from Robert Peterson:
 "We've got eight GFS2 patches for this merge window:

   - Andy Price submitted a patch to make gfs2_write_full_page a static
     function.

   - Dan Carpenter submitted a patch to fix a ERR_PTR thinko.

  Three patches fix bugs related to deleting very large files, which
  cause GFS2 to run out of journal space:

   - The first one prevents GFS2 delete operation from requesting too
     much journal space.

   - The second one fixes a problem whereby GFS2 can hang because it
     wasn't taking journal space demand into its calculations.

   - The third one wakes up IO waiters when a flush is done to restart
     processes stuck waiting for journal space to become available.

  The final three patches are a performance improvement related to
  spin_lock contention between multiple writers:

   - The "tr_touched" variable was switched to a flag to be more atomic
     and eliminate the possibility of some races.

   - Function meta_lo_add was moved inline with its only caller to make
     the code more readable and efficient.

   - Contention on the gfs2_log_lock spinlock was greatly reduced by
     avoiding the lock altogether in cases where we don't really need
     it: buffers that already appear in the appropriate metadata list
     for the journal. Many thanks to Steve Whitehouse for the ideas and
     principles behind these patches"

* tag 'gfs2-4.11.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: Make gfs2_write_full_page static
  GFS2: Reduce contention on gfs2_log_lock
  GFS2: Inline function meta_lo_add
  GFS2: Switch tr_touched to flag in transaction
  GFS2: Wake up io waiters whenever a flush is done
  GFS2: Made logd daemon take into account log demand
  GFS2: Limit number of transaction blocks requested for truncates
  GFS2: Fix reference to ERR_PTR in gfs2_glock_iter_next
  • Loading branch information
Linus Torvalds committed Feb 21, 2017
2 parents 70fcf5c + c548a1c commit 9763dd6
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 60 deletions.
4 changes: 2 additions & 2 deletions fs/gfs2/aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
/* This is the same as calling block_write_full_page, but it also
* writes pages outside of i_size
*/
int gfs2_write_full_page(struct page *page, get_block_t *get_block,
struct writeback_control *wbc)
static int gfs2_write_full_page(struct page *page, get_block_t *get_block,
struct writeback_control *wbc)
{
struct inode * const inode = page->mapping->host;
loff_t i_size = i_size_read(inode);
Expand Down
29 changes: 26 additions & 3 deletions fs/gfs2/bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrp_list rlist;
struct gfs2_trans *tr;
u64 bn, bstart;
u32 blen, btotal;
__be64 *p;
Expand All @@ -728,6 +729,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
unsigned int revokes = 0;
int x;
int error;
int jblocks_rqsted;

error = gfs2_rindex_update(sdp);
if (error)
Expand Down Expand Up @@ -791,12 +793,17 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
if (gfs2_rs_active(&ip->i_res)) /* needs to be done with the rgrp glock held */
gfs2_rs_deltree(&ip->i_res);

error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +
RES_INDIRECT + RES_STATFS + RES_QUOTA,
revokes);
restart:
jblocks_rqsted = rg_blocks + RES_DINODE +
RES_INDIRECT + RES_STATFS + RES_QUOTA +
gfs2_struct2blk(sdp, revokes, sizeof(u64));
if (jblocks_rqsted > atomic_read(&sdp->sd_log_thresh2))
jblocks_rqsted = atomic_read(&sdp->sd_log_thresh2);
error = gfs2_trans_begin(sdp, jblocks_rqsted, revokes);
if (error)
goto out_rg_gunlock;

tr = current->journal_info;
down_write(&ip->i_rw_mutex);

gfs2_trans_add_meta(ip->i_gl, dibh);
Expand All @@ -810,6 +817,16 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
if (!*p)
continue;

/* check for max reasonable journal transaction blocks */
if (tr->tr_num_buf_new + RES_STATFS +
RES_QUOTA >= atomic_read(&sdp->sd_log_thresh2)) {
if (rg_blocks >= tr->tr_num_buf_new)
rg_blocks -= tr->tr_num_buf_new;
else
rg_blocks = 0;
break;
}

bn = be64_to_cpu(*p);

if (bstart + blen == bn)
Expand All @@ -827,6 +844,9 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
*p = 0;
gfs2_add_inode_blocks(&ip->i_inode, -1);
}
if (p == bottom)
rg_blocks = 0;

if (bstart) {
__gfs2_free_blocks(ip, bstart, blen, metadata);
btotal += blen;
Expand All @@ -844,6 +864,9 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,

gfs2_trans_end(sdp);

if (rg_blocks)
goto restart;

out_rg_gunlock:
gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
out_rlist:
Expand Down
12 changes: 7 additions & 5 deletions fs/gfs2/glock.c
Original file line number Diff line number Diff line change
Expand Up @@ -1802,16 +1802,18 @@ void gfs2_glock_exit(void)

static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi)
{
do {
gi->gl = rhashtable_walk_next(&gi->hti);
while ((gi->gl = rhashtable_walk_next(&gi->hti))) {
if (IS_ERR(gi->gl)) {
if (PTR_ERR(gi->gl) == -EAGAIN)
continue;
gi->gl = NULL;
return;
}
/* Skip entries for other sb and dead entries */
} while ((gi->gl) && ((gi->sdp != gi->gl->gl_name.ln_sbd) ||
__lockref_is_dead(&gi->gl->gl_lockref)));
/* Skip entries for other sb and dead entries */
if (gi->sdp == gi->gl->gl_name.ln_sbd &&
!__lockref_is_dead(&gi->gl->gl_lockref))
return;
}
}

static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
Expand Down
11 changes: 8 additions & 3 deletions fs/gfs2/incore.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,15 +470,19 @@ struct gfs2_quota_data {
struct rcu_head qd_rcu;
};

enum {
TR_TOUCHED = 1,
TR_ATTACHED = 2,
TR_ALLOCED = 3,
};

struct gfs2_trans {
unsigned long tr_ip;

unsigned int tr_blocks;
unsigned int tr_revokes;
unsigned int tr_reserved;
unsigned int tr_touched:1;
unsigned int tr_attached:1;
unsigned int tr_alloced:1;
unsigned long tr_flags;

unsigned int tr_num_buf_new;
unsigned int tr_num_databuf_new;
Expand Down Expand Up @@ -794,6 +798,7 @@ struct gfs2_sbd {
atomic_t sd_log_thresh1;
atomic_t sd_log_thresh2;
atomic_t sd_log_blks_free;
atomic_t sd_log_blks_needed;
wait_queue_head_t sd_log_waitq;
wait_queue_head_t sd_logd_waitq;

Expand Down
21 changes: 15 additions & 6 deletions fs/gfs2/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
if (gfs2_assert_warn(sdp, blks) ||
gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks))
return -EINVAL;
atomic_add(blks, &sdp->sd_log_blks_needed);
retry:
free_blocks = atomic_read(&sdp->sd_log_blks_free);
if (unlikely(free_blocks <= wanted)) {
Expand All @@ -370,6 +371,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
wake_up(&sdp->sd_reserving_log_wait);
goto retry;
}
atomic_sub(blks, &sdp->sd_log_blks_needed);
trace_gfs2_log_blocks(sdp, -blks);

/*
Expand Down Expand Up @@ -797,7 +799,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,

static void gfs2_merge_trans(struct gfs2_trans *old, struct gfs2_trans *new)
{
WARN_ON_ONCE(old->tr_attached != 1);
WARN_ON_ONCE(!test_bit(TR_ATTACHED, &old->tr_flags));

old->tr_num_buf_new += new->tr_num_buf_new;
old->tr_num_databuf_new += new->tr_num_databuf_new;
Expand All @@ -821,9 +823,9 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
if (sdp->sd_log_tr) {
gfs2_merge_trans(sdp->sd_log_tr, tr);
} else if (tr->tr_num_buf_new || tr->tr_num_databuf_new) {
gfs2_assert_withdraw(sdp, tr->tr_alloced);
gfs2_assert_withdraw(sdp, test_bit(TR_ALLOCED, &tr->tr_flags));
sdp->sd_log_tr = tr;
tr->tr_attached = 1;
set_bit(TR_ATTACHED, &tr->tr_flags);
}

sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm;
Expand Down Expand Up @@ -891,13 +893,16 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)

static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp)
{
return (atomic_read(&sdp->sd_log_pinned) >= atomic_read(&sdp->sd_log_thresh1));
return (atomic_read(&sdp->sd_log_pinned) +
atomic_read(&sdp->sd_log_blks_needed) >=
atomic_read(&sdp->sd_log_thresh1));
}

static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp)
{
unsigned int used_blocks = sdp->sd_jdesc->jd_blocks - atomic_read(&sdp->sd_log_blks_free);
return used_blocks >= atomic_read(&sdp->sd_log_thresh2);
return used_blocks + atomic_read(&sdp->sd_log_blks_needed) >=
atomic_read(&sdp->sd_log_thresh2);
}

/**
Expand All @@ -913,22 +918,26 @@ int gfs2_logd(void *data)
struct gfs2_sbd *sdp = data;
unsigned long t = 1;
DEFINE_WAIT(wait);
bool did_flush;

while (!kthread_should_stop()) {

did_flush = false;
if (gfs2_jrnl_flush_reqd(sdp) || t == 0) {
gfs2_ail1_empty(sdp);
gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
did_flush = true;
}

if (gfs2_ail_flush_reqd(sdp)) {
gfs2_ail1_start(sdp);
gfs2_ail1_wait(sdp);
gfs2_ail1_empty(sdp);
gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
did_flush = true;
}

if (!gfs2_ail_flush_reqd(sdp))
if (!gfs2_ail_flush_reqd(sdp) || did_flush)
wake_up(&sdp->sd_log_waitq);

t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
Expand Down
6 changes: 3 additions & 3 deletions fs/gfs2/meta_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
wait_on_buffer(bh);
if (unlikely(!buffer_uptodate(bh))) {
struct gfs2_trans *tr = current->journal_info;
if (tr && tr->tr_touched)
if (tr && test_bit(TR_TOUCHED, &tr->tr_flags))
gfs2_io_error_bh(sdp, bh);
brelse(bh);
*bhp = NULL;
Expand All @@ -319,7 +319,7 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)

if (!buffer_uptodate(bh)) {
struct gfs2_trans *tr = current->journal_info;
if (tr && tr->tr_touched)
if (tr && test_bit(TR_TOUCHED, &tr->tr_flags))
gfs2_io_error_bh(sdp, bh);
return -EIO;
}
Expand All @@ -345,7 +345,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, int meta)
tr->tr_num_buf_rm++;
else
tr->tr_num_databuf_rm++;
tr->tr_touched = 1;
set_bit(TR_TOUCHED, &tr->tr_flags);
was_pinned = 1;
brelse(bh);
}
Expand Down
1 change: 1 addition & 0 deletions fs/gfs2/ops_fstype.c
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
goto fail_jindex;
}

atomic_set(&sdp->sd_log_blks_needed, 0);
if (sdp->sd_args.ar_spectator) {
sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0);
atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);
Expand Down
Loading

0 comments on commit 9763dd6

Please sign in to comment.