Skip to content

Commit

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

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)
  • Loading branch information
Linus Torvalds committed May 8, 2019
2 parents 78d9aff + f4686c2 commit ef75bd7
Show file tree
Hide file tree
Showing 20 changed files with 437 additions and 293 deletions.
14 changes: 10 additions & 4 deletions fs/gfs2/aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -649,18 +649,21 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping,
*/
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;
struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
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 +
Expand All @@ -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);
}

/**
Expand Down
118 changes: 76 additions & 42 deletions fs/gfs2/bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -925,6 +925,32 @@ static int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length,
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);
Expand Down Expand Up @@ -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,
};

Expand Down Expand Up @@ -1031,31 +1068,45 @@ 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 (ret)
goto out_trans_fail;
if (unstuff || iomap->type == IOMAP_HOLE) {
struct gfs2_trans *tr;

if (unstuff) {
ret = gfs2_unstuff_dinode(ip, NULL);
if (ret)
goto out_trans_end;
release_metapath(mp);
ret = gfs2_iomap_get(inode, iomap->offset, iomap->length,
flags, iomap, mp);
ret = gfs2_trans_begin(sdp, rblocks,
iomap->length >> inode->i_blkbits);
if (ret)
goto out_trans_end;
}
goto out_trans_fail;

if (iomap->type == IOMAP_HOLE) {
ret = gfs2_iomap_alloc(inode, iomap, flags, mp);
if (ret) {
gfs2_trans_end(sdp);
gfs2_inplace_release(ip);
punch_hole(ip, iomap->offset, iomap->length);
goto out_qunlock;
if (unstuff) {
ret = gfs2_unstuff_dinode(ip, NULL);
if (ret)
goto out_trans_end;
release_metapath(mp);
ret = gfs2_iomap_get(inode, iomap->offset,
iomap->length, flags, iomap, mp);
if (ret)
goto out_trans_end;
}

if (iomap->type == IOMAP_HOLE) {
ret = gfs2_iomap_alloc(inode, iomap, flags, mp);
if (ret) {
gfs2_trans_end(sdp);
gfs2_inplace_release(ip);
punch_hole(ip, iomap->offset, iomap->length);
goto out_qunlock;
}
}

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))

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

Expand Down Expand Up @@ -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;
Expand All @@ -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)) {
Expand All @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions fs/gfs2/bmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */
2 changes: 1 addition & 1 deletion fs/gfs2/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
25 changes: 15 additions & 10 deletions fs/gfs2/glock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -183,15 +184,19 @@ static int demote_ok(const struct gfs2_glock *gl)

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

spin_lock(&lru_lock);

if (!list_empty(&gl->gl_lru))
list_del_init(&gl->gl_lru);
else
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);
}

list_add_tail(&gl->gl_lru, &lru_list);
set_bit(GLF_LRU, &gl->gl_flags);
spin_unlock(&lru_lock);
}

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1456,14 +1460,14 @@ __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;
}
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion fs/gfs2/glops.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "util.h"
#include "trans.h"
#include "dir.h"
#include "lops.h"

struct workqueue_struct *gfs2_freeze_wq;

Expand Down Expand Up @@ -531,7 +532,7 @@ static int freeze_go_xmote_bh(struct gfs2_glock *gl, struct gfs2_holder *gh)
if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);

error = gfs2_find_jhead(sdp->sd_jdesc, &head);
error = gfs2_find_jhead(sdp->sd_jdesc, &head, false);
if (error)
gfs2_consist(sdp);
if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT))
Expand Down
9 changes: 5 additions & 4 deletions fs/gfs2/incore.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ enum {
GLF_OBJECT = 14, /* Used only for tracing */
GLF_BLOCKING = 15,
GLF_INODE_CREATING = 16, /* Inode creation occurring */
GLF_REVOKES = 17, /* Glock has revokes in queue */
};

struct gfs2_glock {
Expand Down Expand Up @@ -374,7 +375,6 @@ struct gfs2_glock {
struct list_head gl_lru;
struct list_head gl_ail_list;
atomic_t gl_ail_count;
atomic_t gl_revokes;
struct delayed_work gl_work;
union {
/* For inode and iopen glocks only */
Expand Down Expand Up @@ -535,7 +535,7 @@ struct gfs2_jdesc {
unsigned long jd_flags;
#define JDF_RECOVERY 1
unsigned int jd_jid;
unsigned int jd_blocks;
u32 jd_blocks;
int jd_recover_error;
/* Replay stuff */

Expand Down Expand Up @@ -621,6 +621,7 @@ enum {
SDF_SKIP_DLM_UNLOCK = 8,
SDF_FORCE_AIL_FLUSH = 9,
SDF_AIL1_IO_ERROR = 10,
SDF_FS_FROZEN = 11,
};

enum gfs2_freeze_state {
Expand Down Expand Up @@ -809,8 +810,8 @@ struct gfs2_sbd {
atomic_t sd_log_pinned;
unsigned int sd_log_num_revoke;

struct list_head sd_log_le_revoke;
struct list_head sd_log_le_ordered;
struct list_head sd_log_revokes;
struct list_head sd_log_ordered;
spinlock_t sd_ordered_lock;

atomic_t sd_log_thresh1;
Expand Down
Loading

0 comments on commit ef75bd7

Please sign in to comment.