Commit a40eb50a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull gfs2 updates from Andreas Gruenbacher:

 - Partially revert "gfs2: do_xmote fixes" to ignore dlm_lock() errors
   during withdraw; passing on those errors doesn't help

 - Change the LM_FLAG_TRY and LM_FLAG_TRY_1CB logic in add_to_queue() to
   check if the holder would actually block

 - Move some more dlm specific code from glock.c to lock_dlm.c

 - Remove the unused dlm alternate locking mode code

 - Add proper locking to make sure that dlm lockspaces are never used
   after being released

 - Various other cleanups

* tag 'gfs2-for-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: Fix unlikely race in gdlm_put_lock
  gfs2: Add proper lockspace locking
  gfs2: Minor run_queue fixes
  gfs2: run_queue cleanup
  gfs2: Simplify do_promote
  gfs2: Get rid of GLF_INVALIDATE_IN_PROGRESS
  gfs2: Fix GLF_INVALIDATE_IN_PROGRESS flag clearing in do_xmote
  gfs2: Remove duplicate check in do_xmote
  gfs2: Fix LM_FLAG_TRY* logic in add_to_queue
  gfs2: Remove DLM_LKF_ALTCW / DLM_LKF_ALTPR code
  gfs2: Further sanitize lock_dlm.c
  gfs2: Do not use atomic operations unnecessarily
  gfs2: Sanitize gfs2_meta_check, gfs2_metatype_check, gfs2_io_error
  gfs2: Turn gfs2_withdraw into a void function
  gfs2: Partially revert "gfs2: do_xmote fixes"
  gfs2: Simplify refcounting in do_xmote
  gfs2: do_xmote cleanup
  gfs2: Remove space before newline
  gfs2: Remove unused sd_withdraw_wait field
  gfs2: Remove unused GIF_FREE_VFS_INODE flag
parents f2c61db2 28c4d9bc
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -1442,6 +1442,7 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
	struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
	struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	int ret;

	if (!(fl->c.flc_flags & FL_POSIX))
		return -ENOLCK;
@@ -1450,14 +1451,20 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
			locks_lock_file_wait(file, fl);
		return -EIO;
	}
	down_read(&ls->ls_sem);
	ret = -ENODEV;
	if (likely(ls->ls_dlm != NULL)) {
		if (cmd == F_CANCELLK)
		return dlm_posix_cancel(ls->ls_dlm, ip->i_no_addr, file, fl);
			ret = dlm_posix_cancel(ls->ls_dlm, ip->i_no_addr, file, fl);
		else if (IS_GETLK(cmd))
		return dlm_posix_get(ls->ls_dlm, ip->i_no_addr, file, fl);
			ret = dlm_posix_get(ls->ls_dlm, ip->i_no_addr, file, fl);
		else if (lock_is_unlock(fl))
		return dlm_posix_unlock(ls->ls_dlm, ip->i_no_addr, file, fl);
			ret = dlm_posix_unlock(ls->ls_dlm, ip->i_no_addr, file, fl);
		else
		return dlm_posix_lock(ls->ls_dlm, ip->i_no_addr, file, cmd, fl);
			ret = dlm_posix_lock(ls->ls_dlm, ip->i_no_addr, file, cmd, fl);
	}
	up_read(&ls->ls_sem);
	return ret;
}

static void __flock_holder_uninit(struct file *file, struct gfs2_holder *fl_gh)
+85 −100
Original line number Diff line number Diff line
@@ -481,11 +481,9 @@ int gfs2_instantiate(struct gfs2_holder *gh)
/**
 * do_promote - promote as many requests as possible on the current queue
 * @gl: The glock
 * 
 * Returns true on success (i.e., progress was made or there are no waiters).
 */

static bool do_promote(struct gfs2_glock *gl)
static void do_promote(struct gfs2_glock *gl)
{
	struct gfs2_holder *gh, *current_gh;

@@ -496,13 +494,10 @@ static bool do_promote(struct gfs2_glock *gl)
		if (!may_grant(gl, current_gh, gh)) {
			/*
			 * If we get here, it means we may not grant this
			 * holder for some reason. If this holder is at the
			 * head of the list, it means we have a blocked holder
			 * at the head, so return false.
			 * holder for some reason.
			 */
			if (list_is_first(&gh->gh_list, &gl->gl_holders))
				return false;
			do_error(gl, 0);
			if (current_gh)
				do_error(gl, 0); /* Fail queued try locks */
			break;
		}
		set_bit(HIF_HOLDER, &gh->gh_iflags);
@@ -511,7 +506,6 @@ static bool do_promote(struct gfs2_glock *gl)
		if (!current_gh)
			current_gh = gh;
	}
	return true;
}

