Commit ef75bd71 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull GFS2 updates from Andreas Gruenbacher:
 "We've got the following patches ready for this merge window:

   - "gfs2: Fix loop in gfs2_rbm_find (v2)"

      A rework of a fix we ended up reverting in 5.0 because of an
      iozone performance regression.

   - "gfs2: read journal in large chunks"
     "gfs2: fix race between gfs2_freeze_func and unmount"

      An improved version of a commit we also ended up reverting in 5.0
      because of a regression in xfstest generic/311. It turns out that
      the journal changes were mostly innocent and that unfreeze didn't
      wait for the freeze to complete, which caused the filesystem to be
      unmounted before it was actually idle.

   - "gfs2: Fix occasional glock use-after-free"
     "gfs2: Fix iomap write page reclaim deadlock"
     "gfs2: Fix lru_count going negative"

      Fixes for various problems reported and partially fixed by Citrix
      engineers. Thank you very much.

   - "gfs2: clean_journal improperly set sd_log_flush_head"

      Another fix from Bob.

   - .. and a few other minor cleanups"

* tag 'gfs2-for-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: read journal in large chunks
  gfs2: Fix iomap write page reclaim deadlock
  gfs2: fix race between gfs2_freeze_func and unmount
  gfs2: Rename gfs2_trans_{add_unrevoke => remove_revoke}
  gfs2: Rename sd_log_le_{revoke,ordered}
  gfs2: Remove unnecessary extern declarations
  gfs2: Remove misleading comments in gfs2_evict_inode
  gfs2: Replace gl_revokes with a GLF flag
  gfs2: Fix occasional glock use-after-free
  gfs2: clean_journal improperly set sd_log_flush_head
  gfs2: Fix lru_count going negative
  gfs2: Fix loop in gfs2_rbm_find (v2)
parents 78d9affb f4686c26
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -649,7 +649,7 @@ out_uninit:
 */
void adjust_fs_space(struct inode *inode)
{
	struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
	struct gfs2_sbd *sdp = GFS2_SB(inode);
	struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
	struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
	struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master;
@@ -657,10 +657,13 @@ void adjust_fs_space(struct inode *inode)
	struct buffer_head *m_bh, *l_bh;
	u64 fs_total, new_free;

	if (gfs2_trans_begin(sdp, 2 * RES_STATFS, 0) != 0)
		return;

	/* Total up the file system space, according to the latest rindex. */
	fs_total = gfs2_ri_total(sdp);
	if (gfs2_meta_inode_buffer(m_ip, &m_bh) != 0)
		return;
		goto out;

	spin_lock(&sdp->sd_statfs_spin);
	gfs2_statfs_change_in(m_sc, m_bh->b_data +
@@ -675,11 +678,14 @@ void adjust_fs_space(struct inode *inode)
	gfs2_statfs_change(sdp, new_free, new_free, 0);

	if (gfs2_meta_inode_buffer(l_ip, &l_bh) != 0)
		goto out;
		goto out2;
	update_statfs(sdp, m_bh, l_bh);
	brelse(l_bh);
out:
out2:
	brelse(m_bh);
out:
	sdp->sd_rindex_uptodate = 0;
	gfs2_trans_end(sdp);
}

/**
+76 −42
Original line number Diff line number Diff line
@@ -142,7 +142,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
		if (error)
			goto out_brelse;
		if (isdir) {
			gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), block, 1);
			gfs2_trans_remove_revoke(GFS2_SB(&ip->i_inode), block, 1);
			error = gfs2_dir_get_new_buffer(ip, block, &bh);
			if (error)
				goto out_brelse;
@@ -676,7 +676,7 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
			goto out;
		alloced += n;
		if (state != ALLOC_DATA || gfs2_is_jdata(ip))
			gfs2_trans_add_unrevoke(sdp, bn, n);
			gfs2_trans_remove_revoke(sdp, bn, n);
		switch (state) {
		/* Growing height of tree */
		case ALLOC_GROW_HEIGHT:
@@ -925,6 +925,32 @@ do_alloc:
	goto out;
}

/**
 * gfs2_lblk_to_dblk - convert logical block to disk block
 * @inode: the inode of the file we're mapping
 * @lblock: the block relative to the start of the file
 * @dblock: the returned dblock, if no error
 *
 * This function maps a single block from a file logical block (relative to
 * the start of the file) to a file system absolute block using iomap.
 *
 * Returns: the absolute file system block, or an error
 */
