aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_sock.c
diff options
context:
space:
mode:
authorDean Jenkins <Dean_Jenkins@mentor.com>2015-10-14 06:18:46 -0400
committerMarcel Holtmann <marcel@holtmann.org>2015-10-20 18:49:26 -0400
commit04ba72e6b24f1e0e2221fcd73f08782870473fa1 (patch)
treeb69e5367ad1922340388abaa96895963a0e6babe /net/bluetooth/l2cap_sock.c
parente7456437c15a2fd42cedd25c2b12b06876f285f0 (diff)
Bluetooth: Reorganize mutex lock in l2cap_sock_shutdown()
This commit reorganizes the mutex lock and is now only protecting l2cap_chan_close(). This is now consistent with other places where l2cap_chan_close() is called. If a conn connection exists, call mutex_lock(&conn->chan_lock) before calling l2cap_chan_close() to ensure other L2CAP protocol operations do not interfere. Note that the conn structure has to be protected from being freed as it is possible for the connection to be disconnected whilst the locks are not held. This solution allows the mutex lock to be used even when the connection has just been disconnected. This commit also reduces the scope of chan locking. The only place where chan locking is needed is the call to l2cap_chan_close(chan, 0) which if necessary closes the channel. Therefore, move the l2cap_chan_lock(chan) and l2cap_chan_lock(chan) locking calls to around l2cap_chan_close(chan, 0). This allows __l2cap_wait_ack(sk, chan) to be called with no chan locks being held so L2CAP messaging over the ACL link can be done unimpaired. Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com> Signed-off-by: Harish Jenny K N <harish_kandiga@mentor.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap_sock.c')
-rw-r--r--net/bluetooth/l2cap_sock.c44
1 files changed, 27 insertions, 17 deletions
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index ca5598d6a201..d06fb54082aa 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1111,6 +1111,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
1111 if (!sk) 1111 if (!sk)
1112 return 0; 1112 return 0;
1113 1113
1114 lock_sock(sk);
1115
1114 if (sk->sk_shutdown) 1116 if (sk->sk_shutdown)
1115 goto shutdown_already; 1117 goto shutdown_already;
1116 1118
@@ -1122,25 +1124,37 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
1122 chan = l2cap_pi(sk)->chan; 1124 chan = l2cap_pi(sk)->chan;
1123 /* prevent chan structure from being freed whilst unlocked */ 1125 /* prevent chan structure from being freed whilst unlocked */
1124 l2cap_chan_hold(chan); 1126 l2cap_chan_hold(chan);
1125 conn = chan->conn;
1126 1127
1127 BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); 1128 BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
1128 1129
1129 if (conn)
1130 mutex_lock(&conn->chan_lock);
1131
1132 l2cap_chan_lock(chan);
1133 lock_sock(sk);
1134
1135 if (chan->mode == L2CAP_MODE_ERTM && 1130 if (chan->mode == L2CAP_MODE_ERTM &&
1136 chan->unacked_frames > 0 && 1131 chan->unacked_frames > 0 &&
1137 chan->state == BT_CONNECTED) 1132 chan->state == BT_CONNECTED)
1138 err = __l2cap_wait_ack(sk, chan); 1133 err = __l2cap_wait_ack(sk, chan);
1139 1134
1140 sk->sk_shutdown = SHUTDOWN_MASK; 1135 sk->sk_shutdown = SHUTDOWN_MASK;
1141
1142 release_sock(sk); 1136 release_sock(sk);
1137
1138 l2cap_chan_lock(chan);
1139 conn = chan->conn;
1140 if (conn)
1141 /* prevent conn structure from being freed */
1142 l2cap_conn_get(conn);
1143 l2cap_chan_unlock(chan);
1144
1145 if (conn)
1146 /* mutex lock must be taken before l2cap_chan_lock() */
1147 mutex_lock(&conn->chan_lock);
1148
1149 l2cap_chan_lock(chan);
1143 l2cap_chan_close(chan, 0); 1150 l2cap_chan_close(chan, 0);
1151 l2cap_chan_unlock(chan);
1152
1153 if (conn) {
1154 mutex_unlock(&conn->chan_lock);
1155 l2cap_conn_put(conn);
1156 }
1157
1144 lock_sock(sk); 1158 lock_sock(sk);
1145 1159
1146 if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && 1160 if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
@@ -1148,20 +1162,16 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
1148 err = bt_sock_wait_state(sk, BT_CLOSED, 1162 err = bt_sock_wait_state(sk, BT_CLOSED,
1149 sk->sk_lingertime); 1163 sk->sk_lingertime);
1150 1164
1165 l2cap_chan_put(chan);
1166 sock_put(sk);
1167
1168shutdown_already:
1151 if (!err && sk->sk_err) 1169 if (!err && sk->sk_err)
1152 err = -sk->sk_err; 1170 err = -sk->sk_err;
1153 1171
1154 release_sock(sk); 1172 release_sock(sk);
1155 l2cap_chan_unlock(chan);
1156
1157 if (conn)
1158 mutex_unlock(&conn->chan_lock);
1159 1173
1160 l2cap_chan_put(chan); 1174 BT_DBG("Sock shutdown complete err: %d", err);
1161 sock_put(sk);
1162
1163shutdown_already:
1164 BT_DBG("err: %d", err);
1165 1175
1166 return err; 1176 return err;
1167} 1177}