/**
@@ -646,8 +640,10 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
	}

	/* Fast path - we got what we asked for */
	if (test_and_clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags))
	if (test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags)) {
		clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
		gfs2_demote_wake(gl);
	}
	if (gl->gl_state != LM_ST_UNLOCKED) {
		if (glops->go_xmote_bh) {
			int rv;
@@ -693,39 +689,18 @@ __acquires(&gl->gl_lockref.lock)
	const struct gfs2_glock_operations *glops = gl->gl_ops;
	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	unsigned int lck_flags = (unsigned int)(gh ? gh->gh_flags : 0);
	int ret;

	if (target != LM_ST_UNLOCKED && glock_blocked_by_withdraw(gl) &&
	    gh && !(gh->gh_flags & LM_FLAG_NOEXP))
		goto skip_inval;

	lck_flags &= (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP);
	GLOCK_BUG_ON(gl, gl->gl_state == target);
	GLOCK_BUG_ON(gl, gl->gl_state == gl->gl_target);
	if ((target == LM_ST_UNLOCKED || target == LM_ST_DEFERRED) &&
	    glops->go_inval) {
		/*
		 * If another process is already doing the invalidate, let that
		 * finish first.  The glock state machine will get back to this
		 * holder again later.
		 */
		if (test_and_set_bit(GLF_INVALIDATE_IN_PROGRESS,
				     &gl->gl_flags))
			return;
		do_error(gl, 0); /* Fail queued try locks */
	}
	gl->gl_req = target;
	set_bit(GLF_BLOCKING, &gl->gl_flags);
	if ((gl->gl_req == LM_ST_UNLOCKED) ||
	    (gl->gl_state == LM_ST_EXCLUSIVE) ||
	    (lck_flags & (LM_FLAG_TRY|LM_FLAG_TRY_1CB)))
		clear_bit(GLF_BLOCKING, &gl->gl_flags);
	if (!glops->go_inval && !glops->go_sync)
	if (!glops->go_inval || !glops->go_sync)
		goto skip_inval;

	spin_unlock(&gl->gl_lockref.lock);
	if (glops->go_sync) {
	ret = glops->go_sync(gl);
	/* If we had a problem syncing (due to io errors or whatever,
	 * we should not invalidate the metadata or tell dlm to
@@ -739,8 +714,8 @@ __acquires(&gl->gl_lockref.lock)
		spin_lock(&gl->gl_lockref.lock);
		goto skip_inval;
	}
	}
	if (test_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags)) {

	if (target == LM_ST_UNLOCKED || target == LM_ST_DEFERRED) {
		/*
		 * The call to go_sync should have cleared out the ail list.
		 * If there are still items, we have a problem. We ought to
@@ -755,12 +730,10 @@ __acquires(&gl->gl_lockref.lock)
			gfs2_dump_glock(NULL, gl, true);
		}
		glops->go_inval(gl, target == LM_ST_DEFERRED ? 0 : DIO_METADATA);
		clear_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags);
	}
	spin_lock(&gl->gl_lockref.lock);

skip_inval:
	gl->gl_lockref.count++;
	/*
	 * Check for an error encountered since we called go_sync and go_inval.
	 * If so, we can't withdraw from the glock code because the withdraw
@@ -803,38 +776,41 @@ __acquires(&gl->gl_lockref.lock)
			if (!test_bit(GLF_CANCELING, &gl->gl_flags))
				clear_bit(GLF_LOCK, &gl->gl_flags);
			clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
			gl->gl_lockref.count++;
			gfs2_glock_queue_work(gl, GL_GLOCK_DFT_HOLD);
			return;
		} else {
			clear_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags);
		}
	}

	if (ls->ls_ops->lm_lock) {
		set_bit(GLF_PENDING_REPLY, &gl->gl_flags);
		spin_unlock(&gl->gl_lockref.lock);
		ret = ls->ls_ops->lm_lock(gl, target, lck_flags);
		ret = ls->ls_ops->lm_lock(gl, target, gh ? gh->gh_flags : 0);
		spin_lock(&gl->gl_lockref.lock);

		if (ret == -EINVAL && gl->gl_target == LM_ST_UNLOCKED &&
		    target == LM_ST_UNLOCKED &&
		    test_bit(DFL_UNMOUNT, &ls->ls_recover_flags)) {
		if (!ret) {
			/* The operation will be completed asynchronously. */
			gl->gl_lockref.count++;
			return;
		}
		clear_bit(GLF_PENDING_REPLY, &gl->gl_flags);

		if (ret == -ENODEV && gl->gl_target == LM_ST_UNLOCKED &&
		    target == LM_ST_UNLOCKED) {
			/*
			 * The lockspace has been released and the lock has
			 * been unlocked implicitly.
			 */
		} else if (ret) {
			fs_err(sdp, "lm_lock ret %d\n", ret);
			target = gl->gl_state | LM_OUT_ERROR;
		} else {
			/* The operation will be completed asynchronously. */
			fs_err(sdp, "lm_lock ret %d\n", ret);
			GLOCK_BUG_ON(gl, !gfs2_withdrawing_or_withdrawn(sdp));
			return;
		}
		clear_bit(GLF_PENDING_REPLY, &gl->gl_flags);
	}

	/* Complete the operation now. */
	finish_xmote(gl, target);
	gl->gl_lockref.count++;
	gfs2_glock_queue_work(gl, 0);
}