int gfs2_lblk_to_dblk(struct inode *inode, u32 lblock, u64 *dblock)
{
	struct iomap iomap = { };
	struct metapath mp = { .mp_aheight = 1, };
	loff_t pos = (loff_t)lblock << inode->i_blkbits;
	int ret;

	ret = gfs2_iomap_get(inode, pos, i_blocksize(inode), 0, &iomap, &mp);
	release_metapath(&mp);
	if (ret == 0)
		*dblock = iomap.addr >> inode->i_blkbits;

	return ret;
}

static int gfs2_write_lock(struct inode *inode)
{
	struct gfs2_inode *ip = GFS2_I(inode);
@@ -965,17 +991,28 @@ static void gfs2_write_unlock(struct inode *inode)
	gfs2_glock_dq_uninit(&ip->i_gh);
}

static int gfs2_iomap_page_prepare(struct inode *inode, loff_t pos,
				   unsigned len, struct iomap *iomap)
{
	struct gfs2_sbd *sdp = GFS2_SB(inode);

	return gfs2_trans_begin(sdp, RES_DINODE + (len >> inode->i_blkbits), 0);
}

static void gfs2_iomap_page_done(struct inode *inode, loff_t pos,
				 unsigned copied, struct page *page,
				 struct iomap *iomap)
{
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_sbd *sdp = GFS2_SB(inode);

	if (page)
	if (page && !gfs2_is_stuffed(ip))
		gfs2_page_add_databufs(ip, page, offset_in_page(pos), copied);
	gfs2_trans_end(sdp);
}

static const struct iomap_page_ops gfs2_iomap_page_ops = {
	.page_prepare = gfs2_iomap_page_prepare,
	.page_done = gfs2_iomap_page_done,
};

@@ -1031,7 +1068,11 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
	if (alloc_required)
		rblocks += gfs2_rg_blocks(ip, data_blocks + ind_blocks);

	ret = gfs2_trans_begin(sdp, rblocks, iomap->length >> inode->i_blkbits);
	if (unstuff || iomap->type == IOMAP_HOLE) {
		struct gfs2_trans *tr;

		ret = gfs2_trans_begin(sdp, rblocks,
				       iomap->length >> inode->i_blkbits);
		if (ret)
			goto out_trans_fail;

@@ -1040,8 +1081,8 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
			if (ret)
				goto out_trans_end;
			release_metapath(mp);
		ret = gfs2_iomap_get(inode, iomap->offset, iomap->length,
				     flags, iomap, mp);
			ret = gfs2_iomap_get(inode, iomap->offset,
					     iomap->length, flags, iomap, mp);
			if (ret)
				goto out_trans_end;
		}
@@ -1055,7 +1096,17 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
				goto out_qunlock;
			}
		}
	if (!gfs2_is_stuffed(ip) && gfs2_is_jdata(ip))

		tr = current->journal_info;
		if (tr->tr_num_buf_new)
			__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
		else
			gfs2_trans_add_meta(ip->i_gl, mp->mp_bh[0]);

		gfs2_trans_end(sdp);
	}

	if (gfs2_is_stuffed(ip) || gfs2_is_jdata(ip))
		iomap->page_ops = &gfs2_iomap_page_ops;
	return 0;

@@ -1095,10 +1146,6 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
		    iomap->type != IOMAP_MAPPED)
			ret = -ENOTBLK;
	}
	if (!ret) {
		get_bh(mp.mp_bh[0]);
		iomap->private = mp.mp_bh[0];
	}
	release_metapath(&mp);
	trace_gfs2_iomap_end(ip, iomap, ret);
	return ret;
@@ -1109,27 +1156,16 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
{
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_sbd *sdp = GFS2_SB(inode);
	struct gfs2_trans *tr = current->journal_info;
	struct buffer_head *dibh = iomap->private;

	if ((flags & (IOMAP_WRITE | IOMAP_DIRECT)) != IOMAP_WRITE)
		goto out;

	if (iomap->type != IOMAP_INLINE) {
	if (!gfs2_is_stuffed(ip))
		gfs2_ordered_add_inode(ip);

		if (tr->tr_num_buf_new)
			__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
		else
			gfs2_trans_add_meta(ip->i_gl, dibh);
	}

	if (inode == sdp->sd_rindex) {
	if (inode == sdp->sd_rindex)
		adjust_fs_space(inode);
		sdp->sd_rindex_uptodate = 0;
	}

	gfs2_trans_end(sdp);
	gfs2_inplace_release(ip);

	if (length != written && (iomap->flags & IOMAP_F_NEW)) {
@@ -1149,8 +1185,6 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
	gfs2_write_unlock(inode);

out:
	if (dibh)
		brelse(dibh);
	return 0;
}

+1 −0
Original line number Diff line number Diff line
@@ -64,5 +64,6 @@ extern int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
extern int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd);
extern void gfs2_free_journal_extents(struct gfs2_jdesc *jd);
extern int __gfs2_punch_hole(struct file *file, loff_t offset, loff_t length);
extern int gfs2_lblk_to_dblk(struct inode *inode, u32 lblock, u64 *dblock);

