Commit c2131f7e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull gfs2 fixes from Andreas Gruenbacher:
 "Various gfs2 fixes"

* tag 'gfs2-v5.13-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: Fix use-after-free in gfs2_glock_shrink_scan
  gfs2: Fix mmap locking for write faults
  gfs2: Clean up revokes on normal withdraws
  gfs2: fix a deadlock on withdraw-during-mount
  gfs2: fix scheduling while atomic bug in glocks
  gfs2: Fix I_NEW check in gfs2_dinode_in
  gfs2: Prevent direct-I/O write fallback errors from getting lost
parents 36c79551 1ab19c5d
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -540,9 +540,11 @@ static vm_fault_t gfs2_fault(struct vm_fault *vmf)
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_holder gh;
	vm_fault_t ret;
	u16 state;
	int err;

	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
	state = (vmf->flags & FAULT_FLAG_WRITE) ? LM_ST_EXCLUSIVE : LM_ST_SHARED;
	gfs2_holder_init(ip->i_gl, state, 0, &gh);
	err = gfs2_glock_nq(&gh);
	if (err) {
		ret = block_page_mkwrite_return(err);
@@ -911,8 +913,11 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
		current->backing_dev_info = inode_to_bdi(inode);
		buffered = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops);
		current->backing_dev_info = NULL;
		if (unlikely(buffered <= 0))
		if (unlikely(buffered <= 0)) {
			if (!ret)
				ret = buffered;
			goto out_unlock;
		}

		/*
		 * We need to ensure that the page cache pages are written to
+24 −4
Original line number Diff line number Diff line
@@ -582,6 +582,16 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
	spin_unlock(&gl->gl_lockref.lock);
}

static bool is_system_glock(struct gfs2_glock *gl)
{
	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
	struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);

	if (gl == m_ip->i_gl)
		return true;
	return false;
}

/**
 * do_xmote - Calls the DLM to change the state of a lock
 * @gl: The lock state
@@ -671,17 +681,25 @@ __acquires(&gl->gl_lockref.lock)
	 * to see sd_log_error and withdraw, and in the meantime, requeue the
	 * work for later.
	 *
	 * We make a special exception for some system glocks, such as the
	 * system statfs inode glock, which needs to be granted before the
	 * gfs2_quotad daemon can exit, and that exit needs to finish before
	 * we can unmount the withdrawn file system.
	 *
	 * However, if we're just unlocking the lock (say, for unmount, when
	 * gfs2_gl_hash_clear calls clear_glock) and recovery is complete
	 * then it's okay to tell dlm to unlock it.
	 */
	if (unlikely(sdp->sd_log_error && !gfs2_withdrawn(sdp)))
		gfs2_withdraw_delayed(sdp);
	if (glock_blocked_by_withdraw(gl)) {
		if (target != LM_ST_UNLOCKED ||
		    test_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags)) {
	if (glock_blocked_by_withdraw(gl) &&
	    (target != LM_ST_UNLOCKED ||
	     test_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags))) {
		if (!is_system_glock(gl)) {
			gfs2_glock_queue_work(gl, GL_GLOCK_DFT_HOLD);
			goto out;
		} else {
			clear_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags);
		}
	}

@@ -1466,9 +1484,11 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
	    glock_blocked_by_withdraw(gl) &&
	    gh->gh_gl != sdp->sd_jinode_gl) {
		sdp->sd_glock_dqs_held++;
		spin_unlock(&gl->gl_lockref.lock);
		might_sleep();
		wait_on_bit(&sdp->sd_flags, SDF_WITHDRAW_RECOVERY,
			    TASK_UNINTERRUPTIBLE);
		spin_lock(&gl->gl_lockref.lock);
	}
	if (gh->gh_flags & GL_NOCACHE)
		handle_callback(gl, LM_ST_UNLOCKED, 0, false);
@@ -1775,6 +1795,7 @@ __acquires(&lru_lock)
	while(!list_empty(list)) {
		gl = list_first_entry(list, struct gfs2_glock, gl_lru);
		list_del_init(&gl->gl_lru);
		clear_bit(GLF_LRU, &gl->gl_flags);
		if (!spin_trylock(&gl->gl_lockref.lock)) {
add_back_to_lru:
			list_add(&gl->gl_lru, &lru_list);
@@ -1820,7 +1841,6 @@ 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;
		}
+1 −1
Original line number Diff line number Diff line
@@ -396,7 +396,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
	struct timespec64 atime;
	u16 height, depth;
	umode_t mode = be32_to_cpu(str->di_mode);
	bool is_new = ip->i_inode.i_flags & I_NEW;
	bool is_new = ip->i_inode.i_state & I_NEW;

	if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)))
		goto corrupt;
+3 −3
Original line number Diff line number Diff line
@@ -926,10 +926,10 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
}

/**
 * ail_drain - drain the ail lists after a withdraw
 * gfs2_ail_drain - drain the ail lists after a withdraw
 * @sdp: Pointer to GFS2 superblock
 */
static void ail_drain(struct gfs2_sbd *sdp)
void gfs2_ail_drain(struct gfs2_sbd *sdp)
{
	struct gfs2_trans *tr;

@@ -956,6 +956,7 @@ static void ail_drain(struct gfs2_sbd *sdp)
		list_del(&tr->tr_list);
		gfs2_trans_free(sdp, tr);
	}
	gfs2_drain_revokes(sdp);
	spin_unlock(&sdp->sd_ail_lock);
}

@@ -1162,7 +1163,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
	if (tr && list_empty(&tr->tr_list))
		list_add(&tr->tr_list, &sdp->sd_ail1_list);
	spin_unlock(&sdp->sd_ail_lock);
	ail_drain(sdp); /* frees all transactions */
	tr = NULL;
	goto out_end;
}
+1 −0
Original line number Diff line number Diff line
@@ -93,5 +93,6 @@ extern int gfs2_logd(void *data);
extern void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
extern void gfs2_glock_remove_revoke(struct gfs2_glock *gl);
extern void gfs2_flush_revokes(struct gfs2_sbd *sdp);
extern void gfs2_ail_drain(struct gfs2_sbd *sdp);

#endif /* __LOG_DOT_H__ */
Loading