aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2012-08-22 10:15:26 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-09 08:08:21 -0500
commitc02abda2b28734a7e97e15db866507b3cb92b7d0 (patch)
treec85af57b2f3e9689d4374895c125da37d7ae7fad /drivers/block/drbd
parentc1fd29a11f433ca8ae37723768016ffe6cdd487b (diff)
drbd: mutex_unlock "... must no be used in interrupt context"
Documentation of mutex_unlock says we must not use it in interrupt context. So do not call it while holding the spin_lock_irq, but give up the spinlock temporarily. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd')
-rw-r--r--drivers/block/drbd/drbd_state.c74
1 files changed, 39 insertions, 35 deletions
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index ce1495187f02..755425a7a99b 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -1721,38 +1721,6 @@ _conn_rq_cond(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state
1721 return rv; 1721 return rv;
1722} 1722}
1723 1723
1724static enum drbd_state_rv
1725conn_cl_wide(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
1726 enum chg_state_flags f)
1727{
1728 enum drbd_state_rv rv;
1729
1730 spin_unlock_irq(&tconn->req_lock);
1731 mutex_lock(&tconn->cstate_mutex);
1732
1733 set_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
1734 if (conn_send_state_req(tconn, mask, val)) {
1735 clear_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
1736 /* if (f & CS_VERBOSE)
1737 print_st_err(mdev, os, ns, rv); */
1738 mutex_unlock(&tconn->cstate_mutex);
1739 spin_lock_irq(&tconn->req_lock);
1740 return SS_CW_FAILED_BY_PEER;
1741 }
1742
1743 if (val.conn == C_DISCONNECTING)
1744 set_bit(DISCONNECT_SENT, &tconn->flags);
1745
1746 spin_lock_irq(&tconn->req_lock);
1747
1748 wait_event_lock_irq(tconn->ping_wait, (rv = _conn_rq_cond(tconn, mask, val)), tconn->req_lock,);
1749 clear_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
1750
1751 mutex_unlock(&tconn->cstate_mutex);
1752
1753 return rv;
1754}
1755
1756enum drbd_state_rv 1724enum drbd_state_rv
1757_conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, 1725_conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
1758 enum chg_state_flags flags) 1726 enum chg_state_flags flags)
@@ -1761,6 +1729,7 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
1761 struct after_conn_state_chg_work *acscw; 1729 struct after_conn_state_chg_work *acscw;
1762 enum drbd_conns oc = tconn->cstate; 1730 enum drbd_conns oc = tconn->cstate;
1763 union drbd_state ns_max, ns_min, os; 1731 union drbd_state ns_max, ns_min, os;
1732 bool have_mutex = false;
1764 1733
1765 rv = is_valid_conn_transition(oc, val.conn); 1734 rv = is_valid_conn_transition(oc, val.conn);
1766 if (rv < SS_SUCCESS) 1735 if (rv < SS_SUCCESS)
@@ -1772,7 +1741,35 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
1772 1741
1773 if (oc == C_WF_REPORT_PARAMS && val.conn == C_DISCONNECTING && 1742 if (oc == C_WF_REPORT_PARAMS && val.conn == C_DISCONNECTING &&
1774 !(flags & (CS_LOCAL_ONLY | CS_HARD))) { 1743 !(flags & (CS_LOCAL_ONLY | CS_HARD))) {
1775 rv = conn_cl_wide(tconn, mask, val, flags); 1744
1745 /* This will be a cluster-wide state change.
1746 * Need to give up the spinlock, grab the mutex,
1747 * then send the state change request, ... */
1748 spin_unlock_irq(&tconn->req_lock);
1749 mutex_lock(&tconn->cstate_mutex);
1750 have_mutex = true;
1751
1752 set_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
1753 if (conn_send_state_req(tconn, mask, val)) {
1754 /* sending failed. */
1755 clear_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
1756 rv = SS_CW_FAILED_BY_PEER;
1757 /* need to re-aquire the spin lock, though */
1758 goto abort_unlocked;
1759 }
1760
1761 if (val.conn == C_DISCONNECTING)
1762 set_bit(DISCONNECT_SENT, &tconn->flags);
1763
1764 /* ... and re-aquire the spinlock.
1765 * If _conn_rq_cond() returned >= SS_SUCCESS, we must call
1766 * conn_set_state() within the same spinlock. */
1767 spin_lock_irq(&tconn->req_lock);
1768 wait_event_lock_irq(tconn->ping_wait,
1769 (rv = _conn_rq_cond(tconn, mask, val)),
1770 tconn->req_lock,
1771 );
1772 clear_bit(CONN_WD_ST_CHG_REQ, &tconn->flags);
1776 if (rv < SS_SUCCESS) 1773 if (rv < SS_SUCCESS)
1777 goto abort; 1774 goto abort;
1778 } 1775 }
@@ -1796,9 +1793,16 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
1796 conn_err(tconn, "Could not kmalloc an acscw\n"); 1793 conn_err(tconn, "Could not kmalloc an acscw\n");
1797 } 1794 }
1798 1795
1799 return rv;
1800 abort: 1796 abort:
1801 if (flags & CS_VERBOSE) { 1797 if (have_mutex) {
1798 /* mutex_unlock() "... must not be used in interrupt context.",
1799 * so give up the spinlock, then re-aquire it */
1800 spin_unlock_irq(&tconn->req_lock);
1801 abort_unlocked:
1802 mutex_unlock(&tconn->cstate_mutex);
1803 spin_lock_irq(&tconn->req_lock);
1804 }
1805 if (rv < SS_SUCCESS && flags & CS_VERBOSE) {
1802 conn_err(tconn, "State change failed: %s\n", drbd_set_st_err_str(rv)); 1806 conn_err(tconn, "State change failed: %s\n", drbd_set_st_err_str(rv));
1803 conn_err(tconn, " state = { cs:%s }\n", drbd_conn_str(oc)); 1807 conn_err(tconn, " state = { cs:%s }\n", drbd_conn_str(oc));
1804 conn_err(tconn, "wanted = { cs:%s }\n", drbd_conn_str(val.conn)); 1808 conn_err(tconn, "wanted = { cs:%s }\n", drbd_conn_str(val.conn));