Skip to content

Commit

Permalink
Merge tag 'gfs2-v5.16-rc4-fixes' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/gfs2/linux-gfs2

Pull gfs2 fixes from Andreas Gruenbacher:

 - Since commit 486408d ("gfs2: Cancel remote delete work
   asynchronously"), inode create and lookup-by-number can overlap more
   easily and we can end up with temporary duplicate inodes. Fix the
   code to prevent that.

 - Fix a BUG demoting weak glock holders from a remote node.

* tag 'gfs2-v5.16-rc4-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: gfs2_create_inode rework
  gfs2: gfs2_inode_lookup rework
  gfs2: gfs2_inode_lookup cleanup
  gfs2: Fix remote demote of weak glock holders
  • Loading branch information
torvalds committed Dec 4, 2021
2 parents 12119cf + 3d36e57 commit 5c623c3
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 67 deletions.
10 changes: 7 additions & 3 deletions fs/gfs2/glock.c
Original file line number Diff line number Diff line change
Expand Up @@ -1857,7 +1857,6 @@ void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs)

void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
{
struct gfs2_holder mock_gh = { .gh_gl = gl, .gh_state = state, };
unsigned long delay = 0;
unsigned long holdtime;
unsigned long now = jiffies;
Expand Down Expand Up @@ -1890,8 +1889,13 @@ void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
* keep the glock until the last strong holder is done with it.
*/
if (!find_first_strong_holder(gl)) {
if (state == LM_ST_UNLOCKED)
mock_gh.gh_state = LM_ST_EXCLUSIVE;
struct gfs2_holder mock_gh = {
.gh_gl = gl,
.gh_state = (state == LM_ST_UNLOCKED) ?
LM_ST_EXCLUSIVE : state,
.gh_iflags = BIT(HIF_HOLDER)
};

demote_incompat_holders(gl, &mock_gh);
}
handle_callback(gl, state, delay, true);
Expand Down
109 changes: 45 additions & 64 deletions fs/gfs2/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,37 +40,6 @@ static const struct inode_operations gfs2_file_iops;
static const struct inode_operations gfs2_dir_iops;
static const struct inode_operations gfs2_symlink_iops;

static int iget_test(struct inode *inode, void *opaque)
{
u64 no_addr = *(u64 *)opaque;

return GFS2_I(inode)->i_no_addr == no_addr;
}

static int iget_set(struct inode *inode, void *opaque)
{
u64 no_addr = *(u64 *)opaque;

GFS2_I(inode)->i_no_addr = no_addr;
inode->i_ino = no_addr;
return 0;
}

static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr)
{
struct inode *inode;

repeat:
inode = iget5_locked(sb, no_addr, iget_test, iget_set, &no_addr);
if (!inode)
return inode;
if (is_bad_inode(inode)) {
iput(inode);
goto repeat;
}
return inode;
}

/**
* gfs2_set_iop - Sets inode operations
* @inode: The inode with correct i_mode filled in
Expand Down Expand Up @@ -104,6 +73,22 @@ static void gfs2_set_iop(struct inode *inode)
}
}

static int iget_test(struct inode *inode, void *opaque)
{
u64 no_addr = *(u64 *)opaque;

return GFS2_I(inode)->i_no_addr == no_addr;
}

static int iget_set(struct inode *inode, void *opaque)
{
u64 no_addr = *(u64 *)opaque;

GFS2_I(inode)->i_no_addr = no_addr;
inode->i_ino = no_addr;
return 0;
}

/**
* gfs2_inode_lookup - Lookup an inode
* @sb: The super block
Expand Down Expand Up @@ -132,35 +117,28 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
{
struct inode *inode;
struct gfs2_inode *ip;
struct gfs2_glock *io_gl = NULL;
struct gfs2_holder i_gh;
int error;

gfs2_holder_mark_uninitialized(&i_gh);
inode = gfs2_iget(sb, no_addr);
inode = iget5_locked(sb, no_addr, iget_test, iget_set, &no_addr);
if (!inode)
return ERR_PTR(-ENOMEM);

ip = GFS2_I(inode);

if (inode->i_state & I_NEW) {
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_glock *io_gl;

error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
if (unlikely(error))
goto fail;
flush_delayed_work(&ip->i_gl->gl_work);

error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
if (unlikely(error))
goto fail;
if (blktype != GFS2_BLKST_UNLINKED)
gfs2_cancel_delete_work(io_gl);

if (type == DT_UNKNOWN || blktype != GFS2_BLKST_FREE) {
/*
* The GL_SKIP flag indicates to skip reading the inode
* block. We read the inode with gfs2_inode_refresh
* block. We read the inode when instantiating it
* after possibly checking the block type.
*/
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE,
Expand All @@ -181,56 +159,55 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
}
}

