mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 14:41:39 +00:00
Fixes in gfs2:
* Since commit486408d690
("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. -----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEEJZs3krPW0xkhLMTc1b+f6wMTZToFAmGrPtYUHGFncnVlbmJh QHJlZGhhdC5jb20ACgkQ1b+f6wMTZTrtgA/+MESXTK8h/HK+M+CAnsJ5jFSVXV8W wmhhOtqikNGGruxnTJdkipe9PcPRsdwh4XLtmbfGairXnmFqJ+oEG8oRk/Tqoap8 9RxWN+B+Wzh79mNvI3Il3RtvUJGNQGrfDSuT5F4jZ6eZSfjsyY3cgO2KMt2TN5sL 7WXwYnj4VyPa8TdkSFIhfxwiXyal7aC8BVS6UX83CUIrhJvNG70A3hqVrIuKymUf dNiLWURdQ2oiDnX7hMjq/RnX84zAcp2B2wfKZVsX0ZcIqVdmHS5Er4PKqffEVOzq nf2SU4pAo4q7L7/66TdUtGoRgUSK74O83VTqsb1Lex5roON7unmVsjKyc7dmKUrR xt2Is4/OsCSZEsErWdMgtqer3fOxG1oGdSHzmgdRwqA22+Im5COTKjOBJ+3MXHaW E/36FGYYiugOLQn8hrqTqp3MIdPoZe8B/4ZF82qu6qYBQiA3PIHMlfElym5+45oR fqWLcwids4LV5esHK3YzZdQ3f9+FVIvcBayUUx71ZCD0QkNDUzTnckb5vTxwF3r1 zU/jIsv84dvQiTsCMhTxQq+JDY98V544sapa+0k7chwtwpTdeajTHjocECGRKE1E o5vCWX6gAiJQ/5RtgfBS2DWXrBQNueUsYpBQM9jp2fr6kxK+Hc5MT8JMdZWw7Rb7 1ZDw9PNs8TpByzc= =7HvB -----END PGP SIGNATURE----- Merge tag 'gfs2-v5.16-rc4-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2 Pull gfs2 fixes from Andreas Gruenbacher: - Since commit486408d690
("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
This commit is contained in:
commit
5c623c3689
@ -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;
|
||||
@ -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);
|
||||
|
109
fs/gfs2/inode.c
109
fs/gfs2/inode.c
@ -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
|
||||
@ -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
|
||||
@ -132,12 +117,11 @@ 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);
|
||||
|
||||
@ -145,22 +129,16 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
|
||||
|
||||
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,
|
||||
@ -181,24 +159,31 @@ 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);
|
||||
@ -206,31 +191,23 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int 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);
|
||||
@ -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;
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -829,7 +807,10 @@ fail_gunlock:
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user