Skip to content

Commit

Permalink
gfs2: Move the inode glock locking to gfs2_file_buffered_write
Browse files Browse the repository at this point in the history
commit b924bda upstream

So far, for buffered writes, we were taking the inode glock in
gfs2_iomap_begin and dropping it in gfs2_iomap_end with the intention of
not holding the inode glock while iomap_write_actor faults in user
pages.  It turns out that iomap_write_actor is called inside iomap_begin
... iomap_end, so the user pages were still faulted in while holding the
inode glock and the locking code in iomap_begin / iomap_end was
completely pointless.

Move the locking into gfs2_file_buffered_write instead.  We'll take care
of the potential deadlocks due to faulting in user pages while holding a
glock in a subsequent patch.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Anand Jain <anand.jain@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Andreas Gruenbacher authored and gregkh committed May 1, 2022
1 parent 416a705 commit 8d363d8
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 59 deletions.
60 changes: 1 addition & 59 deletions fs/gfs2/bmap.c
Expand Up @@ -961,46 +961,6 @@ static int __gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length,
goto out;
}

static int gfs2_write_lock(struct inode *inode)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
int error;

gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);
error = gfs2_glock_nq(&ip->i_gh);
if (error)
goto out_uninit;
if (&ip->i_inode == sdp->sd_rindex) {
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);

error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE,
GL_NOCACHE, &m_ip->i_gh);
if (error)
goto out_unlock;
}
return 0;

out_unlock:
gfs2_glock_dq(&ip->i_gh);
out_uninit:
gfs2_holder_uninit(&ip->i_gh);
return error;
}

static void gfs2_write_unlock(struct inode *inode)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);

if (&ip->i_inode == sdp->sd_rindex) {
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);

gfs2_glock_dq_uninit(&m_ip->i_gh);
}
gfs2_glock_dq_uninit(&ip->i_gh);
}

static int gfs2_iomap_page_prepare(struct inode *inode, loff_t pos,
unsigned len)
{
Expand Down Expand Up @@ -1118,11 +1078,6 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
return ret;
}

static inline bool gfs2_iomap_need_write_lock(unsigned flags)
{
return (flags & IOMAP_WRITE) && !(flags & IOMAP_DIRECT);
}

static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
unsigned flags, struct iomap *iomap,
struct iomap *srcmap)
Expand All @@ -1135,12 +1090,6 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
iomap->flags |= IOMAP_F_BUFFER_HEAD;

trace_gfs2_iomap_start(ip, pos, length, flags);
if (gfs2_iomap_need_write_lock(flags)) {
ret = gfs2_write_lock(inode);
if (ret)
goto out;
}

ret = __gfs2_iomap_get(inode, pos, length, flags, iomap, &mp);
if (ret)
goto out_unlock;
Expand Down Expand Up @@ -1168,10 +1117,7 @@ static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp);

out_unlock:
if (ret && gfs2_iomap_need_write_lock(flags))
gfs2_write_unlock(inode);
release_metapath(&mp);
out:
trace_gfs2_iomap_end(ip, iomap, ret);
return ret;
}
Expand Down Expand Up @@ -1219,15 +1165,11 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
}

if (unlikely(!written))
goto out_unlock;
return 0;

if (iomap->flags & IOMAP_F_SIZE_CHANGED)
mark_inode_dirty(inode);
set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);

out_unlock:
if (gfs2_iomap_need_write_lock(flags))
gfs2_write_unlock(inode);
return 0;
}

Expand Down
27 changes: 27 additions & 0 deletions fs/gfs2/file.c
Expand Up @@ -881,13 +881,40 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb, struct iov_iter *fro
{
struct file *file = iocb->ki_filp;
struct inode *inode = file_inode(file);
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
ssize_t ret;

gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);
ret = gfs2_glock_nq(&ip->i_gh);
if (ret)
goto out_uninit;

if (inode == sdp->sd_rindex) {
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);

ret = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE,
GL_NOCACHE, &m_ip->i_gh);
if (ret)
goto out_unlock;
}

current->backing_dev_info = inode_to_bdi(inode);
ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops);
current->backing_dev_info = NULL;
if (ret > 0)
iocb->ki_pos += ret;

if (inode == sdp->sd_rindex) {
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);

gfs2_glock_dq_uninit(&m_ip->i_gh);
}

out_unlock:
gfs2_glock_dq(&ip->i_gh);
out_uninit:
gfs2_holder_uninit(&ip->i_gh);
return ret;
}

Expand Down

0 comments on commit 8d363d8

Please sign in to comment.