glock_set_object(ip->i_gl, ip);
set_bit(GLF_INSTANTIATE_NEEDED, &ip->i_gl->gl_flags);
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);

error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
if (unlikely(error))
goto fail;
glock_set_object(ip->i_iopen_gh.gh_gl, ip);
if (blktype != GFS2_BLKST_UNLINKED)
gfs2_cancel_delete_work(io_gl);
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
gfs2_glock_put(io_gl);
io_gl = NULL;
if (unlikely(error))
goto fail;

/* Lowest possible timestamp; will be overwritten in gfs2_dinode_in. */
inode->i_atime.tv_sec = 1LL << (8 * sizeof(inode->i_atime.tv_sec) - 1);
inode->i_atime.tv_nsec = 0;

glock_set_object(ip->i_gl, ip);

if (type == DT_UNKNOWN) {
/* Inode glock must be locked already */
error = gfs2_instantiate(&i_gh);
if (error)
if (error) {
glock_clear_object(ip->i_gl, ip);
goto fail;
}
} else {
ip->i_no_formal_ino = no_formal_ino;
inode->i_mode = DT2IF(type);
}

if (gfs2_holder_initialized(&i_gh))
gfs2_glock_dq_uninit(&i_gh);
glock_set_object(ip->i_iopen_gh.gh_gl, ip);

gfs2_set_iop(inode);
unlock_new_inode(inode);
}

if (no_formal_ino && ip->i_no_formal_ino &&
no_formal_ino != ip->i_no_formal_ino) {
error = -ESTALE;
if (inode->i_state & I_NEW)
goto fail;
iput(inode);
return ERR_PTR(error);
return ERR_PTR(-ESTALE);
}

if (inode->i_state & I_NEW)
unlock_new_inode(inode);

return inode;

fail:
if (gfs2_holder_initialized(&ip->i_iopen_gh)) {
glock_clear_object(ip->i_iopen_gh.gh_gl, ip);
if (gfs2_holder_initialized(&ip->i_iopen_gh))
gfs2_glock_dq_uninit(&ip->i_iopen_gh);
}
if (io_gl)
gfs2_glock_put(io_gl);
if (gfs2_holder_initialized(&i_gh))
gfs2_glock_dq_uninit(&i_gh);
iget_failed(inode);
Expand Down Expand Up @@ -730,18 +707,19 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
if (error)
goto fail_free_inode;
flush_delayed_work(&ip->i_gl->gl_work);

error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
if (error)
goto fail_free_inode;
gfs2_cancel_delete_work(io_gl);

error = insert_inode_locked4(inode, ip->i_no_addr, iget_test, &ip->i_no_addr);
BUG_ON(error);

error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
if (error)
goto fail_gunlock2;

glock_set_object(ip->i_gl, ip);
error = gfs2_trans_begin(sdp, blocks, 0);
if (error)
goto fail_gunlock2;
Expand All @@ -757,9 +735,9 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
if (error)
goto fail_gunlock2;

glock_set_object(ip->i_gl, ip);
glock_set_object(io_gl, ip);
gfs2_set_iop(inode);
insert_inode_hash(inode);

free_vfs_inode = 0; /* After this point, the inode is no longer
considered free. Any failures need to undo
Expand Down Expand Up @@ -801,17 +779,17 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
gfs2_glock_dq_uninit(ghs + 1);
gfs2_glock_put(io_gl);
gfs2_qa_put(dip);
unlock_new_inode(inode);
return error;

fail_gunlock3:
glock_clear_object(ip->i_gl, ip);
glock_clear_object(io_gl, ip);
gfs2_glock_dq_uninit(&ip->i_iopen_gh);
fail_gunlock2:
glock_clear_object(io_gl, ip);
gfs2_glock_put(io_gl);
fail_free_inode:
if (ip->i_gl) {
glock_clear_object(ip->i_gl, ip);
if (free_vfs_inode) /* else evict will do the put for us */
gfs2_glock_put(ip->i_gl);
}
Expand All @@ -829,7 +807,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
mark_inode_dirty(inode);
set_bit(free_vfs_inode ? GIF_FREE_VFS_INODE : GIF_ALLOC_FAILED,
&GFS2_I(inode)->i_flags);
iput(inode);
if (inode->i_state & I_NEW)
iget_failed(inode);
else
iput(inode);
}
if (gfs2_holder_initialized(ghs + 1))
gfs2_glock_dq_uninit(ghs + 1);
Expand Down

0 comments on commit 5c623c3

Please sign in to comment.