@@ -855,11 +831,20 @@ __acquires(&gl->gl_lockref.lock)
		return;
	set_bit(GLF_LOCK, &gl->gl_flags);

	/* While a demote is in progress, the GLF_LOCK flag must be set. */
	/*
	 * The GLF_DEMOTE_IN_PROGRESS flag is only set intermittently during
	 * locking operations.  We have just started a locking operation by
	 * setting the GLF_LOCK flag, so the GLF_DEMOTE_IN_PROGRESS flag must
	 * be cleared.
	 */
	GLOCK_BUG_ON(gl, test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags));

	if (test_bit(GLF_DEMOTE, &gl->gl_flags) &&
	    gl->gl_demote_state != gl->gl_state) {
	if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
		if (gl->gl_demote_state == gl->gl_state) {
			gfs2_demote_wake(gl);
			goto promote;
		}

		if (find_first_holder(gl))
			goto out_unlock;
		if (nonblock)
@@ -869,31 +854,31 @@ __acquires(&gl->gl_lockref.lock)
		gl->gl_target = gl->gl_demote_state;
		do_xmote(gl, NULL, gl->gl_target);
		return;
	} else {
		if (test_bit(GLF_DEMOTE, &gl->gl_flags))
			gfs2_demote_wake(gl);
		if (do_promote(gl))
	}

promote:
	do_promote(gl);
	if (find_first_holder(gl))
		goto out_unlock;
	gh = find_first_waiter(gl);
	if (!gh)
		goto out_unlock;
	if (nonblock)
		goto out_sched;
	gl->gl_target = gh->gh_state;
	if (!(gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)))
		do_error(gl, 0); /* Fail queued try locks */
	do_xmote(gl, gh, gl->gl_target);
	return;
	}

out_sched:
	clear_bit(GLF_LOCK, &gl->gl_flags);
	smp_mb__after_atomic();
	gl->gl_lockref.count++;
	gfs2_glock_queue_work(gl, 0);
	return;

out_unlock:
	clear_bit(GLF_LOCK, &gl->gl_flags);
	smp_mb__after_atomic();
}

/**
@@ -1462,6 +1447,24 @@ void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...)
	va_end(args);
}

static bool gfs2_should_queue_trylock(struct gfs2_glock *gl,
				      struct gfs2_holder *gh)
{
	struct gfs2_holder *current_gh, *gh2;

	current_gh = find_first_holder(gl);
	if (current_gh && !may_grant(gl, current_gh, gh))
		return false;

	list_for_each_entry(gh2, &gl->gl_holders, gh_list) {
		if (test_bit(HIF_HOLDER, &gh2->gh_iflags))
			continue;
		if (!(gh2->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)))
			return false;
	}
	return true;
}

static inline bool pid_is_meaningful(const struct gfs2_holder *gh)
{
        if (!(gh->gh_flags & GL_NOPID))
@@ -1480,27 +1483,20 @@ static inline bool pid_is_meaningful(const struct gfs2_holder *gh)
 */

