Commit 5c623c36 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull gfs2 fixes from Andreas Gruenbacher:

 - Since commit 486408d6 ("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
parents 12119cfa 3d36e57f
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -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);
+45 −64
Original line number Diff line number Diff line
@@ -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,6 +807,9 @@ 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);
		if (inode->i_state & I_NEW)
			iget_failed(inode);
		else
			iput(inode);
	}
	if (gfs2_holder_initialized(ghs + 1))