#endif /* __BMAP_DOT_H__ */
+1 −1
Original line number Diff line number Diff line
@@ -883,7 +883,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
	if (!bh)
		return NULL;

	gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, 1);
	gfs2_trans_remove_revoke(GFS2_SB(inode), bn, 1);
	gfs2_trans_add_meta(ip->i_gl, bh);
	gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF);
	leaf = (struct gfs2_leaf *)bh->b_data;
+15 −10
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@ void gfs2_glock_free(struct gfs2_glock *gl)
{
	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;

	BUG_ON(test_bit(GLF_REVOKES, &gl->gl_flags));
	rhashtable_remove_fast(&gl_hash_table, &gl->gl_node, ht_parms);
	smp_mb();
	wake_up_glock(gl);
@@ -183,15 +184,19 @@ static int demote_ok(const struct gfs2_glock *gl)

void gfs2_glock_add_to_lru(struct gfs2_glock *gl)
{
	spin_lock(&lru_lock);
	if (!(gl->gl_ops->go_flags & GLOF_LRU))
		return;

	if (!list_empty(&gl->gl_lru))
		list_del_init(&gl->gl_lru);
	else
		atomic_inc(&lru_count);
	spin_lock(&lru_lock);

	list_del(&gl->gl_lru);
	list_add_tail(&gl->gl_lru, &lru_list);

	if (!test_bit(GLF_LRU, &gl->gl_flags)) {
		set_bit(GLF_LRU, &gl->gl_flags);
		atomic_inc(&lru_count);
	}

	spin_unlock(&lru_lock);
}

@@ -201,7 +206,7 @@ static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl)
		return;

	spin_lock(&lru_lock);
	if (!list_empty(&gl->gl_lru)) {
	if (test_bit(GLF_LRU, &gl->gl_flags)) {
		list_del_init(&gl->gl_lru);
		atomic_dec(&lru_count);
		clear_bit(GLF_LRU, &gl->gl_flags);
@@ -1159,8 +1164,7 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
		    !test_bit(GLF_DEMOTE, &gl->gl_flags))
			fast_path = 1;
	}
	if (!test_bit(GLF_LFLUSH, &gl->gl_flags) && demote_ok(gl) &&
	    (glops->go_flags & GLOF_LRU))
	if (!test_bit(GLF_LFLUSH, &gl->gl_flags) && demote_ok(gl))
		gfs2_glock_add_to_lru(gl);

	trace_gfs2_glock_queue(gh, 0);
@@ -1456,6 +1460,7 @@ __acquires(&lru_lock)
		if (!spin_trylock(&gl->gl_lockref.lock)) {
add_back_to_lru:
			list_add(&gl->gl_lru, &lru_list);
			set_bit(GLF_LRU, &gl->gl_flags);
			atomic_inc(&lru_count);
			continue;
		}
@@ -1463,7 +1468,6 @@ add_back_to_lru:
			spin_unlock(&gl->gl_lockref.lock);
			goto add_back_to_lru;
		}
		clear_bit(GLF_LRU, &gl->gl_flags);
		gl->gl_lockref.count++;
		if (demote_ok(gl))
			handle_callback(gl, LM_ST_UNLOCKED, 0, false);
@@ -1498,6 +1502,7 @@ static long gfs2_scan_glock_lru(int nr)
		if (!test_bit(GLF_LOCK, &gl->gl_flags)) {
			list_move(&gl->gl_lru, &dispose);
			atomic_dec(&lru_count);
			clear_bit(GLF_LRU, &gl->gl_flags);
			freed++;
			continue;
		}
@@ -1796,7 +1801,7 @@ void gfs2_dump_glock(struct seq_file *seq, struct gfs2_glock *gl)
		  state2str(gl->gl_target),
		  state2str(gl->gl_demote_state), dtime,
		  atomic_read(&gl->gl_ail_count),
		  atomic_read(&gl->gl_revokes),
		  test_bit(GLF_REVOKES, &gl->gl_flags) ? 1 : 0,
		  (int)gl->gl_lockref.count, gl->gl_hold_time);

	list_for_each_entry(gh, &gl->gl_holders, gh_list)
Loading