static inline void add_to_queue(struct gfs2_holder *gh)
__releases(&gl->gl_lockref.lock)
__acquires(&gl->gl_lockref.lock)
{
	struct gfs2_glock *gl = gh->gh_gl;
	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
	struct gfs2_holder *gh2;
	int try_futile = 0;

	GLOCK_BUG_ON(gl, gh->gh_owner_pid == NULL);
	if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
		GLOCK_BUG_ON(gl, true);

	if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
		if (test_bit(GLF_LOCK, &gl->gl_flags)) {
			struct gfs2_holder *current_gh;

			current_gh = find_first_holder(gl);
			try_futile = !may_grant(gl, current_gh, gh);
		}
		if (test_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags))
			goto fail;
	if ((gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) &&
	    !gfs2_should_queue_trylock(gl, gh)) {
		gh->gh_error = GLR_TRYFAILED;
		gfs2_holder_wake(gh);
		return;
	}

	list_for_each_entry(gh2, &gl->gl_holders, gh_list) {
@@ -1512,15 +1508,6 @@ __acquires(&gl->gl_lockref.lock)
			continue;
		goto trap_recursive;
	}
	list_for_each_entry(gh2, &gl->gl_holders, gh_list) {
		if (try_futile &&
		    !(gh2->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) {
fail:
			gh->gh_error = GLR_TRYFAILED;
			gfs2_holder_wake(gh);
			return;
		}
	}
	trace_gfs2_glock_queue(gh, 1);
	gfs2_glstats_inc(gl, GFS2_LKS_QCOUNT);
	gfs2_sbstats_inc(gl, GFS2_LKS_QCOUNT);
@@ -2321,8 +2308,6 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
		*p++ = 'y';
	if (test_bit(GLF_LFLUSH, gflags))
		*p++ = 'f';
	if (test_bit(GLF_INVALIDATE_IN_PROGRESS, gflags))
		*p++ = 'i';
	if (test_bit(GLF_PENDING_REPLY, gflags))
		*p++ = 'R';
	if (test_bit(GLF_HAVE_REPLY, gflags))
+4 −0
Original line number Diff line number Diff line
@@ -68,6 +68,10 @@ enum {
 * also be granted in SHARED.  The preferred state is whichever is compatible
 * with other granted locks, or the specified state if no other locks exist.
 *
 * In addition, when a lock is already held in EX mode locally, a SHARED or
 * DEFERRED mode request with the LM_FLAG_ANY flag set will be granted.
 * (The LM_FLAG_ANY flag is only use for SHARED mode requests currently.)
 *
 * LM_FLAG_NODE_SCOPE
 * This holder agrees to share the lock within this node. In other words,
 * the glock is held in EX mode according to DLM, but local holders on the
+2 −3
Original line number Diff line number Diff line
@@ -319,7 +319,6 @@ enum {
	GLF_DEMOTE_IN_PROGRESS		= 5,
	GLF_DIRTY			= 6,
	GLF_LFLUSH			= 7,
	GLF_INVALIDATE_IN_PROGRESS	= 8,
	GLF_HAVE_REPLY			= 9,
	GLF_INITIAL			= 10,
	GLF_HAVE_FROZEN_REPLY		= 11,
@@ -376,7 +375,6 @@ struct gfs2_glock {
enum {
	GIF_QD_LOCKED		= 1,
	GIF_SW_PAGED		= 3,
	GIF_FREE_VFS_INODE      = 5,
	GIF_GLOP_PENDING	= 6,
};

@@ -658,6 +656,8 @@ struct lm_lockstruct {
	struct completion ls_sync_wait; /* {control,mounted}_{lock,unlock} */
	char *ls_lvb_bits;

	struct rw_semaphore ls_sem;

	spinlock_t ls_recover_spin; /* protects following fields */
	unsigned long ls_recover_flags; /* DFL_ */
	uint32_t ls_recover_mount; /* gen in first recover_done cb */
@@ -823,7 +823,6 @@ struct gfs2_sbd {
	atomic_t sd_log_in_flight;
	wait_queue_head_t sd_log_flush_wait;
	int sd_log_error; /* First log error */
	wait_queue_head_t sd_withdraw_wait;

	unsigned int sd_log_tail;
	unsigned int sd_log_flush_tail;
+60 −40
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ static inline void gfs2_update_stats(struct gfs2_lkstats *s, unsigned index,
/**
 * gfs2_update_reply_times - Update locking statistics
 * @gl: The glock to update
 * @blocking: The operation may have been blocking
 *
 * This assumes that gl->gl_dstamp has been set earlier.
 *
@@ -72,12 +73,12 @@ static inline void gfs2_update_stats(struct gfs2_lkstats *s, unsigned index,
 * TRY_1CB flags are set are classified as non-blocking. All
 * other DLM requests are counted as (potentially) blocking.
 */
static inline void gfs2_update_reply_times(struct gfs2_glock *gl)
static inline void gfs2_update_reply_times(struct gfs2_glock *gl,
					   bool blocking)
{
	struct gfs2_pcpu_lkstats *lks;
	const unsigned gltype = gl->gl_name.ln_type;
	unsigned index = test_bit(GLF_BLOCKING, &gl->gl_flags) ?
			 GFS2_LKS_SRTTB : GFS2_LKS_SRTT;
	unsigned index = blocking ? GFS2_LKS_SRTTB : GFS2_LKS_SRTT;
	s64 rtt;

	preempt_disable();
@@ -119,14 +120,18 @@ static inline void gfs2_update_request_times(struct gfs2_glock *gl)
static void gdlm_ast(void *arg)
{
	struct gfs2_glock *gl = arg;
	bool blocking;
	unsigned ret;

	blocking = test_bit(GLF_BLOCKING, &gl->gl_flags);
	gfs2_update_reply_times(gl, blocking);
	clear_bit(GLF_BLOCKING, &gl->gl_flags);

	/* If the glock is dead, we only react to a dlm_unlock() reply. */
	if (__lockref_is_dead(&gl->gl_lockref) &&
	    gl->gl_lksb.sb_status != -DLM_EUNLOCK)
		return;

	gfs2_update_reply_times(gl);
	BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED);

	if ((gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID) && gl->gl_lksb.sb_lvbptr)
@@ -157,14 +162,6 @@ static void gdlm_ast(void *arg)
	}

	ret = gl->gl_req;
	if (gl->gl_lksb.sb_flags & DLM_SBF_ALTMODE) {
		if (gl->gl_req == LM_ST_SHARED)
			ret = LM_ST_DEFERRED;
		else if (gl->gl_req == LM_ST_DEFERRED)
			ret = LM_ST_SHARED;
		else
			BUG();
	}

	/*
	 * The GLF_INITIAL flag is initially set for new glocks.  Upon the
@@ -241,7 +238,7 @@ static bool down_conversion(int cur, int req)
}

static u32 make_flags(struct gfs2_glock *gl, const unsigned int gfs_flags,
		      const int cur, const int req)
		      const int req, bool blocking)
{
	u32 lkf = 0;

@@ -256,15 +253,6 @@ static u32 make_flags(struct gfs2_glock *gl, const unsigned int gfs_flags,
		lkf |= DLM_LKF_NOQUEUEBAST;
	}

	if (gfs_flags & LM_FLAG_ANY) {
		if (req == DLM_LOCK_PR)
			lkf |= DLM_LKF_ALTCW;
		else if (req == DLM_LOCK_CW)
			lkf |= DLM_LKF_ALTPR;
		else
			BUG();
	}

	if (!test_bit(GLF_INITIAL, &gl->gl_flags)) {
		lkf |= DLM_LKF_CONVERT;

@@ -274,7 +262,7 @@ static u32 make_flags(struct gfs2_glock *gl, const unsigned int gfs_flags,
		 * "upward" lock conversions or else DLM will reject the
		 * request as invalid.
		 */
		if (!down_conversion(cur, req))
		if (blocking)
			lkf |= DLM_LKF_QUECVT;
	}

@@ -294,14 +282,20 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
		     unsigned int flags)
{
	struct lm_lockstruct *ls = &gl->gl_name.ln_sbd->sd_lockstruct;
	bool blocking;
	int cur, req;
	u32 lkf;
	char strname[GDLM_STRNAME_BYTES] = "";
	int error;

	gl->gl_req = req_state;
	cur = make_mode(gl->gl_name.ln_sbd, gl->gl_state);
	req = make_mode(gl->gl_name.ln_sbd, req_state);
	lkf = make_flags(gl, flags, cur, req);
	blocking = !down_conversion(cur, req) &&
		   !(flags & (LM_FLAG_TRY|LM_FLAG_TRY_1CB));
	lkf = make_flags(gl, flags, req, blocking);
	if (blocking)
		set_bit(GLF_BLOCKING, &gl->gl_flags);
	gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT);
	gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
	if (test_bit(GLF_INITIAL, &gl->gl_flags)) {
@@ -318,8 +312,13 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
	 */

again:
	down_read(&ls->ls_sem);
	error = -ENODEV;
	if (likely(ls->ls_dlm != NULL)) {
		error = dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
				GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
	}
	up_read(&ls->ls_sem);
	if (error == -EBUSY) {
		msleep(20);
		goto again;
@@ -341,17 +340,10 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
		return;
	}

	clear_bit(GLF_BLOCKING, &gl->gl_flags);
	gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT);
	gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
	gfs2_update_request_times(gl);

	/* don't want to call dlm if we've unmounted the lock protocol */
	if (test_bit(DFL_UNMOUNT, &ls->ls_recover_flags)) {
		gfs2_glock_free(gl);
		return;
	}

	/*
	 * When the lockspace is released, all remaining glocks will be
	 * unlocked automatically.  This is more efficient than unlocking them
@@ -369,13 +361,23 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
		flags |= DLM_LKF_VALBLK;

again:
	down_read(&ls->ls_sem);
	error = -ENODEV;
	if (likely(ls->ls_dlm != NULL)) {
		error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, flags,
				   NULL, gl);
	}
	up_read(&ls->ls_sem);
	if (error == -EBUSY) {
		msleep(20);
		goto again;
	}

	if (error == -ENODEV) {
		gfs2_glock_free(gl);
		return;
	}

	if (error) {
		fs_err(sdp, "gdlm_unlock %x,%llx err=%d\n",
		       gl->gl_name.ln_type,
@@ -386,8 +388,13 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
static void gdlm_cancel(struct gfs2_glock *gl)
{
	struct lm_lockstruct *ls = &gl->gl_name.ln_sbd->sd_lockstruct;

	down_read(&ls->ls_sem);
	if (likely(ls->ls_dlm != NULL)) {
		dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_CANCEL, NULL, gl);
	}
	up_read(&ls->ls_sem);
}

/*
 * dlm/gfs2 recovery coordination using dlm_recover callbacks
@@ -567,7 +574,11 @@ static int sync_unlock(struct gfs2_sbd *sdp, struct dlm_lksb *lksb, char *name)
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	int error;

	down_read(&ls->ls_sem);
	error = -ENODEV;
	if (likely(ls->ls_dlm != NULL))
		error = dlm_unlock(ls->ls_dlm, lksb->sb_lkid, 0, lksb, ls);
	up_read(&ls->ls_sem);
	if (error) {
		fs_err(sdp, "%s lkid %x error %d\n",
		       name, lksb->sb_lkid, error);
@@ -594,9 +605,14 @@ static int sync_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags,
	memset(strname, 0, GDLM_STRNAME_BYTES);
	snprintf(strname, GDLM_STRNAME_BYTES, "%8x%16x", LM_TYPE_NONDISK, num);

	down_read(&ls->ls_sem);
	error = -ENODEV;
	if (likely(ls->ls_dlm != NULL)) {
		error = dlm_lock(ls->ls_dlm, mode, lksb, flags,
				 strname, GDLM_STRNAME_BYTES - 1,
				 0, sync_wait_cb, ls, NULL);
	}
	up_read(&ls->ls_sem);
	if (error) {
		fs_err(sdp, "%s lkid %x flags %x mode %d error %d\n",
		       name, lksb->sb_lkid, flags, mode, error);
@@ -1323,6 +1339,7 @@ static int gdlm_mount(struct gfs2_sbd *sdp, const char *table)
	 */

	INIT_DELAYED_WORK(&sdp->sd_control_work, gfs2_control_func);
	ls->ls_dlm = NULL;
	spin_lock_init(&ls->ls_recover_spin);
	ls->ls_recover_flags = 0;
	ls->ls_recover_mount = 0;
@@ -1357,6 +1374,7 @@ static int gdlm_mount(struct gfs2_sbd *sdp, const char *table)
	 * create/join lockspace
	 */

	init_rwsem(&ls->ls_sem);
	error = dlm_new_lockspace(fsname, cluster, flags, GDLM_LVB_SIZE,
				  &gdlm_lockspace_ops, sdp, &ops_result,
				  &ls->ls_dlm);
@@ -1436,10 +1454,12 @@ static void gdlm_unmount(struct gfs2_sbd *sdp)

	/* mounted_lock and control_lock will be purged in dlm recovery */
release:
	down_write(&ls->ls_sem);
	if (ls->ls_dlm) {
		dlm_release_lockspace(ls->ls_dlm, 2);
		ls->ls_dlm = NULL;
	}
	up_write(&ls->ls_sem);

	free_recover_size(ls);
}
Loading