diff options
| author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2012-08-22 10:15:26 -0400 |
|---|---|---|
| committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-09 08:08:21 -0500 |
| commit | c02abda2b28734a7e97e15db866507b3cb92b7d0 (patch) | |
| tree | c85af57b2f3e9689d4374895c125da37d7ae7fad /drivers/block/drbd | |
| parent | c1fd29a11f433ca8ae37723768016ffe6cdd487b (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.c | 74 |
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 | ||
| 1724 | static enum drbd_state_rv | ||
| 1725 | conn_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 | |||
| 1756 | enum drbd_state_rv | 1724 | enum 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)); |
